mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-06 14:44:26 +00:00
Merge m-c to autoland. a=merge
--HG-- extra : rebase_source : 0de29cc9f544d8882d3e8c13572d3c4b98ba3c26
This commit is contained in:
commit
187beffa39
@ -521,34 +521,6 @@ DocManager::CreateDocOrRootAccessible(nsIDocument* aDocument)
|
||||
docAcc->FireDelayedEvent(nsIAccessibleEvent::EVENT_REORDER,
|
||||
ApplicationAcc());
|
||||
|
||||
if (IPCAccessibilityActive()) {
|
||||
nsIDocShell* docShell = aDocument->GetDocShell();
|
||||
if (docShell) {
|
||||
nsCOMPtr<nsITabChild> tabChild = docShell->GetTabChild();
|
||||
|
||||
// XXX We may need to handle the case that we don't have a tab child
|
||||
// differently. It may be that this will cause us to fail to notify
|
||||
// the parent process about important accessible documents.
|
||||
if (tabChild) {
|
||||
DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
|
||||
docAcc->SetIPCDoc(ipcDoc);
|
||||
|
||||
#if defined(XP_WIN)
|
||||
IAccessibleHolder holder(CreateHolderFromAccessible(docAcc));
|
||||
#endif
|
||||
|
||||
static_cast<TabChild*>(tabChild.get())->
|
||||
SendPDocAccessibleConstructor(ipcDoc, nullptr, 0,
|
||||
#if defined(XP_WIN)
|
||||
AccessibleWrap::GetChildIDFor(docAcc),
|
||||
holder
|
||||
#else
|
||||
0, 0
|
||||
#endif
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
parentDocAcc->BindChildDocument(docAcc);
|
||||
}
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/dom/DocumentType.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
||||
@ -1460,8 +1461,25 @@ DocAccessible::NotifyOfLoading(bool aIsReloading)
|
||||
void
|
||||
DocAccessible::DoInitialUpdate()
|
||||
{
|
||||
if (nsCoreUtils::IsTabDocument(mDocumentNode))
|
||||
if (nsCoreUtils::IsTabDocument(mDocumentNode)) {
|
||||
mDocFlags |= eTabDocument;
|
||||
if (IPCAccessibilityActive()) {
|
||||
nsIDocShell* docShell = mDocumentNode->GetDocShell();
|
||||
if (RefPtr<dom::TabChild> tabChild = dom::TabChild::GetFrom(docShell)) {
|
||||
DocAccessibleChild* ipcDoc = new DocAccessibleChild(this);
|
||||
SetIPCDoc(ipcDoc);
|
||||
|
||||
#if defined(XP_WIN)
|
||||
IAccessibleHolder holder(CreateHolderFromAccessible(this));
|
||||
int32_t childID = AccessibleWrap::GetChildIDFor(this);
|
||||
#else
|
||||
int32_t holder = 0, childID = 0;
|
||||
#endif
|
||||
tabChild->SendPDocAccessibleConstructor(ipcDoc, nullptr, 0, childID,
|
||||
holder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mLoadState |= eTreeConstructed;
|
||||
|
||||
|
@ -872,6 +872,12 @@ function _loadURIWithFlags(browser, uri, params) {
|
||||
referrer, referrerPolicy,
|
||||
postData, null, null);
|
||||
} else {
|
||||
// Check if the current browser is allowed to unload.
|
||||
let {permitUnload, timedOut} = browser.permitUnload();
|
||||
if (!timedOut && !permitUnload) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (postData) {
|
||||
postData = NetUtil.readInputStreamToString(postData, postData.available());
|
||||
}
|
||||
@ -4360,7 +4366,7 @@ var XULBrowserWindow = {
|
||||
},
|
||||
|
||||
// Check whether this URI should load in the current process
|
||||
shouldLoadURI(aDocShell, aURI, aReferrer) {
|
||||
shouldLoadURI(aDocShell, aURI, aReferrer, aTriggeringPrincipal) {
|
||||
if (!gMultiProcessBrowser)
|
||||
return true;
|
||||
|
||||
@ -4374,7 +4380,7 @@ var XULBrowserWindow = {
|
||||
return true;
|
||||
|
||||
if (!E10SUtils.shouldLoadURI(aDocShell, aURI, aReferrer)) {
|
||||
E10SUtils.redirectLoad(aDocShell, aURI, aReferrer);
|
||||
E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -704,9 +704,9 @@ var WebBrowserChrome = {
|
||||
},
|
||||
|
||||
// Check whether this URI should load in the current process
|
||||
shouldLoadURI(aDocShell, aURI, aReferrer) {
|
||||
shouldLoadURI(aDocShell, aURI, aReferrer, aTriggeringPrincipal) {
|
||||
if (!E10SUtils.shouldLoadURI(aDocShell, aURI, aReferrer)) {
|
||||
E10SUtils.redirectLoad(aDocShell, aURI, aReferrer);
|
||||
E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -718,8 +718,8 @@ var WebBrowserChrome = {
|
||||
},
|
||||
|
||||
// Try to reload the currently active or currently loading page in a new process.
|
||||
reloadInFreshProcess(aDocShell, aURI, aReferrer) {
|
||||
E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, true);
|
||||
reloadInFreshProcess(aDocShell, aURI, aReferrer, aTriggeringPrincipal) {
|
||||
E10SUtils.redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, true);
|
||||
return true;
|
||||
},
|
||||
|
||||
|
@ -135,6 +135,9 @@ support-files =
|
||||
!/toolkit/mozapps/extensions/test/xpinstall/restartless.xpi
|
||||
!/toolkit/mozapps/extensions/test/xpinstall/theme.xpi
|
||||
!/toolkit/mozapps/extensions/test/xpinstall/slowinstall.sjs
|
||||
file_about_child.html
|
||||
file_about_parent.html
|
||||
file_register_about_page.js
|
||||
|
||||
[browser_aboutAccounts.js]
|
||||
skip-if = os == "linux" # Bug 958026
|
||||
@ -482,6 +485,7 @@ tags = mcb
|
||||
[browser_addCertException.js]
|
||||
[browser_bug1045809.js]
|
||||
tags = mcb
|
||||
[browser_e10s_about_page_triggeringprincipal.js]
|
||||
[browser_e10s_switchbrowser.js]
|
||||
[browser_e10s_about_process.js]
|
||||
[browser_e10s_chrome_process.js]
|
||||
|
@ -0,0 +1,44 @@
|
||||
"use strict";
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.ppmm.broadcastAsyncMessage("AboutPrincipalTest:Unregister");
|
||||
BrowserTestUtils.waitForMessage(Services.ppmm, "AboutPrincipalTest:Unregistered").then(
|
||||
Services.ppmm.removeDelayedProcessScript(
|
||||
"chrome://mochitests/content/browser/browser/base/content/test/general/file_register_about_page.js"
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function* test_principal() {
|
||||
Services.ppmm.loadProcessScript(
|
||||
"chrome://mochitests/content/browser/browser/base/content/test/general/file_register_about_page.js",
|
||||
true
|
||||
);
|
||||
|
||||
yield BrowserTestUtils.withNewTab("about:test-about-principal-parent", function*(browser) {
|
||||
let loadPromise = BrowserTestUtils.browserLoaded(browser, false, "about:test-about-principal-child");
|
||||
let myLink = browser.contentDocument.getElementById("aboutchildprincipal");
|
||||
myLink.click();
|
||||
yield loadPromise;
|
||||
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() {
|
||||
let channel = content.document.docShell.currentDocumentChannel;
|
||||
is(channel.originalURI.asciiSpec,
|
||||
"about:test-about-principal-child",
|
||||
"sanity check - make sure we test the principal for the correct URI");
|
||||
|
||||
let triggeringPrincipal = channel.loadInfo.triggeringPrincipal;
|
||||
ok(Services.scriptSecurityManager.isSystemPrincipal(triggeringPrincipal),
|
||||
"loading about: from privileged page must have a triggering of System");
|
||||
|
||||
let contentPolicyType = channel.loadInfo.externalContentPolicyType;
|
||||
is(contentPolicyType, Ci.nsIContentPolicy.TYPE_DOCUMENT,
|
||||
"sanity check - loading a top level document");
|
||||
|
||||
let loadingPrincipal = channel.loadInfo.loadingPrincipal;
|
||||
is(loadingPrincipal, null,
|
||||
"sanity check - load of TYPE_DOCUMENT must have a null loadingPrincipal");
|
||||
});
|
||||
});
|
||||
});
|
10
browser/base/content/test/general/file_about_child.html
Normal file
10
browser/base/content/test/general/file_about_child.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1329032</title>
|
||||
</head>
|
||||
<body>
|
||||
Just an about page that only loads in the child!
|
||||
</body>
|
||||
</html>
|
10
browser/base/content/test/general/file_about_parent.html
Normal file
10
browser/base/content/test/general/file_about_parent.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1329032</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="about:test-about-principal-child" id="aboutchildprincipal">about:test-about-principal-child</a>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,81 @@
|
||||
const { interfaces: Ci, results: Cr, manager: Cm, utils: Cu } = Components;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
function AboutPage(chromeURL, aboutHost, classID, description, uriFlags) {
|
||||
this.chromeURL = chromeURL;
|
||||
this.aboutHost = aboutHost;
|
||||
this.classID = Components.ID(classID);
|
||||
this.description = description;
|
||||
this.uriFlags = uriFlags;
|
||||
}
|
||||
|
||||
AboutPage.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
|
||||
getURIFlags(aURI) { // eslint-disable-line no-unused-vars
|
||||
return this.uriFlags;
|
||||
},
|
||||
|
||||
newChannel(aURI, aLoadInfo) {
|
||||
let newURI = Services.io.newURI(this.chromeURL);
|
||||
let channel = Services.io.newChannelFromURIWithLoadInfo(newURI,
|
||||
aLoadInfo);
|
||||
channel.originalURI = aURI;
|
||||
|
||||
if (this.uriFlags & Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT) {
|
||||
channel.owner = null;
|
||||
}
|
||||
return channel;
|
||||
},
|
||||
|
||||
createInstance(outer, iid) {
|
||||
if (outer !== null) {
|
||||
throw Cr.NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
return this.QueryInterface(iid);
|
||||
},
|
||||
|
||||
register() {
|
||||
Cm.QueryInterface(Ci.nsIComponentRegistrar).registerFactory(
|
||||
this.classID, this.description,
|
||||
"@mozilla.org/network/protocol/about;1?what=" + this.aboutHost, this);
|
||||
},
|
||||
|
||||
unregister() {
|
||||
Cm.QueryInterface(Ci.nsIComponentRegistrar).unregisterFactory(
|
||||
this.classID, this);
|
||||
}
|
||||
};
|
||||
|
||||
/* exported AboutPrincipalTest */
|
||||
var AboutPrincipalTest = {};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(AboutPrincipalTest, "aboutChild", () =>
|
||||
new AboutPage("chrome://mochitests/content/browser/browser/base/content/test/general/file_about_child.html",
|
||||
"test-about-principal-child",
|
||||
"{df6cbd19-c95b-4011-874b-315347c0832c}",
|
||||
"About Principal Child Test",
|
||||
Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD |
|
||||
Ci.nsIAboutModule.ALLOW_SCRIPT)
|
||||
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(AboutPrincipalTest, "aboutParent", () =>
|
||||
new AboutPage("chrome://mochitests/content/browser/browser/base/content/test/general/file_about_parent.html",
|
||||
"test-about-principal-parent",
|
||||
"{15e1a03d-9f94-4352-bfb8-94216140d3ab}",
|
||||
"About Principal Parent Test",
|
||||
Ci.nsIAboutModule.ALLOW_SCRIPT)
|
||||
);
|
||||
|
||||
AboutPrincipalTest.aboutParent.register();
|
||||
AboutPrincipalTest.aboutChild.register();
|
||||
|
||||
function onUnregisterMessage() {
|
||||
removeMessageListener("AboutPrincipalTest:Unregister", onUnregisterMessage);
|
||||
AboutPrincipalTest.aboutParent.unregister();
|
||||
AboutPrincipalTest.aboutChild.unregister();
|
||||
sendAsyncMessage("AboutPrincipalTest:Unregistered");
|
||||
}
|
||||
|
||||
addMessageListener("AboutPrincipalTest:Unregister", onUnregisterMessage);
|
@ -204,6 +204,9 @@ ContentRestoreInternal.prototype = {
|
||||
: Ci.nsIHttpChannel.REFERRER_POLICY_UNSET);
|
||||
let postData = loadArguments.postData ?
|
||||
Utils.makeInputStream(loadArguments.postData) : null;
|
||||
let triggeringPrincipal = loadArguments.triggeringPrincipal
|
||||
? Utils.deserializePrincipal(loadArguments.triggeringPrincipal)
|
||||
: null;
|
||||
|
||||
if (loadArguments.userContextId) {
|
||||
webNavigation.setOriginAttributesBeforeLoading({ userContextId: loadArguments.userContextId });
|
||||
@ -211,7 +214,7 @@ ContentRestoreInternal.prototype = {
|
||||
|
||||
webNavigation.loadURIWithOptions(loadArguments.uri, loadArguments.flags,
|
||||
referrer, referrerPolicy, postData,
|
||||
null, null);
|
||||
null, null, triggeringPrincipal);
|
||||
} else if (tabData.userTypedValue && tabData.userTypedClear) {
|
||||
// If the user typed a URL into the URL bar and hit enter right before
|
||||
// we crashed, we want to start loading that page again. A non-zero
|
||||
|
@ -13,6 +13,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "useRemoteWebExtensions",
|
||||
"extensions.webextensions.remote", false);
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Utils",
|
||||
"resource://gre/modules/sessionstore/Utils.jsm");
|
||||
|
||||
function getAboutModule(aURL) {
|
||||
// Needs to match NS_GetAboutModuleName
|
||||
@ -163,7 +165,7 @@ this.E10SUtils = {
|
||||
return this.shouldLoadURIInThisProcess(aURI);
|
||||
},
|
||||
|
||||
redirectLoad(aDocShell, aURI, aReferrer, aFreshProcess) {
|
||||
redirectLoad(aDocShell, aURI, aReferrer, aTriggeringPrincipal, aFreshProcess) {
|
||||
// Retarget the load to the correct process
|
||||
let messageManager = aDocShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIContentFrameMessageManager);
|
||||
@ -174,6 +176,9 @@ this.E10SUtils = {
|
||||
uri: aURI.spec,
|
||||
flags: Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
|
||||
referrer: aReferrer ? aReferrer.spec : null,
|
||||
triggeringPrincipal: aTriggeringPrincipal
|
||||
? Utils.serializePrincipal(aTriggeringPrincipal)
|
||||
: null,
|
||||
reloadInFreshProcess: !!aFreshProcess,
|
||||
},
|
||||
historyIndex: sessionHistory.requestedIndex,
|
||||
|
@ -8,6 +8,7 @@ const { Ci, Cu, Cr } = require("chrome");
|
||||
const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const Services = require("Services");
|
||||
const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
|
||||
const { Utils } = require("resource://gre/modules/sessionstore/Utils.jsm");
|
||||
|
||||
function readInputStreamToString(stream) {
|
||||
return NetUtil.readInputStreamToString(stream, stream.available());
|
||||
@ -61,11 +62,11 @@ BrowserElementWebNavigation.prototype = {
|
||||
// No equivalent in the current BrowserElement API
|
||||
this.loadURIWithOptions(uri, flags, referrer,
|
||||
Ci.nsIHttpChannel.REFERRER_POLICY_UNSET,
|
||||
postData, headers, null);
|
||||
postData, headers, null, null);
|
||||
},
|
||||
|
||||
loadURIWithOptions(uri, flags, referrer, referrerPolicy, postData, headers,
|
||||
baseURI) {
|
||||
baseURI, triggeringPrincipal) {
|
||||
// No equivalent in the current BrowserElement API
|
||||
this._sendMessage("WebNavigation:LoadURI", {
|
||||
uri,
|
||||
@ -75,6 +76,9 @@ BrowserElementWebNavigation.prototype = {
|
||||
postData: postData ? readInputStreamToString(postData) : null,
|
||||
headers: headers ? readInputStreamToString(headers) : null,
|
||||
baseURI: baseURI ? baseURI.spec : null,
|
||||
triggeringPrincipal: triggeringPrincipal
|
||||
? Utils.serializePrincipal(triggeringPrincipal)
|
||||
: null,
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -4698,7 +4698,7 @@ nsDocShell::LoadURI(const char16_t* aURI,
|
||||
{
|
||||
return LoadURIWithOptions(aURI, aLoadFlags, aReferringURI,
|
||||
mozilla::net::RP_Unset, aPostStream,
|
||||
aHeaderStream, nullptr);
|
||||
aHeaderStream, nullptr, nullptr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -4708,7 +4708,8 @@ nsDocShell::LoadURIWithOptions(const char16_t* aURI,
|
||||
uint32_t aReferrerPolicy,
|
||||
nsIInputStream* aPostStream,
|
||||
nsIInputStream* aHeaderStream,
|
||||
nsIURI* aBaseURI)
|
||||
nsIURI* aBaseURI,
|
||||
nsIPrincipal* aTriggeringPrincipal)
|
||||
{
|
||||
NS_ASSERTION((aLoadFlags & 0xf) == 0, "Unexpected flags");
|
||||
|
||||
@ -4824,6 +4825,7 @@ nsDocShell::LoadURIWithOptions(const char16_t* aURI,
|
||||
loadInfo->SetReferrerPolicy(aReferrerPolicy);
|
||||
loadInfo->SetHeadersStream(aHeaderStream);
|
||||
loadInfo->SetBaseURI(aBaseURI);
|
||||
loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
|
||||
|
||||
if (fixupInfo) {
|
||||
nsAutoString searchProvider, keyword;
|
||||
@ -10467,25 +10469,6 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the webbrowser chrome wants the load to proceed; this can be
|
||||
// used to cancel attempts to load URIs in the wrong process.
|
||||
nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
|
||||
if (browserChrome3) {
|
||||
// In case this is a remote newtab load, set aURI to aOriginalURI (newtab).
|
||||
// This ensures that the verifySignedContent flag is set on loadInfo in
|
||||
// DoURILoad.
|
||||
nsIURI* uriForShouldLoadCheck = aURI;
|
||||
if (IsAboutNewtab(aOriginalURI)) {
|
||||
uriForShouldLoadCheck = aOriginalURI;
|
||||
}
|
||||
bool shouldLoad;
|
||||
rv = browserChrome3->ShouldLoadURI(this, uriForShouldLoadCheck, aReferrer,
|
||||
&shouldLoad);
|
||||
if (NS_SUCCEEDED(rv) && !shouldLoad) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// mContentViewer->PermitUnload can destroy |this| docShell, which
|
||||
// causes the next call of CanSavePresentation to crash.
|
||||
// Hold onto |this| until we return, to prevent a crash from happening.
|
||||
@ -10524,6 +10507,25 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
||||
mTiming->NotifyUnloadAccepted(mCurrentURI);
|
||||
}
|
||||
|
||||
// Check if the webbrowser chrome wants the load to proceed; this can be
|
||||
// used to cancel attempts to load URIs in the wrong process.
|
||||
nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
|
||||
if (browserChrome3) {
|
||||
// In case this is a remote newtab load, set aURI to aOriginalURI (newtab).
|
||||
// This ensures that the verifySignedContent flag is set on loadInfo in
|
||||
// DoURILoad.
|
||||
nsIURI* uriForShouldLoadCheck = aURI;
|
||||
if (IsAboutNewtab(aOriginalURI)) {
|
||||
uriForShouldLoadCheck = aOriginalURI;
|
||||
}
|
||||
bool shouldLoad;
|
||||
rv = browserChrome3->ShouldLoadURI(this, uriForShouldLoadCheck, aReferrer,
|
||||
aTriggeringPrincipal, &shouldLoad);
|
||||
if (NS_SUCCEEDED(rv) && !shouldLoad) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (browserChrome3 && aCheckForPrerender) {
|
||||
nsCOMPtr<nsIRunnable> ev =
|
||||
new InternalLoadEvent(this, aURI, aOriginalURI, aLoadReplace,
|
||||
|
@ -9,6 +9,7 @@ interface nsIDOMDocument;
|
||||
interface nsIInputStream;
|
||||
interface nsISHistory;
|
||||
interface nsIURI;
|
||||
interface nsIPrincipal;
|
||||
|
||||
/**
|
||||
* The nsIWebNavigation interface defines an interface for navigating the web.
|
||||
@ -282,14 +283,20 @@ interface nsIWebNavigation : nsISupports
|
||||
* that at present this argument is only used with view-source aURIs
|
||||
* and cannot be used to resolve aURI.
|
||||
* This parameter is optional and may be null.
|
||||
* @param aTriggeringPrincipal
|
||||
* The principal that initiated the load of aURI. If omitted docShell
|
||||
* tries to create a codeBasePrincipal from aReferrer if not null. If
|
||||
* aReferrer is also null docShell peforms a load using the
|
||||
* SystemPrincipal as the triggeringPrincipal.
|
||||
*/
|
||||
void loadURIWithOptions(in wstring aURI,
|
||||
in unsigned long aLoadFlags,
|
||||
in nsIURI aReferrer,
|
||||
in unsigned long aReferrerPolicy,
|
||||
in nsIInputStream aPostData,
|
||||
in nsIInputStream aHeaders,
|
||||
in nsIURI aBaseURI);
|
||||
void loadURIWithOptions(in wstring aURI,
|
||||
in unsigned long aLoadFlags,
|
||||
in nsIURI aReferrer,
|
||||
in unsigned long aReferrerPolicy,
|
||||
in nsIInputStream aPostData,
|
||||
in nsIInputStream aHeaders,
|
||||
in nsIURI aBaseURI,
|
||||
[optional] in nsIPrincipal aTriggeringPrincipal);
|
||||
|
||||
/**
|
||||
* Tells the Object to reload the current page. There may be cases where the
|
||||
|
@ -1618,7 +1618,8 @@ nsSHistory::LoadURIWithOptions(const char16_t* aURI,
|
||||
uint32_t aReferrerPolicy,
|
||||
nsIInputStream* aPostStream,
|
||||
nsIInputStream* aExtraHeaderStream,
|
||||
nsIURI* aBaseURI)
|
||||
nsIURI* aBaseURI,
|
||||
nsIPrincipal* aTriggeringPrincipal)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ Attr::GetBaseURI(bool aTryUseXHRDocBaseURI) const
|
||||
|
||||
void
|
||||
Attr::GetTextContentInternal(nsAString& aTextContent,
|
||||
ErrorResult& aError)
|
||||
OOMReporter& aError)
|
||||
{
|
||||
OwnerDoc()->WarnOnceAbout(nsIDocument::eTextContent);
|
||||
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
// nsIDOMNode interface
|
||||
NS_FORWARD_NSIDOMNODE_TO_NSINODE
|
||||
virtual void GetTextContentInternal(nsAString& aTextContent,
|
||||
ErrorResult& aError) override;
|
||||
OOMReporter& aError) override;
|
||||
virtual void SetTextContentInternal(const nsAString& aTextContent,
|
||||
ErrorResult& aError) override;
|
||||
virtual void GetNodeValueInternal(nsAString& aNodeValue) override;
|
||||
|
@ -14,24 +14,34 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* static */ void
|
||||
/* static */ nsresult
|
||||
DocGroup::GetKey(nsIPrincipal* aPrincipal, nsACString& aKey)
|
||||
{
|
||||
aKey.Truncate();
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_OK; // aKey is the empty string
|
||||
}
|
||||
|
||||
// GetBaseDomain works fine if |uri| is null, but it outputs a warning
|
||||
// which ends up cluttering the logs.
|
||||
if (NS_SUCCEEDED(rv) && uri) {
|
||||
nsCOMPtr<nsIEffectiveTLDService> tldService =
|
||||
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
||||
if (tldService) {
|
||||
rv = tldService->GetBaseDomain(uri, 0, aKey);
|
||||
if (NS_FAILED(rv)) {
|
||||
aKey.Truncate();
|
||||
}
|
||||
}
|
||||
if (!uri) {
|
||||
return NS_OK; // aKey is the empty string
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEffectiveTLDService> tldService =
|
||||
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
||||
if (!tldService) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = tldService->GetBaseDomain(uri, 0, aKey);
|
||||
if (NS_FAILED(rv)) {
|
||||
aKey.Truncate();
|
||||
}
|
||||
|
||||
return NS_OK; // aKey may be the empty string
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -44,7 +44,12 @@ public:
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
static void GetKey(nsIPrincipal* aPrincipal, nsACString& aString);
|
||||
// Returns NS_ERROR_FAILURE and sets |aString| to an empty string if the TLD
|
||||
// service isn't available. Returns NS_OK on success, but may still set
|
||||
// |aString| may still be set to an empty string.
|
||||
static MOZ_MUST_USE nsresult
|
||||
GetKey(nsIPrincipal* aPrincipal, nsACString& aString);
|
||||
|
||||
bool MatchesKey(const nsACString& aKey)
|
||||
{
|
||||
return aKey == mKey;
|
||||
|
@ -1161,10 +1161,10 @@ FragmentOrElement::RemoveChildAt(uint32_t aIndex, bool aNotify)
|
||||
|
||||
void
|
||||
FragmentOrElement::GetTextContentInternal(nsAString& aTextContent,
|
||||
ErrorResult& aError)
|
||||
OOMReporter& aError)
|
||||
{
|
||||
if (!nsContentUtils::GetNodeTextContent(this, true, aTextContent, fallible)) {
|
||||
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
aError.ReportOOM();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ public:
|
||||
bool aNotify) override;
|
||||
virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
|
||||
virtual void GetTextContentInternal(nsAString& aTextContent,
|
||||
mozilla::ErrorResult& aError) override;
|
||||
mozilla::OOMReporter& aError) override;
|
||||
virtual void SetTextContentInternal(const nsAString& aTextContent,
|
||||
mozilla::ErrorResult& aError) override;
|
||||
|
||||
|
@ -18,6 +18,7 @@ Timeout::Timeout()
|
||||
: mCleared(false),
|
||||
mRunning(false),
|
||||
mIsInterval(false),
|
||||
mIsTracking(false),
|
||||
mReason(Reason::eTimeoutOrInterval),
|
||||
mTimeoutId(0),
|
||||
mInterval(0),
|
||||
|
@ -73,6 +73,9 @@ public:
|
||||
// True if this is a repeating/interval timer
|
||||
bool mIsInterval;
|
||||
|
||||
// True if this is a timeout coming from a tracking script
|
||||
bool mIsTracking;
|
||||
|
||||
Reason mReason;
|
||||
|
||||
// Returned as value of setTimeout()
|
||||
|
@ -20,18 +20,25 @@ static int32_t gRunningTimeoutDepth = 0;
|
||||
// The default shortest interval/timeout we permit
|
||||
#define DEFAULT_MIN_TIMEOUT_VALUE 4 // 4ms
|
||||
#define DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE 1000 // 1000ms
|
||||
static int32_t gMinTimeoutValue;
|
||||
static int32_t gMinBackgroundTimeoutValue;
|
||||
#define DEFAULT_MIN_TRACKING_TIMEOUT_VALUE 4 // 4ms
|
||||
#define DEFAULT_MIN_TRACKING_BACKGROUND_TIMEOUT_VALUE 1000 // 1000ms
|
||||
static int32_t gMinTimeoutValue = 0;
|
||||
static int32_t gMinBackgroundTimeoutValue = 0;
|
||||
static int32_t gMinTrackingTimeoutValue = 0;
|
||||
static int32_t gMinTrackingBackgroundTimeoutValue = 0;
|
||||
int32_t
|
||||
TimeoutManager::DOMMinTimeoutValue() const {
|
||||
TimeoutManager::DOMMinTimeoutValue(bool aIsTracking) const {
|
||||
// First apply any back pressure delay that might be in effect.
|
||||
int32_t value = std::max(mBackPressureDelayMS, 0);
|
||||
// Don't use the background timeout value when there are audio contexts
|
||||
// present, so that background audio can keep running smoothly. (bug 1181073)
|
||||
bool isBackground = !mWindow.AsInner()->HasAudioContexts() &&
|
||||
mWindow.IsBackgroundInternal();
|
||||
return
|
||||
std::max(isBackground ? gMinBackgroundTimeoutValue : gMinTimeoutValue, value);
|
||||
auto minValue = aIsTracking ? (isBackground ? gMinTrackingBackgroundTimeoutValue
|
||||
: gMinTrackingTimeoutValue)
|
||||
: (isBackground ? gMinBackgroundTimeoutValue
|
||||
: gMinTimeoutValue);
|
||||
return std::max(minValue, value);
|
||||
}
|
||||
|
||||
#define TRACKING_SEPARATE_TIMEOUT_BUCKETING_STRATEGY 0 // Consider all timeouts coming from tracking scripts as tracking
|
||||
@ -120,6 +127,12 @@ TimeoutManager::Initialize()
|
||||
Preferences::AddIntVarCache(&gMinBackgroundTimeoutValue,
|
||||
"dom.min_background_timeout_value",
|
||||
DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE);
|
||||
Preferences::AddIntVarCache(&gMinTrackingTimeoutValue,
|
||||
"dom.min_tracking_timeout_value",
|
||||
DEFAULT_MIN_TRACKING_TIMEOUT_VALUE);
|
||||
Preferences::AddIntVarCache(&gMinTrackingBackgroundTimeoutValue,
|
||||
"dom.min_tracking_background_timeout_value",
|
||||
DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE);
|
||||
Preferences::AddIntVarCache(&gTimeoutBucketingStrategy,
|
||||
"dom.timeout_bucketing_strategy",
|
||||
TRACKING_SEPARATE_TIMEOUT_BUCKETING_STRATEGY);
|
||||
@ -167,6 +180,27 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
|
||||
timeout->mScriptHandler = aHandler;
|
||||
timeout->mReason = aReason;
|
||||
|
||||
switch (gTimeoutBucketingStrategy) {
|
||||
default:
|
||||
case TRACKING_SEPARATE_TIMEOUT_BUCKETING_STRATEGY: {
|
||||
const char* filename = nullptr;
|
||||
uint32_t dummyLine = 0, dummyColumn = 0;
|
||||
aHandler->GetLocation(&filename, &dummyLine, &dummyColumn);
|
||||
timeout->mIsTracking = doc->IsScriptTracking(nsDependentCString(filename));
|
||||
break;
|
||||
}
|
||||
case ALL_NORMAL_TIMEOUT_BUCKETING_STRATEGY:
|
||||
// timeout->mIsTracking is already false!
|
||||
MOZ_DIAGNOSTIC_ASSERT(!timeout->mIsTracking);
|
||||
break;
|
||||
case ALTERNATE_TIMEOUT_BUCKETING_STRATEGY:
|
||||
timeout->mIsTracking = (mTimeoutIdCounter % 2) == 0;
|
||||
break;
|
||||
case RANDOM_TIMEOUT_BUCKETING_STRATEGY:
|
||||
timeout->mIsTracking = (rand() % 2) == 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// Now clamp the actual interval we will use for the timer based on
|
||||
uint32_t nestingLevel = sNestingLevel + 1;
|
||||
uint32_t realInterval = interval;
|
||||
@ -174,7 +208,8 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
|
||||
mBackPressureDelayMS > 0 || mWindow.IsBackgroundInternal()) {
|
||||
// Don't allow timeouts less than DOMMinTimeoutValue() from
|
||||
// now...
|
||||
realInterval = std::max(realInterval, uint32_t(DOMMinTimeoutValue()));
|
||||
realInterval = std::max(realInterval,
|
||||
uint32_t(DOMMinTimeoutValue(timeout->mIsTracking)));
|
||||
}
|
||||
|
||||
timeout->mWindow = &mWindow;
|
||||
@ -229,30 +264,9 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
|
||||
}
|
||||
}
|
||||
|
||||
bool isTracking = false;
|
||||
switch (gTimeoutBucketingStrategy) {
|
||||
default:
|
||||
case TRACKING_SEPARATE_TIMEOUT_BUCKETING_STRATEGY: {
|
||||
const char* filename = nullptr;
|
||||
uint32_t dummyLine = 0, dummyColumn = 0;
|
||||
aHandler->GetLocation(&filename, &dummyLine, &dummyColumn);
|
||||
isTracking = doc->IsScriptTracking(nsDependentCString(filename));
|
||||
break;
|
||||
}
|
||||
case ALL_NORMAL_TIMEOUT_BUCKETING_STRATEGY:
|
||||
// isTracking is already false!
|
||||
break;
|
||||
case ALTERNATE_TIMEOUT_BUCKETING_STRATEGY:
|
||||
isTracking = (mTimeoutIdCounter % 2) == 0;
|
||||
break;
|
||||
case RANDOM_TIMEOUT_BUCKETING_STRATEGY:
|
||||
isTracking = (rand() % 2) == 0;
|
||||
break;
|
||||
}
|
||||
|
||||
Timeouts::SortBy sort(mWindow.IsFrozen() ? Timeouts::SortBy::TimeRemaining
|
||||
: Timeouts::SortBy::TimeWhen);
|
||||
if (isTracking) {
|
||||
if (timeout->mIsTracking) {
|
||||
mTrackingTimeouts.Insert(timeout, sort);
|
||||
} else {
|
||||
mNormalTimeouts.Insert(timeout, sort);
|
||||
@ -680,8 +694,9 @@ TimeoutManager::RescheduleTimeout(Timeout* aTimeout, const TimeStamp& now,
|
||||
// Compute time to next timeout for interval timer.
|
||||
// Make sure nextInterval is at least DOMMinTimeoutValue().
|
||||
TimeDuration nextInterval =
|
||||
TimeDuration::FromMilliseconds(std::max(aTimeout->mInterval,
|
||||
uint32_t(DOMMinTimeoutValue())));
|
||||
TimeDuration::FromMilliseconds(
|
||||
std::max(aTimeout->mInterval,
|
||||
uint32_t(DOMMinTimeoutValue(aTimeout->mIsTracking))));
|
||||
|
||||
// If we're running pending timeouts, set the next interval to be
|
||||
// relative to "now", and not to when the timeout that was pending
|
||||
@ -752,18 +767,17 @@ TimeoutManager::ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
auto minTimeout = DOMMinTimeoutValue();
|
||||
Timeouts::SortBy sortBy = mWindow.IsFrozen() ? Timeouts::SortBy::TimeRemaining
|
||||
: Timeouts::SortBy::TimeWhen;
|
||||
|
||||
nsCOMPtr<nsIEventTarget> queue = mWindow.EventTargetFor(TaskCategory::Timer);
|
||||
nsresult rv = mNormalTimeouts.ResetTimersForThrottleReduction(aPreviousThrottleDelayMS,
|
||||
minTimeout,
|
||||
*this,
|
||||
sortBy,
|
||||
queue);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mTrackingTimeouts.ResetTimersForThrottleReduction(aPreviousThrottleDelayMS,
|
||||
minTimeout,
|
||||
*this,
|
||||
sortBy,
|
||||
queue);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -773,7 +787,7 @@ TimeoutManager::ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS
|
||||
|
||||
nsresult
|
||||
TimeoutManager::Timeouts::ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS,
|
||||
int32_t aMinTimeoutValueMS,
|
||||
const TimeoutManager& aTimeoutManager,
|
||||
SortBy aSortBy,
|
||||
nsIEventTarget* aQueue)
|
||||
{
|
||||
@ -809,8 +823,10 @@ TimeoutManager::Timeouts::ResetTimersForThrottleReduction(int32_t aPreviousThrot
|
||||
// Compute the interval the timer should have had if it had not been set in a
|
||||
// background window
|
||||
TimeDuration interval =
|
||||
TimeDuration::FromMilliseconds(std::max(timeout->mInterval,
|
||||
uint32_t(aMinTimeoutValueMS)));
|
||||
TimeDuration::FromMilliseconds(
|
||||
std::max(timeout->mInterval,
|
||||
uint32_t(aTimeoutManager.
|
||||
DOMMinTimeoutValue(timeout->mIsTracking))));
|
||||
uint32_t oldIntervalMillisecs = 0;
|
||||
timeout->mTimer->GetDelay(&oldIntervalMillisecs);
|
||||
TimeDuration oldInterval = TimeDuration::FromMilliseconds(oldIntervalMillisecs);
|
||||
@ -1014,7 +1030,7 @@ TimeoutManager::Resume()
|
||||
if (aTimeout->When() > now) {
|
||||
remaining = static_cast<int32_t>((aTimeout->When() - now).ToMilliseconds());
|
||||
}
|
||||
uint32_t delay = std::max(remaining, DOMMinTimeoutValue());
|
||||
uint32_t delay = std::max(remaining, DOMMinTimeoutValue(aTimeout->mIsTracking));
|
||||
|
||||
aTimeout->mTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
if (!aTimeout->mTimer) {
|
||||
|
@ -67,7 +67,7 @@ public:
|
||||
// order to bound how many timers must be examined.
|
||||
nsresult ResetTimersForThrottleReduction();
|
||||
|
||||
int32_t DOMMinTimeoutValue() const;
|
||||
int32_t DOMMinTimeoutValue(bool aIsTracking) const;
|
||||
|
||||
// aTimeout is the timeout that we're about to start running. This function
|
||||
// returns the current timeout.
|
||||
@ -129,7 +129,7 @@ private:
|
||||
};
|
||||
void Insert(mozilla::dom::Timeout* aTimeout, SortBy aSortBy);
|
||||
nsresult ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS,
|
||||
int32_t aMinTimeoutValueMS,
|
||||
const TimeoutManager& aTimeoutManager,
|
||||
SortBy aSortBy,
|
||||
nsIEventTarget* aQueue);
|
||||
|
||||
|
@ -9776,9 +9776,13 @@ nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel)
|
||||
rv = aChannel->GetReferrer(getter_AddRefs(referrer));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
|
||||
nsCOMPtr<nsIPrincipal> triggeringPrincipal = loadInfo->TriggeringPrincipal();
|
||||
|
||||
// Actually perform the cross process load
|
||||
bool reloadSucceeded = false;
|
||||
rv = wbc3->ReloadInFreshProcess(docShell, uri, referrer, &reloadSucceeded);
|
||||
rv = wbc3->ReloadInFreshProcess(docShell, uri, referrer,
|
||||
triggeringPrincipal, &reloadSucceeded);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return reloadSucceeded;
|
||||
|
@ -2867,8 +2867,12 @@ nsIDocument::GetDocGroup() const
|
||||
// Sanity check that we have an up-to-date and accurate docgroup
|
||||
if (mDocGroup) {
|
||||
nsAutoCString docGroupKey;
|
||||
mozilla::dom::DocGroup::GetKey(NodePrincipal(), docGroupKey);
|
||||
MOZ_ASSERT(mDocGroup->MatchesKey(docGroupKey));
|
||||
|
||||
// GetKey() can fail, e.g. after the TLD service has shut down.
|
||||
nsresult rv = mozilla::dom::DocGroup::GetKey(NodePrincipal(), docGroupKey);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
MOZ_ASSERT(mDocGroup->MatchesKey(docGroupKey));
|
||||
}
|
||||
// XXX: Check that the TabGroup is correct as well!
|
||||
}
|
||||
#endif
|
||||
@ -4201,10 +4205,13 @@ nsDocument::SetStyleSheetApplicableState(StyleSheet* aSheet,
|
||||
}
|
||||
|
||||
if (!mSSApplicableStateNotificationPending) {
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
nsCOMPtr<nsIRunnable> notification = NewRunnableMethod(this,
|
||||
&nsDocument::NotifyStyleSheetApplicableStateChanged);
|
||||
mSSApplicableStateNotificationPending =
|
||||
NS_SUCCEEDED(NS_DispatchToCurrentThread(notification));
|
||||
NS_SUCCEEDED(
|
||||
Dispatch("nsDocument::NotifyStyleSheetApplicableStateChanged",
|
||||
TaskCategory::Other, notification.forget()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -4377,9 +4384,12 @@ nsDocument::SetScopeObject(nsIGlobalObject* aGlobal)
|
||||
// We should already have the principal, and now that we have been added to a
|
||||
// window, we should be able to join a DocGroup!
|
||||
nsAutoCString docGroupKey;
|
||||
mozilla::dom::DocGroup::GetKey(NodePrincipal(), docGroupKey);
|
||||
nsresult rv =
|
||||
mozilla::dom::DocGroup::GetKey(NodePrincipal(), docGroupKey);
|
||||
if (mDocGroup) {
|
||||
MOZ_RELEASE_ASSERT(mDocGroup->MatchesKey(docGroupKey));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
MOZ_RELEASE_ASSERT(mDocGroup->MatchesKey(docGroupKey));
|
||||
}
|
||||
} else {
|
||||
mDocGroup = tabgroup->AddDocument(docGroupKey, this);
|
||||
MOZ_ASSERT(mDocGroup);
|
||||
@ -6752,10 +6762,11 @@ nsDocument::NotifyPossibleTitleChange(bool aBoundTitleElement)
|
||||
if (mPendingTitleChangeEvent.IsPending())
|
||||
return;
|
||||
|
||||
RefPtr<nsRunnableMethod<nsDocument, void, false> > event =
|
||||
NewNonOwningRunnableMethod(this,
|
||||
&nsDocument::DoNotifyPossibleTitleChange);
|
||||
nsresult rv = NS_DispatchToCurrentThread(event);
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
RefPtr<nsRunnableMethod<nsDocument, void, false>> event =
|
||||
NewNonOwningRunnableMethod(this, &nsDocument::DoNotifyPossibleTitleChange);
|
||||
nsresult rv = Dispatch("nsDocument::DoNotifyPossibleTitleChange",
|
||||
TaskCategory::Other, do_AddRef(event));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mPendingTitleChangeEvent = event;
|
||||
}
|
||||
@ -8625,8 +8636,10 @@ private:
|
||||
void
|
||||
nsDocument::PostUnblockOnloadEvent()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
nsCOMPtr<nsIRunnable> evt = new nsUnblockOnloadEvent(this);
|
||||
nsresult rv = NS_DispatchToCurrentThread(evt);
|
||||
nsresult rv =
|
||||
Dispatch("nsUnblockOnloadEvent", TaskCategory::Other, evt.forget());
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Stabilize block count so we don't post more events while this one is up
|
||||
++mOnloadBlockCount;
|
||||
@ -9556,7 +9569,9 @@ nsDocument::UnsuppressEventHandlingAndFireEvents(nsIDocument::SuppressionType aW
|
||||
}
|
||||
|
||||
if (aFireEvents) {
|
||||
NS_DispatchToCurrentThread(new nsDelayedEventDispatcher(args.mDocs));
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
nsCOMPtr<nsIRunnable> ded = new nsDelayedEventDispatcher(args.mDocs);
|
||||
Dispatch("nsDelayedEventDispatcher", TaskCategory::Other, ded.forget());
|
||||
} else {
|
||||
FireOrClearDelayedEvents(args.mDocs, false);
|
||||
}
|
||||
@ -10580,7 +10595,13 @@ private:
|
||||
/* static */ void
|
||||
nsIDocument::AsyncExitFullscreen(nsIDocument* aDoc)
|
||||
{
|
||||
NS_DispatchToCurrentThread(new nsCallExitFullscreen(aDoc));
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
nsCOMPtr<nsIRunnable> exit = new nsCallExitFullscreen(aDoc);
|
||||
if (aDoc) {
|
||||
aDoc->Dispatch("nsCallExitFullscreen", TaskCategory::Other, exit.forget());
|
||||
} else {
|
||||
NS_DispatchToCurrentThread(exit.forget());
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -10850,8 +10871,9 @@ nsDocument::AsyncRequestFullScreen(UniquePtr<FullscreenRequest>&& aRequest)
|
||||
}
|
||||
|
||||
// Request full-screen asynchronously.
|
||||
nsCOMPtr<nsIRunnable> event(new nsCallRequestFullScreen(Move(aRequest)));
|
||||
NS_DispatchToCurrentThread(event);
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
nsCOMPtr<nsIRunnable> event = new nsCallRequestFullScreen(Move(aRequest));
|
||||
Dispatch("nsCallRequestFullScreen", TaskCategory::Other, event.forget());
|
||||
}
|
||||
|
||||
void
|
||||
@ -11725,8 +11747,9 @@ nsDocument::RequestPointerLock(Element* aElement, CallerType aCallerType)
|
||||
|
||||
bool userInputOrSystemCaller = EventStateManager::IsHandlingUserInput() ||
|
||||
aCallerType == CallerType::System;
|
||||
NS_DispatchToMainThread(new PointerLockRequest(aElement,
|
||||
userInputOrSystemCaller));
|
||||
nsCOMPtr<nsIRunnable> request =
|
||||
new PointerLockRequest(aElement, userInputOrSystemCaller);
|
||||
Dispatch("PointerLockRequest", TaskCategory::Other, request.forget());
|
||||
}
|
||||
|
||||
bool
|
||||
@ -12450,9 +12473,11 @@ nsDocument::UpdateIntersectionObservations()
|
||||
void
|
||||
nsDocument::ScheduleIntersectionObserverNotification()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> notification = NewRunnableMethod(this,
|
||||
&nsDocument::NotifyIntersectionObservers);
|
||||
NS_DispatchToCurrentThread(notification);
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
nsCOMPtr<nsIRunnable> notification =
|
||||
NewRunnableMethod(this, &nsDocument::NotifyIntersectionObservers);
|
||||
Dispatch("nsDocument::IntersectionObserverNotification", TaskCategory::Other,
|
||||
notification.forget());
|
||||
}
|
||||
|
||||
void
|
||||
@ -12734,9 +12759,11 @@ nsIDocument::RebuildUserFontSet()
|
||||
// which starts font loads, whose completion causes another style
|
||||
// change reflow).
|
||||
if (!mPostedFlushUserFontSet) {
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
nsCOMPtr<nsIRunnable> ev =
|
||||
NewRunnableMethod(this, &nsIDocument::HandleRebuildUserFontSet);
|
||||
if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
|
||||
if (NS_SUCCEEDED(Dispatch("nsIDocument::HandleRebuildUserFontSet",
|
||||
TaskCategory::Other, ev.forget()))) {
|
||||
mPostedFlushUserFontSet = true;
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ public:
|
||||
bool aNotify) override;
|
||||
virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) override;
|
||||
virtual void GetTextContentInternal(nsAString& aTextContent,
|
||||
mozilla::ErrorResult& aError) override
|
||||
mozilla::OOMReporter& aError) override
|
||||
{
|
||||
GetNodeValue(aTextContent);
|
||||
}
|
||||
|
@ -8604,7 +8604,8 @@ public:
|
||||
static nsresult
|
||||
PostCloseEvent(nsGlobalWindow* aWindow, bool aIndirect) {
|
||||
nsCOMPtr<nsIRunnable> ev = new nsCloseEvent(aWindow, aIndirect);
|
||||
nsresult rv = NS_DispatchToCurrentThread(ev);
|
||||
nsresult rv =
|
||||
aWindow->Dispatch("nsCloseEvent", TaskCategory::Other, ev.forget());
|
||||
if (NS_SUCCEEDED(rv))
|
||||
aWindow->MaybeForgiveSpamCount();
|
||||
return rv;
|
||||
@ -9083,7 +9084,8 @@ void
|
||||
nsGlobalWindow::NotifyWindowIDDestroyed(const char* aTopic)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable = new WindowDestroyedEvent(this, mWindowID, aTopic);
|
||||
nsresult rv = NS_DispatchToCurrentThread(runnable);
|
||||
nsresult rv =
|
||||
Dispatch("WindowDestroyedEvent", TaskCategory::Other, runnable.forget());
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mNotifiedIDDestroyed = true;
|
||||
}
|
||||
@ -10346,7 +10348,7 @@ nsGlobalWindow::DispatchAsyncHashchange(nsIURI *aOldURI, nsIURI *aNewURI)
|
||||
|
||||
nsCOMPtr<nsIRunnable> callback =
|
||||
new HashchangeCallback(oldWideSpec, newWideSpec, this);
|
||||
return NS_DispatchToMainThread(callback);
|
||||
return Dispatch("HashchangeCallback", TaskCategory::Other, callback.forget());
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -10950,7 +10952,8 @@ nsGlobalWindow::NotifyIdleObserver(IdleObserverHolder* aIdleObserverHolder,
|
||||
new NotifyIdleObserverRunnable(aIdleObserverHolder->mIdleObserver,
|
||||
aIdleObserverHolder->mTimeInS,
|
||||
aCallOnidle, this);
|
||||
if (NS_FAILED(NS_DispatchToCurrentThread(caller))) {
|
||||
if (NS_FAILED(Dispatch("NotifyIdleObserverRunnable", TaskCategory::Other,
|
||||
caller.forget()))) {
|
||||
NS_WARNING("Failed to dispatch thread for idle observer notification.");
|
||||
}
|
||||
}
|
||||
@ -12146,7 +12149,9 @@ public:
|
||||
~AutoUnblockScriptClosing()
|
||||
{
|
||||
void (nsGlobalWindow::*run)() = &nsGlobalWindow::UnblockScriptedClosing;
|
||||
NS_DispatchToCurrentThread(NewRunnableMethod(mWin, run));
|
||||
nsCOMPtr<nsIRunnable> caller = NewRunnableMethod(mWin, run);
|
||||
mWin->Dispatch("nsGlobalWindow::UnblockScriptedClosing",
|
||||
TaskCategory::Other, caller.forget());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -410,7 +410,7 @@ nsINode::ChildNodes()
|
||||
}
|
||||
|
||||
void
|
||||
nsINode::GetTextContentInternal(nsAString& aTextContent, ErrorResult& aError)
|
||||
nsINode::GetTextContentInternal(nsAString& aTextContent, OOMReporter& aError)
|
||||
{
|
||||
SetDOMStringToNull(aTextContent);
|
||||
}
|
||||
|
@ -1309,7 +1309,7 @@ protected:
|
||||
|
||||
public:
|
||||
void GetTextContent(nsAString& aTextContent,
|
||||
mozilla::ErrorResult& aError)
|
||||
mozilla::OOMReporter& aError)
|
||||
{
|
||||
GetTextContentInternal(aTextContent, aError);
|
||||
}
|
||||
@ -1930,7 +1930,7 @@ protected:
|
||||
}
|
||||
|
||||
virtual void GetTextContentInternal(nsAString& aTextContent,
|
||||
mozilla::ErrorResult& aError);
|
||||
mozilla::OOMReporter& aError);
|
||||
virtual void SetTextContentInternal(const nsAString& aTextContent,
|
||||
mozilla::ErrorResult& aError)
|
||||
{
|
||||
|
@ -1852,16 +1852,6 @@ AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||
nsTArray<nsString>& names,
|
||||
bool shadowPrototypeProperties, JS::AutoIdVector& props);
|
||||
|
||||
namespace binding_detail {
|
||||
|
||||
class FastErrorResult :
|
||||
public mozilla::binding_danger::TErrorResult<
|
||||
mozilla::binding_danger::JustAssertCleanupPolicy>
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace binding_detail
|
||||
|
||||
enum StringificationBehavior {
|
||||
eStringify,
|
||||
eEmpty,
|
||||
|
@ -7081,7 +7081,8 @@ class CGCallGenerator(CGThing):
|
||||
if needsCallerType:
|
||||
args.append(CGGeneric(callerTypeGetterForDescriptor(descriptor)))
|
||||
|
||||
if isFallible:
|
||||
canOOM = "canOOM" in extendedAttributes
|
||||
if isFallible or canOOM:
|
||||
args.append(CGGeneric("rv"))
|
||||
args.extend(CGGeneric(arg) for arg in argsPost)
|
||||
|
||||
@ -7147,8 +7148,12 @@ class CGCallGenerator(CGThing):
|
||||
""",
|
||||
getPrincipal=getPrincipal)))
|
||||
|
||||
if isFallible:
|
||||
self.cgRoot.prepend(CGGeneric("binding_detail::FastErrorResult rv;\n"))
|
||||
if isFallible or canOOM:
|
||||
if isFallible:
|
||||
reporterClass = "binding_detail::FastErrorResult"
|
||||
else:
|
||||
reporterClass = "binding_danger::OOMReporterInstantiator"
|
||||
self.cgRoot.prepend(CGGeneric("%s rv;\n" % reporterClass))
|
||||
self.cgRoot.append(CGGeneric(dedent(
|
||||
"""
|
||||
if (MOZ_UNLIKELY(rv.MaybeSetPendingException(cx))) {
|
||||
@ -8931,9 +8936,10 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
|
||||
nativeName = MakeNativeName(descriptor.binaryNameFor(name))
|
||||
_, resultOutParam, _, _, _ = getRetvalDeclarationForType(attr.type,
|
||||
descriptor)
|
||||
infallible = ('infallible' in
|
||||
descriptor.getExtendedAttributes(attr, getter=True))
|
||||
if resultOutParam or attr.type.nullable() or not infallible:
|
||||
extendedAttrs = descriptor.getExtendedAttributes(attr, getter=True)
|
||||
canFail = ('infallible' not in extendedAttrs or
|
||||
'canOOM' in extendedAttrs)
|
||||
if resultOutParam or attr.type.nullable() or canFail:
|
||||
nativeName = "Get" + nativeName
|
||||
return nativeName
|
||||
|
||||
@ -9231,13 +9237,26 @@ class CGMemberJITInfo(CGThing):
|
||||
# while we have the right type.
|
||||
getter = ("(JSJitGetterOp)get_%s" %
|
||||
IDLToCIdentifier(self.member.identifier.name))
|
||||
getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True)
|
||||
extendedAttrs = self.descriptor.getExtendedAttributes(self.member, getter=True)
|
||||
getterinfal = "infallible" in extendedAttrs
|
||||
|
||||
# At this point getterinfal is true if our getter either can't throw
|
||||
# at all, or can only throw OOM. In both cases, it's safe to move,
|
||||
# or dead-code-eliminate, the getter, because throwing OOM is not
|
||||
# semantically meaningful, so code can't rely on it happening. Note
|
||||
# that this makes the behavior consistent for OOM thrown from the
|
||||
# getter itself and OOM thrown from the to-JS conversion of the
|
||||
# return value (see the "canOOM" and "infallibleForMember" checks
|
||||
# below).
|
||||
movable = self.mayBeMovable() and getterinfal
|
||||
eliminatable = self.mayBeEliminatable() and getterinfal
|
||||
aliasSet = self.aliasSet()
|
||||
|
||||
getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor)
|
||||
# Now we have to set getterinfal to whether we can _really_ ever
|
||||
# throw, from the point of view of the JS engine.
|
||||
getterinfal = (getterinfal and
|
||||
"canOOM" not in extendedAttrs and
|
||||
infallibleForMember(self.member, self.member.type, self.descriptor))
|
||||
isAlwaysInSlot = self.member.getExtendedAttribute("StoreInSlot")
|
||||
if self.member.slotIndices is not None:
|
||||
assert isAlwaysInSlot or self.member.getExtendedAttribute("Cached")
|
||||
@ -9300,7 +9319,16 @@ class CGMemberJITInfo(CGThing):
|
||||
# argument conversions, since argument conversions that can
|
||||
# reliably throw would be effectful anyway and the jit doesn't
|
||||
# move effectful things.
|
||||
hasInfallibleImpl = "infallible" in self.descriptor.getExtendedAttributes(self.member)
|
||||
extendedAttrs = self.descriptor.getExtendedAttributes(self.member)
|
||||
hasInfallibleImpl = "infallible" in extendedAttrs
|
||||
# At this point hasInfallibleImpl is true if our method either
|
||||
# can't throw at all, or can only throw OOM. In both cases, it
|
||||
# may be safe to move, or dead-code-eliminate, the method,
|
||||
# because throwing OOM is not semantically meaningful, so code
|
||||
# can't rely on it happening. Note that this makes the behavior
|
||||
# consistent for OOM thrown from the method itself and OOM
|
||||
# thrown from the to-JS conversion of the return value (see the
|
||||
# "canOOM" and "infallibleForMember" checks below).
|
||||
movable = self.mayBeMovable() and hasInfallibleImpl
|
||||
eliminatable = self.mayBeEliminatable() and hasInfallibleImpl
|
||||
# XXXbz can we move the smarts about fallibility due to arg
|
||||
@ -9310,7 +9338,8 @@ class CGMemberJITInfo(CGThing):
|
||||
# We have arguments or our return-value boxing can fail
|
||||
methodInfal = False
|
||||
else:
|
||||
methodInfal = hasInfallibleImpl
|
||||
methodInfal = (hasInfallibleImpl and
|
||||
"canOOM" not in extendedAttrs)
|
||||
# For now, only bother to output args if we're side-effect-free.
|
||||
if self.member.affects == "Nothing":
|
||||
args = sig[1]
|
||||
@ -14182,10 +14211,13 @@ class CGNativeMember(ClassMethod):
|
||||
# And the caller type, if desired.
|
||||
if needsCallerType(self.member):
|
||||
args.append(Argument("CallerType", "aCallerType"))
|
||||
# And the ErrorResult
|
||||
# And the ErrorResult or OOMReporter
|
||||
if 'infallible' not in self.extendedAttrs:
|
||||
# Use aRv so it won't conflict with local vars named "rv"
|
||||
args.append(Argument("ErrorResult&", "aRv"))
|
||||
elif 'canOOM' in self.extendedAttrs:
|
||||
args.append(Argument("OOMReporter&", "aRv"))
|
||||
|
||||
# The legacycaller thisval
|
||||
if self.member.isMethod() and self.member.isLegacycaller():
|
||||
# If it has an identifier, we can't deal with it yet
|
||||
@ -16868,6 +16900,8 @@ class CGEventGetter(CGNativeMember):
|
||||
def getArgs(self, returnType, argList):
|
||||
if 'infallible' not in self.extendedAttrs:
|
||||
raise TypeError("Event code generator does not support [Throws]!")
|
||||
if 'canOOM' in self.extendedAttrs:
|
||||
raise TypeError("Event code generator does not support [CanOOM]!")
|
||||
if not self.member.isAttr():
|
||||
raise TypeError("Event code generator does not support methods")
|
||||
if self.member.isStatic():
|
||||
|
@ -568,17 +568,29 @@ class Descriptor(DescriptorProvider):
|
||||
return self.isGlobal() and self.supportsNamedProperties()
|
||||
|
||||
def getExtendedAttributes(self, member, getter=False, setter=False):
|
||||
def ensureValidThrowsExtendedAttribute(attr):
|
||||
def ensureValidBoolExtendedAttribute(attr, name):
|
||||
if (attr is not None and attr is not True):
|
||||
raise TypeError("Unknown value for 'Throws': " + attr[0])
|
||||
raise TypeError("Unknown value for '%s': %s" % (name, attr[0]))
|
||||
|
||||
def ensureValidThrowsExtendedAttribute(attr):
|
||||
ensureValidBoolExtendedAttribute(attr, "Throws")
|
||||
|
||||
def ensureValidCanOOMExtendedAttribute(attr):
|
||||
ensureValidBoolExtendedAttribute(attr, "CanOOM")
|
||||
|
||||
def maybeAppendInfallibleToAttrs(attrs, throws):
|
||||
ensureValidThrowsExtendedAttribute(throws)
|
||||
if throws is None:
|
||||
attrs.append("infallible")
|
||||
|
||||
def maybeAppendCanOOMToAttrs(attrs, canOOM):
|
||||
ensureValidCanOOMExtendedAttribute(canOOM)
|
||||
if canOOM is not None:
|
||||
attrs.append("canOOM")
|
||||
|
||||
name = member.identifier.name
|
||||
throws = self.interface.isJSImplemented() or member.getExtendedAttribute("Throws")
|
||||
canOOM = member.getExtendedAttribute("CanOOM")
|
||||
if member.isMethod():
|
||||
# JSObject-returning [NewObject] methods must be fallible,
|
||||
# since they have to (fallibly) allocate the new JSObject.
|
||||
@ -587,6 +599,7 @@ class Descriptor(DescriptorProvider):
|
||||
throws = True
|
||||
attrs = self.extendedAttributes['all'].get(name, [])
|
||||
maybeAppendInfallibleToAttrs(attrs, throws)
|
||||
maybeAppendCanOOMToAttrs(attrs, canOOM)
|
||||
return attrs
|
||||
|
||||
assert member.isAttr()
|
||||
@ -597,6 +610,10 @@ class Descriptor(DescriptorProvider):
|
||||
throwsAttr = "GetterThrows" if getter else "SetterThrows"
|
||||
throws = member.getExtendedAttribute(throwsAttr)
|
||||
maybeAppendInfallibleToAttrs(attrs, throws)
|
||||
if canOOM is None:
|
||||
canOOMAttr = "GetterCanOOM" if getter else "SetterCanOOM"
|
||||
canOOM = member.getExtendedAttribute(canOOMAttr)
|
||||
maybeAppendCanOOMToAttrs(attrs, canOOM)
|
||||
return attrs
|
||||
|
||||
def supportsIndexedProperties(self):
|
||||
|
@ -102,6 +102,7 @@ struct StringArrayAppender
|
||||
} // namespace dom
|
||||
|
||||
class ErrorResult;
|
||||
class OOMReporter;
|
||||
|
||||
namespace binding_danger {
|
||||
|
||||
@ -162,6 +163,7 @@ public:
|
||||
}
|
||||
|
||||
operator ErrorResult&();
|
||||
operator OOMReporter&();
|
||||
|
||||
void Throw(nsresult rv) {
|
||||
MOZ_ASSERT(NS_FAILED(rv), "Please don't try throwing success");
|
||||
@ -537,6 +539,82 @@ class IgnoredErrorResult :
|
||||
{
|
||||
};
|
||||
|
||||
namespace dom {
|
||||
namespace binding_detail {
|
||||
class FastErrorResult :
|
||||
public mozilla::binding_danger::TErrorResult<
|
||||
mozilla::binding_danger::JustAssertCleanupPolicy>
|
||||
{
|
||||
};
|
||||
} // namespace binding_detail
|
||||
} // namespace dom
|
||||
|
||||
// This part is a bit annoying. We want an OOMReporter class that has the
|
||||
// following properties:
|
||||
//
|
||||
// 1) Can be cast to from any ErrorResult-like type.
|
||||
// 2) Has a fast destructor (because we want to use it from bindings).
|
||||
// 3) Won't be randomly instantiated by non-binding code (because the fast
|
||||
// destructor is not so safe.
|
||||
// 4) Doesn't look ugly on the callee side (e.g. isn't in the binding_detail or
|
||||
// binding_danger namespace).
|
||||
//
|
||||
// We do this by having two classes: The class callees should use, which has the
|
||||
// things we want and a private constructor, and a friend subclass in the
|
||||
// binding_danger namespace that can be used to construct it.
|
||||
namespace binding_danger {
|
||||
class OOMReporterInstantiator;
|
||||
} // namespace binding_danger
|
||||
|
||||
class OOMReporter : private dom::binding_detail::FastErrorResult
|
||||
{
|
||||
public:
|
||||
void ReportOOM()
|
||||
{
|
||||
Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
private:
|
||||
// OOMReporterInstantiator is a friend so it can call our constructor and
|
||||
// MaybeSetPendingException.
|
||||
friend class binding_danger::OOMReporterInstantiator;
|
||||
|
||||
// TErrorResult is a friend so its |operator OOMReporter&()| can work.
|
||||
template<typename CleanupPolicy>
|
||||
friend class binding_danger::TErrorResult;
|
||||
|
||||
OOMReporter()
|
||||
: dom::binding_detail::FastErrorResult()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
namespace binding_danger {
|
||||
class OOMReporterInstantiator : public OOMReporter
|
||||
{
|
||||
public:
|
||||
OOMReporterInstantiator()
|
||||
: OOMReporter()
|
||||
{
|
||||
}
|
||||
|
||||
// We want to be able to call MaybeSetPendingException from codegen. The one
|
||||
// on OOMReporter is not callable directly, because it comes from a private
|
||||
// superclass. But we're a friend, so _we_ can call it.
|
||||
bool MaybeSetPendingException(JSContext* cx)
|
||||
{
|
||||
return OOMReporter::MaybeSetPendingException(cx);
|
||||
}
|
||||
};
|
||||
} // namespace binding_danger
|
||||
|
||||
template<typename CleanupPolicy>
|
||||
binding_danger::TErrorResult<CleanupPolicy>::operator OOMReporter&()
|
||||
{
|
||||
return *static_cast<OOMReporter*>(
|
||||
reinterpret_cast<TErrorResult<JustAssertCleanupPolicy>*>(this));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
** Macros for checking results
|
||||
******************************************************************************/
|
||||
|
@ -4083,15 +4083,19 @@ class IDLAttribute(IDLInterfaceMember):
|
||||
|
||||
def handleExtendedAttribute(self, attr):
|
||||
identifier = attr.identifier()
|
||||
if identifier == "SetterThrows" and self.readonly:
|
||||
if ((identifier == "SetterThrows" or identifier == "SetterCanOOM")
|
||||
and self.readonly):
|
||||
raise WebIDLError("Readonly attributes must not be flagged as "
|
||||
"[SetterThrows]",
|
||||
"[%s]" % identifier,
|
||||
[self.location])
|
||||
elif (((identifier == "Throws" or identifier == "GetterThrows") and
|
||||
elif (((identifier == "Throws" or identifier == "GetterThrows" or
|
||||
identifier == "CanOOM" or identifier == "GetterCanOOM") and
|
||||
self.getExtendedAttribute("StoreInSlot")) or
|
||||
(identifier == "StoreInSlot" and
|
||||
(self.getExtendedAttribute("Throws") or
|
||||
self.getExtendedAttribute("GetterThrows")))):
|
||||
self.getExtendedAttribute("GetterThrows") or
|
||||
self.getExtendedAttribute("CanOOM") or
|
||||
self.getExtendedAttribute("GetterCanOOM")))):
|
||||
raise WebIDLError("Throwing things can't be [StoreInSlot]",
|
||||
[attr.location])
|
||||
elif identifier == "LenientThis":
|
||||
@ -4255,6 +4259,9 @@ class IDLAttribute(IDLInterfaceMember):
|
||||
identifier == "SetterThrows" or
|
||||
identifier == "Throws" or
|
||||
identifier == "GetterThrows" or
|
||||
identifier == "SetterCanOOM" or
|
||||
identifier == "CanOOM" or
|
||||
identifier == "GetterCanOOM" or
|
||||
identifier == "ChromeOnly" or
|
||||
identifier == "Func" or
|
||||
identifier == "SecureContext" or
|
||||
@ -4902,13 +4909,12 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
|
||||
def handleExtendedAttribute(self, attr):
|
||||
identifier = attr.identifier()
|
||||
if identifier == "GetterThrows":
|
||||
if (identifier == "GetterThrows" or
|
||||
identifier == "SetterThrows" or
|
||||
identifier == "GetterCanOOM" or
|
||||
identifier == "SetterCanOOM"):
|
||||
raise WebIDLError("Methods must not be flagged as "
|
||||
"[GetterThrows]",
|
||||
[attr.location, self.location])
|
||||
elif identifier == "SetterThrows":
|
||||
raise WebIDLError("Methods must not be flagged as "
|
||||
"[SetterThrows]",
|
||||
"[%s]" % identifier,
|
||||
[attr.location, self.location])
|
||||
elif identifier == "Unforgeable":
|
||||
if self.isStatic():
|
||||
@ -4981,6 +4987,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
"attributes and operations",
|
||||
[attr.location, self.location])
|
||||
elif (identifier == "Throws" or
|
||||
identifier == "CanOOM" or
|
||||
identifier == "NewObject" or
|
||||
identifier == "ChromeOnly" or
|
||||
identifier == "UnsafeInPrerendering" or
|
||||
|
@ -936,6 +936,13 @@ public:
|
||||
void SetThrowingGetterAttr(bool arg);
|
||||
bool ThrowingSetterAttr() const;
|
||||
void SetThrowingSetterAttr(bool arg, ErrorResult& aRv);
|
||||
void CanOOMMethod(OOMReporter& aRv);
|
||||
bool GetCanOOMAttr(OOMReporter& aRv) const;
|
||||
void SetCanOOMAttr(bool arg, OOMReporter& aRv);
|
||||
bool GetCanOOMGetterAttr(OOMReporter& aRv) const;
|
||||
void SetCanOOMGetterAttr(bool arg);
|
||||
bool CanOOMSetterAttr() const;
|
||||
void SetCanOOMSetterAttr(bool arg, OOMReporter& aRv);
|
||||
void NeedsSubjectPrincipalMethod(nsIPrincipal&);
|
||||
bool NeedsSubjectPrincipalAttr(nsIPrincipal&);
|
||||
void SetNeedsSubjectPrincipalAttr(bool, nsIPrincipal&);
|
||||
|
@ -946,6 +946,10 @@ interface TestInterface {
|
||||
[Throws] attribute boolean throwingAttr;
|
||||
[GetterThrows] attribute boolean throwingGetterAttr;
|
||||
[SetterThrows] attribute boolean throwingSetterAttr;
|
||||
[CanOOM] void canOOMMethod();
|
||||
[CanOOM] attribute boolean canOOMAttr;
|
||||
[GetterCanOOM] attribute boolean canOOMGetterAttr;
|
||||
[SetterCanOOM] attribute boolean canOOMSetterAttr;
|
||||
[NeedsSubjectPrincipal] void needsSubjectPrincipalMethod();
|
||||
[NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr;
|
||||
[NeedsCallerType] void needsCallerTypeMethod();
|
||||
|
@ -776,6 +776,10 @@ interface TestExampleInterface {
|
||||
[Throws] attribute boolean throwingAttr;
|
||||
[GetterThrows] attribute boolean throwingGetterAttr;
|
||||
[SetterThrows] attribute boolean throwingSetterAttr;
|
||||
[CanOOM] void canOOMMethod();
|
||||
[CanOOM] attribute boolean canOOMAttr;
|
||||
[GetterCanOOM] attribute boolean canOOMGetterAttr;
|
||||
[SetterCanOOM] attribute boolean canOOMSetterAttr;
|
||||
[NeedsSubjectPrincipal] void needsSubjectPrincipalMethod();
|
||||
[NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr;
|
||||
[NeedsCallerType] void needsCallerTypeMethod();
|
||||
|
@ -797,6 +797,10 @@ interface TestJSImplInterface {
|
||||
[Throws] attribute boolean throwingAttr;
|
||||
[GetterThrows] attribute boolean throwingGetterAttr;
|
||||
[SetterThrows] attribute boolean throwingSetterAttr;
|
||||
[CanOOM] void canOOMMethod();
|
||||
[CanOOM] attribute boolean canOOMAttr;
|
||||
[GetterCanOOM] attribute boolean canOOMGetterAttr;
|
||||
[SetterCanOOM] attribute boolean canOOMSetterAttr;
|
||||
// NeedsSubjectPrincipal not supported on JS-implemented things for
|
||||
// now, because we always pass in the caller principal anyway.
|
||||
// [NeedsSubjectPrincipal] void needsSubjectPrincipalMethod();
|
||||
|
@ -114,6 +114,9 @@ WebGLContextOptions::WebGLContextOptions()
|
||||
|
||||
WebGLContext::WebGLContext()
|
||||
: WebGLContextUnchecked(nullptr)
|
||||
, mMaxPerfWarnings(gfxPrefs::WebGLMaxPerfWarnings())
|
||||
, mNumPerfWarnings(0)
|
||||
, mMaxAcceptableFBStatusInvals(gfxPrefs::WebGLMaxAcceptableFBStatusInvals())
|
||||
, mBufferFetchingIsVerified(false)
|
||||
, mBufferFetchingHasPerVertex(false)
|
||||
, mMaxFetchedVertices(0)
|
||||
|
@ -331,6 +331,10 @@ class WebGLContext
|
||||
static const uint32_t kMinMaxColorAttachments;
|
||||
static const uint32_t kMinMaxDrawBuffers;
|
||||
|
||||
const uint32_t mMaxPerfWarnings;
|
||||
mutable uint64_t mNumPerfWarnings;
|
||||
const uint32_t mMaxAcceptableFBStatusInvals;
|
||||
|
||||
public:
|
||||
WebGLContext();
|
||||
|
||||
@ -1937,6 +1941,10 @@ protected:
|
||||
|
||||
bool ShouldGenerateWarnings() const;
|
||||
|
||||
bool ShouldGeneratePerfWarnings() const {
|
||||
return mNumPerfWarnings < mMaxPerfWarnings;
|
||||
}
|
||||
|
||||
uint64_t mLastUseIndex;
|
||||
|
||||
bool mNeedsFakeNoAlpha;
|
||||
@ -2029,6 +2037,8 @@ public:
|
||||
void GenerateWarning(const char* fmt, ...);
|
||||
void GenerateWarning(const char* fmt, va_list ap);
|
||||
|
||||
void GeneratePerfWarning(const char* fmt, ...) const;
|
||||
|
||||
public:
|
||||
UniquePtr<webgl::FormatUsageAuthority> mFormatUsage;
|
||||
|
||||
|
@ -348,16 +348,17 @@ WebGLContext::DeleteFramebuffer(WebGLFramebuffer* fbuf)
|
||||
void
|
||||
WebGLContext::DeleteRenderbuffer(WebGLRenderbuffer* rbuf)
|
||||
{
|
||||
if (!ValidateDeleteObject("deleteRenderbuffer", rbuf))
|
||||
const char funcName[] = "deleteRenderbuffer";
|
||||
if (!ValidateDeleteObject(funcName, rbuf))
|
||||
return;
|
||||
|
||||
if (mBoundDrawFramebuffer)
|
||||
mBoundDrawFramebuffer->DetachRenderbuffer(rbuf);
|
||||
mBoundDrawFramebuffer->DetachRenderbuffer(funcName, rbuf);
|
||||
|
||||
if (mBoundReadFramebuffer)
|
||||
mBoundReadFramebuffer->DetachRenderbuffer(rbuf);
|
||||
mBoundReadFramebuffer->DetachRenderbuffer(funcName, rbuf);
|
||||
|
||||
rbuf->InvalidateStatusOfAttachedFBs();
|
||||
rbuf->InvalidateStatusOfAttachedFBs(funcName);
|
||||
|
||||
if (mBoundRenderbuffer == rbuf)
|
||||
BindRenderbuffer(LOCAL_GL_RENDERBUFFER, nullptr);
|
||||
@ -368,14 +369,15 @@ WebGLContext::DeleteRenderbuffer(WebGLRenderbuffer* rbuf)
|
||||
void
|
||||
WebGLContext::DeleteTexture(WebGLTexture* tex)
|
||||
{
|
||||
if (!ValidateDeleteObject("deleteTexture", tex))
|
||||
const char funcName[] = "deleteTexture";
|
||||
if (!ValidateDeleteObject(funcName, tex))
|
||||
return;
|
||||
|
||||
if (mBoundDrawFramebuffer)
|
||||
mBoundDrawFramebuffer->DetachTexture(tex);
|
||||
mBoundDrawFramebuffer->DetachTexture(funcName, tex);
|
||||
|
||||
if (mBoundReadFramebuffer)
|
||||
mBoundReadFramebuffer->DetachTexture(tex);
|
||||
mBoundReadFramebuffer->DetachTexture(funcName, tex);
|
||||
|
||||
GLuint activeTexture = mActiveTexture;
|
||||
for (int32_t i = 0; i < mGLMaxTextureUnits; i++) {
|
||||
|
@ -90,7 +90,7 @@ WebGLContext::GenerateWarning(const char* fmt, va_list ap)
|
||||
}
|
||||
|
||||
JSContext* cx = api.cx();
|
||||
JS_ReportWarningASCII(cx, "WebGL: %s", buf);
|
||||
JS_ReportWarningASCII(cx, "WebGL warning: %s", buf);
|
||||
if (!ShouldGenerateWarnings()) {
|
||||
JS_ReportWarningASCII(cx,
|
||||
"WebGL: No further warnings will be reported for"
|
||||
@ -109,6 +109,43 @@ WebGLContext::ShouldGenerateWarnings() const
|
||||
return mAlreadyGeneratedWarnings < mMaxWarnings;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::GeneratePerfWarning(const char* fmt, ...) const
|
||||
{
|
||||
if (!ShouldGeneratePerfWarnings())
|
||||
return;
|
||||
|
||||
if (!mCanvasElement)
|
||||
return;
|
||||
|
||||
dom::AutoJSAPI api;
|
||||
if (!api.Init(mCanvasElement->OwnerDoc()->GetScopeObject()))
|
||||
return;
|
||||
JSContext* cx = api.cx();
|
||||
|
||||
////
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
char buf[1024];
|
||||
PR_vsnprintf(buf, 1024, fmt, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
////
|
||||
|
||||
JS_ReportWarningASCII(cx, "WebGL perf warning: %s", buf);
|
||||
mNumPerfWarnings++;
|
||||
|
||||
if (!ShouldGeneratePerfWarnings()) {
|
||||
JS_ReportWarningASCII(cx,
|
||||
"WebGL: After reporting %u, no further perf warnings will"
|
||||
" be reported for this WebGL context.",
|
||||
uint32_t(mNumPerfWarnings));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::SynthesizeGLError(GLenum err)
|
||||
{
|
||||
|
@ -47,7 +47,8 @@ WebGLFBAttachPoint::~WebGLFBAttachPoint()
|
||||
void
|
||||
WebGLFBAttachPoint::Unlink()
|
||||
{
|
||||
Clear();
|
||||
const char funcName[] = "WebGLFramebuffer::GC";
|
||||
Clear(funcName);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -114,7 +115,7 @@ WebGLFBAttachPoint::IsReadableFloat() const
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFBAttachPoint::Clear()
|
||||
WebGLFBAttachPoint::Clear(const char* funcName)
|
||||
{
|
||||
if (mRenderbufferPtr) {
|
||||
MOZ_ASSERT(!mTexturePtr);
|
||||
@ -126,14 +127,14 @@ WebGLFBAttachPoint::Clear()
|
||||
mTexturePtr = nullptr;
|
||||
mRenderbufferPtr = nullptr;
|
||||
|
||||
OnBackingStoreRespecified();
|
||||
OnBackingStoreRespecified(funcName);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFBAttachPoint::SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level,
|
||||
GLint layer)
|
||||
WebGLFBAttachPoint::SetTexImage(const char* funcName, WebGLTexture* tex,
|
||||
TexImageTarget target, GLint level, GLint layer)
|
||||
{
|
||||
Clear();
|
||||
Clear(funcName);
|
||||
|
||||
mTexturePtr = tex;
|
||||
mTexImageTarget = target;
|
||||
@ -146,9 +147,9 @@ WebGLFBAttachPoint::SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFBAttachPoint::SetRenderbuffer(WebGLRenderbuffer* rb)
|
||||
WebGLFBAttachPoint::SetRenderbuffer(const char* funcName, WebGLRenderbuffer* rb)
|
||||
{
|
||||
Clear();
|
||||
Clear(funcName);
|
||||
|
||||
mRenderbufferPtr = rb;
|
||||
|
||||
@ -226,9 +227,9 @@ WebGLFBAttachPoint::Size(uint32_t* const out_width, uint32_t* const out_height)
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFBAttachPoint::OnBackingStoreRespecified() const
|
||||
WebGLFBAttachPoint::OnBackingStoreRespecified(const char* funcName) const
|
||||
{
|
||||
mFB->InvalidateFramebufferStatus();
|
||||
mFB->InvalidateFramebufferStatus(funcName);
|
||||
}
|
||||
|
||||
void
|
||||
@ -619,6 +620,7 @@ WebGLFBAttachPoint::GetParameter(const char* funcName, WebGLContext* webgl, JSCo
|
||||
WebGLFramebuffer::WebGLFramebuffer(WebGLContext* webgl, GLuint fbo)
|
||||
: WebGLRefCountedObject(webgl)
|
||||
, mGLName(fbo)
|
||||
, mNumFBStatusInvals(0)
|
||||
#ifdef ANDROID
|
||||
, mIsFB(false)
|
||||
#endif
|
||||
@ -641,14 +643,16 @@ WebGLFramebuffer::WebGLFramebuffer(WebGLContext* webgl, GLuint fbo)
|
||||
void
|
||||
WebGLFramebuffer::Delete()
|
||||
{
|
||||
InvalidateFramebufferStatus();
|
||||
const char funcName[] = "WebGLFramebuffer::Delete";
|
||||
|
||||
mDepthAttachment.Clear();
|
||||
mStencilAttachment.Clear();
|
||||
mDepthStencilAttachment.Clear();
|
||||
InvalidateFramebufferStatus(funcName);
|
||||
|
||||
mDepthAttachment.Clear(funcName);
|
||||
mStencilAttachment.Clear(funcName);
|
||||
mDepthStencilAttachment.Clear(funcName);
|
||||
|
||||
for (auto& cur : mColorAttachments) {
|
||||
cur.Clear();
|
||||
cur.Clear(funcName);
|
||||
}
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
@ -709,11 +713,11 @@ WebGLFramebuffer::GetAttachPoint(GLenum attachPoint)
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFramebuffer::DetachTexture(const WebGLTexture* tex)
|
||||
WebGLFramebuffer::DetachTexture(const char* funcName, const WebGLTexture* tex)
|
||||
{
|
||||
const auto fnDetach = [&](WebGLFBAttachPoint& attach) {
|
||||
if (attach.Texture() == tex) {
|
||||
attach.Clear();
|
||||
attach.Clear(funcName);
|
||||
}
|
||||
};
|
||||
|
||||
@ -721,11 +725,11 @@ WebGLFramebuffer::DetachTexture(const WebGLTexture* tex)
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer* rb)
|
||||
WebGLFramebuffer::DetachRenderbuffer(const char* funcName, const WebGLRenderbuffer* rb)
|
||||
{
|
||||
const auto fnDetach = [&](WebGLFBAttachPoint& attach) {
|
||||
if (attach.Renderbuffer() == rb) {
|
||||
attach.Clear();
|
||||
attach.Clear(funcName);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1135,6 +1139,21 @@ WebGLFramebuffer::ResolvedData::ResolvedData(const WebGLFramebuffer& parent)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFramebuffer::InvalidateFramebufferStatus(const char* funcName)
|
||||
{
|
||||
if (mResolvedCompleteData) {
|
||||
mNumFBStatusInvals++;
|
||||
if (mNumFBStatusInvals > mContext->mMaxAcceptableFBStatusInvals) {
|
||||
mContext->GeneratePerfWarning("%s: FB was invalidated after being complete %u"
|
||||
" times.",
|
||||
funcName, uint32_t(mNumFBStatusInvals));
|
||||
}
|
||||
}
|
||||
|
||||
mResolvedCompleteData = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFramebuffer::RefreshResolvedData()
|
||||
{
|
||||
@ -1354,13 +1373,13 @@ WebGLFramebuffer::FramebufferRenderbuffer(const char* funcName, GLenum attachEnu
|
||||
// End of validation.
|
||||
|
||||
if (mContext->IsWebGL2() && attachEnum == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
mDepthAttachment.SetRenderbuffer(rb);
|
||||
mStencilAttachment.SetRenderbuffer(rb);
|
||||
mDepthAttachment.SetRenderbuffer(funcName, rb);
|
||||
mStencilAttachment.SetRenderbuffer(funcName, rb);
|
||||
} else {
|
||||
attach->SetRenderbuffer(rb);
|
||||
attach->SetRenderbuffer(funcName, rb);
|
||||
}
|
||||
|
||||
InvalidateFramebufferStatus();
|
||||
InvalidateFramebufferStatus(funcName);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1442,13 +1461,13 @@ WebGLFramebuffer::FramebufferTexture2D(const char* funcName, GLenum attachEnum,
|
||||
// End of validation.
|
||||
|
||||
if (mContext->IsWebGL2() && attachEnum == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
mDepthAttachment.SetTexImage(tex, texImageTarget, level);
|
||||
mStencilAttachment.SetTexImage(tex, texImageTarget, level);
|
||||
mDepthAttachment.SetTexImage(funcName, tex, texImageTarget, level);
|
||||
mStencilAttachment.SetTexImage(funcName, tex, texImageTarget, level);
|
||||
} else {
|
||||
attach->SetTexImage(tex, texImageTarget, level);
|
||||
attach->SetTexImage(funcName, tex, texImageTarget, level);
|
||||
}
|
||||
|
||||
InvalidateFramebufferStatus();
|
||||
InvalidateFramebufferStatus(funcName);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1526,13 +1545,13 @@ WebGLFramebuffer::FramebufferTextureLayer(const char* funcName, GLenum attachEnu
|
||||
// End of validation.
|
||||
|
||||
if (mContext->IsWebGL2() && attachEnum == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
mDepthAttachment.SetTexImage(tex, texImageTarget, level, layer);
|
||||
mStencilAttachment.SetTexImage(tex, texImageTarget, level, layer);
|
||||
mDepthAttachment.SetTexImage(funcName, tex, texImageTarget, level, layer);
|
||||
mStencilAttachment.SetTexImage(funcName, tex, texImageTarget, level, layer);
|
||||
} else {
|
||||
attach->SetTexImage(tex, texImageTarget, level, layer);
|
||||
attach->SetTexImage(funcName, tex, texImageTarget, level, layer);
|
||||
}
|
||||
|
||||
InvalidateFramebufferStatus();
|
||||
InvalidateFramebufferStatus(funcName);
|
||||
}
|
||||
|
||||
JS::Value
|
||||
|
@ -66,11 +66,11 @@ public:
|
||||
bool HasAlpha() const;
|
||||
bool IsReadableFloat() const;
|
||||
|
||||
void Clear();
|
||||
void Clear(const char* funcName);
|
||||
|
||||
void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level,
|
||||
GLint layer = 0);
|
||||
void SetRenderbuffer(WebGLRenderbuffer* rb);
|
||||
void SetTexImage(const char* funcName, WebGLTexture* tex, TexImageTarget target,
|
||||
GLint level, GLint layer = 0);
|
||||
void SetRenderbuffer(const char* funcName, WebGLRenderbuffer* rb);
|
||||
|
||||
WebGLTexture* Texture() const { return mTexturePtr; }
|
||||
WebGLRenderbuffer* Renderbuffer() const { return mRenderbufferPtr; }
|
||||
@ -100,7 +100,7 @@ public:
|
||||
GLenum target, GLenum attachment, GLenum pname,
|
||||
ErrorResult* const out_error) const;
|
||||
|
||||
void OnBackingStoreRespecified() const;
|
||||
void OnBackingStoreRespecified(const char* funcName) const;
|
||||
|
||||
bool IsEquivalentForFeedback(const WebGLFBAttachPoint& other) const {
|
||||
if (!IsDefined() || !other.IsDefined())
|
||||
@ -154,6 +154,9 @@ public:
|
||||
|
||||
const GLuint mGLName;
|
||||
|
||||
private:
|
||||
uint64_t mNumFBStatusInvals;
|
||||
|
||||
protected:
|
||||
#ifdef ANDROID
|
||||
// Bug 1140459: Some drivers (including our test slaves!) don't
|
||||
@ -230,8 +233,8 @@ protected:
|
||||
bool ResolveAttachmentData(const char* funcName) const;
|
||||
|
||||
public:
|
||||
void DetachTexture(const WebGLTexture* tex);
|
||||
void DetachRenderbuffer(const WebGLRenderbuffer* rb);
|
||||
void DetachTexture(const char* funcName, const WebGLTexture* tex);
|
||||
void DetachRenderbuffer(const char* funcName, const WebGLRenderbuffer* rb);
|
||||
bool ValidateAndInitAttachments(const char* funcName);
|
||||
bool ValidateClearBufferType(const char* funcName, GLenum buffer, uint32_t drawBuffer,
|
||||
GLenum funcType) const;
|
||||
@ -258,11 +261,7 @@ public:
|
||||
// Invalidation
|
||||
|
||||
bool IsResolvedComplete() const { return bool(mResolvedCompleteData); }
|
||||
|
||||
void InvalidateFramebufferStatus() {
|
||||
mResolvedCompleteData = nullptr;
|
||||
}
|
||||
|
||||
void InvalidateFramebufferStatus(const char* funcName);
|
||||
void RefreshResolvedData();
|
||||
|
||||
////////////////
|
||||
|
@ -31,12 +31,12 @@ WebGLFramebufferAttachable::UnmarkAttachment(const WebGLFBAttachPoint& attachmen
|
||||
}
|
||||
|
||||
void
|
||||
WebGLFramebufferAttachable::InvalidateStatusOfAttachedFBs() const
|
||||
WebGLFramebufferAttachable::InvalidateStatusOfAttachedFBs(const char* funcName) const
|
||||
{
|
||||
const size_t count = mAttachmentPoints.Length();
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
MOZ_ASSERT(mAttachmentPoints[i]->mFB);
|
||||
mAttachmentPoints[i]->mFB->InvalidateFramebufferStatus();
|
||||
mAttachmentPoints[i]->mFB->InvalidateFramebufferStatus(funcName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ public:
|
||||
// Track FBO/Attachment combinations
|
||||
void MarkAttachment(const WebGLFBAttachPoint& attachment);
|
||||
void UnmarkAttachment(const WebGLFBAttachPoint& attachment);
|
||||
void InvalidateStatusOfAttachedFBs() const;
|
||||
void InvalidateStatusOfAttachedFBs(const char* funcName) const;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -224,7 +224,7 @@ WebGLRenderbuffer::RenderbufferStorage(const char* funcName, uint32_t samples,
|
||||
mHeight = height;
|
||||
mImageDataStatus = WebGLImageDataStatus::UninitializedImageData;
|
||||
|
||||
InvalidateStatusOfAttachedFBs();
|
||||
InvalidateStatusOfAttachedFBs(funcName);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -33,12 +33,12 @@ Mutable(const T& x)
|
||||
}
|
||||
|
||||
void
|
||||
WebGLTexture::ImageInfo::Clear()
|
||||
WebGLTexture::ImageInfo::Clear(const char* funcName)
|
||||
{
|
||||
if (!IsDefined())
|
||||
return;
|
||||
|
||||
OnRespecify();
|
||||
OnRespecify(funcName);
|
||||
|
||||
Mutable(mFormat) = LOCAL_GL_NONE;
|
||||
Mutable(mWidth) = 0;
|
||||
@ -48,8 +48,8 @@ WebGLTexture::ImageInfo::Clear()
|
||||
MOZ_ASSERT(!IsDefined());
|
||||
}
|
||||
|
||||
WebGLTexture::ImageInfo&
|
||||
WebGLTexture::ImageInfo::operator =(const ImageInfo& a)
|
||||
void
|
||||
WebGLTexture::ImageInfo::Set(const char* funcName, const ImageInfo& a)
|
||||
{
|
||||
MOZ_ASSERT(a.IsDefined());
|
||||
|
||||
@ -62,9 +62,7 @@ WebGLTexture::ImageInfo::operator =(const ImageInfo& a)
|
||||
|
||||
// But *don't* transfer mAttachPoints!
|
||||
MOZ_ASSERT(a.mAttachPoints.empty());
|
||||
OnRespecify();
|
||||
|
||||
return *this;
|
||||
OnRespecify(funcName);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -91,10 +89,10 @@ WebGLTexture::ImageInfo::RemoveAttachPoint(WebGLFBAttachPoint* attachPoint)
|
||||
}
|
||||
|
||||
void
|
||||
WebGLTexture::ImageInfo::OnRespecify() const
|
||||
WebGLTexture::ImageInfo::OnRespecify(const char* funcName) const
|
||||
{
|
||||
for (auto cur : mAttachPoints) {
|
||||
cur->OnBackingStoreRespecified();
|
||||
cur->OnBackingStoreRespecified(funcName);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,8 +147,9 @@ WebGLTexture::WebGLTexture(WebGLContext* webgl, GLuint tex)
|
||||
void
|
||||
WebGLTexture::Delete()
|
||||
{
|
||||
const char funcName[] = "WebGLTexture::Delete";
|
||||
for (auto& cur : mImageInfoArr) {
|
||||
cur.Clear();
|
||||
cur.Clear(funcName);
|
||||
}
|
||||
|
||||
mContext->MakeContextCurrent();
|
||||
@ -173,18 +172,20 @@ WebGLTexture::MemoryUsage() const
|
||||
}
|
||||
|
||||
void
|
||||
WebGLTexture::SetImageInfo(ImageInfo* target, const ImageInfo& newInfo)
|
||||
WebGLTexture::SetImageInfo(const char* funcName, ImageInfo* target,
|
||||
const ImageInfo& newInfo)
|
||||
{
|
||||
*target = newInfo;
|
||||
target->Set(funcName, newInfo);
|
||||
|
||||
InvalidateResolveCache();
|
||||
}
|
||||
|
||||
void
|
||||
WebGLTexture::SetImageInfosAtLevel(uint32_t level, const ImageInfo& newInfo)
|
||||
WebGLTexture::SetImageInfosAtLevel(const char* funcName, uint32_t level,
|
||||
const ImageInfo& newInfo)
|
||||
{
|
||||
for (uint8_t i = 0; i < mFaceCount; i++) {
|
||||
ImageInfoAtFace(i, level) = newInfo;
|
||||
ImageInfoAtFace(i, level).Set(funcName, newInfo);
|
||||
}
|
||||
|
||||
InvalidateResolveCache();
|
||||
@ -773,7 +774,8 @@ WebGLTexture::ClampLevelBaseAndMax()
|
||||
}
|
||||
|
||||
void
|
||||
WebGLTexture::PopulateMipChain(uint32_t firstLevel, uint32_t lastLevel)
|
||||
WebGLTexture::PopulateMipChain(const char* funcName, uint32_t firstLevel,
|
||||
uint32_t lastLevel)
|
||||
{
|
||||
const ImageInfo& baseImageInfo = ImageInfoAtFace(0, firstLevel);
|
||||
MOZ_ASSERT(baseImageInfo.IsDefined());
|
||||
@ -804,7 +806,7 @@ WebGLTexture::PopulateMipChain(uint32_t firstLevel, uint32_t lastLevel)
|
||||
const ImageInfo cur(baseImageInfo.mFormat, refWidth, refHeight, refDepth,
|
||||
baseImageInfo.IsDataInitialized());
|
||||
|
||||
SetImageInfosAtLevel(level, cur);
|
||||
SetImageInfosAtLevel(funcName, level, cur);
|
||||
}
|
||||
}
|
||||
|
||||
@ -854,6 +856,7 @@ WebGLTexture::BindTexture(TexTarget texTarget)
|
||||
void
|
||||
WebGLTexture::GenerateMipmap(TexTarget texTarget)
|
||||
{
|
||||
const char funcName[] = "generateMipmap";
|
||||
// GLES 3.0.4 p160:
|
||||
// "Mipmap generation replaces texel array levels level base + 1 through q with arrays
|
||||
// derived from the level base array, regardless of their previous contents. All
|
||||
@ -861,33 +864,35 @@ WebGLTexture::GenerateMipmap(TexTarget texTarget)
|
||||
// computation."
|
||||
const ImageInfo& baseImageInfo = BaseImageInfo();
|
||||
if (!baseImageInfo.IsDefined()) {
|
||||
mContext->ErrorInvalidOperation("generateMipmap: The base level of the texture is"
|
||||
" not defined.");
|
||||
mContext->ErrorInvalidOperation("%s: The base level of the texture is not"
|
||||
" defined.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsCubeMap() && !IsCubeComplete()) {
|
||||
mContext->ErrorInvalidOperation("generateMipmap: Cube maps must be \"cube"
|
||||
" complete\".");
|
||||
mContext->ErrorInvalidOperation("%s: Cube maps must be \"cube complete\".",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mContext->IsWebGL2() && !baseImageInfo.IsPowerOfTwo()) {
|
||||
mContext->ErrorInvalidOperation("generateMipmap: The base level of the texture"
|
||||
" does not have power-of-two dimensions.");
|
||||
mContext->ErrorInvalidOperation("%s: The base level of the texture does not have"
|
||||
" power-of-two dimensions.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
auto format = baseImageInfo.mFormat->format;
|
||||
if (format->compression) {
|
||||
mContext->ErrorInvalidOperation("generateMipmap: Texture data at base level is"
|
||||
" compressed.");
|
||||
mContext->ErrorInvalidOperation("%s: Texture data at base level is compressed.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (format->d) {
|
||||
mContext->ErrorInvalidOperation("generateMipmap: Depth textures are not"
|
||||
" supported.");
|
||||
mContext->ErrorInvalidOperation("%s: Depth textures are not supported.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -910,9 +915,10 @@ WebGLTexture::GenerateMipmap(TexTarget texTarget)
|
||||
}
|
||||
|
||||
if (!canGenerateMipmap) {
|
||||
mContext->ErrorInvalidOperation("generateMipmap: Texture at base level is not unsized"
|
||||
mContext->ErrorInvalidOperation("%s: Texture at base level is not unsized"
|
||||
" internal format or is not"
|
||||
" color-renderable or texture-filterable.");
|
||||
" color-renderable or texture-filterable.",
|
||||
funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -940,7 +946,7 @@ WebGLTexture::GenerateMipmap(TexTarget texTarget)
|
||||
// Note that we don't use MaxEffectiveMipmapLevel() here, since that returns
|
||||
// mBaseMipmapLevel if the min filter doesn't require mipmaps.
|
||||
const uint32_t maxLevel = mBaseMipmapLevel + baseImageInfo.PossibleMipmapLevels() - 1;
|
||||
PopulateMipChain(mBaseMipmapLevel, maxLevel);
|
||||
PopulateMipChain(funcName, mBaseMipmapLevel, maxLevel);
|
||||
}
|
||||
|
||||
JS::Value
|
||||
|
@ -105,17 +105,19 @@ public:
|
||||
// And in turn, it needs these forwards:
|
||||
protected:
|
||||
// We need to forward these.
|
||||
void SetImageInfo(ImageInfo* target, const ImageInfo& newInfo);
|
||||
void SetImageInfosAtLevel(uint32_t level, const ImageInfo& newInfo);
|
||||
void SetImageInfo(const char* funcName, ImageInfo* target, const ImageInfo& newInfo);
|
||||
void SetImageInfosAtLevel(const char* funcName, uint32_t level,
|
||||
const ImageInfo& newInfo);
|
||||
|
||||
public:
|
||||
// We store information about the various images that are part of this
|
||||
// texture. (cubemap faces, mipmap levels)
|
||||
class ImageInfo
|
||||
{
|
||||
friend void WebGLTexture::SetImageInfo(ImageInfo* target,
|
||||
friend void WebGLTexture::SetImageInfo(const char* funcName, ImageInfo* target,
|
||||
const ImageInfo& newInfo);
|
||||
friend void WebGLTexture::SetImageInfosAtLevel(uint32_t level,
|
||||
friend void WebGLTexture::SetImageInfosAtLevel(const char* funcName,
|
||||
uint32_t level,
|
||||
const ImageInfo& newInfo);
|
||||
|
||||
public:
|
||||
@ -155,15 +157,14 @@ public:
|
||||
MOZ_ASSERT(mFormat);
|
||||
}
|
||||
|
||||
void Clear();
|
||||
void Clear(const char* funcName);
|
||||
|
||||
~ImageInfo() {
|
||||
if (!IsDefined())
|
||||
Clear();
|
||||
MOZ_ASSERT(!mAttachPoints.size());
|
||||
}
|
||||
|
||||
protected:
|
||||
ImageInfo& operator =(const ImageInfo& a);
|
||||
void Set(const char* funcName, const ImageInfo& a);
|
||||
|
||||
public:
|
||||
uint32_t PossibleMipmapLevels() const {
|
||||
@ -177,7 +178,7 @@ public:
|
||||
|
||||
void AddAttachPoint(WebGLFBAttachPoint* attachPoint);
|
||||
void RemoveAttachPoint(WebGLFBAttachPoint* attachPoint);
|
||||
void OnRespecify() const;
|
||||
void OnRespecify(const char* funcName) const;
|
||||
|
||||
size_t MemoryUsage() const;
|
||||
|
||||
@ -289,7 +290,7 @@ public:
|
||||
protected:
|
||||
void ClampLevelBaseAndMax();
|
||||
|
||||
void PopulateMipChain(uint32_t baseLevel, uint32_t maxLevel);
|
||||
void PopulateMipChain(const char* funcName, uint32_t baseLevel, uint32_t maxLevel);
|
||||
|
||||
bool MaxEffectiveMipmapLevel(uint32_t texUnit, uint32_t* const out) const;
|
||||
|
||||
@ -330,11 +331,11 @@ public:
|
||||
return const_cast<WebGLTexture*>(this)->ImageInfoAt(texImageTarget, level);
|
||||
}
|
||||
|
||||
void SetImageInfoAt(TexImageTarget texImageTarget, GLint level,
|
||||
void SetImageInfoAt(const char* funcName, TexImageTarget texImageTarget, GLint level,
|
||||
const ImageInfo& val)
|
||||
{
|
||||
ImageInfo* target = &ImageInfoAt(texImageTarget, level);
|
||||
SetImageInfo(target, val);
|
||||
SetImageInfo(funcName, target, val);
|
||||
}
|
||||
|
||||
const ImageInfo& BaseImageInfo() const {
|
||||
|
@ -1185,9 +1185,9 @@ WebGLTexture::TexStorage(const char* funcName, TexTarget target, GLsizei levels,
|
||||
const bool isDataInitialized = false;
|
||||
const WebGLTexture::ImageInfo newInfo(dstUsage, width, height, depth,
|
||||
isDataInitialized);
|
||||
SetImageInfosAtLevel(0, newInfo);
|
||||
SetImageInfosAtLevel(funcName, 0, newInfo);
|
||||
|
||||
PopulateMipChain(0, levels-1);
|
||||
PopulateMipChain(funcName, 0, levels-1);
|
||||
|
||||
mImmutable = true;
|
||||
mImmutableLevelCount = levels;
|
||||
@ -1317,7 +1317,7 @@ WebGLTexture::TexImage(const char* funcName, TexImageTarget target, GLint level,
|
||||
////////////////////////////////////
|
||||
// Update our specification data.
|
||||
|
||||
SetImageInfo(imageInfo, newImageInfo);
|
||||
SetImageInfo(funcName, imageInfo, newImageInfo);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1523,7 +1523,7 @@ WebGLTexture::CompressedTexImage(const char* funcName, TexImageTarget target, GL
|
||||
const bool isDataInitialized = true;
|
||||
const ImageInfo newImageInfo(usage, blob->mWidth, blob->mHeight, blob->mDepth,
|
||||
isDataInitialized);
|
||||
SetImageInfo(imageInfo, newImageInfo);
|
||||
SetImageInfo(funcName, imageInfo, newImageInfo);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@ -2170,7 +2170,7 @@ WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internal
|
||||
|
||||
const bool isDataInitialized = true;
|
||||
const ImageInfo newImageInfo(dstUsage, width, height, depth, isDataInitialized);
|
||||
SetImageInfo(imageInfo, newImageInfo);
|
||||
SetImageInfo(funcName, imageInfo, newImageInfo);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -319,8 +319,10 @@ DataTransferItem::GetAsEntry(nsIPrincipal& aSubjectPrincipal,
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> directoryFile;
|
||||
nsresult rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(fullpath),
|
||||
true, getter_AddRefs(directoryFile));
|
||||
// fullPath is already in unicode, we don't have to use
|
||||
// NS_NewNativeLocalFile.
|
||||
nsresult rv = NS_NewLocalFile(fullpath, true,
|
||||
getter_AddRefs(directoryFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -98,9 +98,8 @@ CreateDirectoryTaskChild::SetSuccessRequestResult(const FileSystemResponseValue&
|
||||
const FileSystemDirectoryResponse& r =
|
||||
aValue.get_FileSystemDirectoryResponse();
|
||||
|
||||
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(r.realPath()), true,
|
||||
getter_AddRefs(mTargetPath));
|
||||
NS_WARNING_ASSERTION(!aRv.Failed(), "NS_NewNativeLocalFile failed");
|
||||
aRv = NS_NewLocalFile(r.realPath(), true, getter_AddRefs(mTargetPath));
|
||||
NS_WARNING_ASSERTION(!aRv.Failed(), "NS_NewLocalFile failed");
|
||||
}
|
||||
|
||||
void
|
||||
@ -149,8 +148,8 @@ CreateDirectoryTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
RefPtr<CreateDirectoryTaskParent> task =
|
||||
new CreateDirectoryTaskParent(aFileSystem, aParam, aParent);
|
||||
|
||||
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(aParam.realPath()), true,
|
||||
getter_AddRefs(task->mTargetPath));
|
||||
aRv = NS_NewLocalFile(aParam.realPath(), true,
|
||||
getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -140,8 +140,7 @@ CreateFileTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aVal
|
||||
|
||||
const FileSystemFileResponse& r = aValue.get_FileSystemFileResponse();
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(r.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
|
||||
aRv = NS_NewLocalFile(r.realPath(), true, getter_AddRefs(mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
@ -194,8 +193,8 @@ CreateFileTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
RefPtr<CreateFileTaskParent> task =
|
||||
new CreateFileTaskParent(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
aRv = NS_NewLocalFile(aParam.realPath(), true,
|
||||
getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -100,8 +100,8 @@ Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
|
||||
MOZ_ASSERT(aFileSystem);
|
||||
|
||||
nsCOMPtr<nsIFile> path;
|
||||
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(aFileSystem->LocalOrDeviceStorageRootPath()),
|
||||
true, getter_AddRefs(path));
|
||||
aRv = NS_NewLocalFile(aFileSystem->LocalOrDeviceStorageRootPath(),
|
||||
true, getter_AddRefs(path));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -122,8 +122,7 @@ Directory::Constructor(const GlobalObject& aGlobal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIFile> path;
|
||||
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(aRealPath),
|
||||
true, getter_AddRefs(path));
|
||||
aRv = NS_NewLocalFile(aRealPath, true, getter_AddRefs(path));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -88,8 +88,7 @@ FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const
|
||||
return false;
|
||||
}
|
||||
|
||||
rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(filePath),
|
||||
true, aPath);
|
||||
rv = NS_NewLocalFile(filePath, true, aPath);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return false;
|
||||
@ -134,8 +133,8 @@ FileSystemBase::GetDOMPath(nsIFile* aFile,
|
||||
aRetval.Truncate();
|
||||
|
||||
nsCOMPtr<nsIFile> fileSystemPath;
|
||||
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(LocalOrDeviceStorageRootPath()),
|
||||
true, getter_AddRefs(fileSystemPath));
|
||||
aRv = NS_NewLocalFile(LocalOrDeviceStorageRootPath(),
|
||||
true, getter_AddRefs(fileSystemPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
@ -166,8 +166,8 @@ GetDirectoryListingTaskChild::HandlerCallback()
|
||||
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsIFile> path;
|
||||
NS_ConvertUTF16toUTF8 fullPath(mTargetData[i].mPath);
|
||||
nsresult rv = NS_NewNativeLocalFile(fullPath, true, getter_AddRefs(path));
|
||||
nsresult rv = NS_NewLocalFile(mTargetData[i].mPath, true,
|
||||
getter_AddRefs(path));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(rv);
|
||||
mPromise = nullptr;
|
||||
@ -246,8 +246,8 @@ GetDirectoryListingTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
RefPtr<GetDirectoryListingTaskParent> task =
|
||||
new GetDirectoryListingTaskParent(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
aRv = NS_NewLocalFile(aParam.realPath(), true,
|
||||
getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -100,8 +100,7 @@ GetFileOrDirectoryTaskChild::SetSuccessRequestResult(const FileSystemResponseVal
|
||||
case FileSystemResponseValue::TFileSystemFileResponse: {
|
||||
FileSystemFileResponse r = aValue;
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(r.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
|
||||
aRv = NS_NewLocalFile(r.realPath(), true, getter_AddRefs(mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
@ -112,8 +111,7 @@ GetFileOrDirectoryTaskChild::SetSuccessRequestResult(const FileSystemResponseVal
|
||||
case FileSystemResponseValue::TFileSystemDirectoryResponse: {
|
||||
FileSystemDirectoryResponse r = aValue;
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(r.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(mTargetPath));
|
||||
aRv = NS_NewLocalFile(r.realPath(), true, getter_AddRefs(mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
@ -183,8 +181,8 @@ GetFileOrDirectoryTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
RefPtr<GetFileOrDirectoryTaskParent> task =
|
||||
new GetFileOrDirectoryTaskParent(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
aRv = NS_NewLocalFile(aParam.realPath(), true,
|
||||
getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -271,8 +271,7 @@ GetFilesHelper::RunIO()
|
||||
MOZ_ASSERT(!mListingCompleted);
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
mErrorResult = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(mDirectoryPath), true,
|
||||
getter_AddRefs(file));
|
||||
mErrorResult = NS_NewLocalFile(mDirectoryPath, true, getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(mErrorResult))) {
|
||||
return;
|
||||
}
|
||||
@ -306,8 +305,8 @@ GetFilesHelper::RunMainThread()
|
||||
for (uint32_t i = 0; i < mTargetPathArray.Length(); ++i) {
|
||||
nsCOMPtr<nsIFile> file;
|
||||
mErrorResult =
|
||||
NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(mTargetPathArray[i].mRealPath),
|
||||
true, getter_AddRefs(file));
|
||||
NS_NewLocalFile(mTargetPathArray[i].mRealPath, true,
|
||||
getter_AddRefs(file));
|
||||
if (NS_WARN_IF(NS_FAILED(mErrorResult))) {
|
||||
mFiles.Clear();
|
||||
return;
|
||||
|
@ -154,8 +154,8 @@ GetFilesTaskChild::HandlerCallback()
|
||||
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
nsCOMPtr<nsIFile> path;
|
||||
NS_ConvertUTF16toUTF8 fullPath(mTargetData[i].mRealPath);
|
||||
nsresult rv = NS_NewNativeLocalFile(fullPath, true, getter_AddRefs(path));
|
||||
nsresult rv = NS_NewLocalFile(mTargetData[i].mRealPath, true,
|
||||
getter_AddRefs(path));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
mPromise = nullptr;
|
||||
@ -210,8 +210,8 @@ GetFilesTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
RefPtr<GetFilesTaskParent> task =
|
||||
new GetFilesTaskParent(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.realPath());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
aRv = NS_NewLocalFile(aParam.realPath(), true,
|
||||
getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -162,17 +162,16 @@ RemoveTaskParent::Create(FileSystemBase* aFileSystem,
|
||||
RefPtr<RemoveTaskParent> task =
|
||||
new RemoveTaskParent(aFileSystem, aParam, aParent);
|
||||
|
||||
NS_ConvertUTF16toUTF8 directoryPath(aParam.directory());
|
||||
aRv = NS_NewNativeLocalFile(directoryPath, true,
|
||||
getter_AddRefs(task->mDirPath));
|
||||
aRv = NS_NewLocalFile(aParam.directory(), true,
|
||||
getter_AddRefs(task->mDirPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
task->mRecursive = aParam.recursive();
|
||||
|
||||
NS_ConvertUTF16toUTF8 path(aParam.targetDirectory());
|
||||
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
|
||||
aRv = NS_NewLocalFile(aParam.targetDirectory(), true,
|
||||
getter_AddRefs(task->mTargetPath));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -316,7 +316,7 @@ HangMonitorChild::InterruptCallback()
|
||||
if (forcePaint) {
|
||||
RefPtr<TabChild> tabChild = TabChild::FindTabChild(forcePaintTab);
|
||||
if (tabChild) {
|
||||
JS::AutoAssertNoGC nogc(mContext);
|
||||
js::AutoAssertNoContentJS nojs(mContext);
|
||||
tabChild->ForcePaint(forcePaintEpoch);
|
||||
}
|
||||
}
|
||||
|
@ -1098,11 +1098,17 @@ TabChild::ActorDestroy(ActorDestroyReason why)
|
||||
DestroyWindow();
|
||||
|
||||
if (mTabChildGlobal) {
|
||||
// The messageManager relays messages via the TabChild which
|
||||
// no longer exists.
|
||||
static_cast<nsFrameMessageManager*>
|
||||
(mTabChildGlobal->mMessageManager.get())->Disconnect();
|
||||
mTabChildGlobal->mMessageManager = nullptr;
|
||||
// We should have a message manager if the global is alive, but it
|
||||
// seems sometimes we don't. Assert in aurora/nightly, but don't
|
||||
// crash in release builds.
|
||||
MOZ_DIAGNOSTIC_ASSERT(mTabChildGlobal->mMessageManager);
|
||||
if (mTabChildGlobal->mMessageManager) {
|
||||
// The messageManager relays messages via the TabChild which
|
||||
// no longer exists.
|
||||
static_cast<nsFrameMessageManager*>
|
||||
(mTabChildGlobal->mMessageManager.get())->Disconnect();
|
||||
mTabChildGlobal->mMessageManager = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
CompositorBridgeChild* compositorChild = static_cast<CompositorBridgeChild*>(CompositorBridgeChild::Get());
|
||||
@ -2104,16 +2110,26 @@ TabChild::RecvAsyncMessage(const nsString& aMessage,
|
||||
const IPC::Principal& aPrincipal,
|
||||
const ClonedMessageData& aData)
|
||||
{
|
||||
if (mTabChildGlobal) {
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> kungFuDeathGrip(GetGlobal());
|
||||
StructuredCloneData data;
|
||||
UnpackClonedMessageDataForChild(aData, data);
|
||||
RefPtr<nsFrameMessageManager> mm =
|
||||
static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
|
||||
CrossProcessCpowHolder cpows(Manager(), aCpows);
|
||||
mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal), nullptr,
|
||||
aMessage, false, &data, &cpows, aPrincipal, nullptr);
|
||||
if (!mTabChildGlobal) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
// We should have a message manager if the global is alive, but it
|
||||
// seems sometimes we don't. Assert in aurora/nightly, but don't
|
||||
// crash in release builds.
|
||||
MOZ_DIAGNOSTIC_ASSERT(mTabChildGlobal->mMessageManager);
|
||||
if (!mTabChildGlobal->mMessageManager) {
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXPConnectJSObjectHolder> kungFuDeathGrip(GetGlobal());
|
||||
StructuredCloneData data;
|
||||
UnpackClonedMessageDataForChild(aData, data);
|
||||
RefPtr<nsFrameMessageManager> mm =
|
||||
static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
|
||||
CrossProcessCpowHolder cpows(Manager(), aCpows);
|
||||
mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal), nullptr,
|
||||
aMessage, false, &data, &cpows, aPrincipal, nullptr);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
@ -2503,7 +2519,6 @@ TabChild::InitTabChildGlobal()
|
||||
NS_ENSURE_TRUE(chromeHandler, false);
|
||||
|
||||
RefPtr<TabChildGlobal> scope = new TabChildGlobal(this);
|
||||
mTabChildGlobal = scope;
|
||||
|
||||
nsISupports* scopeSupports = NS_ISUPPORTS_CAST(EventTarget*, scope);
|
||||
|
||||
@ -2515,6 +2530,8 @@ TabChild::InitTabChildGlobal()
|
||||
nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
|
||||
NS_ENSURE_TRUE(root, false);
|
||||
root->SetParentTarget(scope);
|
||||
|
||||
mTabChildGlobal = scope.forget();;
|
||||
}
|
||||
|
||||
if (!mTriedBrowserInit) {
|
||||
|
@ -18,6 +18,7 @@ const {
|
||||
} = Components;
|
||||
Cu.import("resource://gre/modules/ManifestObtainer.jsm");
|
||||
Cu.import("resource://gre/modules/ManifestFinder.jsm");
|
||||
Cu.import("resource://gre/modules/ManifestIcons.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
const MessageHandler = {
|
||||
@ -34,6 +35,10 @@ const MessageHandler = {
|
||||
"DOM:Manifest:FireAppInstalledEvent",
|
||||
this.fireAppInstalledEvent.bind(this)
|
||||
);
|
||||
addMessageListener(
|
||||
"DOM:WebManifest:fetchIcon",
|
||||
this.fetchIcon.bind(this)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -76,7 +81,24 @@ const MessageHandler = {
|
||||
content.dispatchEvent(ev);
|
||||
}
|
||||
sendAsyncMessage("DOM:Manifest:FireAppInstalledEvent", response);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Given a manifest and an expected icon size, ask ManifestIcons
|
||||
* to fetch the appropriate icon and send along result
|
||||
*/
|
||||
fetchIcon: Task.async(function* ({data: {id, manifest, iconSize}}) {
|
||||
const response = makeMsgResponse(id);
|
||||
try {
|
||||
response.result =
|
||||
yield ManifestIcons.contentFetchIcon(content, manifest, iconSize);
|
||||
response.success = true;
|
||||
} catch (err) {
|
||||
response.result = serializeError(err);
|
||||
}
|
||||
sendAsyncMessage("DOM:WebManifest:fetchIcon", response);
|
||||
}),
|
||||
|
||||
};
|
||||
/**
|
||||
* Utility function to Serializes an JS Error, so it can be transferred over
|
||||
|
42
dom/manifest/Manifest.jsm
Normal file
42
dom/manifest/Manifest.jsm
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Manifest.jsm is the top level api for managing installed web applications
|
||||
* https://www.w3.org/TR/appmanifest/
|
||||
*
|
||||
* It is used to trigger the installation of a web application via .install()
|
||||
* and to access the manifest data (including icons).
|
||||
*
|
||||
* TODO:
|
||||
* - Persist installed manifest data to disk and keep track of which
|
||||
* origins have installed applications
|
||||
* - Trigger appropriate app installed events
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
const { ManifestObtainer } =
|
||||
Cu.import('resource://gre/modules/ManifestObtainer.jsm', {});
|
||||
const { ManifestIcons } =
|
||||
Cu.import('resource://gre/modules/ManifestIcons.jsm', {});
|
||||
|
||||
function Manifest(browser) {
|
||||
this.browser = browser;
|
||||
this.data = null;
|
||||
}
|
||||
|
||||
Manifest.prototype.install = Task.async(function* () {
|
||||
this.data = yield ManifestObtainer.browserObtainManifest(this.browser);
|
||||
});
|
||||
|
||||
Manifest.prototype.icon = Task.async(function* (expectedSize) {
|
||||
return yield ManifestIcons.browserFetchIcon(this.browser, this.data, expectedSize);
|
||||
});
|
||||
|
||||
Manifest.prototype.name = function () {
|
||||
return this.data.short_name || this.data.short_url;
|
||||
}
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["Manifest"]; // jshint ignore:line
|
85
dom/manifest/ManifestIcons.jsm
Normal file
85
dom/manifest/ManifestIcons.jsm
Normal file
@ -0,0 +1,85 @@
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
utils: Cu,
|
||||
classes: Cc,
|
||||
interfaces: Ci
|
||||
} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/PromiseMessage.jsm");
|
||||
|
||||
this.ManifestIcons = {
|
||||
|
||||
async browserFetchIcon(aBrowser, manifest, iconSize) {
|
||||
const msgKey = "DOM:WebManifest:fetchIcon";
|
||||
const mm = aBrowser.messageManager;
|
||||
const {data: {success, result}} =
|
||||
await PromiseMessage.send(mm, msgKey, {manifest, iconSize});
|
||||
if (!success) {
|
||||
throw result;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
async contentFetchIcon(aWindow, manifest, iconSize) {
|
||||
return await getIcon(aWindow, toIconArray(manifest.icons), iconSize);
|
||||
}
|
||||
};
|
||||
|
||||
function parseIconSize(size) {
|
||||
if (size === "any" || size === "") {
|
||||
// We want icons without size specified to sorted
|
||||
// as the largest available icons
|
||||
return Number.MAX_SAFE_INTEGER;
|
||||
}
|
||||
// 100x100 will parse as 100
|
||||
return parseInt(size, 10);
|
||||
}
|
||||
|
||||
// Create an array of icons sorted by their size
|
||||
function toIconArray(icons) {
|
||||
const iconBySize = [];
|
||||
icons.forEach(icon => {
|
||||
const sizes = ("sizes" in icon) ? icon.sizes : "";
|
||||
sizes.split(" ").forEach(size => {
|
||||
iconBySize.push({src: icon.src, size: parseIconSize(size)});
|
||||
});
|
||||
});
|
||||
return iconBySize.sort((a, b) => a.size - b.size);
|
||||
}
|
||||
|
||||
async function getIcon(aWindow, icons, expectedSize) {
|
||||
if (!icons.length) {
|
||||
throw new Error("Could not find valid icon");
|
||||
}
|
||||
// We start trying the smallest icon that is larger than the requested
|
||||
// size and go up to the largest icon if they fail, if all those fail
|
||||
// go back down to the smallest
|
||||
let index = icons.findIndex(icon => icon.size >= expectedSize);
|
||||
if (index === -1) {
|
||||
index = icons.length - 1;
|
||||
}
|
||||
|
||||
return fetchIcon(aWindow, icons[index].src).catch(err => {
|
||||
// Remove all icons with the failed source, the same source
|
||||
// may have been used for multiple sizes
|
||||
icons = icons.filter(x => x.src === icons[index].src);
|
||||
return getIcon(aWindow, icons, expectedSize);
|
||||
});
|
||||
}
|
||||
|
||||
function fetchIcon(aWindow, src) {
|
||||
const manifestURL = new aWindow.URL(src);
|
||||
const request = new aWindow.Request(manifestURL, {mode: "cors"});
|
||||
request.overrideContentPolicyType(Ci.nsIContentPolicy.TYPE_WEB_MANIFEST);
|
||||
return aWindow.fetch(request)
|
||||
.then(response => response.blob())
|
||||
.then(blob => new Promise((resolve, reject) => {
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = () => resolve(reader.result);
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(blob);
|
||||
}));
|
||||
}
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["ManifestIcons"]; // jshint ignore:line
|
@ -6,7 +6,9 @@
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'ImageObjectProcessor.jsm',
|
||||
'Manifest.jsm',
|
||||
'ManifestFinder.jsm',
|
||||
'ManifestIcons.jsm',
|
||||
'ManifestObtainer.jsm',
|
||||
'ManifestProcessor.jsm',
|
||||
'ValueExtractor.jsm',
|
||||
|
BIN
dom/manifest/test/blue-150.png
Normal file
BIN
dom/manifest/test/blue-150.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 534 B |
@ -4,6 +4,9 @@ support-files =
|
||||
file_testserver.sjs
|
||||
manifestLoader.html
|
||||
resource.sjs
|
||||
red-50.png
|
||||
blue-150.png
|
||||
[browser_ManifestFinder_browserHasManifestLink.js]
|
||||
[browser_ManifestIcons_browserFetchIcon.js]
|
||||
[browser_ManifestObtainer_obtain.js]
|
||||
[browser_fire_appinstalled_event.js]
|
56
dom/manifest/test/browser_ManifestIcons_browserFetchIcon.js
Normal file
56
dom/manifest/test/browser_ManifestIcons_browserFetchIcon.js
Normal file
@ -0,0 +1,56 @@
|
||||
//Used by JSHint:
|
||||
/*global Cu, BrowserTestUtils, ok, add_task, gBrowser */
|
||||
"use strict";
|
||||
const { ManifestIcons } = Cu.import("resource://gre/modules/ManifestIcons.jsm", {});
|
||||
const { ManifestObtainer } = Cu.import("resource://gre/modules/ManifestObtainer.jsm", {});
|
||||
|
||||
const defaultURL = new URL("http://example.org/browser/dom/manifest/test/resource.sjs");
|
||||
defaultURL.searchParams.set("Content-Type", "application/manifest+json");
|
||||
|
||||
const manifest = JSON.stringify({
|
||||
icons: [{
|
||||
sizes: "50x50",
|
||||
src: "red-50.png?Content-type=image/png"
|
||||
}, {
|
||||
sizes: "150x150",
|
||||
src: "blue-150.png?Content-type=image/png"
|
||||
}]
|
||||
});
|
||||
|
||||
function makeTestURL(manifest) {
|
||||
const url = new URL(defaultURL);
|
||||
const body = `<link rel="manifest" href='${defaultURL}&body=${manifest}'>`;
|
||||
url.searchParams.set("Content-Type", "text/html; charset=utf-8");
|
||||
url.searchParams.set("body", encodeURIComponent(body));
|
||||
return url.href;
|
||||
}
|
||||
|
||||
function getIconColor(icon) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const canvas = content.document.createElement('canvas');
|
||||
const ctx = canvas.getContext("2d");
|
||||
const image = new content.Image();
|
||||
image.onload = function() {
|
||||
ctx.drawImage(image, 0, 0);
|
||||
resolve(ctx.getImageData(1, 1, 1, 1).data);
|
||||
};
|
||||
image.onerror = function() {
|
||||
reject(new Error("could not create image"));
|
||||
};
|
||||
image.src = icon;
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
const tabOptions = {gBrowser, url: makeTestURL(manifest)};
|
||||
yield BrowserTestUtils.withNewTab(tabOptions, function*(browser) {
|
||||
const manifest = yield ManifestObtainer.browserObtainManifest(browser);
|
||||
let icon = yield ManifestIcons.browserFetchIcon(browser, manifest, 25);
|
||||
let color = yield ContentTask.spawn(browser, icon, getIconColor);
|
||||
is(color[0], 255, 'Fetched red icon');
|
||||
|
||||
icon = yield ManifestIcons.browserFetchIcon(browser, manifest, 500);
|
||||
color = yield ContentTask.spawn(browser, icon, getIconColor);
|
||||
is(color[2], 255, 'Fetched blue icon');
|
||||
});
|
||||
});
|
BIN
dom/manifest/test/icon.png
Normal file
BIN
dom/manifest/test/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.0 KiB |
BIN
dom/manifest/test/red-50.png
Normal file
BIN
dom/manifest/test/red-50.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 141 B |
@ -2808,11 +2808,14 @@ nsPluginHost::WritePluginInfo()
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool flashOnly = Preferences::GetBool("plugin.load_flash_only", true);
|
||||
|
||||
PR_fprintf(fd, "Generated File. Do not edit.\n");
|
||||
|
||||
PR_fprintf(fd, "\n[HEADER]\nVersion%c%s%c%c\nArch%c%s%c%c\n",
|
||||
PR_fprintf(fd, "\n[HEADER]\nVersion%c%s%c%c%c\nArch%c%s%c%c\n",
|
||||
PLUGIN_REGISTRY_FIELD_DELIMITER,
|
||||
kPluginRegistryVersion,
|
||||
flashOnly ? 't' : 'f',
|
||||
PLUGIN_REGISTRY_FIELD_DELIMITER,
|
||||
PLUGIN_REGISTRY_END_OF_LINE_MARKER,
|
||||
PLUGIN_REGISTRY_FIELD_DELIMITER,
|
||||
@ -3008,7 +3011,12 @@ nsPluginHost::ReadPluginInfo()
|
||||
return rv;
|
||||
|
||||
// If we're reading an old registry, ignore it
|
||||
if (strcmp(values[1], kPluginRegistryVersion) != 0) {
|
||||
// If we flipped the flash-only pref, ignore it
|
||||
bool flashOnly = Preferences::GetBool("plugin.load_flash_only", true);
|
||||
nsAutoCString expectedVersion(kPluginRegistryVersion);
|
||||
expectedVersion.Append(flashOnly ? 't' : 'f');
|
||||
|
||||
if (!expectedVersion.Equals(values[1])) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -4078,6 +4078,13 @@ PluginInstanceChild::InvalidateRectDelayed(void)
|
||||
}
|
||||
|
||||
mCurrentInvalidateTask = nullptr;
|
||||
|
||||
// When this method is run asynchronously, we can end up switching to
|
||||
// direct drawing before while we wait to run. In that case, bail.
|
||||
if (IsUsingDirectDrawing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mAccumulatedInvalidRect.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -1206,7 +1206,7 @@ PluginInstanceParent::SetScrollCaptureId(uint64_t aScrollCaptureId)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mImageContainer = new ImageContainer(aScrollCaptureId);
|
||||
mImageContainer = new ImageContainer(CompositableHandle(aScrollCaptureId));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ load 572938-4.svg
|
||||
load 588287-1.svg
|
||||
load 588287-2.svg
|
||||
asserts-if(stylo,2) load 590425-1.html # bug 1324669
|
||||
asserts-if(stylo,8-11) load 592477-1.xhtml # bug 1324669
|
||||
asserts-if(stylo,1-27) load 592477-1.xhtml # bug 1324669
|
||||
load 594653-1.svg
|
||||
load 596796-1.svg
|
||||
load 605345-1.svg
|
||||
|
@ -19,6 +19,8 @@ disabled = Does not reliably pass on 32-bit systems - bug 1314098
|
||||
skip-if = !e10s
|
||||
[browser_autofocus_background.js]
|
||||
[browser_autofocus_preference.js]
|
||||
[browser_beforeunload_between_chrome_content.js]
|
||||
skip-if = !e10s
|
||||
[browser_bug396843.js]
|
||||
[browser_bug1004814.js]
|
||||
[browser_bug1008941_dismissGeolocationHanger.js]
|
||||
|
144
dom/tests/browser/browser_beforeunload_between_chrome_content.js
Normal file
144
dom/tests/browser/browser_beforeunload_between_chrome_content.js
Normal file
@ -0,0 +1,144 @@
|
||||
const TEST_URL = "http://www.example.com/browser/dom/tests/browser/dummy.html";
|
||||
|
||||
function pageScript() {
|
||||
window.addEventListener("beforeunload", function (event) {
|
||||
var str = "Leaving?";
|
||||
event.returnValue = str;
|
||||
return str;
|
||||
}, true);
|
||||
}
|
||||
|
||||
function frameScript() {
|
||||
content.window.addEventListener("beforeunload", function (event) {
|
||||
sendAsyncMessage("Test:OnBeforeUnloadReceived");
|
||||
var str = "Leaving?";
|
||||
event.returnValue = str;
|
||||
return str;
|
||||
}, true);
|
||||
}
|
||||
|
||||
// Wait for onbeforeunload dialog, and dismiss it immediately.
|
||||
function awaitAndCloseBeforeUnloadDialog(doStayOnPage) {
|
||||
return new Promise(resolve => {
|
||||
function onDialogShown(node) {
|
||||
Services.obs.removeObserver(onDialogShown, "tabmodal-dialog-loaded");
|
||||
let button = doStayOnPage ? node.ui.button1 : node.ui.button0;
|
||||
button.click();
|
||||
resolve();
|
||||
}
|
||||
|
||||
Services.obs.addObserver(onDialogShown, "tabmodal-dialog-loaded");
|
||||
});
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{"set": [["dom.require_user_interaction_for_beforeunload", false]]});
|
||||
|
||||
/**
|
||||
* Test navigation from a content page to a chrome page. Also check that only
|
||||
* one beforeunload event is fired.
|
||||
*/
|
||||
add_task(function* () {
|
||||
let beforeUnloadCount = 0;
|
||||
messageManager.addMessageListener("Test:OnBeforeUnloadReceived", function() {
|
||||
beforeUnloadCount++;
|
||||
});
|
||||
|
||||
// Open a content page.
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
ok(browser.isRemoteBrowser, "Browser should be remote.");
|
||||
browser.messageManager.loadFrameScript(
|
||||
"data:,(" + frameScript.toString() + ")();", true);
|
||||
|
||||
// Navigate to a chrome page.
|
||||
let dialogShown1 = awaitAndCloseBeforeUnloadDialog(false);
|
||||
yield BrowserTestUtils.loadURI(browser, "about:support");
|
||||
yield Promise.all([
|
||||
dialogShown1,
|
||||
BrowserTestUtils.browserLoaded(browser)
|
||||
]);
|
||||
is(beforeUnloadCount, 1, "Should have received one beforeunload event.");
|
||||
ok(!browser.isRemoteBrowser, "Browser should not be remote.");
|
||||
|
||||
// Go back to content page.
|
||||
ok(gBrowser.webNavigation.canGoBack, "Should be able to go back.");
|
||||
gBrowser.goBack();
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
browser.messageManager.loadFrameScript(
|
||||
"data:,(" + frameScript.toString() + ")();", true);
|
||||
|
||||
// Test that going forward triggers beforeunload prompt as well.
|
||||
ok(gBrowser.webNavigation.canGoForward, "Should be able to go forward.");
|
||||
let dialogShown2 = awaitAndCloseBeforeUnloadDialog(false);
|
||||
gBrowser.goForward();
|
||||
yield Promise.all([
|
||||
dialogShown2,
|
||||
BrowserTestUtils.browserLoaded(browser)
|
||||
]);
|
||||
is(beforeUnloadCount, 2, "Should have received two beforeunload events.");
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Test navigation from a chrome page to a content page. Also check that only
|
||||
* one beforeunload event is fired.
|
||||
*/
|
||||
add_task(function* () {
|
||||
let beforeUnloadCount = 0;
|
||||
messageManager.addMessageListener("Test:OnBeforeUnloadReceived", function() {
|
||||
beforeUnloadCount++;
|
||||
});
|
||||
|
||||
// Open a chrome page.
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser,
|
||||
"about:support");
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
ok(!browser.isRemoteBrowser, "Browser should not be remote.");
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
content.window.addEventListener("beforeunload", function (event) {
|
||||
sendAsyncMessage("Test:OnBeforeUnloadReceived");
|
||||
var str = "Leaving?";
|
||||
event.returnValue = str;
|
||||
return str;
|
||||
}, true);
|
||||
});
|
||||
|
||||
// Navigate to a content page.
|
||||
let dialogShown1 = awaitAndCloseBeforeUnloadDialog(false);
|
||||
yield BrowserTestUtils.loadURI(browser, TEST_URL);
|
||||
yield Promise.all([
|
||||
dialogShown1,
|
||||
BrowserTestUtils.browserLoaded(browser)
|
||||
]);
|
||||
is(beforeUnloadCount, 1, "Should have received one beforeunload event.");
|
||||
ok(browser.isRemoteBrowser, "Browser should be remote.");
|
||||
|
||||
// Go back to chrome page.
|
||||
ok(gBrowser.webNavigation.canGoBack, "Should be able to go back.");
|
||||
gBrowser.goBack();
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
content.window.addEventListener("beforeunload", function (event) {
|
||||
sendAsyncMessage("Test:OnBeforeUnloadReceived");
|
||||
var str = "Leaving?";
|
||||
event.returnValue = str;
|
||||
return str;
|
||||
}, true);
|
||||
});
|
||||
|
||||
// Test that going forward triggers beforeunload prompt as well.
|
||||
ok(gBrowser.webNavigation.canGoForward, "Should be able to go forward.");
|
||||
let dialogShown2 = awaitAndCloseBeforeUnloadDialog(false);
|
||||
gBrowser.goForward();
|
||||
yield Promise.all([
|
||||
dialogShown2,
|
||||
BrowserTestUtils.browserLoaded(browser)
|
||||
]);
|
||||
is(beforeUnloadCount, 2, "Should have received two beforeunload events.");
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
@ -59,7 +59,7 @@ interface Node : EventTarget {
|
||||
|
||||
[SetterThrows, Pure]
|
||||
attribute DOMString? nodeValue;
|
||||
[Throws, Pure]
|
||||
[SetterThrows, GetterCanOOM, Pure]
|
||||
attribute DOMString? textContent;
|
||||
[Throws]
|
||||
Node insertBefore(Node node, Node? child);
|
||||
|
@ -75,8 +75,8 @@ SimpleTest.waitForFocus(function() {
|
||||
// Position set at the beginning , middle and end of the text.
|
||||
sel.collapse(theText, tests[i][1]);
|
||||
|
||||
synthesizeKey("KEY_Enter", {});
|
||||
synthesizeKey("x", {});
|
||||
synthesizeKey("KEY_Enter", { code: "Enter" });
|
||||
synthesizeKey("x", { code: "KeyX" });
|
||||
is(theEdit.innerHTML, tests[i][2], "unexpected HTML for test " + i.toString());
|
||||
}
|
||||
|
||||
|
@ -714,6 +714,19 @@ struct ParamTraits<mozilla::layers::LayerHandle>
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ParamTraits<mozilla::layers::CompositableHandle>
|
||||
{
|
||||
typedef mozilla::layers::CompositableHandle paramType;
|
||||
|
||||
static void Write(Message* msg, const paramType& param) {
|
||||
WriteParam(msg, param.mHandle);
|
||||
}
|
||||
static bool Read(const Message* msg, PickleIterator* iter, paramType* result) {
|
||||
return ReadParam(msg, iter, &result->mHandle);
|
||||
}
|
||||
};
|
||||
|
||||
// Helper class for reading bitfields.
|
||||
// If T has bitfields members, derive ParamTraits<T> from BitfieldHelper<T>.
|
||||
template <typename ParamType>
|
||||
|
@ -29,7 +29,6 @@ AsyncCanvasRenderer::AsyncCanvasRenderer()
|
||||
, mIsAlphaPremultiplied(true)
|
||||
, mWidth(0)
|
||||
, mHeight(0)
|
||||
, mCanvasClientAsyncID(0)
|
||||
, mCanvasClient(nullptr)
|
||||
, mMutex("AsyncCanvasRenderer::mMutex")
|
||||
{
|
||||
@ -116,9 +115,9 @@ AsyncCanvasRenderer::SetCanvasClient(CanvasClient* aClient)
|
||||
{
|
||||
mCanvasClient = aClient;
|
||||
if (aClient) {
|
||||
mCanvasClientAsyncID = aClient->GetAsyncID();
|
||||
mCanvasClientAsyncHandle = aClient->GetAsyncHandle();
|
||||
} else {
|
||||
mCanvasClientAsyncID = 0;
|
||||
mCanvasClientAsyncHandle = CompositableHandle();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,9 +106,9 @@ public:
|
||||
return gfx::IntSize(mWidth, mHeight);
|
||||
}
|
||||
|
||||
uint64_t GetCanvasClientAsyncID() const
|
||||
CompositableHandle GetCanvasClientAsyncHandle() const
|
||||
{
|
||||
return mCanvasClientAsyncID;
|
||||
return mCanvasClientAsyncHandle;
|
||||
}
|
||||
|
||||
CanvasClient* GetCanvasClient() const
|
||||
@ -140,7 +140,7 @@ private:
|
||||
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
uint64_t mCanvasClientAsyncID;
|
||||
CompositableHandle mCanvasClientAsyncHandle;
|
||||
|
||||
// The lifetime of this pointer is controlled by OffscreenCanvas
|
||||
// Can be accessed in active thread and ImageBridge thread.
|
||||
|
@ -136,7 +136,7 @@ ImageContainer::EnsureImageClient(bool aCreate)
|
||||
if (imageBridge) {
|
||||
mImageClient = imageBridge->CreateImageClient(CompositableType::IMAGE, this);
|
||||
if (mImageClient) {
|
||||
mAsyncContainerID = mImageClient->GetAsyncID();
|
||||
mAsyncContainerHandle = mImageClient->GetAsyncHandle();
|
||||
mNotifyCompositeListener = new ImageContainerListener(this);
|
||||
}
|
||||
}
|
||||
@ -153,22 +153,20 @@ ImageContainer::ImageContainer(Mode flag)
|
||||
{
|
||||
if (flag == ASYNCHRONOUS) {
|
||||
EnsureImageClient(true);
|
||||
} else {
|
||||
mAsyncContainerID = sInvalidAsyncContainerId;
|
||||
}
|
||||
}
|
||||
|
||||
ImageContainer::ImageContainer(uint64_t aAsyncContainerID)
|
||||
ImageContainer::ImageContainer(const CompositableHandle& aHandle)
|
||||
: mReentrantMonitor("ImageContainer.mReentrantMonitor"),
|
||||
mGenerationCounter(++sGenerationCounter),
|
||||
mPaintCount(0),
|
||||
mDroppedImageCount(0),
|
||||
mImageFactory(nullptr),
|
||||
mRecycleBin(nullptr),
|
||||
mAsyncContainerID(aAsyncContainerID),
|
||||
mAsyncContainerHandle(aHandle),
|
||||
mCurrentProducerID(-1)
|
||||
{
|
||||
MOZ_ASSERT(mAsyncContainerID != sInvalidAsyncContainerId);
|
||||
MOZ_ASSERT(mAsyncContainerHandle);
|
||||
}
|
||||
|
||||
ImageContainer::~ImageContainer()
|
||||
@ -176,9 +174,9 @@ ImageContainer::~ImageContainer()
|
||||
if (mNotifyCompositeListener) {
|
||||
mNotifyCompositeListener->ClearImageContainer();
|
||||
}
|
||||
if (mAsyncContainerID) {
|
||||
if (mAsyncContainerHandle) {
|
||||
if (RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton()) {
|
||||
imageBridge->ForgetImageContainer(mAsyncContainerID);
|
||||
imageBridge->ForgetImageContainer(mAsyncContainerHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -344,14 +342,14 @@ ImageContainer::SetCurrentImagesInTransaction(const nsTArray<NonOwningImage>& aI
|
||||
|
||||
bool ImageContainer::IsAsync() const
|
||||
{
|
||||
return mAsyncContainerID != sInvalidAsyncContainerId;
|
||||
return !!mAsyncContainerHandle;
|
||||
}
|
||||
|
||||
uint64_t ImageContainer::GetAsyncContainerID()
|
||||
CompositableHandle ImageContainer::GetAsyncContainerHandle()
|
||||
{
|
||||
NS_ASSERTION(IsAsync(),"Shared image ID is only relevant to async ImageContainers");
|
||||
EnsureImageClient(false);
|
||||
return mAsyncContainerID;
|
||||
return mAsyncContainerHandle;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -385,7 +385,7 @@ public:
|
||||
* async container ID.
|
||||
* @param aAsyncContainerID async container ID for which we are a proxy
|
||||
*/
|
||||
explicit ImageContainer(uint64_t aAsyncContainerID);
|
||||
explicit ImageContainer(const CompositableHandle& aHandle);
|
||||
|
||||
typedef uint32_t FrameID;
|
||||
typedef uint32_t ProducerID;
|
||||
@ -486,7 +486,7 @@ public:
|
||||
*
|
||||
* Can be called from any thread.
|
||||
*/
|
||||
uint64_t GetAsyncContainerID();
|
||||
CompositableHandle GetAsyncContainerHandle();
|
||||
|
||||
/**
|
||||
* Returns if the container currently has an image.
|
||||
@ -649,7 +649,7 @@ private:
|
||||
// asynchronusly using the ImageBridge IPDL protocol.
|
||||
RefPtr<ImageClient> mImageClient;
|
||||
|
||||
uint64_t mAsyncContainerID;
|
||||
CompositableHandle mAsyncContainerHandle;
|
||||
|
||||
nsTArray<FrameID> mFrameIDsNotYetComposited;
|
||||
// ProducerID for last current image(s), including the frames in
|
||||
|
@ -279,6 +279,36 @@ private:
|
||||
uint64_t mHandle;
|
||||
};
|
||||
|
||||
// This is used to communicate Compositables across IPC channels. The Handle is valid
|
||||
// for layers in the same PLayerTransaction or PImageBridge. Handles are created by
|
||||
// ClientLayerManager or ImageBridgeChild, and are cached in the parent side on first
|
||||
// use.
|
||||
class CompositableHandle
|
||||
{
|
||||
friend struct IPC::ParamTraits<mozilla::layers::CompositableHandle>;
|
||||
public:
|
||||
CompositableHandle() : mHandle(0)
|
||||
{}
|
||||
CompositableHandle(const CompositableHandle& aOther) : mHandle(aOther.mHandle)
|
||||
{}
|
||||
explicit CompositableHandle(uint64_t aHandle) : mHandle(aHandle)
|
||||
{}
|
||||
bool IsValid() const {
|
||||
return mHandle != 0;
|
||||
}
|
||||
explicit operator bool() const {
|
||||
return IsValid();
|
||||
}
|
||||
bool operator ==(const CompositableHandle& aOther) const {
|
||||
return mHandle == aOther.mHandle;
|
||||
}
|
||||
uint64_t Value() const {
|
||||
return mHandle;
|
||||
}
|
||||
private:
|
||||
uint64_t mHandle;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -55,14 +55,14 @@ CanvasClientBridge::UpdateAsync(AsyncCanvasRenderer* aRenderer)
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t asyncID = aRenderer->GetCanvasClientAsyncID();
|
||||
if (asyncID == 0 || mAsyncID == asyncID) {
|
||||
CompositableHandle asyncID = aRenderer->GetCanvasClientAsyncHandle();
|
||||
if (!asyncID || mAsyncHandle == asyncID) {
|
||||
return;
|
||||
}
|
||||
|
||||
static_cast<ShadowLayerForwarder*>(GetForwarder())
|
||||
->AttachAsyncCompositable(asyncID, mLayer);
|
||||
mAsyncID = asyncID;
|
||||
mAsyncHandle = asyncID;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -184,7 +184,6 @@ public:
|
||||
CanvasClientBridge(CompositableForwarder* aLayerForwarder,
|
||||
TextureFlags aFlags)
|
||||
: CanvasClient(aLayerForwarder, aFlags)
|
||||
, mAsyncID(0)
|
||||
, mLayer(nullptr)
|
||||
{
|
||||
}
|
||||
@ -206,7 +205,7 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
uint64_t mAsyncID;
|
||||
CompositableHandle mAsyncHandle;
|
||||
ShadowableLayer* mLayer;
|
||||
};
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "mozilla/hal_sandbox/PHal.h" // for ScreenConfiguration
|
||||
#include "mozilla/layers/CompositableClient.h"
|
||||
#include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
|
||||
#include "mozilla/layers/ContentClient.h"
|
||||
#include "mozilla/layers/FrameUniformityData.h"
|
||||
#include "mozilla/layers/ISurfaceAllocator.h"
|
||||
#include "mozilla/layers/LayersMessages.h" // for EditReply, etc
|
||||
@ -660,7 +659,8 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
|
||||
// Skip the synchronization for buffer since we also skip the painting during
|
||||
// device-reset status.
|
||||
if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
|
||||
if (mForwarder->GetSyncObject()) {
|
||||
if (mForwarder->GetSyncObject() &&
|
||||
mForwarder->GetSyncObject()->IsSyncObjectValid()) {
|
||||
mForwarder->GetSyncObject()->FinalizeFrame();
|
||||
}
|
||||
}
|
||||
@ -680,35 +680,12 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
|
||||
}
|
||||
|
||||
// forward this transaction's changeset to our LayerManagerComposite
|
||||
bool sent;
|
||||
AutoTArray<EditReply, 10> replies;
|
||||
if (mForwarder->EndTransaction(&replies, mRegionToClear,
|
||||
mLatestTransactionId, aScheduleComposite, mPaintSequenceNumber,
|
||||
mIsRepeatTransaction, transactionStart, &sent)) {
|
||||
for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) {
|
||||
const EditReply& reply = replies[i];
|
||||
|
||||
switch (reply.type()) {
|
||||
case EditReply::TOpContentBufferSwap: {
|
||||
MOZ_LAYERS_LOG(("[LayersForwarder] DoubleBufferSwap"));
|
||||
|
||||
const OpContentBufferSwap& obs = reply.get_OpContentBufferSwap();
|
||||
|
||||
RefPtr<CompositableClient> compositable =
|
||||
CompositableClient::FromIPDLActor(obs.compositableChild());
|
||||
ContentClientRemote* contentClient =
|
||||
static_cast<ContentClientRemote*>(compositable.get());
|
||||
MOZ_ASSERT(contentClient);
|
||||
|
||||
contentClient->SwapBuffers(obs.frontUpdatedRegion());
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("not reached");
|
||||
}
|
||||
}
|
||||
|
||||
bool sent = false;
|
||||
bool ok = mForwarder->EndTransaction(
|
||||
mRegionToClear, mLatestTransactionId, aScheduleComposite,
|
||||
mPaintSequenceNumber, mIsRepeatTransaction, transactionStart,
|
||||
&sent);
|
||||
if (ok) {
|
||||
if (sent) {
|
||||
mNeedsComposite = false;
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ ClientPaintedLayer::PaintThebes()
|
||||
mValidRegion.Or(mValidRegion, state.mRegionToDraw);
|
||||
|
||||
ContentClientRemote* contentClientRemote = static_cast<ContentClientRemote*>(mContentClient.get());
|
||||
MOZ_ASSERT(contentClientRemote->GetIPDLActor());
|
||||
MOZ_ASSERT(contentClientRemote->GetIPCHandle());
|
||||
|
||||
// Hold(this) ensures this layer is kept alive through the current transaction
|
||||
// The ContentClient assumes this layer is kept alive (e.g., in CreateBuffer),
|
||||
|
@ -1,116 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "CompositableChild.h"
|
||||
#include "CompositableClient.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/* static */ PCompositableChild*
|
||||
CompositableChild::CreateActor()
|
||||
{
|
||||
CompositableChild* child = new CompositableChild();
|
||||
child->AddRef();
|
||||
return child;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
CompositableChild::DestroyActor(PCompositableChild* aChild)
|
||||
{
|
||||
static_cast<CompositableChild*>(aChild)->Release();
|
||||
}
|
||||
|
||||
CompositableChild::CompositableChild()
|
||||
: mCompositableClient(nullptr),
|
||||
mCanSend(true)
|
||||
{
|
||||
}
|
||||
|
||||
CompositableChild::~CompositableChild()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
CompositableChild::IsConnected() const
|
||||
{
|
||||
return mCompositableClient && mCanSend;
|
||||
}
|
||||
|
||||
void
|
||||
CompositableChild::Init(CompositableClient* aCompositable)
|
||||
{
|
||||
mCompositableClient = aCompositable;
|
||||
}
|
||||
|
||||
void
|
||||
CompositableChild::RevokeCompositableClient()
|
||||
{
|
||||
mCompositableClient = nullptr;
|
||||
}
|
||||
|
||||
RefPtr<CompositableClient>
|
||||
CompositableChild::GetCompositableClient()
|
||||
{
|
||||
return mCompositableClient;
|
||||
}
|
||||
|
||||
void
|
||||
CompositableChild::ActorDestroy(ActorDestroyReason)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mCanSend = false;
|
||||
|
||||
if (mCompositableClient) {
|
||||
mCompositableClient->mCompositableChild = nullptr;
|
||||
mCompositableClient = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ PCompositableChild*
|
||||
AsyncCompositableChild::CreateActor(uint64_t aAsyncID)
|
||||
{
|
||||
AsyncCompositableChild* child = new AsyncCompositableChild(aAsyncID);
|
||||
child->AddRef();
|
||||
return child;
|
||||
}
|
||||
|
||||
AsyncCompositableChild::AsyncCompositableChild(uint64_t aAsyncID)
|
||||
: mLock("AsyncCompositableChild.mLock"),
|
||||
mAsyncID(aAsyncID)
|
||||
{
|
||||
}
|
||||
|
||||
AsyncCompositableChild::~AsyncCompositableChild()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
AsyncCompositableChild::ActorDestroy(ActorDestroyReason)
|
||||
{
|
||||
mCanSend = false;
|
||||
|
||||
// We do not revoke CompositableClient::mCompositableChild here, since that
|
||||
// could race with the main thread.
|
||||
RevokeCompositableClient();
|
||||
}
|
||||
|
||||
void
|
||||
AsyncCompositableChild::RevokeCompositableClient()
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
mCompositableClient = nullptr;
|
||||
}
|
||||
|
||||
RefPtr<CompositableClient>
|
||||
AsyncCompositableChild::GetCompositableClient()
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
return CompositableChild::GetCompositableClient();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
@ -1,91 +0,0 @@
|
||||
/* -*- 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_layers_client_CompositableChild_h
|
||||
#define mozilla_gfx_layers_client_CompositableChild_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include "IPDLActor.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/layers/PCompositableChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class CompositableClient;
|
||||
class AsyncCompositableChild;
|
||||
|
||||
/**
|
||||
* IPDL actor used by CompositableClient to match with its corresponding
|
||||
* CompositableHost on the compositor side.
|
||||
*
|
||||
* CompositableChild is owned by a CompositableClient.
|
||||
*/
|
||||
class CompositableChild : public PCompositableChild
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositableChild)
|
||||
|
||||
static PCompositableChild* CreateActor();
|
||||
static void DestroyActor(PCompositableChild* aChild);
|
||||
|
||||
void Init(CompositableClient* aCompositable);
|
||||
virtual void RevokeCompositableClient();
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason) override;
|
||||
|
||||
virtual RefPtr<CompositableClient> GetCompositableClient();
|
||||
|
||||
virtual AsyncCompositableChild* AsAsyncCompositableChild() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// These should only be called on the IPDL thread.
|
||||
bool IsConnected() const;
|
||||
bool CanSend() const {
|
||||
return mCanSend;
|
||||
}
|
||||
|
||||
protected:
|
||||
CompositableChild();
|
||||
virtual ~CompositableChild();
|
||||
|
||||
protected:
|
||||
CompositableClient* mCompositableClient;
|
||||
bool mCanSend;
|
||||
};
|
||||
|
||||
// This CompositableChild can be used off the main thread.
|
||||
class AsyncCompositableChild final : public CompositableChild
|
||||
{
|
||||
public:
|
||||
static PCompositableChild* CreateActor(uint64_t aAsyncID);
|
||||
|
||||
void RevokeCompositableClient() override;
|
||||
RefPtr<CompositableClient> GetCompositableClient() override;
|
||||
|
||||
void ActorDestroy(ActorDestroyReason) override;
|
||||
|
||||
AsyncCompositableChild* AsAsyncCompositableChild() override {
|
||||
return this;
|
||||
}
|
||||
|
||||
uint64_t GetAsyncID() const {
|
||||
return mAsyncID;
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit AsyncCompositableChild(uint64_t aAsyncID);
|
||||
~AsyncCompositableChild() override;
|
||||
|
||||
private:
|
||||
Mutex mLock;
|
||||
uint64_t mAsyncID;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_gfx_layers_client_CompositableChild_h
|
@ -6,13 +6,11 @@
|
||||
#include "mozilla/layers/CompositableClient.h"
|
||||
#include <stdint.h> // for uint64_t, uint32_t
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "mozilla/layers/CompositableChild.h"
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
#include "mozilla/layers/TextureClient.h" // for TextureClient, etc
|
||||
#include "mozilla/layers/TextureClientOGL.h"
|
||||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||
#include "mozilla/layers/PCompositableChild.h"
|
||||
#include "mozilla/layers/TextureClientRecycleAllocator.h"
|
||||
#ifdef XP_WIN
|
||||
#include "gfxWindowsPlatform.h" // for gfxWindowsPlatform
|
||||
@ -28,36 +26,21 @@ namespace layers {
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
void
|
||||
CompositableClient::InitIPDLActor(PCompositableChild* aActor, uint64_t aAsyncID)
|
||||
CompositableClient::InitIPDL(const CompositableHandle& aHandle)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
MOZ_ASSERT(aHandle);
|
||||
|
||||
mForwarder->AssertInForwarderThread();
|
||||
|
||||
mAsyncID = aAsyncID;
|
||||
mCompositableChild = static_cast<CompositableChild*>(aActor);
|
||||
mCompositableChild->Init(this);
|
||||
}
|
||||
|
||||
/* static */ RefPtr<CompositableClient>
|
||||
CompositableClient::FromIPDLActor(PCompositableChild* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
|
||||
RefPtr<CompositableClient> client = static_cast<CompositableChild*>(aActor)->GetCompositableClient();
|
||||
if (!client) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
client->mForwarder->AssertInForwarderThread();
|
||||
return client;
|
||||
mHandle = aHandle;
|
||||
mIsAsync = !NS_IsMainThread();
|
||||
}
|
||||
|
||||
CompositableClient::CompositableClient(CompositableForwarder* aForwarder,
|
||||
TextureFlags aTextureFlags)
|
||||
: mForwarder(aForwarder)
|
||||
, mTextureFlags(aTextureFlags)
|
||||
, mAsyncID(0)
|
||||
, mIsAsync(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -72,17 +55,11 @@ CompositableClient::GetCompositorBackendType() const
|
||||
return mForwarder->GetCompositorBackendType();
|
||||
}
|
||||
|
||||
PCompositableChild*
|
||||
CompositableClient::GetIPDLActor() const
|
||||
{
|
||||
return mCompositableChild;
|
||||
}
|
||||
|
||||
bool
|
||||
CompositableClient::Connect(ImageContainer* aImageContainer)
|
||||
{
|
||||
MOZ_ASSERT(!mCompositableChild);
|
||||
if (!GetForwarder() || GetIPDLActor()) {
|
||||
MOZ_ASSERT(!mHandle);
|
||||
if (!GetForwarder() || mHandle) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -96,35 +73,29 @@ CompositableClient::IsConnected() const
|
||||
{
|
||||
// CanSend() is only reliable in the same thread as the IPDL channel.
|
||||
mForwarder->AssertInForwarderThread();
|
||||
return mCompositableChild && mCompositableChild->IsConnected();
|
||||
return !!mHandle;
|
||||
}
|
||||
|
||||
void
|
||||
CompositableClient::Destroy()
|
||||
{
|
||||
if (!mCompositableChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTextureClientRecycler) {
|
||||
mTextureClientRecycler->Destroy();
|
||||
}
|
||||
|
||||
// Take away our IPDL's actor reference back to us.
|
||||
mCompositableChild->RevokeCompositableClient();
|
||||
|
||||
// Schedule the IPDL actor to be destroyed on the forwarder's thread.
|
||||
mForwarder->Destroy(mCompositableChild);
|
||||
mCompositableChild = nullptr;
|
||||
if (mHandle) {
|
||||
mForwarder->ReleaseCompositable(mHandle);
|
||||
mHandle = CompositableHandle();
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
CompositableClient::GetAsyncID() const
|
||||
CompositableHandle
|
||||
CompositableClient::GetAsyncHandle() const
|
||||
{
|
||||
if (mCompositableChild) {
|
||||
return mAsyncID;
|
||||
if (mIsAsync) {
|
||||
return mHandle;
|
||||
}
|
||||
return 0; // zero is always an invalid async ID
|
||||
return CompositableHandle();
|
||||
}
|
||||
|
||||
already_AddRefed<TextureClient>
|
||||
|
@ -27,6 +27,7 @@ class CompositableForwarder;
|
||||
class CompositableChild;
|
||||
class PCompositableChild;
|
||||
class TextureClientRecycleAllocator;
|
||||
class ContentClientRemote;
|
||||
|
||||
/**
|
||||
* CompositableClient manages the texture-specific logic for composite layers,
|
||||
@ -113,8 +114,6 @@ public:
|
||||
|
||||
bool IsConnected() const;
|
||||
|
||||
PCompositableChild* GetIPDLActor() const;
|
||||
|
||||
CompositableForwarder* GetForwarder() const
|
||||
{
|
||||
return mForwarder;
|
||||
@ -125,10 +124,17 @@ public:
|
||||
* layer. It is not used if the compositable is used with the regular shadow
|
||||
* layer forwarder.
|
||||
*
|
||||
* If this returns zero, it means the compositable is not async (it is used
|
||||
* If this returns empty, it means the compositable is not async (it is used
|
||||
* on the main thread).
|
||||
*/
|
||||
uint64_t GetAsyncID() const;
|
||||
CompositableHandle GetAsyncHandle() const;
|
||||
|
||||
/**
|
||||
* Handle for IPDL communication.
|
||||
*/
|
||||
CompositableHandle GetIPCHandle() const {
|
||||
return mHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the Compositor to create a TextureHost for this TextureClient.
|
||||
@ -160,9 +166,9 @@ public:
|
||||
*/
|
||||
virtual void RemoveTexture(TextureClient* aTexture);
|
||||
|
||||
static RefPtr<CompositableClient> FromIPDLActor(PCompositableChild* aActor);
|
||||
virtual ContentClientRemote* AsContentClientRemote() { return nullptr; }
|
||||
|
||||
void InitIPDLActor(PCompositableChild* aActor, uint64_t aAsyncID = 0);
|
||||
void InitIPDL(const CompositableHandle& aHandle);
|
||||
|
||||
TextureFlags GetTextureFlags() const { return mTextureFlags; }
|
||||
|
||||
@ -174,14 +180,14 @@ public:
|
||||
TextureClient* aTexture,
|
||||
TextureDumpMode aCompress);
|
||||
protected:
|
||||
RefPtr<CompositableChild> mCompositableChild;
|
||||
RefPtr<CompositableForwarder> mForwarder;
|
||||
// Some layers may want to enforce some flags to all their textures
|
||||
// (like disallowing tiling)
|
||||
TextureFlags mTextureFlags;
|
||||
RefPtr<TextureClientRecycleAllocator> mTextureClientRecycler;
|
||||
|
||||
uint64_t mAsyncID;
|
||||
CompositableHandle mHandle;
|
||||
bool mIsAsync;
|
||||
|
||||
friend class CompositableChild;
|
||||
};
|
||||
|
@ -119,6 +119,10 @@ public:
|
||||
virtual void Updated(const nsIntRegion& aRegionToDraw,
|
||||
const nsIntRegion& aVisibleRegion,
|
||||
bool aDidSelfCopy) = 0;
|
||||
|
||||
ContentClientRemote* AsContentClientRemote() override {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
// thin wrapper around RotatedContentBuffer, for on-mtc
|
||||
|
@ -278,7 +278,6 @@ ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
|
||||
ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags)
|
||||
: ImageClient(aFwd, aFlags, CompositableType::IMAGE_BRIDGE)
|
||||
, mAsyncContainerID(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -288,11 +287,11 @@ ImageClientBridge::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlag
|
||||
if (!GetForwarder() || !mLayer) {
|
||||
return false;
|
||||
}
|
||||
if (mAsyncContainerID == aContainer->GetAsyncContainerID()) {
|
||||
if (mAsyncContainerHandle == aContainer->GetAsyncContainerHandle()) {
|
||||
return true;
|
||||
}
|
||||
mAsyncContainerID = aContainer->GetAsyncContainerID();
|
||||
static_cast<ShadowLayerForwarder*>(GetForwarder())->AttachAsyncCompositable(mAsyncContainerID, mLayer);
|
||||
mAsyncContainerHandle = aContainer->GetAsyncContainerHandle();
|
||||
static_cast<ShadowLayerForwarder*>(GetForwarder())->AttachAsyncCompositable(mAsyncContainerHandle, mLayer);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
uint64_t mAsyncContainerID;
|
||||
CompositableHandle mAsyncContainerHandle;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
@ -111,6 +111,7 @@ public:
|
||||
|
||||
virtual SyncType GetSyncType() = 0;
|
||||
virtual void FinalizeFrame() = 0;
|
||||
virtual bool IsSyncObjectValid() = 0;
|
||||
|
||||
protected:
|
||||
SyncObject() { }
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "nsDebug.h" // for NS_WARNING
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#include "mozilla/layers/PCompositableParent.h"
|
||||
#include "IPDLActor.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -28,38 +27,6 @@ namespace layers {
|
||||
|
||||
class Compositor;
|
||||
|
||||
/**
|
||||
* IPDL actor used by CompositableHost to match with its corresponding
|
||||
* CompositableClient on the content side.
|
||||
*
|
||||
* CompositableParent is owned by the IPDL system. It's deletion is triggered
|
||||
* by either the CompositableChild's deletion, or by the IPDL communication
|
||||
* going down.
|
||||
*/
|
||||
class CompositableParent : public ParentActor<PCompositableParent>
|
||||
{
|
||||
public:
|
||||
CompositableParent(CompositableParentManager* aMgr, const TextureInfo& aTextureInfo)
|
||||
{
|
||||
MOZ_COUNT_CTOR(CompositableParent);
|
||||
mHost = CompositableHost::Create(aTextureInfo);
|
||||
}
|
||||
|
||||
~CompositableParent()
|
||||
{
|
||||
MOZ_COUNT_DTOR(CompositableParent);
|
||||
}
|
||||
|
||||
virtual void Destroy() override
|
||||
{
|
||||
if (mHost) {
|
||||
mHost->Detach(nullptr, CompositableHost::FORCE_DETACH);
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<CompositableHost> mHost;
|
||||
};
|
||||
|
||||
CompositableHost::CompositableHost(const TextureInfo& aTextureInfo)
|
||||
: mTextureInfo(aTextureInfo)
|
||||
, mCompositorID(0)
|
||||
@ -77,27 +44,6 @@ CompositableHost::~CompositableHost()
|
||||
MOZ_COUNT_DTOR(CompositableHost);
|
||||
}
|
||||
|
||||
PCompositableParent*
|
||||
CompositableHost::CreateIPDLActor(CompositableParentManager* aMgr,
|
||||
const TextureInfo& aTextureInfo)
|
||||
{
|
||||
return new CompositableParent(aMgr, aTextureInfo);
|
||||
}
|
||||
|
||||
bool
|
||||
CompositableHost::DestroyIPDLActor(PCompositableParent* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
CompositableHost*
|
||||
CompositableHost::FromIPDLActor(PCompositableParent* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
return static_cast<CompositableParent*>(aActor)->mHost;
|
||||
}
|
||||
|
||||
void
|
||||
CompositableHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
|
||||
{
|
||||
@ -209,11 +155,5 @@ CompositableHost::DumpTextureHost(std::stringstream& aStream, TextureHost* aText
|
||||
aStream << gfxUtils::GetAsDataURI(dSurf).get();
|
||||
}
|
||||
|
||||
void
|
||||
CompositableHost::ReceivedDestroy(PCompositableParent* aActor)
|
||||
{
|
||||
static_cast<CompositableParent*>(aActor)->RecvDestroy();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user