Merge m-c to autoland. a=merge

--HG--
extra : rebase_source : 0de29cc9f544d8882d3e8c13572d3c4b98ba3c26
This commit is contained in:
Ryan VanderMeulen 2017-01-18 09:59:53 -05:00
commit 187beffa39
283 changed files with 18154 additions and 16852 deletions

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
},

View File

@ -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]

View File

@ -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");
});
});
});

View 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>

View 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>

View File

@ -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);

View File

@ -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

View File

@ -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,

View File

@ -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,
});
},

View File

@ -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,

View File

@ -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

View File

@ -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;
}

View File

@ -277,7 +277,7 @@ Attr::GetBaseURI(bool aTryUseXHRDocBaseURI) const
void
Attr::GetTextContentInternal(nsAString& aTextContent,
ErrorResult& aError)
OOMReporter& aError)
{
OwnerDoc()->WarnOnceAbout(nsIDocument::eTextContent);

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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;

View File

@ -18,6 +18,7 @@ Timeout::Timeout()
: mCleared(false),
mRunning(false),
mIsInterval(false),
mIsTracking(false),
mReason(Reason::eTimeoutOrInterval),
mTimeoutId(0),
mInterval(0),

View File

@ -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()

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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());
}
};

View File

@ -410,7 +410,7 @@ nsINode::ChildNodes()
}
void
nsINode::GetTextContentInternal(nsAString& aTextContent, ErrorResult& aError)
nsINode::GetTextContentInternal(nsAString& aTextContent, OOMReporter& aError)
{
SetDOMStringToNull(aTextContent);
}

View File

@ -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)
{

View File

@ -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,

View File

@ -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():

View File

@ -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):

View File

@ -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
******************************************************************************/

View File

@ -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

View File

@ -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&);

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -114,6 +114,9 @@ WebGLContextOptions::WebGLContextOptions()
WebGLContext::WebGLContext()
: WebGLContextUnchecked(nullptr)
, mMaxPerfWarnings(gfxPrefs::WebGLMaxPerfWarnings())
, mNumPerfWarnings(0)
, mMaxAcceptableFBStatusInvals(gfxPrefs::WebGLMaxAcceptableFBStatusInvals())
, mBufferFetchingIsVerified(false)
, mBufferFetchingHasPerVertex(false)
, mMaxFetchedVertices(0)

View File

@ -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;

View File

@ -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++) {

View File

@ -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)
{

View File

@ -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

View File

@ -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();
////////////////

View File

@ -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);
}
}

View File

@ -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

View File

@ -224,7 +224,7 @@ WebGLRenderbuffer::RenderbufferStorage(const char* funcName, uint32_t samples,
mHeight = height;
mImageDataStatus = WebGLImageDataStatus::UninitializedImageData;
InvalidateStatusOfAttachedFBs();
InvalidateStatusOfAttachedFBs(funcName);
}
void

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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
View 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

View 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

View File

@ -6,7 +6,9 @@
EXTRA_JS_MODULES += [
'ImageObjectProcessor.jsm',
'Manifest.jsm',
'ManifestFinder.jsm',
'ManifestIcons.jsm',
'ManifestObtainer.jsm',
'ManifestProcessor.jsm',
'ValueExtractor.jsm',

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

View File

@ -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]

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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]

View 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);
});

View File

@ -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);

View File

@ -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());
}

View File

@ -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>

View File

@ -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();
}
}

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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),

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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;
};

View File

@ -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

View File

@ -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;
}

View File

@ -129,7 +129,7 @@ public:
}
protected:
uint64_t mAsyncContainerID;
CompositableHandle mAsyncContainerHandle;
};
} // namespace layers

View File

@ -111,6 +111,7 @@ public:
virtual SyncType GetSyncType() = 0;
virtual void FinalizeFrame() = 0;
virtual bool IsSyncObjectValid() = 0;
protected:
SyncObject() { }

View File

@ -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