(sysprin);
}
struct IsWhitespace {
diff --git a/caps/nsScriptSecurityManager.h b/caps/nsScriptSecurityManager.h
index da20441dd60a..d633c9a4a941 100644
--- a/caps/nsScriptSecurityManager.h
+++ b/caps/nsScriptSecurityManager.h
@@ -24,7 +24,7 @@
class nsCString;
class nsIIOService;
class nsIStringBundle;
-class nsSystemPrincipal;
+class SystemPrincipal;
namespace mozilla {
class OriginAttributes;
@@ -55,7 +55,7 @@ public:
// Invoked exactly once, by XPConnect.
static void InitStatics();
- static nsSystemPrincipal*
+ static SystemPrincipal*
SystemPrincipalSingletonConstructor();
/**
diff --git a/devtools/client/inspector/boxmodel/components/BoxModelEditable.js b/devtools/client/inspector/boxmodel/components/BoxModelEditable.js
index f90954d5ffe5..9b20cd560338 100644
--- a/devtools/client/inspector/boxmodel/components/BoxModelEditable.js
+++ b/devtools/client/inspector/boxmodel/components/BoxModelEditable.js
@@ -16,7 +16,7 @@ module.exports = createClass({
propTypes: {
box: PropTypes.string.isRequired,
- direction: PropTypes.string.isRequired,
+ direction: PropTypes.string,
property: PropTypes.string.isRequired,
textContent: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
onShowBoxModelEditor: PropTypes.func.isRequired,
@@ -42,13 +42,15 @@ module.exports = createClass({
textContent,
} = this.props;
- let rotate = (direction == "left" || direction == "right") &&
+ let rotate = direction &&
+ (direction == "left" || direction == "right") &&
textContent.toString().length > LONG_TEXT_ROTATE_LIMIT;
return dom.p(
{
- className: `boxmodel-${box} boxmodel-${direction}
- ${rotate ? "boxmodel-rotate" : ""}`,
+ className: `boxmodel-${box}
+ ${direction ? " boxmodel-" + direction : "boxmodel-" + property}
+ ${rotate ? " boxmodel-rotate" : ""}`,
},
dom.span(
{
diff --git a/devtools/client/inspector/boxmodel/components/BoxModelMain.js b/devtools/client/inspector/boxmodel/components/BoxModelMain.js
index 37581a630cae..07a4c84ab4b5 100644
--- a/devtools/client/inspector/boxmodel/components/BoxModelMain.js
+++ b/devtools/client/inspector/boxmodel/components/BoxModelMain.js
@@ -134,6 +134,41 @@ module.exports = createClass({
height = this.getHeightValue(height);
width = this.getWidthValue(width);
+ let contentBox = layout["box-sizing"] == "content-box" ?
+ dom.p(
+ {
+ className: "boxmodel-size",
+ },
+ BoxModelEditable({
+ box: "content",
+ property: "width",
+ textContent: width,
+ onShowBoxModelEditor
+ }),
+ dom.span(
+ {},
+ "\u00D7"
+ ),
+ BoxModelEditable({
+ box: "content",
+ property: "height",
+ textContent: height,
+ onShowBoxModelEditor
+ })
+ )
+ :
+ dom.p(
+ {
+ className: "boxmodel-size",
+ },
+ dom.span(
+ {
+ title: BOXMODEL_L10N.getStr("boxmodel.content"),
+ },
+ SHARED_L10N.getFormatStr("dimensions", width, height)
+ )
+ );
+
return dom.div(
{
className: "boxmodel-main",
@@ -198,7 +233,7 @@ module.exports = createClass({
title: BOXMODEL_L10N.getStr("boxmodel.padding"),
},
dom.div({
- className: "boxmodel-content",
+ className: "boxmodel-contents",
"data-box": "content",
title: BOXMODEL_L10N.getStr("boxmodel.content"),
})
@@ -330,18 +365,7 @@ module.exports = createClass({
textContent: paddingLeft,
onShowBoxModelEditor,
}),
- dom.p(
- {
- className: "boxmodel-size",
- },
- dom.span(
- {
- "data-box": "content",
- title: BOXMODEL_L10N.getStr("boxmodel.content"),
- },
- SHARED_L10N.getFormatStr("dimensions", width, height)
- )
- )
+ contentBox
);
},
diff --git a/devtools/client/inspector/boxmodel/components/ComputedProperty.js b/devtools/client/inspector/boxmodel/components/ComputedProperty.js
index 87fef1a3d4c2..262258ba6184 100644
--- a/devtools/client/inspector/boxmodel/components/ComputedProperty.js
+++ b/devtools/client/inspector/boxmodel/components/ComputedProperty.js
@@ -28,6 +28,7 @@ module.exports = createClass({
return dom.div(
{
className: "property-view",
+ "data-property-name": name,
tabIndex: "0",
ref: container => {
this.container = container;
diff --git a/devtools/client/inspector/boxmodel/test/browser.ini b/devtools/client/inspector/boxmodel/test/browser.ini
index c9881c903937..ba05da95490b 100644
--- a/devtools/client/inspector/boxmodel/test/browser.ini
+++ b/devtools/client/inspector/boxmodel/test/browser.ini
@@ -22,6 +22,7 @@ support-files =
[browser_boxmodel_guides.js]
[browser_boxmodel_navigation.js]
skip-if = true # Bug 1336198
+[browser_boxmodel_properties.js]
[browser_boxmodel_rotate-labels-on-sides.js]
[browser_boxmodel_sync.js]
[browser_boxmodel_tooltips.js]
diff --git a/devtools/client/inspector/boxmodel/test/browser_boxmodel.js b/devtools/client/inspector/boxmodel/test/browser_boxmodel.js
index 9e085cafe232..3ad67b4da72d 100644
--- a/devtools/client/inspector/boxmodel/test/browser_boxmodel.js
+++ b/devtools/client/inspector/boxmodel/test/browser_boxmodel.js
@@ -14,8 +14,12 @@ var res1 = [
value: "160" + "\u00D7" + "160.117"
},
{
- selector: ".boxmodel-size > span",
- value: "100" + "\u00D7" + "100.117"
+ selector: ".boxmodel-size > .boxmodel-width",
+ value: "100"
+ },
+ {
+ selector: ".boxmodel-size > .boxmodel-height",
+ value: "100.117"
},
{
selector: ".boxmodel-margin.boxmodel-top > span",
@@ -73,8 +77,12 @@ var res2 = [
value: "190" + "\u00D7" + "210"
},
{
- selector: ".boxmodel-size > span",
- value: "100" + "\u00D7" + "150"
+ selector: ".boxmodel-size > .boxmodel-width",
+ value: "100"
+ },
+ {
+ selector: ".boxmodel-size > .boxmodel-height",
+ value: "150"
},
{
selector: ".boxmodel-margin.boxmodel-top > span",
diff --git a/devtools/client/inspector/boxmodel/test/browser_boxmodel_properties.js b/devtools/client/inspector/boxmodel/test/browser_boxmodel_properties.js
new file mode 100644
index 000000000000..95479f756538
--- /dev/null
+++ b/devtools/client/inspector/boxmodel/test/browser_boxmodel_properties.js
@@ -0,0 +1,120 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the box model properties list displays the right values
+// and that it updates when the node's style is changed.
+
+const TEST_URI = `
+
+ Test Node
+`;
+
+const res1 = [
+ {
+ property: "box-sizing",
+ value: "border-box"
+ },
+ {
+ property: "display",
+ value: "block"
+ },
+ {
+ property: "float",
+ value: "left"
+ },
+ {
+ property: "line-height",
+ value: "20px"
+ },
+ {
+ property: "position",
+ value: "relative"
+ },
+ {
+ property: "z-index",
+ value: 2
+ },
+];
+
+const res2 = [
+ {
+ property: "box-sizing",
+ value: "content-box"
+ },
+ {
+ property: "display",
+ value: "block"
+ },
+ {
+ property: "float",
+ value: "right"
+ },
+ {
+ property: "line-height",
+ value: "10px"
+ },
+ {
+ property: "position",
+ value: "static"
+ },
+ {
+ property: "z-index",
+ value: 5
+ },
+];
+
+add_task(function* () {
+ yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+ let { inspector, boxmodel, testActor } = yield openLayoutView();
+ yield selectNode("div", inspector);
+
+ yield testInitialValues(inspector, boxmodel);
+ yield testChangingValues(inspector, boxmodel, testActor);
+});
+
+function* testInitialValues(inspector, boxmodel) {
+ info("Test that the initial values of the box model are correct");
+ let doc = boxmodel.document;
+
+ for (let { property, value } of res1) {
+ let elt = doc.querySelector(getPropertySelector(property));
+ is(elt.textContent, value, property + " has the right value.");
+ }
+}
+
+function* testChangingValues(inspector, boxmodel, testActor) {
+ info("Test that changing the document updates the box model");
+ let doc = boxmodel.document;
+
+ let onUpdated = waitForUpdate(inspector);
+ yield testActor.setAttribute("div", "style",
+ "box-sizing:content-box;float:right;" +
+ "line-height:10px;position:static;z-index:5;");
+ yield onUpdated;
+
+ for (let { property, value } of res2) {
+ let elt = doc.querySelector(getPropertySelector(property));
+ is(elt.textContent, value, property + " has the right value after style update.");
+ }
+}
+
+function getPropertySelector(propertyName) {
+ return `.boxmodel-properties-wrapper .property-view` +
+ `[data-property-name=${propertyName}] .property-value`;
+}
diff --git a/devtools/client/inspector/boxmodel/test/doc_boxmodel_iframe2.html b/devtools/client/inspector/boxmodel/test/doc_boxmodel_iframe2.html
index 1f1b0463c3d4..0fa6dc02e97d 100644
--- a/devtools/client/inspector/boxmodel/test/doc_boxmodel_iframe2.html
+++ b/devtools/client/inspector/boxmodel/test/doc_boxmodel_iframe2.html
@@ -1,3 +1,3 @@
-iframe 1
-
+iframe 1
+
diff --git a/devtools/client/inspector/boxmodel/test/head.js b/devtools/client/inspector/boxmodel/test/head.js
index b842968a5595..4df6e686a28e 100644
--- a/devtools/client/inspector/boxmodel/test/head.js
+++ b/devtools/client/inspector/boxmodel/test/head.js
@@ -11,8 +11,10 @@ Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/inspector/test/head.js",
this);
+Services.prefs.setBoolPref("devtools.layoutview.enabled", true);
Services.prefs.setIntPref("devtools.toolbox.footer.height", 350);
registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("devtools.layoutview.enabled");
Services.prefs.clearUserPref("devtools.toolbox.footer.height");
});
@@ -66,6 +68,36 @@ function openBoxModelView() {
});
}
+/**
+ * Open the toolbox, with the inspector tool visible, and the layout view
+ * sidebar tab selected to display the box model view with properties.
+ *
+ * @return {Promise} a promise that resolves when the inspector is ready and the box model
+ * view is visible and ready.
+ */
+function openLayoutView() {
+ return openInspectorSidebarTab("layoutview").then(data => {
+ // The actual highligher show/hide methods are mocked in box model tests.
+ // The highlighter is tested in devtools/inspector/test.
+ function mockHighlighter({highlighter}) {
+ highlighter.showBoxModel = function () {
+ return promise.resolve();
+ };
+ highlighter.hideBoxModel = function () {
+ return promise.resolve();
+ };
+ }
+ mockHighlighter(data.toolbox);
+
+ return {
+ toolbox: data.toolbox,
+ inspector: data.inspector,
+ boxmodel: data.inspector.boxmodel,
+ testActor: data.testActor
+ };
+ });
+}
+
/**
* Wait for the boxmodel-view-updated event.
*
diff --git a/devtools/client/inspector/inspector.js b/devtools/client/inspector/inspector.js
index b58dce429004..349945a49cae 100644
--- a/devtools/client/inspector/inspector.js
+++ b/devtools/client/inspector/inspector.js
@@ -926,10 +926,18 @@ Inspector.prototype = {
this.ruleview.destroy();
}
+ if (this.boxmodel) {
+ this.boxmodel.destroy();
+ }
+
if (this.computedview) {
this.computedview.destroy();
}
+ if (this.gridInspector) {
+ this.gridInspector.destroy();
+ }
+
if (this.layoutview) {
this.layoutview.destroy();
}
diff --git a/devtools/client/jsonview/main.js b/devtools/client/jsonview/main.js
index eb552649717b..b12fe414225b 100644
--- a/devtools/client/jsonview/main.js
+++ b/devtools/client/jsonview/main.js
@@ -50,7 +50,7 @@ var JsonView = {
* in the parent process.
*/
onSave: function (message) {
- JsonViewUtils.getTargetFile(file => {
+ JsonViewUtils.getTargetFile().then(file => {
if (file) {
JsonViewUtils.saveToFile(file, message.data);
}
diff --git a/devtools/client/themes/boxmodel.css b/devtools/client/themes/boxmodel.css
index d8e2b4d31efd..4cef659de5aa 100644
--- a/devtools/client/themes/boxmodel.css
+++ b/devtools/client/themes/boxmodel.css
@@ -52,7 +52,7 @@
/* Regions are 3 nested elements with wide borders and outlines */
-.boxmodel-content {
+.boxmodel-contents {
height: 18px;
}
@@ -84,7 +84,7 @@
border-color: #6a5acd;
}
-.boxmodel-content {
+.boxmodel-contents {
background-color: #87ceeb;
}
@@ -104,7 +104,8 @@
/* Editable region sizes are contained in absolutely positioned */
-.boxmodel-main > p {
+.boxmodel-main > p,
+.boxmodel-size {
position: absolute;
pointer-events: none;
margin: 0;
@@ -112,7 +113,8 @@
}
.boxmodel-main > p > span,
-.boxmodel-main > p > input {
+.boxmodel-main > p > input,
+.boxmodel-content {
vertical-align: middle;
pointer-events: auto;
}
@@ -172,8 +174,8 @@
.boxmodel-position.boxmodel-right,
.boxmodel-margin.boxmodel-right,
.boxmodel-margin.boxmodel-left,
-.boxmodel-border.boxmodel-left,
.boxmodel-border.boxmodel-right,
+.boxmodel-border.boxmodel-left,
.boxmodel-padding.boxmodel-right,
.boxmodel-padding.boxmodel-left {
width: 21px;
@@ -218,6 +220,12 @@
height: 30px;
}
+.boxmodel-size > p {
+ display: inline-block;
+ margin: auto;
+ line-height: 0;
+}
+
.boxmodel-rotate.boxmodel-right.boxmodel-position:not(.boxmodel-editing) {
border-top: none;
border-left: 1px solid var(--theme-highlight-purple);
@@ -290,8 +298,6 @@
border-bottom-color: hsl(0, 0%, 50%);
}
-/* Make sure the content size doesn't appear as editable like the other sizes */
-
.boxmodel-size > span {
cursor: default;
}
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index 04fa021fcb79..6ed2909fb70e 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -120,7 +120,7 @@
#include "nsITimer.h"
#include "nsISHistoryInternal.h"
#include "nsIPrincipal.h"
-#include "nsNullPrincipal.h"
+#include "NullPrincipal.h"
#include "nsISHEntry.h"
#include "nsIWindowWatcher.h"
#include "nsIPromptFactory.h"
@@ -1501,7 +1501,7 @@ nsDocShell::LoadURI(nsIURI* aURI,
//
// We didn't inherit OriginAttributes here as ExpandedPrincipal doesn't
// have origin attributes.
- principalToInherit = nsNullPrincipal::CreateWithInheritedAttributes(this);
+ principalToInherit = NullPrincipal::CreateWithInheritedAttributes(this);
inheritPrincipal = false;
}
}
@@ -1514,7 +1514,7 @@ nsDocShell::LoadURI(nsIURI* aURI,
inheritPrincipal = false;
// If aFirstParty is true and the pref 'privacy.firstparty.isolate' is
// enabled, we will set firstPartyDomain on the origin attributes.
- principalToInherit = nsNullPrincipal::CreateWithInheritedAttributes(this, aFirstParty);
+ principalToInherit = NullPrincipal::CreateWithInheritedAttributes(this, aFirstParty);
}
// If the triggeringPrincipal is not passed explicitly, we first try to create
@@ -8127,9 +8127,9 @@ nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
nsCOMPtr principal;
if (mSandboxFlags & SANDBOXED_ORIGIN) {
if (aPrincipal) {
- principal = nsNullPrincipal::CreateWithInheritedAttributes(aPrincipal);
+ principal = NullPrincipal::CreateWithInheritedAttributes(aPrincipal);
} else {
- principal = nsNullPrincipal::CreateWithInheritedAttributes(this);
+ principal = NullPrincipal::CreateWithInheritedAttributes(this);
}
} else {
principal = aPrincipal;
@@ -12409,13 +12409,13 @@ nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel,
if (!principalToInherit) {
if (loadInfo->GetLoadingSandboxed()) {
if (loadInfo->LoadingPrincipal()) {
- principalToInherit = nsNullPrincipal::CreateWithInheritedAttributes(
+ principalToInherit = NullPrincipal::CreateWithInheritedAttributes(
loadInfo->LoadingPrincipal());
} else {
// get the OriginAttributes
OriginAttributes attrs;
loadInfo->GetOriginAttributes(&attrs);
- principalToInherit = nsNullPrincipal::Create(attrs);
+ principalToInherit = NullPrincipal::Create(attrs);
}
} else {
principalToInherit = loadInfo->PrincipalToInherit();
@@ -12606,7 +12606,7 @@ nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType)
// Ensure that we have a triggeringPrincipal. Otherwise javascript:
// URIs will pick it up from the about:blank page we just loaded,
// and we don't really want even that in this case.
- triggeringPrincipal = nsNullPrincipal::CreateWithInheritedAttributes(this);
+ triggeringPrincipal = NullPrincipal::CreateWithInheritedAttributes(this);
}
}
@@ -14378,7 +14378,7 @@ nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview)
// we QI the mContentViewer if the current URI is either about:blank
// or about:printpreview.
Stop(nsIWebNavigation::STOP_ALL);
- nsCOMPtr principal = nsNullPrincipal::CreateWithInheritedAttributes(this);
+ nsCOMPtr principal = NullPrincipal::CreateWithInheritedAttributes(this);
nsCOMPtr uri;
NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:printpreview"));
nsresult rv = CreateAboutBlankContentViewer(principal, uri);
diff --git a/dom/asmjscache/AsmJSCache.cpp b/dom/asmjscache/AsmJSCache.cpp
index 3c2c959ca8f5..e8f657bff0cf 100644
--- a/dom/asmjscache/AsmJSCache.cpp
+++ b/dom/asmjscache/AsmJSCache.cpp
@@ -1623,18 +1623,24 @@ public:
InitOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
+ const AtomicBool& aCanceled,
UsageInfo* aUsageInfo) override
{
if (!aUsageInfo) {
return NS_OK;
}
- return GetUsageForOrigin(aPersistenceType, aGroup, aOrigin, aUsageInfo);
+ return GetUsageForOrigin(aPersistenceType,
+ aGroup,
+ aOrigin,
+ aCanceled,
+ aUsageInfo);
}
nsresult
GetUsageForOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
+ const AtomicBool& aCanceled,
UsageInfo* aUsageInfo) override
{
QuotaManager* qm = QuotaManager::Get();
@@ -1658,7 +1664,7 @@ public:
bool hasMore;
while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
- hasMore && !aUsageInfo->Canceled()) {
+ hasMore && !aCanceled) {
nsCOMPtr entry;
rv = entries->GetNext(getter_AddRefs(entry));
NS_ENSURE_SUCCESS(rv, rv);
diff --git a/dom/base/DOMParser.cpp b/dom/base/DOMParser.cpp
index 3d063369a49b..da81cfc6b672 100644
--- a/dom/base/DOMParser.cpp
+++ b/dom/base/DOMParser.cpp
@@ -18,7 +18,7 @@
#include "nsDOMJSUtils.h"
#include "nsError.h"
#include "nsPIDOMWindow.h"
-#include "nsNullPrincipal.h"
+#include "NullPrincipal.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/ScriptSettings.h"
@@ -345,7 +345,7 @@ DOMParser::Init(nsIPrincipal* principal, nsIURI* documentURI,
// Don't give DOMParsers the system principal. Use a null
// principal instead.
mOriginalPrincipalWasSystem = true;
- mPrincipal = nsNullPrincipal::Create();
+ mPrincipal = NullPrincipal::Create();
if (!mDocumentURI) {
rv = mPrincipal->GetURI(getter_AddRefs(mDocumentURI));
@@ -456,7 +456,7 @@ DOMParser::SetUpDocument(DocumentFlavor aFlavor, nsIDOMDocument** aResult)
NS_ENSURE_TRUE(!mAttemptedInit, NS_ERROR_NOT_INITIALIZED);
AttemptedInitMarker marker(&mAttemptedInit);
- nsCOMPtr prin = nsNullPrincipal::Create();
+ nsCOMPtr prin = NullPrincipal::Create();
rv = Init(prin, nullptr, nullptr, scriptHandlingObject);
NS_ENSURE_SUCCESS(rv, rv);
}
diff --git a/dom/base/Location.cpp b/dom/base/Location.cpp
index d93dee5f3f52..6a269fe631e4 100644
--- a/dom/base/Location.cpp
+++ b/dom/base/Location.cpp
@@ -31,7 +31,7 @@
#include "nsGlobalWindow.h"
#include "mozilla/Likely.h"
#include "nsCycleCollectionParticipant.h"
-#include "nsNullPrincipal.h"
+#include "NullPrincipal.h"
#include "ScriptSettings.h"
#include "mozilla/Unused.h"
#include "mozilla/dom/LocationBinding.h"
@@ -164,7 +164,7 @@ Location::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo)
sourceURI = docCurrentURI;
}
else {
- // Use principalURI as long as it is not an nsNullPrincipalURI. We
+ // Use principalURI as long as it is not an NullPrincipalURI. We
// could add a method such as GetReferrerURI to principals to make this
// cleaner, but given that we need to start using Source Browsing
// Context for referrer (see Bug 960639) this may be wasted effort at
diff --git a/dom/base/ScriptSettings.cpp b/dom/base/ScriptSettings.cpp
index 7d0e4566b294..a89b3419127a 100644
--- a/dom/base/ScriptSettings.cpp
+++ b/dom/base/ScriptSettings.cpp
@@ -164,7 +164,7 @@ ScriptSettingsStackEntry::~ScriptSettingsStackEntry()
// If the entry or incumbent global ends up being something that the subject
// principal doesn't subsume, we don't want to use it. This never happens on
// the web, but can happen with asymmetric privilege relationships (i.e.
-// nsExpandedPrincipal and System Principal).
+// ExpandedPrincipal and System Principal).
//
// The most correct thing to use instead would be the topmost global on the
// callstack whose principal is subsumed by the subject principal. But that's
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index f7e0c1c9b96e..d3fa869985d8 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -182,7 +182,7 @@
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsNodeInfoManager.h"
-#include "nsNullPrincipal.h"
+#include "NullPrincipal.h"
#include "nsParserCIID.h"
#include "nsParserConstants.h"
#include "nsPIDOMWindow.h"
@@ -514,7 +514,7 @@ nsContentUtils::Init()
sSecurityManager->GetSystemPrincipal(&sSystemPrincipal);
MOZ_ASSERT(sSystemPrincipal);
- RefPtr nullPrincipal = nsNullPrincipal::Create();
+ RefPtr nullPrincipal = NullPrincipal::Create();
if (!nullPrincipal) {
return NS_ERROR_FAILURE;
}
@@ -4790,7 +4790,7 @@ nsContentUtils::ConvertToPlainText(const nsAString& aSourceBuffer,
{
nsCOMPtr uri;
NS_NewURI(getter_AddRefs(uri), "about:blank");
- nsCOMPtr principal = nsNullPrincipal::Create();
+ nsCOMPtr principal = NullPrincipal::Create();
nsCOMPtr domDocument;
nsresult rv = NS_NewDOMDocument(getter_AddRefs(domDocument),
EmptyString(),
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index 159343549fe6..3aab08822895 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1578,12 +1578,12 @@ public:
static bool IsSystemPrincipal(nsIPrincipal* aPrincipal);
/**
- * Returns true if aPrincipal is an nsExpandedPrincipal.
+ * Returns true if aPrincipal is an ExpandedPrincipal.
*/
static bool IsExpandedPrincipal(nsIPrincipal* aPrincipal);
/**
- * Returns true if aPrincipal is the system or an nsExpandedPrincipal.
+ * Returns true if aPrincipal is the system or an ExpandedPrincipal.
*/
static bool IsSystemOrExpandedPrincipal(nsIPrincipal* aPrincipal)
{
diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp
index 58a4b17ceb78..a4602c997103 100644
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -106,7 +106,7 @@
#include "nsIScriptSecurityManager.h"
#include "nsIPermissionManager.h"
#include "nsIPrincipal.h"
-#include "nsNullPrincipal.h"
+#include "NullPrincipal.h"
#include "nsIDOMWindow.h"
#include "nsPIDOMWindow.h"
@@ -2717,7 +2717,7 @@ nsDocument::InitCSP(nsIChannel* aChannel)
if (cspSandboxFlags & SANDBOXED_ORIGIN) {
// If the new CSP sandbox flags do not have the allow-same-origin flag
// reset the document principal to a null principal
- principal = nsNullPrincipal::Create();
+ principal = NullPrincipal::Create();
SetPrincipal(principal);
}
diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp
index 0217c97ffa54..e261b1860f41 100644
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -50,7 +50,7 @@
#include "nsIEditor.h"
#include "nsIMozBrowserFrame.h"
#include "nsISHistory.h"
-#include "nsNullPrincipal.h"
+#include "NullPrincipal.h"
#include "nsIScriptError.h"
#include "nsGlobalWindow.h"
#include "nsPIWindowRoot.h"
@@ -98,7 +98,7 @@
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseNativeHandler.h"
-#include "nsPrincipal.h"
+#include "ContentPrincipal.h"
#ifdef XP_WIN
#include "mozilla/plugins/PPluginWidgetParent.h"
@@ -831,7 +831,7 @@ nsFrameLoader::ReallyStartLoadingInternal()
NS_ENSURE_SUCCESS(rv, rv);
}
- // Use referrer as long as it is not an nsNullPrincipalURI.
+ // Use referrer as long as it is not an NullPrincipalURI.
// We could add a method such as GetReferrerURI to principals to make this
// cleaner, but given that we need to start using Source Browsing Context for
// referrer (see Bug 960639) this may be wasted effort at this stage.
diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp
index 4214a8abc3e5..f0d69a3f0cbf 100644
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -13077,9 +13077,14 @@ nsGlobalWindow::RunTimeoutHandler(Timeout* aTimeout,
AutoEntryScript aes(this, reason, true);
JS::CompileOptions options(aes.cx());
options.setFileAndLine(filename, lineNo).setVersion(JSVERSION_DEFAULT);
+ options.setNoScriptRval(true);
JS::Rooted global(aes.cx(), FastGetGlobalJSObject());
- nsresult rv =
- nsJSUtils::EvaluateString(aes.cx(), script, global, options);
+ nsresult rv = NS_OK;
+ {
+ nsJSUtils::ExecutionContext exec(aes.cx(), global);
+ rv = exec.CompileAndExec(options, script);
+ }
+
if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE) {
abortIntervalHandler = true;
}
diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp
index 98b367b663a4..6fcf17a1fd1e 100644
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -123,156 +123,162 @@ nsJSUtils::CompileFunction(AutoJSAPI& jsapi,
return NS_OK;
}
-nsresult
-nsJSUtils::EvaluateString(JSContext* aCx,
- const nsAString& aScript,
- JS::Handle aEvaluationGlobal,
- JS::CompileOptions& aCompileOptions,
- const EvaluateOptions& aEvaluateOptions,
- JS::MutableHandle aRetValue)
+static nsresult
+EvaluationExceptionToNSResult(JSContext* aCx)
{
- const nsPromiseFlatString& flatScript = PromiseFlatString(aScript);
- JS::SourceBufferHolder srcBuf(flatScript.get(), aScript.Length(),
- JS::SourceBufferHolder::NoOwnership);
- return EvaluateString(aCx, srcBuf, aEvaluationGlobal, aCompileOptions,
- aEvaluateOptions, aRetValue, nullptr);
+ if (JS_IsExceptionPending(aCx)) {
+ return NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW;
+ }
+ return NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE;
+}
+
+nsJSUtils::ExecutionContext::ExecutionContext(JSContext* aCx,
+ JS::Handle aGlobal)
+ : mSamplerRAII("nsJSUtils::ExecutionContext", /* PROFILER_LABEL */
+ js::ProfileEntry::Category::JS, __LINE__)
+ , mCx(aCx)
+ , mCompartment(aCx, aGlobal)
+ , mRetValue(aCx)
+ , mScopeChain(aCx)
+ , mRv(NS_OK)
+ , mSkip(false)
+ , mCoerceToString(false)
+#ifdef DEBUG
+ , mWantsReturnValue(false)
+ , mExpectScopeChain(false)
+#endif
+{
+ MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(nsContentUtils::IsInMicroTask());
+ MOZ_ASSERT(mRetValue.isUndefined());
+
+ MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(aGlobal) == aGlobal);
+ if (MOZ_UNLIKELY(!xpc::Scriptability::Get(aGlobal).Allowed())) {
+ mSkip = true;
+ mRv = NS_OK;
+ }
+}
+
+void
+nsJSUtils::ExecutionContext::SetScopeChain(
+ const JS::AutoObjectVector& aScopeChain)
+{
+ if (mSkip) {
+ return;
+ }
+
+#ifdef DEBUG
+ mExpectScopeChain = true;
+#endif
+ // Now make sure to wrap the scope chain into the right compartment.
+ if (!mScopeChain.reserve(aScopeChain.length())) {
+ mSkip = true;
+ mRv = NS_ERROR_OUT_OF_MEMORY;
+ return;
+ }
+
+ for (size_t i = 0; i < aScopeChain.length(); ++i) {
+ JS::ExposeObjectToActiveJS(aScopeChain[i]);
+ mScopeChain.infallibleAppend(aScopeChain[i]);
+ if (!JS_WrapObject(mCx, mScopeChain[i])) {
+ mSkip = true;
+ mRv = NS_ERROR_OUT_OF_MEMORY;
+ return;
+ }
+ }
}
nsresult
-nsJSUtils::EvaluateString(JSContext* aCx,
- JS::SourceBufferHolder& aSrcBuf,
- JS::Handle aEvaluationGlobal,
- JS::CompileOptions& aCompileOptions,
- const EvaluateOptions& aEvaluateOptions,
- JS::MutableHandle aRetValue,
- void **aOffThreadToken)
+nsJSUtils::ExecutionContext::SyncAndExec(void **aOffThreadToken,
+ JS::MutableHandle aScript)
{
- PROFILER_LABEL("nsJSUtils", "EvaluateString",
- js::ProfileEntry::Category::JS);
+ if (mSkip) {
+ return mRv;
+ }
+
+ MOZ_ASSERT(!mWantsReturnValue);
+ MOZ_ASSERT(!mExpectScopeChain);
+ aScript.set(JS::FinishOffThreadScript(mCx, *aOffThreadToken));
+ *aOffThreadToken = nullptr; // Mark the token as having been finished.
+ if (!aScript || !JS_ExecuteScript(mCx, mScopeChain, aScript)) {
+ mSkip = true;
+ mRv = EvaluationExceptionToNSResult(mCx);
+ return mRv;
+ }
+
+ return NS_OK;
+}
+
+nsresult
+nsJSUtils::ExecutionContext::CompileAndExec(JS::CompileOptions& aCompileOptions,
+ JS::SourceBufferHolder& aSrcBuf)
+{
+ if (mSkip) {
+ return mRv;
+ }
MOZ_ASSERT_IF(aCompileOptions.versionSet,
aCompileOptions.version != JSVERSION_UNKNOWN);
- MOZ_ASSERT_IF(aEvaluateOptions.coerceToString, !aCompileOptions.noScriptRval);
- MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
MOZ_ASSERT(aSrcBuf.get());
- MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(aEvaluationGlobal) ==
- aEvaluationGlobal);
- MOZ_ASSERT_IF(aOffThreadToken, aCompileOptions.noScriptRval);
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(nsContentUtils::IsInMicroTask());
-
- // Unfortunately, the JS engine actually compiles scripts with a return value
- // in a different, less efficient way. Furthermore, it can't JIT them in many
- // cases. So we need to be explicitly told whether the caller cares about the
- // return value. Callers can do this by calling the other overload of
- // EvaluateString() which calls this function with
- // aCompileOptions.noScriptRval set to true.
- aRetValue.setUndefined();
-
- nsresult rv = NS_OK;
-
- NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK);
-
- bool ok = true;
- // Scope the JSAutoCompartment so that we can later wrap the return value
- // into the caller's cx.
- {
- JSAutoCompartment ac(aCx, aEvaluationGlobal);
-
- // Now make sure to wrap the scope chain into the right compartment.
- JS::AutoObjectVector scopeChain(aCx);
- if (!scopeChain.reserve(aEvaluateOptions.scopeChain.length())) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
-
- for (size_t i = 0; i < aEvaluateOptions.scopeChain.length(); ++i) {
- JS::ExposeObjectToActiveJS(aEvaluateOptions.scopeChain[i]);
- scopeChain.infallibleAppend(aEvaluateOptions.scopeChain[i]);
- if (!JS_WrapObject(aCx, scopeChain[i])) {
- ok = false;
- break;
- }
- }
-
- if (ok && aOffThreadToken) {
- JS::Rooted
- script(aCx, JS::FinishOffThreadScript(aCx, *aOffThreadToken));
- *aOffThreadToken = nullptr; // Mark the token as having been finished.
- if (script) {
- ok = JS_ExecuteScript(aCx, scopeChain, script);
- } else {
- ok = false;
- }
- } else if (ok) {
- ok = JS::Evaluate(aCx, scopeChain, aCompileOptions, aSrcBuf, aRetValue);
- }
-
- if (ok && aEvaluateOptions.coerceToString && !aRetValue.isUndefined()) {
- JS::Rooted value(aCx, aRetValue);
- JSString* str = JS::ToString(aCx, value);
- ok = !!str;
- aRetValue.set(ok ? JS::StringValue(str) : JS::UndefinedValue());
- }
+ MOZ_ASSERT(mRetValue.isUndefined());
+#ifdef DEBUG
+ mWantsReturnValue = !aCompileOptions.noScriptRval;
+#endif
+ MOZ_ASSERT(!mCoerceToString || mWantsReturnValue);
+ if (!JS::Evaluate(mCx, mScopeChain, aCompileOptions, aSrcBuf, &mRetValue)) {
+ mSkip = true;
+ mRv = EvaluationExceptionToNSResult(mCx);
+ return mRv;
}
- if (!ok) {
- if (JS_IsExceptionPending(aCx)) {
- rv = NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW;
- } else {
- rv = NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE;
- }
-
- if (!aCompileOptions.noScriptRval) {
- aRetValue.setUndefined();
- }
- }
-
- // Wrap the return value into whatever compartment aCx was in.
- if (ok && !aCompileOptions.noScriptRval) {
- if (!JS_WrapValue(aCx, aRetValue)) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- }
- return rv;
+ return NS_OK;
}
nsresult
-nsJSUtils::EvaluateString(JSContext* aCx,
- JS::SourceBufferHolder& aSrcBuf,
- JS::Handle aEvaluationGlobal,
- JS::CompileOptions& aCompileOptions,
- const EvaluateOptions& aEvaluateOptions,
- JS::MutableHandle aRetValue)
+nsJSUtils::ExecutionContext::CompileAndExec(JS::CompileOptions& aCompileOptions,
+ const nsAString& aScript)
{
- return EvaluateString(aCx, aSrcBuf, aEvaluationGlobal, aCompileOptions,
- aEvaluateOptions, aRetValue, nullptr);
+ if (mSkip) {
+ return mRv;
+ }
+
+ const nsPromiseFlatString& flatScript = PromiseFlatString(aScript);
+ JS::SourceBufferHolder srcBuf(flatScript.get(), aScript.Length(),
+ JS::SourceBufferHolder::NoOwnership);
+ return CompileAndExec(aCompileOptions, srcBuf);
}
nsresult
-nsJSUtils::EvaluateString(JSContext* aCx,
- const nsAString& aScript,
- JS::Handle aEvaluationGlobal,
- JS::CompileOptions& aCompileOptions)
+nsJSUtils::ExecutionContext::ExtractReturnValue(JS::MutableHandle aRetValue)
{
- EvaluateOptions options(aCx);
- aCompileOptions.setNoScriptRval(true);
- JS::RootedValue unused(aCx);
- return EvaluateString(aCx, aScript, aEvaluationGlobal, aCompileOptions,
- options, &unused);
-}
+ MOZ_ASSERT(aRetValue.isUndefined());
+ if (mSkip) {
+ // Repeat earlier result, as NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW are not
+ // failures cases.
+#ifdef DEBUG
+ mWantsReturnValue = false;
+#endif
+ return mRv;
+ }
-nsresult
-nsJSUtils::EvaluateString(JSContext* aCx,
- JS::SourceBufferHolder& aSrcBuf,
- JS::Handle aEvaluationGlobal,
- JS::CompileOptions& aCompileOptions,
- void **aOffThreadToken)
-{
- EvaluateOptions options(aCx);
- aCompileOptions.setNoScriptRval(true);
- JS::RootedValue unused(aCx);
- return EvaluateString(aCx, aSrcBuf, aEvaluationGlobal, aCompileOptions,
- options, &unused, aOffThreadToken);
+ MOZ_ASSERT(mWantsReturnValue);
+#ifdef DEBUG
+ mWantsReturnValue = false;
+#endif
+ if (mCoerceToString && !mRetValue.isUndefined()) {
+ JSString* str = JS::ToString(mCx, mRetValue);
+ if (!str) {
+ // ToString can be a function call, so an exception can be raised while
+ // executing the function.
+ mSkip = true;
+ return EvaluationExceptionToNSResult(mCx);
+ }
+ mRetValue.set(JS::StringValue(str));
+ }
+
+ aRetValue.set(mRetValue);
+ return NS_OK;
}
nsresult
diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h
index 4affab2d3644..e6285b9bf9da 100644
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -16,6 +16,7 @@
#include "mozilla/Assertions.h"
+#include "GeckoProfiler.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "js/Conversions.h"
@@ -64,52 +65,95 @@ public:
const nsAString& aBody,
JSObject** aFunctionObject);
- struct MOZ_STACK_CLASS EvaluateOptions {
- bool coerceToString;
- JS::AutoObjectVector scopeChain;
- explicit EvaluateOptions(JSContext* cx)
- : coerceToString(false)
- , scopeChain(cx)
- {}
+ // ExecutionContext is used to switch compartment.
+ class MOZ_STACK_CLASS ExecutionContext {
+ // Register stack annotations for the Gecko profiler.
+ mozilla::SamplerStackFrameRAII mSamplerRAII;
- EvaluateOptions& setCoerceToString(bool aCoerce) {
- coerceToString = aCoerce;
+ JSContext* mCx;
+
+ // Handles switching to our global's compartment.
+ JSAutoCompartment mCompartment;
+
+ // Set to a valid handle if a return value is expected.
+ JS::Rooted mRetValue;
+
+ // Scope chain in which the execution takes place.
+ JS::AutoObjectVector mScopeChain;
+
+ // returned value forwarded when we have to interupt the execution eagerly
+ // with mSkip.
+ nsresult mRv;
+
+ // Used to skip upcoming phases in case of a failure. In such case the
+ // result is carried by mRv.
+ bool mSkip;
+
+ // Should the result be serialized before being returned.
+ bool mCoerceToString;
+
+#ifdef DEBUG
+ // Should we set the return value.
+ bool mWantsReturnValue;
+
+ bool mExpectScopeChain;
+#endif
+
+ public:
+
+ // Enter compartment in which the code would be executed. The JSContext
+ // must come from an AutoEntryScript that has had
+ // TakeOwnershipOfErrorReporting() called on it.
+ ExecutionContext(JSContext* aCx, JS::Handle aGlobal);
+
+ ExecutionContext(const ExecutionContext&) = delete;
+ ExecutionContext(ExecutionContext&&) = delete;
+
+ ~ExecutionContext() {
+ // This flag is resetted, when the returned value is extracted.
+ MOZ_ASSERT(!mWantsReturnValue);
+ }
+
+ // The returned value would be converted to a string if the
+ // |aCoerceToString| is flag set.
+ ExecutionContext& SetCoerceToString(bool aCoerceToString) {
+ mCoerceToString = aCoerceToString;
return *this;
}
+
+ // Set the scope chain in which the code should be executed.
+ void SetScopeChain(const JS::AutoObjectVector& aScopeChain);
+
+ // Copy the returned value in the mutable handle argument, in case of a
+ // evaluation failure either during the execution or the conversion of the
+ // result to a string, the nsresult would be set to the corresponding result
+ // code, and the mutable handle argument would remain unchanged.
+ //
+ // The value returned in the mutable handle argument is part of the
+ // compartment given as argument to the ExecutionContext constructor. If the
+ // caller is in a different compartment, then the out-param value should be
+ // wrapped by calling |JS_WrapValue|.
+ MOZ_MUST_USE nsresult
+ ExtractReturnValue(JS::MutableHandle aRetValue);
+
+ // After getting a notification that an off-thread compilation terminated,
+ // this function will synchronize the result by moving it to the main thread
+ // before starting the execution of the script.
+ //
+ // The compiled script would be returned in the |aScript| out-param.
+ MOZ_MUST_USE nsresult SyncAndExec(void **aOffThreadToken,
+ JS::MutableHandle aScript);
+
+ // Compile a script contained in a SourceBuffer, and execute it.
+ nsresult CompileAndExec(JS::CompileOptions& aCompileOptions,
+ JS::SourceBufferHolder& aSrcBuf);
+
+ // Compile a script contained in a string, and execute it.
+ nsresult CompileAndExec(JS::CompileOptions& aCompileOptions,
+ const nsAString& aScript);
};
- // aEvaluationGlobal is the global to evaluate in. The return value
- // will then be wrapped back into the compartment aCx is in when
- // this function is called. For all the EvaluateString overloads,
- // the JSContext must come from an AutoJSAPI that has had
- // TakeOwnershipOfErrorReporting() called on it.
- static nsresult EvaluateString(JSContext* aCx,
- const nsAString& aScript,
- JS::Handle aEvaluationGlobal,
- JS::CompileOptions &aCompileOptions,
- const EvaluateOptions& aEvaluateOptions,
- JS::MutableHandle aRetValue);
-
- static nsresult EvaluateString(JSContext* aCx,
- JS::SourceBufferHolder& aSrcBuf,
- JS::Handle aEvaluationGlobal,
- JS::CompileOptions &aCompileOptions,
- const EvaluateOptions& aEvaluateOptions,
- JS::MutableHandle aRetValue);
-
-
- static nsresult EvaluateString(JSContext* aCx,
- const nsAString& aScript,
- JS::Handle aEvaluationGlobal,
- JS::CompileOptions &aCompileOptions);
-
- static nsresult EvaluateString(JSContext* aCx,
- JS::SourceBufferHolder& aSrcBuf,
- JS::Handle aEvaluationGlobal,
- JS::CompileOptions &aCompileOptions,
- void **aOffThreadToken);
-
static nsresult CompileModule(JSContext* aCx,
JS::SourceBufferHolder& aSrcBuf,
JS::Handle aEvaluationGlobal,
@@ -129,16 +173,6 @@ public:
JS::AutoObjectVector& aScopeChain);
static void ResetTimeZone();
-
-private:
- // Implementation for our EvaluateString bits
- static nsresult EvaluateString(JSContext* aCx,
- JS::SourceBufferHolder& aSrcBuf,
- JS::Handle aEvaluationGlobal,
- JS::CompileOptions& aCompileOptions,
- const EvaluateOptions& aEvaluateOptions,
- JS::MutableHandle aRetValue,
- void **aOffThreadToken);
};
template
diff --git a/dom/base/nsNodeInfoManager.cpp b/dom/base/nsNodeInfoManager.cpp
index 66c8c84cfd31..b0169b82ba0e 100644
--- a/dom/base/nsNodeInfoManager.cpp
+++ b/dom/base/nsNodeInfoManager.cpp
@@ -30,7 +30,7 @@
#include "nsCCUncollectableMarker.h"
#include "nsNameSpaceManager.h"
#include "nsDocument.h"
-#include "nsNullPrincipal.h"
+#include "NullPrincipal.h"
using namespace mozilla;
using mozilla::dom::NodeInfo;
@@ -182,7 +182,7 @@ nsNodeInfoManager::Init(nsIDocument *aDocument)
NS_PRECONDITION(!mPrincipal,
"Being inited when we already have a principal?");
- mPrincipal = nsNullPrincipal::Create();
+ mPrincipal = NullPrincipal::Create();
if (aDocument) {
mBindingManager = new nsBindingManager(aDocument);
diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp
index 76eb388b171e..e3aab285aa20 100644
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -2152,8 +2152,6 @@ nsScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI&jsapi,
aOptions->setFileAndLine(aRequest->mURL.get(), aRequest->mLineNo);
aOptions->setVersion(JSVersion(aRequest->mJSVersion));
aOptions->setIsRunOnce(true);
- // We only need the setNoScriptRval bit when compiling off-thread here, since
- // otherwise nsJSUtils::EvaluateString will set it up for us.
aOptions->setNoScriptRval(true);
if (aRequest->mHasSourceMapURL) {
aOptions->setSourceMapURL(aRequest->mSourceMapURL.get());
@@ -2258,10 +2256,17 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest)
rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
if (NS_SUCCEEDED(rv)) {
- nsAutoString inlineData;
- SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData);
- rv = nsJSUtils::EvaluateString(aes.cx(), srcBuf, global, options,
- aRequest->OffThreadTokenPtr());
+ {
+ nsJSUtils::ExecutionContext exec(aes.cx(), global);
+ if (aRequest->mOffThreadToken) {
+ JS::Rooted script(aes.cx());
+ rv = exec.SyncAndExec(&aRequest->mOffThreadToken, &script);
+ } else {
+ nsAutoString inlineData;
+ SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData);
+ rv = exec.CompileAndExec(options, srcBuf);
+ }
+ }
}
}
}
diff --git a/dom/base/nsTreeSanitizer.cpp b/dom/base/nsTreeSanitizer.cpp
index c234a15301ba..b9dd8e4e1db0 100644
--- a/dom/base/nsTreeSanitizer.cpp
+++ b/dom/base/nsTreeSanitizer.cpp
@@ -19,7 +19,7 @@
#include "nsIScriptSecurityManager.h"
#include "nsNetUtil.h"
#include "nsComponentManagerUtils.h"
-#include "nsNullPrincipal.h"
+#include "NullPrincipal.h"
#include "nsContentUtils.h"
#include "nsIParserUtils.h"
#include "nsIDocument.h"
@@ -1522,7 +1522,7 @@ nsTreeSanitizer::InitializeStatics()
sAttributesMathML->PutEntry(*kAttributesMathML[i]);
}
- nsCOMPtr principal = nsNullPrincipal::Create();
+ nsCOMPtr principal = NullPrincipal::Create();
principal.forget(&sNullPrincipal);
}
diff --git a/dom/bindings/SimpleGlobalObject.cpp b/dom/bindings/SimpleGlobalObject.cpp
index 5659138c852f..2a9f5656c532 100644
--- a/dom/bindings/SimpleGlobalObject.cpp
+++ b/dom/bindings/SimpleGlobalObject.cpp
@@ -10,7 +10,7 @@
#include "js/Class.h"
#include "nsJSPrincipals.h"
-#include "nsNullPrincipal.h"
+#include "NullPrincipal.h"
#include "nsThreadUtils.h"
#include "nsContentUtils.h"
@@ -113,7 +113,7 @@ SimpleGlobalObject::Create(GlobalType globalType, JS::Handle proto)
.setSystemZone();
if (NS_IsMainThread()) {
- nsCOMPtr principal = nsNullPrincipal::Create();
+ nsCOMPtr principal = NullPrincipal::Create();
options.creationOptions().setTrace(xpc::TraceXPCGlobal);
global = xpc::CreateGlobalObject(cx, js::Jsvalify(&SimpleGlobalClass),
nsJSPrincipals::get(principal),
diff --git a/dom/cache/QuotaClient.cpp b/dom/cache/QuotaClient.cpp
index b33fa8c34a31..5641c953c6c0 100644
--- a/dom/cache/QuotaClient.cpp
+++ b/dom/cache/QuotaClient.cpp
@@ -16,6 +16,7 @@
namespace {
+using mozilla::Atomic;
using mozilla::dom::ContentParentId;
using mozilla::dom::cache::Manager;
using mozilla::dom::quota::Client;
@@ -25,7 +26,8 @@ using mozilla::dom::quota::UsageInfo;
using mozilla::ipc::AssertIsOnBackgroundThread;
static nsresult
-GetBodyUsage(nsIFile* aDir, UsageInfo* aUsageInfo)
+GetBodyUsage(nsIFile* aDir, const Atomic& aCanceled,
+ UsageInfo* aUsageInfo)
{
nsCOMPtr entries;
nsresult rv = aDir->GetDirectoryEntries(getter_AddRefs(entries));
@@ -33,7 +35,7 @@ GetBodyUsage(nsIFile* aDir, UsageInfo* aUsageInfo)
bool hasMore;
while (NS_SUCCEEDED(rv = entries->HasMoreElements(&hasMore)) && hasMore &&
- !aUsageInfo->Canceled()) {
+ !aCanceled) {
nsCOMPtr entry;
rv = entries->GetNext(getter_AddRefs(entry));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@@ -45,7 +47,7 @@ GetBodyUsage(nsIFile* aDir, UsageInfo* aUsageInfo)
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
if (isDir) {
- rv = GetBodyUsage(file, aUsageInfo);
+ rv = GetBodyUsage(file, aCanceled, aUsageInfo);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
continue;
}
@@ -72,7 +74,8 @@ public:
virtual nsresult
InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup,
- const nsACString& aOrigin, UsageInfo* aUsageInfo) override
+ const nsACString& aOrigin, const AtomicBool& aCanceled,
+ UsageInfo* aUsageInfo) override
{
// The QuotaManager passes a nullptr UsageInfo if there is no quota being
// enforced against the origin.
@@ -80,12 +83,13 @@ public:
return NS_OK;
}
- return GetUsageForOrigin(aPersistenceType, aGroup, aOrigin, aUsageInfo);
+ return GetUsageForOrigin(aPersistenceType, aGroup, aOrigin, aCanceled,
+ aUsageInfo);
}
virtual nsresult
GetUsageForOrigin(PersistenceType aPersistenceType, const nsACString& aGroup,
- const nsACString& aOrigin,
+ const nsACString& aOrigin, const AtomicBool& aCanceled,
UsageInfo* aUsageInfo) override
{
MOZ_DIAGNOSTIC_ASSERT(aUsageInfo);
@@ -107,7 +111,7 @@ public:
bool hasMore;
while (NS_SUCCEEDED(rv = entries->HasMoreElements(&hasMore)) && hasMore &&
- !aUsageInfo->Canceled()) {
+ !aCanceled) {
nsCOMPtr entry;
rv = entries->GetNext(getter_AddRefs(entry));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@@ -124,7 +128,7 @@ public:
if (isDir) {
if (leafName.EqualsLiteral("morgue")) {
- rv = GetBodyUsage(file, aUsageInfo);
+ rv = GetBodyUsage(file, aCanceled, aUsageInfo);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
} else {
NS_WARNING("Unknown Cache directory found!");
diff --git a/dom/cache/test/mochitest/test_cache_orphaned_body.html b/dom/cache/test/mochitest/test_cache_orphaned_body.html
index a806cb30005f..049a97a79421 100644
--- a/dom/cache/test/mochitest/test_cache_orphaned_body.html
+++ b/dom/cache/test/mochitest/test_cache_orphaned_body.html
@@ -37,7 +37,8 @@ function storageUsage() {
var qms = SpecialPowers.Services.qms;
var principal = SpecialPowers.wrap(document).nodePrincipal;
var cb = SpecialPowers.wrapCallback(function(request) {
- resolve(request.usage, request.fileUsage);
+ var result = request.result;
+ resolve(result.usage, result.fileUsage);
});
qms.getUsageForPrincipal(principal, cb);
});
diff --git a/dom/cache/test/mochitest/test_cache_orphaned_cache.html b/dom/cache/test/mochitest/test_cache_orphaned_cache.html
index c797da7b2f75..c6086e4877fc 100644
--- a/dom/cache/test/mochitest/test_cache_orphaned_cache.html
+++ b/dom/cache/test/mochitest/test_cache_orphaned_cache.html
@@ -37,7 +37,8 @@ function storageUsage() {
var qms = SpecialPowers.Services.qms;
var principal = SpecialPowers.wrap(document).nodePrincipal;
var cb = SpecialPowers.wrapCallback(function(request) {
- resolve(request.usage, request.fileUsage);
+ var result = request.result;
+ resolve(result.usage, result.fileUsage);
});
qms.getUsageForPrincipal(principal, cb);
});
diff --git a/dom/cache/test/mochitest/test_cache_shrink.html b/dom/cache/test/mochitest/test_cache_shrink.html
index e6b362eb2215..b7136cb750f4 100644
--- a/dom/cache/test/mochitest/test_cache_shrink.html
+++ b/dom/cache/test/mochitest/test_cache_shrink.html
@@ -37,7 +37,8 @@ function storageUsage() {
var qms = SpecialPowers.Services.qms;
var principal = SpecialPowers.wrap(document).nodePrincipal;
var cb = SpecialPowers.wrapCallback(function(request) {
- resolve(request.usage, request.fileUsage);
+ var result = request.result;
+ resolve(result.usage, result.fileUsage);
});
qms.getUsageForPrincipal(principal, cb);
});
diff --git a/dom/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp
index b574cb5946ef..7c98e1e2696a 100644
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -379,9 +379,10 @@ nsTextInputSelectionImpl::ScrollSelectionIntoView(
if (!mFrameSelection)
return NS_ERROR_FAILURE;
- return mFrameSelection->ScrollSelectionIntoView(
- ToSelectionType(aRawSelectionType),
- aRegion, aFlags);
+ RefPtr frameSelection = mFrameSelection;
+ return frameSelection->ScrollSelectionIntoView(
+ ToSelectionType(aRawSelectionType),
+ aRegion, aFlags);
}
NS_IMETHODIMP
@@ -390,7 +391,8 @@ nsTextInputSelectionImpl::RepaintSelection(RawSelectionType aRawSelectionType)
if (!mFrameSelection)
return NS_ERROR_FAILURE;
- return mFrameSelection->RepaintSelection(ToSelectionType(aRawSelectionType));
+ RefPtr frameSelection = mFrameSelection;
+ return frameSelection->RepaintSelection(ToSelectionType(aRawSelectionType));
}
nsresult
@@ -400,7 +402,8 @@ nsTextInputSelectionImpl::RepaintSelection(nsPresContext* aPresContext,
if (!mFrameSelection)
return NS_ERROR_FAILURE;
- return mFrameSelection->RepaintSelection(aSelectionType);
+ RefPtr frameSelection = mFrameSelection;
+ return frameSelection->RepaintSelection(aSelectionType);
}
NS_IMETHODIMP
@@ -487,48 +490,60 @@ NS_IMETHODIMP
nsTextInputSelectionImpl::PhysicalMove(int16_t aDirection, int16_t aAmount,
bool aExtend)
{
- if (mFrameSelection)
- return mFrameSelection->PhysicalMove(aDirection, aAmount, aExtend);
+ if (mFrameSelection) {
+ RefPtr frameSelection = mFrameSelection;
+ return frameSelection->PhysicalMove(aDirection, aAmount, aExtend);
+ }
return NS_ERROR_NULL_POINTER;
}
NS_IMETHODIMP
nsTextInputSelectionImpl::CharacterMove(bool aForward, bool aExtend)
{
- if (mFrameSelection)
- return mFrameSelection->CharacterMove(aForward, aExtend);
+ if (mFrameSelection) {
+ RefPtr frameSelection = mFrameSelection;
+ return frameSelection->CharacterMove(aForward, aExtend);
+ }
return NS_ERROR_NULL_POINTER;
}
NS_IMETHODIMP
nsTextInputSelectionImpl::CharacterExtendForDelete()
{
- if (mFrameSelection)
- return mFrameSelection->CharacterExtendForDelete();
+ if (mFrameSelection) {
+ RefPtr frameSelection = mFrameSelection;
+ return frameSelection->CharacterExtendForDelete();
+ }
return NS_ERROR_NULL_POINTER;
}
NS_IMETHODIMP
nsTextInputSelectionImpl::CharacterExtendForBackspace()
{
- if (mFrameSelection)
- return mFrameSelection->CharacterExtendForBackspace();
+ if (mFrameSelection) {
+ RefPtr frameSelection = mFrameSelection;
+ return frameSelection->CharacterExtendForBackspace();
+ }
return NS_ERROR_NULL_POINTER;
}
NS_IMETHODIMP
nsTextInputSelectionImpl::WordMove(bool aForward, bool aExtend)
{
- if (mFrameSelection)
- return mFrameSelection->WordMove(aForward, aExtend);
+ if (mFrameSelection) {
+ RefPtr frameSelection = mFrameSelection;
+ return frameSelection->WordMove(aForward, aExtend);
+ }
return NS_ERROR_NULL_POINTER;
}
NS_IMETHODIMP
nsTextInputSelectionImpl::WordExtendForDelete(bool aForward)
{
- if (mFrameSelection)
- return mFrameSelection->WordExtendForDelete(aForward);
+ if (mFrameSelection) {
+ RefPtr frameSelection = mFrameSelection;
+ return frameSelection->WordExtendForDelete(aForward);
+ }
return NS_ERROR_NULL_POINTER;
}
@@ -537,7 +552,8 @@ nsTextInputSelectionImpl::LineMove(bool aForward, bool aExtend)
{
if (mFrameSelection)
{
- nsresult result = mFrameSelection->LineMove(aForward, aExtend);
+ RefPtr frameSelection = mFrameSelection;
+ nsresult result = frameSelection->LineMove(aForward, aExtend);
if (NS_FAILED(result))
result = CompleteMove(aForward,aExtend);
return result;
@@ -549,8 +565,10 @@ nsTextInputSelectionImpl::LineMove(bool aForward, bool aExtend)
NS_IMETHODIMP
nsTextInputSelectionImpl::IntraLineMove(bool aForward, bool aExtend)
{
- if (mFrameSelection)
- return mFrameSelection->IntraLineMove(aForward, aExtend);
+ if (mFrameSelection) {
+ RefPtr frameSelection = mFrameSelection;
+ return frameSelection->IntraLineMove(aForward, aExtend);
+ }
return NS_ERROR_NULL_POINTER;
}
@@ -562,7 +580,8 @@ nsTextInputSelectionImpl::PageMove(bool aForward, bool aExtend)
// and to remain relative position of the caret in view. see Bug 4302.
if (mScrollFrame)
{
- mFrameSelection->CommonPageMove(aForward, aExtend, mScrollFrame);
+ RefPtr frameSelection = mFrameSelection;
+ frameSelection->CommonPageMove(aForward, aExtend, mScrollFrame);
}
// After ScrollSelectionIntoView(), the pending notifications might be
// flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
@@ -590,8 +609,11 @@ nsTextInputSelectionImpl::CompleteScroll(bool aForward)
NS_IMETHODIMP
nsTextInputSelectionImpl::CompleteMove(bool aForward, bool aExtend)
{
+ NS_ENSURE_STATE(mFrameSelection);
+ RefPtr frameSelection = mFrameSelection;
+
// grab the parent / root DIV for this text widget
- nsIContent* parentDIV = mFrameSelection->GetLimiter();
+ nsIContent* parentDIV = frameSelection->GetLimiter();
if (!parentDIV)
return NS_ERROR_UNEXPECTED;
@@ -617,7 +639,7 @@ nsTextInputSelectionImpl::CompleteMove(bool aForward, bool aExtend)
}
}
- mFrameSelection->HandleClick(parentDIV, offset, offset, aExtend,
+ frameSelection->HandleClick(parentDIV, offset, offset, aExtend,
false, hint);
// if we got this far, attempt to scroll no matter what the above result is
@@ -672,8 +694,10 @@ nsTextInputSelectionImpl::ScrollCharacter(bool aRight)
NS_IMETHODIMP
nsTextInputSelectionImpl::SelectAll()
{
- if (mFrameSelection)
- return mFrameSelection->SelectAll();
+ if (mFrameSelection) {
+ RefPtr frameSelection = mFrameSelection;
+ return frameSelection->SelectAll();
+ }
return NS_ERROR_NULL_POINTER;
}
diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp
index d30f58e8d456..083810be7723 100644
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -9347,12 +9347,14 @@ public:
InitOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
+ const AtomicBool& aCanceled,
UsageInfo* aUsageInfo) override;
nsresult
GetUsageForOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
+ const AtomicBool& aCanceled,
UsageInfo* aUsageInfo) override;
void
@@ -9394,13 +9396,14 @@ private:
nsresult
GetDatabaseFilenames(nsIFile* aDirectory,
- UsageInfo* aUsageInfo,
+ const AtomicBool& aCanceled,
bool aForUpgrade,
nsTArray& aSubdirsToProcess,
nsTHashtable& aDatabaseFilename);
nsresult
GetUsageForDirectoryInternal(nsIFile* aDirectory,
+ const AtomicBool& aCanceled,
UsageInfo* aUsageInfo,
bool aDatabaseFiles);
@@ -17828,10 +17831,11 @@ QuotaClient::UpgradeStorageFrom1_0To2_0(nsIFile* aDirectory)
AssertIsOnIOThread();
MOZ_ASSERT(aDirectory);
+ AtomicBool dummy(false);
AutoTArray subdirsToProcess;
nsTHashtable databaseFilenames(20);
nsresult rv = GetDatabaseFilenames(aDirectory,
- nullptr,
+ /* aCanceled */ dummy,
/* aForUpgrade */ true,
subdirsToProcess,
databaseFilenames);
@@ -17924,6 +17928,7 @@ nsresult
QuotaClient::InitOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
+ const AtomicBool& aCanceled,
UsageInfo* aUsageInfo)
{
AssertIsOnIOThread();
@@ -17942,7 +17947,7 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType,
AutoTArray subdirsToProcess;
nsTHashtable databaseFilenames(20);
rv = GetDatabaseFilenames(directory,
- aUsageInfo,
+ aCanceled,
/* aForUpgrade */ false,
subdirsToProcess,
databaseFilenames);
@@ -17974,7 +17979,9 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType,
const NS_ConvertASCIItoUTF16 walSuffix(kSQLiteWALSuffix,
LiteralStringLength(kSQLiteWALSuffix));
- for (auto iter = databaseFilenames.ConstIter(); !iter.Done(); iter.Next()) {
+ for (auto iter = databaseFilenames.ConstIter();
+ !iter.Done() && !aCanceled;
+ iter.Next()) {
auto& databaseFilename = iter.Get()->GetKey();
nsCOMPtr fmDirectory;
@@ -18022,7 +18029,7 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType,
return rv;
}
- if (aUsageInfo && !aUsageInfo->Canceled()) {
+ if (aUsageInfo) {
int64_t fileSize;
rv = databaseFile->GetFileSize(&fileSize);
if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -18059,6 +18066,7 @@ nsresult
QuotaClient::GetUsageForOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
+ const AtomicBool& aCanceled,
UsageInfo* aUsageInfo)
{
AssertIsOnIOThread();
@@ -18071,7 +18079,7 @@ QuotaClient::GetUsageForOrigin(PersistenceType aPersistenceType,
return rv;
}
- rv = GetUsageForDirectoryInternal(directory, aUsageInfo, true);
+ rv = GetUsageForDirectoryInternal(directory, aCanceled, aUsageInfo, true);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -18260,12 +18268,13 @@ QuotaClient::GetDirectory(PersistenceType aPersistenceType,
nsresult
QuotaClient::GetDatabaseFilenames(
nsIFile* aDirectory,
- UsageInfo* aUsageInfo,
+ const AtomicBool& aCanceled,
bool aForUpgrade,
nsTArray& aSubdirsToProcess,
nsTHashtable& aDatabaseFilenames)
{
AssertIsOnIOThread();
+ MOZ_ASSERT(aDirectory);
nsCOMPtr entries;
nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
@@ -18286,7 +18295,7 @@ QuotaClient::GetDatabaseFilenames(
bool hasMore;
while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
hasMore &&
- (!aUsageInfo || !aUsageInfo->Canceled())) {
+ !aCanceled) {
nsCOMPtr entry;
rv = entries->GetNext(getter_AddRefs(entry));
if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -18362,6 +18371,7 @@ QuotaClient::GetDatabaseFilenames(
nsresult
QuotaClient::GetUsageForDirectoryInternal(nsIFile* aDirectory,
+ const AtomicBool& aCanceled,
UsageInfo* aUsageInfo,
bool aDatabaseFiles)
{
@@ -18388,7 +18398,7 @@ QuotaClient::GetUsageForDirectoryInternal(nsIFile* aDirectory,
bool hasMore;
while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
hasMore &&
- !aUsageInfo->Canceled()) {
+ !aCanceled) {
nsCOMPtr entry;
rv = entries->GetNext(getter_AddRefs(entry));
if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -18423,7 +18433,7 @@ QuotaClient::GetUsageForDirectoryInternal(nsIFile* aDirectory,
if (isDirectory) {
if (aDatabaseFiles) {
- rv = GetUsageForDirectoryInternal(file, aUsageInfo, false);
+ rv = GetUsageForDirectoryInternal(file, aCanceled, aUsageInfo, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -21236,8 +21246,7 @@ FactoryOp::CheckPermission(ContentParent* aContentParent,
if (State::Initial == mState) {
QuotaManager::GetInfoForChrome(&mSuffix, &mGroup, &mOrigin);
- MOZ_ASSERT(
- QuotaManager::IsOriginWhitelistedForPersistentStorage(mOrigin));
+ MOZ_ASSERT(QuotaManager::IsOriginInternal(mOrigin));
mEnforcingQuota = false;
}
@@ -21269,7 +21278,7 @@ FactoryOp::CheckPermission(ContentParent* aContentParent,
PermissionRequestBase::PermissionValue permission;
if (persistenceType == PERSISTENCE_TYPE_PERSISTENT) {
- if (QuotaManager::IsOriginWhitelistedForPersistentStorage(origin)) {
+ if (QuotaManager::IsOriginInternal(origin)) {
permission = PermissionRequestBase::kPermissionAllowed;
} else {
#ifdef IDB_MOBILE
diff --git a/dom/indexedDB/test/file.js b/dom/indexedDB/test/file.js
index 6c70eff1be25..744a92b33a0c 100644
--- a/dom/indexedDB/test/file.js
+++ b/dom/indexedDB/test/file.js
@@ -220,10 +220,10 @@ function verifyWasmModule(module1, module2)
function grabFileUsageAndContinueHandler(request)
{
- testGenerator.next(request.fileUsage);
+ testGenerator.next(request.result.fileUsage);
}
-function getUsage(usageHandler)
+function getCurrentUsage(usageHandler)
{
let qms = SpecialPowers.Services.qms;
let principal = SpecialPowers.wrap(document).nodePrincipal;
diff --git a/dom/indexedDB/test/test_file_os_delete.html b/dom/indexedDB/test/test_file_os_delete.html
index e5acf079c420..81c8fd1a8c50 100644
--- a/dom/indexedDB/test/test_file_os_delete.html
+++ b/dom/indexedDB/test/test_file_os_delete.html
@@ -18,7 +18,7 @@
const objectStoreName = "Blobs";
- getUsage(grabFileUsageAndContinueHandler);
+ getCurrentUsage(grabFileUsageAndContinueHandler);
let startUsage = yield undefined;
const fileData1 = {
@@ -61,7 +61,7 @@
is(event.type, "success", "Got correct event type");
- getUsage(grabFileUsageAndContinueHandler);
+ getCurrentUsage(grabFileUsageAndContinueHandler);
let usage = yield undefined;
is(usage, startUsage + fileData1.obj.file.size + fileData2.obj.file.size,
@@ -74,7 +74,7 @@
is(event.type, "complete", "Got correct event type");
- getUsage(grabFileUsageAndContinueHandler);
+ getCurrentUsage(grabFileUsageAndContinueHandler);
usage = yield undefined;
is(usage, startUsage + fileData1.obj.file.size + fileData2.obj.file.size,
@@ -90,7 +90,7 @@
// Flush pending file deletions before checking usage.
flushPendingFileDeletions();
- getUsage(grabFileUsageAndContinueHandler);
+ getCurrentUsage(grabFileUsageAndContinueHandler);
let endUsage = yield undefined;
is(endUsage, startUsage, "OS files deleted");
diff --git a/dom/indexedDB/test/unit/test_idle_maintenance.js b/dom/indexedDB/test/unit/test_idle_maintenance.js
index 51bcf0b11c93..a0cf01fd778d 100644
--- a/dom/indexedDB/test/unit/test_idle_maintenance.js
+++ b/dom/indexedDB/test/unit/test_idle_maintenance.js
@@ -122,8 +122,9 @@ function* testSteps()
let usageBeforeMaintenance;
quotaManagerService.getUsageForPrincipal(principal, (request) => {
- ok(request.usage > 0, "Usage is non-zero");
- usageBeforeMaintenance = request.usage;
+ let usage = request.result.usage;
+ ok(usage > 0, "Usage is non-zero");
+ usageBeforeMaintenance = usage;
continueToNextStep();
});
yield undefined;
@@ -155,8 +156,9 @@ function* testSteps()
let usageAfterMaintenance;
quotaManagerService.getUsageForPrincipal(principal, (request) => {
- ok(request.usage > 0, "Usage is non-zero");
- usageAfterMaintenance = request.usage;
+ let usage = request.result.usage;
+ ok(usage > 0, "Usage is non-zero");
+ usageAfterMaintenance = usage;
continueToNextStep();
});
yield undefined;
diff --git a/dom/indexedDB/test/unit/test_view_put_get_values.js b/dom/indexedDB/test/unit/test_view_put_get_values.js
index 2dad2f64c653..2b4b8bf060ce 100644
--- a/dom/indexedDB/test/unit/test_view_put_get_values.js
+++ b/dom/indexedDB/test/unit/test_view_put_get_values.js
@@ -80,7 +80,7 @@ function* testSteps()
verifyView(request.result, viewData.view);
yield undefined;
- getUsage(grabFileUsageAndContinueHandler);
+ getCurrentUsage(grabFileUsageAndContinueHandler);
let fileUsage = yield undefined;
if (external) {
diff --git a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
index d56e8269cf8a..ba757ba9a248 100644
--- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
+++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
@@ -516,10 +516,10 @@ function verifyWasmModule(module1, module2)
function grabFileUsageAndContinueHandler(request)
{
- testGenerator.next(request.fileUsage);
+ testGenerator.next(request.result.fileUsage);
}
-function getUsage(usageHandler)
+function getCurrentUsage(usageHandler)
{
let qms = Cc["@mozilla.org/dom/quota-manager-service;1"]
.getService(Ci.nsIQuotaManagerService);
diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp
index 06b69a77a49a..87163e1bcb91 100644
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -58,7 +58,6 @@
#include "nsIDOMWindowUtils.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsILoadInfo.h"
-#include "nsPrincipal.h"
#include "nsIPromptFactory.h"
#include "nsIURI.h"
#include "nsIWindowWatcher.h"
@@ -69,6 +68,7 @@
#include "nsViewManager.h"
#include "nsVariant.h"
#include "nsIWidget.h"
+#include "nsNetUtil.h"
#ifndef XP_WIN
#include "nsJARProtocolHandler.h"
#endif
diff --git a/dom/json/nsJSON.cpp b/dom/json/nsJSON.cpp
index 4a6503fb8eaf..2884c7bc96f3 100644
--- a/dom/json/nsJSON.cpp
+++ b/dom/json/nsJSON.cpp
@@ -22,7 +22,7 @@
#include "nsIScriptError.h"
#include "nsCRTGlue.h"
#include "nsIScriptSecurityManager.h"
-#include "nsNullPrincipal.h"
+#include "NullPrincipal.h"
#include "mozilla/Maybe.h"
#include
@@ -407,7 +407,7 @@ nsJSON::DecodeInternal(JSContext* cx,
}
nsresult rv;
- nsCOMPtr nullPrincipal = nsNullPrincipal::Create();
+ nsCOMPtr nullPrincipal = NullPrincipal::Create();
// The ::Decode function is deprecated [Bug 675797] and the following
// channel is never openend, so it does not matter what securityFlags
diff --git a/dom/jsurl/nsJSProtocolHandler.cpp b/dom/jsurl/nsJSProtocolHandler.cpp
index bd8f70e2bc87..0c1b5d9599fc 100644
--- a/dom/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/jsurl/nsJSProtocolHandler.cpp
@@ -269,10 +269,14 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
JS::CompileOptions options(cx);
options.setFileAndLine(mURL.get(), 1)
.setVersion(JSVERSION_DEFAULT);
- nsJSUtils::EvaluateOptions evalOptions(cx);
- evalOptions.setCoerceToString(true);
- rv = nsJSUtils::EvaluateString(cx, NS_ConvertUTF8toUTF16(script),
- globalJSObject, options, evalOptions, &v);
+ {
+ nsJSUtils::ExecutionContext exec(cx, globalJSObject);
+ exec.SetCoerceToString(true);
+ exec.CompileAndExec(options, NS_ConvertUTF8toUTF16(script));
+ rv = exec.ExtractReturnValue(&v);
+ }
+
+ js::AssertSameCompartment(cx, v);
if (NS_FAILED(rv) || !(v.isString() || v.isUndefined())) {
return NS_ERROR_MALFORMED_URI;
diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp
index 7a81f835a086..2e3763325484 100644
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -28,7 +28,6 @@
#include "nsIIDNService.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
-#include "nsPrincipal.h"
#include "nsICryptoHash.h"
#include "nsICryptoHMAC.h"
#include "nsIKeyModule.h"
@@ -54,7 +53,7 @@
#include "VideoUtils.h"
#include "Latency.h"
#include "nsProxyRelease.h"
-#include "nsNullPrincipal.h"
+#include "NullPrincipal.h"
#include "nsVariant.h"
// For snprintf
@@ -1155,7 +1154,7 @@ public:
nsCOMPtr principal;
if (mPeerIdentity) {
- principal = nsNullPrincipal::CreateWithInheritedAttributes(window->GetExtantDoc()->NodePrincipal());
+ principal = NullPrincipal::CreateWithInheritedAttributes(window->GetExtantDoc()->NodePrincipal());
} else {
principal = window->GetExtantDoc()->NodePrincipal();
}
diff --git a/dom/media/MediaStreamTrack.h b/dom/media/MediaStreamTrack.h
index cb11e919ac2e..c433f1a5656c 100644
--- a/dom/media/MediaStreamTrack.h
+++ b/dom/media/MediaStreamTrack.h
@@ -97,7 +97,7 @@ public:
* This is used in WebRTC. A peerIdentity constrained MediaStreamTrack cannot
* be sent across the network to anything other than a peer with the provided
* identity. If this is set, then GetPrincipal() should return an instance of
- * nsNullPrincipal.
+ * NullPrincipal.
*
* A track's PeerIdentity is immutable and will not change during the track's
* lifetime.
diff --git a/dom/media/mediasink/AudioSink.cpp b/dom/media/mediasink/AudioSink.cpp
index a92d8294d708..4938a870748f 100644
--- a/dom/media/mediasink/AudioSink.cpp
+++ b/dom/media/mediasink/AudioSink.cpp
@@ -258,27 +258,6 @@ AudioSink::PopFrames(uint32_t aFrames)
AudioDataValue* const mData;
};
- class SilentChunk : public AudioStream::Chunk {
- public:
- SilentChunk(uint32_t aFrames, uint32_t aChannels, uint32_t aRate)
- : mFrames(aFrames)
- , mChannels(aChannels)
- , mRate(aRate)
- , mData(MakeUnique(aChannels * aFrames)) {
- memset(mData.get(), 0, aChannels * aFrames * sizeof(AudioDataValue));
- }
- const AudioDataValue* Data() const { return mData.get(); }
- uint32_t Frames() const { return mFrames; }
- uint32_t Channels() const { return mChannels; }
- uint32_t Rate() const { return mRate; }
- AudioDataValue* GetWritable() const { return mData.get(); }
- private:
- const uint32_t mFrames;
- const uint32_t mChannels;
- const uint32_t mRate;
- UniquePtr mData;
- };
-
bool needPopping = false;
if (!mCurrentData) {
// No data in the queue. Return an empty chunk.
diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
index f0e97c75fdae..b78b6478b54f 100644
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
@@ -384,10 +384,9 @@ FindD3D9BlacklistedDLL()
class CreateDXVAManagerEvent : public Runnable
{
public:
- CreateDXVAManagerEvent(LayersBackend aBackend,
- layers::KnowsCompositor* aKnowsCompositor,
+ CreateDXVAManagerEvent(layers::KnowsCompositor* aKnowsCompositor,
nsCString& aFailureReason)
- : mBackend(aBackend)
+ : mBackend(LayersBackend::LAYERS_D3D11)
, mKnowsCompositor(aKnowsCompositor)
, mFailureReason(aFailureReason)
{
@@ -435,7 +434,7 @@ public:
};
bool
-WMFVideoMFTManager::InitializeDXVA(bool aForceD3D9)
+WMFVideoMFTManager::InitializeDXVA()
{
// If we use DXVA but aren't running with a D3D layer manager then the
// readback of decoded video frames from GPU to CPU memory grinds painting
@@ -447,17 +446,14 @@ WMFVideoMFTManager::InitializeDXVA(bool aForceD3D9)
}
MOZ_ASSERT(!mDXVA2Manager);
LayersBackend backend = GetCompositorBackendType(mKnowsCompositor);
- if (backend != LayersBackend::LAYERS_D3D9
- && backend != LayersBackend::LAYERS_D3D11) {
+ if (backend != LayersBackend::LAYERS_D3D11) {
mDXVAFailureReason.AssignLiteral("Unsupported layers backend");
return false;
}
// The DXVA manager must be created on the main thread.
RefPtr event =
- new CreateDXVAManagerEvent(aForceD3D9 ? LayersBackend::LAYERS_D3D9
- : backend,
- mKnowsCompositor,
+ new CreateDXVAManagerEvent(mKnowsCompositor,
mDXVAFailureReason);
if (NS_IsMainThread()) {
@@ -499,7 +495,7 @@ WMFVideoMFTManager::Init()
return false;
}
- bool success = InitInternal(/* aForceD3D9 = */ false);
+ bool success = InitInternal();
if (success && mDXVA2Manager) {
// If we had some failures but eventually made it work,
@@ -515,10 +511,10 @@ WMFVideoMFTManager::Init()
}
bool
-WMFVideoMFTManager::InitInternal(bool aForceD3D9)
+WMFVideoMFTManager::InitInternal()
{
mUseHwAccel = false; // default value; changed if D3D setup succeeds.
- bool useDxva = InitializeDXVA(aForceD3D9);
+ bool useDxva = InitializeDXVA();
RefPtr decoder(new MFTDecoder());
@@ -836,8 +832,7 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
nsIntRect pictureRegion = mVideoInfo.ScaledImageRect(videoWidth, videoHeight);
LayersBackend backend = GetCompositorBackendType(mKnowsCompositor);
- if (backend != LayersBackend::LAYERS_D3D9 &&
- backend != LayersBackend::LAYERS_D3D11) {
+ if (backend != LayersBackend::LAYERS_D3D11) {
RefPtr v =
VideoData::CreateAndCopyData(mVideoInfo,
mImageContainer,
diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.h b/dom/media/platforms/wmf/WMFVideoMFTManager.h
index 7d9851790135..56dbfaac1314 100644
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.h
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.h
@@ -69,9 +69,9 @@ public:
private:
bool ValidateVideoInfo();
- bool InitializeDXVA(bool aForceD3D9);
+ bool InitializeDXVA();
- bool InitInternal(bool aForceD3D9);
+ bool InitInternal();
HRESULT CreateBasicVideoFrame(IMFSample* aSample,
int64_t aStreamOffset,
diff --git a/dom/plugins/base/nsNPAPIPlugin.cpp b/dom/plugins/base/nsNPAPIPlugin.cpp
index af8a182b5e99..6fcc157ce7b9 100644
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -1368,14 +1368,23 @@ _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result)
options.setFileAndLine(spec, 0)
.setVersion(JSVERSION_DEFAULT);
JS::Rooted rval(cx);
- nsJSUtils::EvaluateOptions evalOptions(cx);
+ JS::AutoObjectVector scopeChain(cx);
if (obj != js::GetGlobalForObjectCrossCompartment(obj) &&
- !evalOptions.scopeChain.append(obj)) {
+ !scopeChain.append(obj)) {
return false;
}
obj = js::GetGlobalForObjectCrossCompartment(obj);
- nsresult rv = nsJSUtils::EvaluateString(cx, utf16script, obj, options,
- evalOptions, &rval);
+ nsresult rv = NS_OK;
+ {
+ nsJSUtils::ExecutionContext exec(cx, obj);
+ exec.SetScopeChain(scopeChain);
+ exec.CompileAndExec(options, utf16script);
+ rv = exec.ExtractReturnValue(&rval);
+ }
+
+ if (!JS_WrapValue(cx, &rval)) {
+ return false;
+ }
return NS_SUCCEEDED(rv) &&
(!result || JSValToNPVariant(npp, cx, rval, result));
diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp
index 24816654569f..3b8ace19e1ee 100644
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -94,7 +94,7 @@
#include "nsIImageLoadingContent.h"
#include "mozilla/Preferences.h"
#include "nsVersionComparator.h"
-#include "nsNullPrincipal.h"
+#include "NullPrincipal.h"
#if defined(XP_WIN)
#include "nsIWindowMediator.h"
diff --git a/dom/plugins/base/nsPluginStreamListenerPeer.cpp b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
index 283f1da7e277..a6d0634fbdfc 100644
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -33,7 +33,7 @@
#include "GeckoProfiler.h"
#include "nsPluginInstanceOwner.h"
#include "nsDataHashtable.h"
-#include "nsNullPrincipal.h"
+#include "NullPrincipal.h"
#define BYTERANGE_REQUEST_CONTEXT 0x01020304
diff --git a/dom/quota/ActorsChild.cpp b/dom/quota/ActorsChild.cpp
index ab900dc39e6e..364896c54695 100644
--- a/dom/quota/ActorsChild.cpp
+++ b/dom/quota/ActorsChild.cpp
@@ -9,6 +9,7 @@
#include "nsVariant.h"
#include "QuotaManagerService.h"
#include "QuotaRequests.h"
+#include "QuotaResults.h"
namespace mozilla {
namespace dom {
@@ -141,14 +142,56 @@ QuotaUsageRequestChild::HandleResponse(nsresult aResponse)
}
void
-QuotaUsageRequestChild::HandleResponse(const UsageResponse& aResponse)
+QuotaUsageRequestChild::HandleResponse(const nsTArray& aResponse)
{
AssertIsOnOwningThread();
MOZ_ASSERT(mRequest);
- mRequest->SetResult(aResponse.usage(),
- aResponse.fileUsage(),
- aResponse.limit());
+ RefPtr variant = new nsVariant();
+
+ if (aResponse.IsEmpty()) {
+ variant->SetAsEmptyArray();
+ } else {
+ nsTArray> usageResults;
+
+ const uint32_t count = aResponse.Length();
+
+ usageResults.SetCapacity(count);
+
+ for (uint32_t index = 0; index < count; index++) {
+ auto& originUsage = aResponse[index];
+
+ RefPtr usageResult = new UsageResult(originUsage.origin(),
+ originUsage.persisted(),
+ originUsage.usage());
+
+ usageResults.AppendElement(usageResult.forget());
+ }
+
+ variant->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS,
+ &NS_GET_IID(nsIQuotaUsageResult),
+ usageResults.Length(),
+ static_cast(usageResults.Elements()));
+ }
+
+ mRequest->SetResult(variant);
+}
+
+void
+QuotaUsageRequestChild::HandleResponse(const OriginUsageResponse& aResponse)
+{
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(mRequest);
+
+ RefPtr result =
+ new OriginUsageResult(aResponse.usage(),
+ aResponse.fileUsage(),
+ aResponse.limit());
+
+ RefPtr variant = new nsVariant();
+ variant->SetAsInterface(NS_GET_IID(nsIQuotaOriginUsageResult), result);
+
+ mRequest->SetResult(variant);
}
void
@@ -175,8 +218,12 @@ QuotaUsageRequestChild::Recv__delete__(const UsageRequestResponse& aResponse)
HandleResponse(aResponse.get_nsresult());
break;
- case UsageRequestResponse::TUsageResponse:
- HandleResponse(aResponse.get_UsageResponse());
+ case UsageRequestResponse::TAllUsageResponse:
+ HandleResponse(aResponse.get_AllUsageResponse().originUsages());
+ break;
+
+ case UsageRequestResponse::TOriginUsageResponse:
+ HandleResponse(aResponse.get_OriginUsageResponse());
break;
default:
diff --git a/dom/quota/ActorsChild.h b/dom/quota/ActorsChild.h
index 90a952e3b65e..fe1abf1094d0 100644
--- a/dom/quota/ActorsChild.h
+++ b/dom/quota/ActorsChild.h
@@ -98,7 +98,10 @@ private:
HandleResponse(nsresult aResponse);
void
- HandleResponse(const UsageResponse& aResponse);
+ HandleResponse(const nsTArray& aResponse);
+
+ void
+ HandleResponse(const OriginUsageResponse& aResponse);
// IPDL methods are only called by IPDL.
virtual void
diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp
index 22a3559d39bb..9e2bceee0044 100644
--- a/dom/quota/ActorsParent.cpp
+++ b/dom/quota/ActorsParent.cpp
@@ -915,6 +915,7 @@ class NormalOriginOperationBase
protected:
Nullable mPersistenceType;
OriginScope mOriginScope;
+ mozilla::Atomic mCanceled;
const bool mExclusive;
public:
@@ -1042,49 +1043,103 @@ private:
RecvStopIdleMaintenance() override;
};
-class GetUsageOp final
+class QuotaUsageRequestBase
: public NormalOriginOperationBase
, public PQuotaUsageRequestParent
+{
+public:
+ // May be overridden by subclasses if they need to perform work on the
+ // background thread before being run.
+ virtual bool
+ Init(Quota* aQuota);
+
+protected:
+ QuotaUsageRequestBase()
+ : NormalOriginOperationBase(Nullable(),
+ OriginScope::FromNull(),
+ /* aExclusive */ false)
+ { }
+
+ nsresult
+ GetUsageForOrigin(QuotaManager* aQuotaManager,
+ PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin,
+ UsageInfo* aUsageInfo);
+
+ // Subclasses use this override to set the IPDL response value.
+ virtual void
+ GetResponse(UsageRequestResponse& aResponse) = 0;
+
+private:
+ void
+ SendResults() override;
+
+ // IPDL methods.
+ void
+ ActorDestroy(ActorDestroyReason aWhy) override;
+
+ mozilla::ipc::IPCResult
+ RecvCancel() override;
+};
+
+class GetUsageOp final
+ : public QuotaUsageRequestBase
+{
+ nsTArray mOriginUsages;
+ nsDataHashtable mOriginUsagesIndex;
+
+ bool mGetAll;
+
+public:
+ explicit GetUsageOp(const UsageRequestParams& aParams);
+
+private:
+ ~GetUsageOp()
+ { }
+
+ nsresult
+ TraverseRepository(QuotaManager* aQuotaManager,
+ PersistenceType aPersistenceType);
+
+ nsresult
+ DoDirectoryWork(QuotaManager* aQuotaManager) override;
+
+ void
+ GetResponse(UsageRequestResponse& aResponse) override;
+};
+
+class GetOriginUsageOp final
+ : public QuotaUsageRequestBase
{
// If mGetGroupUsage is false, we use mUsageInfo to record the origin usage
// and the file usage. Otherwise, we use it to record the group usage and the
// limit.
UsageInfo mUsageInfo;
- const UsageParams mParams;
+ const OriginUsageParams mParams;
nsCString mSuffix;
nsCString mGroup;
bool mGetGroupUsage;
public:
- explicit GetUsageOp(const UsageRequestParams& aParams);
+ explicit GetOriginUsageOp(const UsageRequestParams& aParams);
MOZ_IS_CLASS_INIT bool
- Init(Quota* aQuota);
+ Init(Quota* aQuota) override;
private:
- ~GetUsageOp()
+ ~GetOriginUsageOp()
{ }
MOZ_IS_CLASS_INIT virtual nsresult
DoInitOnMainThread() override;
- nsresult
- AddToUsage(QuotaManager* aQuotaManager,
- PersistenceType aPersistenceType);
-
virtual nsresult
DoDirectoryWork(QuotaManager* aQuotaManager) override;
- virtual void
- SendResults() override;
-
- // IPDL methods.
- virtual void
- ActorDestroy(ActorDestroyReason aWhy) override;
-
- virtual mozilla::ipc::IPCResult
- RecvCancel() override;
+ void
+ GetResponse(UsageRequestResponse& aResponse) override;
};
class QuotaRequestBase
@@ -4196,7 +4251,11 @@ QuotaManager::InitializeOrigin(PersistenceType aPersistenceType,
return NS_ERROR_UNEXPECTED;
}
- rv = mClients[clientType]->InitOrigin(aPersistenceType, aGroup, aOrigin,
+ Atomic dummy(false);
+ rv = mClients[clientType]->InitOrigin(aPersistenceType,
+ aGroup,
+ aOrigin,
+ /* aCanceled */ dummy,
usageInfo);
NS_ENSURE_SUCCESS(rv, rv);
}
@@ -5296,10 +5355,9 @@ QuotaManager::GetInfoForChrome(nsACString* aSuffix,
// static
bool
-QuotaManager::IsOriginWhitelistedForPersistentStorage(const nsACString& aOrigin)
+QuotaManager::IsOriginInternal(const nsACString& aOrigin)
{
- // The first prompt and quota tracking is not required for these origins in
- // persistent storage.
+ // The first prompt is not required for these origins.
if (aOrigin.EqualsLiteral(kChromeOrigin) ||
StringBeginsWith(aOrigin, nsDependentCString(kAboutHomeOriginPrefix)) ||
StringBeginsWith(aOrigin, nsDependentCString(kIndexedDBOriginPrefix)) ||
@@ -6230,7 +6288,25 @@ Quota::ActorDestroy(ActorDestroyReason aWhy)
PQuotaUsageRequestParent*
Quota::AllocPQuotaUsageRequestParent(const UsageRequestParams& aParams)
{
- RefPtr actor = new GetUsageOp(aParams);
+ AssertIsOnBackgroundThread();
+ MOZ_ASSERT(aParams.type() != UsageRequestParams::T__None);
+
+ RefPtr actor;
+
+ switch (aParams.type()) {
+ case UsageRequestParams::TAllUsageParams:
+ actor = new GetUsageOp(aParams);
+ break;
+
+ case UsageRequestParams::TOriginUsageParams:
+ actor = new GetOriginUsageOp(aParams);
+ break;
+
+ default:
+ MOZ_CRASH("Should never get here!");
+ }
+
+ MOZ_ASSERT(actor);
// Transfer ownership to IPDL.
return actor.forget().take();
@@ -6244,7 +6320,7 @@ Quota::RecvPQuotaUsageRequestConstructor(PQuotaUsageRequestParent* aActor,
MOZ_ASSERT(aActor);
MOZ_ASSERT(aParams.type() != UsageRequestParams::T__None);
- auto* op = static_cast(aActor);
+ auto* op = static_cast(aActor);
if (NS_WARN_IF(!op->Init(this))) {
return IPC_FAIL_NO_REASON(this);
@@ -6261,8 +6337,8 @@ Quota::DeallocPQuotaUsageRequestParent(PQuotaUsageRequestParent* aActor)
MOZ_ASSERT(aActor);
// Transfer ownership back from IPDL.
- RefPtr actor =
- dont_AddRef(static_cast(aActor));
+ RefPtr actor =
+ dont_AddRef(static_cast(aActor));
return true;
}
@@ -6336,6 +6412,7 @@ Quota::RecvPQuotaRequestConstructor(PQuotaRequestParent* aActor,
MOZ_ASSERT(aParams.type() != RequestParams::T__None);
auto* op = static_cast(aActor);
+
if (NS_WARN_IF(!op->Init(this))) {
return IPC_FAIL_NO_REASON(this);
}
@@ -6414,67 +6491,32 @@ Quota::RecvStopIdleMaintenance()
return IPC_OK();
}
-GetUsageOp::GetUsageOp(const UsageRequestParams& aParams)
- : NormalOriginOperationBase(Nullable(),
- OriginScope::FromNull(),
- /* aExclusive */ false)
- , mParams(aParams.get_UsageParams())
- , mGetGroupUsage(aParams.get_UsageParams().getGroupUsage())
-{
- AssertIsOnOwningThread();
- MOZ_ASSERT(aParams.type() == UsageRequestParams::TUsageParams);
-}
-
bool
-GetUsageOp::Init(Quota* aQuota)
+QuotaUsageRequestBase::Init(Quota* aQuota)
{
AssertIsOnOwningThread();
MOZ_ASSERT(aQuota);
- mNeedsMainThreadInit = true;
mNeedsQuotaManagerInit = true;
return true;
}
nsresult
-GetUsageOp::DoInitOnMainThread()
-{
- MOZ_ASSERT(NS_IsMainThread());
- MOZ_ASSERT(GetState() == State_Initializing);
- MOZ_ASSERT(mNeedsMainThreadInit);
-
- const PrincipalInfo& principalInfo = mParams.principalInfo();
-
- nsresult rv;
- nsCOMPtr principal =
- PrincipalInfoToPrincipal(principalInfo, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- // Figure out which origin we're dealing with.
- nsCString origin;
- rv = QuotaManager::GetInfoFromPrincipal(principal, &mSuffix, &mGroup,
- &origin);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- mOriginScope.SetFromOrigin(origin);
-
- return NS_OK;
-}
-
-nsresult
-GetUsageOp::AddToUsage(QuotaManager* aQuotaManager,
- PersistenceType aPersistenceType)
+QuotaUsageRequestBase::GetUsageForOrigin(QuotaManager* aQuotaManager,
+ PersistenceType aPersistenceType,
+ const nsACString& aGroup,
+ const nsACString& aOrigin,
+ UsageInfo* aUsageInfo)
{
AssertIsOnIOThread();
+ MOZ_ASSERT(aQuotaManager);
+ MOZ_ASSERT(aUsageInfo);
+ MOZ_ASSERT(aUsageInfo->TotalUsage() == 0);
nsCOMPtr directory;
nsresult rv = aQuotaManager->GetDirectoryForOrigin(aPersistenceType,
- mOriginScope.GetOrigin(),
+ aOrigin,
getter_AddRefs(directory));
NS_ENSURE_SUCCESS(rv, rv);
@@ -6484,12 +6526,11 @@ GetUsageOp::AddToUsage(QuotaManager* aQuotaManager,
// If the directory exists then enumerate all the files inside, adding up
// the sizes to get the final usage statistic.
- if (exists && !mUsageInfo.Canceled()) {
+ if (exists && !mCanceled) {
bool initialized;
if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
- initialized =
- aQuotaManager->IsOriginInitialized(mOriginScope.GetOrigin());
+ initialized = aQuotaManager->IsOriginInitialized(aOrigin);
} else {
initialized = aQuotaManager->IsTemporaryStorageInitialized();
}
@@ -6500,7 +6541,7 @@ GetUsageOp::AddToUsage(QuotaManager* aQuotaManager,
bool hasMore;
while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
- hasMore && !mUsageInfo.Canceled()) {
+ hasMore && !mCanceled) {
nsCOMPtr entry;
rv = entries->GetNext(getter_AddRefs(entry));
NS_ENSURE_SUCCESS(rv, rv);
@@ -6562,15 +6603,17 @@ GetUsageOp::AddToUsage(QuotaManager* aQuotaManager,
if (initialized) {
rv = client->GetUsageForOrigin(aPersistenceType,
- mGroup,
- mOriginScope.GetOrigin(),
- &mUsageInfo);
+ aGroup,
+ aOrigin,
+ mCanceled,
+ aUsageInfo);
}
else {
rv = client->InitOrigin(aPersistenceType,
- mGroup,
- mOriginScope.GetOrigin(),
- &mUsageInfo);
+ aGroup,
+ aOrigin,
+ mCanceled,
+ aUsageInfo);
}
NS_ENSURE_SUCCESS(rv, rv);
}
@@ -6579,17 +6622,290 @@ GetUsageOp::AddToUsage(QuotaManager* aQuotaManager,
return NS_OK;
}
+void
+QuotaUsageRequestBase::SendResults()
+{
+ AssertIsOnOwningThread();
+
+ if (IsActorDestroyed()) {
+ if (NS_SUCCEEDED(mResultCode)) {
+ mResultCode = NS_ERROR_FAILURE;
+ }
+ } else {
+ if (mCanceled) {
+ mResultCode = NS_ERROR_FAILURE;
+ }
+
+ UsageRequestResponse response;
+
+ if (NS_SUCCEEDED(mResultCode)) {
+ GetResponse(response);
+ } else {
+ response = mResultCode;
+ }
+
+ Unused << PQuotaUsageRequestParent::Send__delete__(this, response);
+ }
+}
+
+void
+QuotaUsageRequestBase::ActorDestroy(ActorDestroyReason aWhy)
+{
+ AssertIsOnOwningThread();
+
+ NoteActorDestroyed();
+}
+
+mozilla::ipc::IPCResult
+QuotaUsageRequestBase::RecvCancel()
+{
+ AssertIsOnOwningThread();
+
+ if (mCanceled.exchange(true)) {
+ NS_WARNING("Canceled more than once?!");
+ return IPC_FAIL_NO_REASON(this);
+ }
+
+ return IPC_OK();
+}
+
+GetUsageOp::GetUsageOp(const UsageRequestParams& aParams)
+ : mGetAll(aParams.get_AllUsageParams().getAll())
+{
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(aParams.type() == UsageRequestParams::TAllUsageParams);
+}
+
+nsresult
+GetUsageOp::TraverseRepository(QuotaManager* aQuotaManager,
+ PersistenceType aPersistenceType)
+{
+ AssertIsOnIOThread();
+ MOZ_ASSERT(aQuotaManager);
+
+ nsresult rv;
+
+ nsCOMPtr directory =
+ do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ rv = directory->InitWithPath(aQuotaManager->GetStoragePath(aPersistenceType));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ bool exists;
+ rv = directory->Exists(&exists);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ if (!exists) {
+ return NS_OK;
+ }
+
+ nsCOMPtr entries;
+ rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ bool persistent = aPersistenceType == PERSISTENCE_TYPE_PERSISTENT;
+
+ bool hasMore;
+ while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
+ hasMore && !mCanceled) {
+ nsCOMPtr entry;
+ rv = entries->GetNext(getter_AddRefs(entry));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ nsCOMPtr originDir = do_QueryInterface(entry);
+ MOZ_ASSERT(originDir);
+
+ bool isDirectory;
+ rv = originDir->IsDirectory(&isDirectory);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ if (!isDirectory) {
+ nsString leafName;
+ rv = originDir->GetLeafName(leafName);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ if (!IsOSMetadata(leafName)) {
+ UNKNOWN_FILE_WARNING(leafName);
+ }
+ continue;
+ }
+
+ int64_t timestamp;
+ bool persisted;
+ nsCString suffix;
+ nsCString group;
+ nsCString origin;
+ rv = aQuotaManager->GetDirectoryMetadata2WithRestore(originDir,
+ persistent,
+ ×tamp,
+ &persisted,
+ suffix,
+ group,
+ origin);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ if (!mGetAll && aQuotaManager->IsOriginInternal(origin)) {
+ continue;
+ }
+
+ OriginUsage* originUsage;
+
+ // We can't store pointers to OriginUsage objects in the hashtable
+ // since AppendElement() reallocates its internal array buffer as number
+ // of elements grows.
+ uint32_t index;
+ if (mOriginUsagesIndex.Get(origin, &index)) {
+ originUsage = &mOriginUsages[index];
+ } else {
+ index = mOriginUsages.Length();
+
+ originUsage = mOriginUsages.AppendElement();
+
+ originUsage->origin() = origin;
+ originUsage->persisted() = false;
+ originUsage->usage() = 0;
+
+ mOriginUsagesIndex.Put(origin, index);
+ }
+
+ if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) {
+ originUsage->persisted() = persisted;
+ }
+
+ UsageInfo usageInfo;
+ rv = GetUsageForOrigin(aQuotaManager,
+ aPersistenceType,
+ group,
+ origin,
+ &usageInfo);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ originUsage->usage() = originUsage->usage() + usageInfo.TotalUsage();
+ }
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ return NS_OK;
+}
+
nsresult
GetUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager)
{
AssertIsOnIOThread();
- MOZ_ASSERT(mUsageInfo.TotalUsage() == 0);
PROFILER_LABEL("Quota", "GetUsageOp::DoDirectoryWork",
js::ProfileEntry::Category::OTHER);
nsresult rv;
+ for (const PersistenceType type : kAllPersistenceTypes) {
+ rv = TraverseRepository(aQuotaManager, type);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ }
+
+ return NS_OK;
+}
+
+void
+GetUsageOp::GetResponse(UsageRequestResponse& aResponse)
+{
+ AssertIsOnOwningThread();
+
+ aResponse = AllUsageResponse();
+
+ if (!mOriginUsages.IsEmpty()) {
+ nsTArray& originUsages =
+ aResponse.get_AllUsageResponse().originUsages();
+
+ mOriginUsages.SwapElements(originUsages);
+ }
+}
+
+GetOriginUsageOp::GetOriginUsageOp(const UsageRequestParams& aParams)
+ : mParams(aParams.get_OriginUsageParams())
+ , mGetGroupUsage(aParams.get_OriginUsageParams().getGroupUsage())
+{
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(aParams.type() == UsageRequestParams::TOriginUsageParams);
+}
+
+bool
+GetOriginUsageOp::Init(Quota* aQuota)
+{
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(aQuota);
+
+ if (NS_WARN_IF(!QuotaUsageRequestBase::Init(aQuota))) {
+ return false;
+ }
+
+ mNeedsMainThreadInit = true;
+
+ return true;
+}
+
+nsresult
+GetOriginUsageOp::DoInitOnMainThread()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(GetState() == State_Initializing);
+ MOZ_ASSERT(mNeedsMainThreadInit);
+
+ const PrincipalInfo& principalInfo = mParams.principalInfo();
+
+ nsresult rv;
+ nsCOMPtr principal =
+ PrincipalInfoToPrincipal(principalInfo, &rv);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ // Figure out which origin we're dealing with.
+ nsCString origin;
+ rv = QuotaManager::GetInfoFromPrincipal(principal, &mSuffix, &mGroup,
+ &origin);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ mOriginScope.SetFromOrigin(origin);
+
+ return NS_OK;
+}
+
+nsresult
+GetOriginUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager)
+{
+ AssertIsOnIOThread();
+ MOZ_ASSERT(mUsageInfo.TotalUsage() == 0);
+
+ PROFILER_LABEL("Quota", "GetOriginUsageOp::DoDirectoryWork",
+ js::ProfileEntry::Category::OTHER);
+
+ nsresult rv;
+
if (mGetGroupUsage) {
nsCOMPtr directory;
@@ -6611,72 +6927,40 @@ GetUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager)
// Add all the persistent/temporary/default storage files we care about.
for (const PersistenceType type : kAllPersistenceTypes) {
- rv = AddToUsage(aQuotaManager, type);
+ UsageInfo usageInfo;
+ rv = GetUsageForOrigin(aQuotaManager,
+ type,
+ mGroup,
+ mOriginScope.GetOrigin(),
+ &usageInfo);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
+
+ mUsageInfo.Append(usageInfo);
}
return NS_OK;
}
void
-GetUsageOp::SendResults()
+GetOriginUsageOp::GetResponse(UsageRequestResponse& aResponse)
{
AssertIsOnOwningThread();
- if (IsActorDestroyed()) {
- if (NS_SUCCEEDED(mResultCode)) {
- mResultCode = NS_ERROR_FAILURE;
- }
+ OriginUsageResponse usageResponse;
+
+ // We'll get the group usage when mGetGroupUsage is true and get the
+ // origin usage when mGetGroupUsage is false.
+ usageResponse.usage() = mUsageInfo.TotalUsage();
+
+ if (mGetGroupUsage) {
+ usageResponse.limit() = mUsageInfo.Limit();
} else {
- if (mUsageInfo.Canceled()) {
- mResultCode = NS_ERROR_FAILURE;
- }
-
- UsageRequestResponse response;
-
- if (NS_SUCCEEDED(mResultCode)) {
- UsageResponse usageResponse;
-
- // We'll get the group usage when mGetGroupUsage is true and get the
- // origin usage when mGetGroupUsage is false.
- usageResponse.usage() = mUsageInfo.TotalUsage();
-
- if (mGetGroupUsage) {
- usageResponse.limit() = mUsageInfo.Limit();
- } else {
- usageResponse.fileUsage() = mUsageInfo.FileUsage();
- }
-
- response = usageResponse;
- } else {
- response = mResultCode;
- }
-
- Unused << PQuotaUsageRequestParent::Send__delete__(this, response);
- }
-}
-
-void
-GetUsageOp::ActorDestroy(ActorDestroyReason aWhy)
-{
- AssertIsOnOwningThread();
-
- NoteActorDestroyed();
-}
-
-mozilla::ipc::IPCResult
-GetUsageOp::RecvCancel()
-{
- AssertIsOnOwningThread();
-
- nsresult rv = mUsageInfo.Cancel();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return IPC_FAIL_NO_REASON(this);
+ usageResponse.fileUsage() = mUsageInfo.FileUsage();
}
- return IPC_OK();
+ aResponse = usageResponse;
}
bool
@@ -8185,9 +8469,7 @@ CreateOrUpgradeDirectoryMetadataHelper::CreateOrUpgradeMetadataFiles()
}
}
else {
- bool persistent =
- QuotaManager::IsOriginWhitelistedForPersistentStorage(
- originProps.mSpec);
+ bool persistent = QuotaManager::IsOriginInternal(originProps.mSpec);
originProps.mTimestamp = GetLastModifiedTime(originDir, persistent);
}
@@ -8331,9 +8613,8 @@ CreateOrUpgradeDirectoryMetadataHelper::ProcessOriginDirectory(
return rv;
}
- // Move whitelisted origins to new persistent storage.
- if (QuotaManager::IsOriginWhitelistedForPersistentStorage(
- aOriginProps.mSpec)) {
+ // Move internal origins to new persistent storage.
+ if (QuotaManager::IsOriginInternal(aOriginProps.mSpec)) {
if (!mPermanentStorageDir) {
mPermanentStorageDir =
do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
diff --git a/dom/quota/Client.h b/dom/quota/Client.h
index b70d3e606914..4ee5ed228646 100644
--- a/dom/quota/Client.h
+++ b/dom/quota/Client.h
@@ -31,6 +31,8 @@ class UsageInfo;
class Client
{
public:
+ typedef mozilla::Atomic AtomicBool;
+
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
enum Type {
@@ -100,12 +102,14 @@ public:
InitOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
+ const AtomicBool& aCanceled,
UsageInfo* aUsageInfo) = 0;
virtual nsresult
GetUsageForOrigin(PersistenceType aPersistenceType,
const nsACString& aGroup,
const nsACString& aOrigin,
+ const AtomicBool& aCanceled,
UsageInfo* aUsageInfo) = 0;
virtual void
diff --git a/dom/quota/PQuota.ipdl b/dom/quota/PQuota.ipdl
index 88333e5bee6b..566cb02eef76 100644
--- a/dom/quota/PQuota.ipdl
+++ b/dom/quota/PQuota.ipdl
@@ -27,7 +27,12 @@ struct InitOriginParams
PersistenceType persistenceType;
};
-struct UsageParams
+struct AllUsageParams
+{
+ bool getAll;
+};
+
+struct OriginUsageParams
{
PrincipalInfo principalInfo;
bool getGroupUsage;
@@ -35,7 +40,8 @@ struct UsageParams
union UsageRequestParams
{
- UsageParams;
+ AllUsageParams;
+ OriginUsageParams;
};
struct ClearOriginParams
diff --git a/dom/quota/PQuotaUsageRequest.ipdl b/dom/quota/PQuotaUsageRequest.ipdl
index fbf7941c15d1..16994e627d1b 100644
--- a/dom/quota/PQuotaUsageRequest.ipdl
+++ b/dom/quota/PQuotaUsageRequest.ipdl
@@ -8,7 +8,19 @@ namespace mozilla {
namespace dom {
namespace quota {
-struct UsageResponse
+struct OriginUsage
+{
+ nsCString origin;
+ bool persisted;
+ uint64_t usage;
+};
+
+struct AllUsageResponse
+{
+ OriginUsage[] originUsages;
+};
+
+struct OriginUsageResponse
{
uint64_t usage;
uint64_t fileUsage;
@@ -18,7 +30,8 @@ struct UsageResponse
union UsageRequestResponse
{
nsresult;
- UsageResponse;
+ AllUsageResponse;
+ OriginUsageResponse;
};
protocol PQuotaUsageRequest
diff --git a/dom/quota/QuotaManager.h b/dom/quota/QuotaManager.h
index 176ec5c3fe33..2d4c893cf1ce 100644
--- a/dom/quota/QuotaManager.h
+++ b/dom/quota/QuotaManager.h
@@ -398,7 +398,7 @@ public:
nsACString* aOrigin);
static bool
- IsOriginWhitelistedForPersistentStorage(const nsACString& aOrigin);
+ IsOriginInternal(const nsACString& aOrigin);
static void
ChromeOrigin(nsACString& aOrigin);
diff --git a/dom/quota/QuotaManagerService.cpp b/dom/quota/QuotaManagerService.cpp
index 659d87a9e102..01be3f87e203 100644
--- a/dom/quota/QuotaManagerService.cpp
+++ b/dom/quota/QuotaManagerService.cpp
@@ -584,6 +584,31 @@ QuotaManagerService::InitStoragesForPrincipal(
return NS_OK;
}
+NS_IMETHODIMP
+QuotaManagerService::GetUsage(nsIQuotaUsageCallback* aCallback,
+ bool aGetAll,
+ nsIQuotaUsageRequest** _retval)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(aCallback);
+
+ RefPtr request = new UsageRequest(aCallback);
+
+ AllUsageParams params;
+
+ params.getAll() = aGetAll;
+
+ nsAutoPtr info(new UsageRequestInfo(request, params));
+
+ nsresult rv = InitiateRequest(info);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ request.forget(_retval);
+ return NS_OK;
+}
+
NS_IMETHODIMP
QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal,
nsIQuotaUsageCallback* aCallback,
@@ -596,7 +621,7 @@ QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal,
RefPtr request = new UsageRequest(aPrincipal, aCallback);
- UsageParams params;
+ OriginUsageParams params;
nsresult rv = CheckedPrincipalToPrincipalInfo(aPrincipal,
params.principalInfo());
diff --git a/dom/quota/QuotaRequests.cpp b/dom/quota/QuotaRequests.cpp
index 10b36b04078d..c9c1cbff6764 100644
--- a/dom/quota/QuotaRequests.cpp
+++ b/dom/quota/QuotaRequests.cpp
@@ -91,13 +91,19 @@ RequestBase::GetResultCode(nsresult* aResultCode)
return NS_OK;
}
+UsageRequest::UsageRequest(nsIQuotaUsageCallback* aCallback)
+ : mCallback(aCallback)
+ , mBackgroundActor(nullptr)
+ , mCanceled(false)
+{
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(aCallback);
+}
+
UsageRequest::UsageRequest(nsIPrincipal* aPrincipal,
nsIQuotaUsageCallback* aCallback)
: RequestBase(aPrincipal)
, mCallback(aCallback)
- , mUsage(0)
- , mFileUsage(0)
- , mLimit(0)
, mBackgroundActor(nullptr)
, mCanceled(false)
{
@@ -126,14 +132,14 @@ UsageRequest::SetBackgroundActor(QuotaUsageRequestChild* aBackgroundActor)
}
void
-UsageRequest::SetResult(uint64_t aUsage, uint64_t aFileUsage, uint64_t aLimit)
+UsageRequest::SetResult(nsIVariant* aResult)
{
AssertIsOnOwningThread();
+ MOZ_ASSERT(aResult);
MOZ_ASSERT(!mHaveResultOrErrorCode);
- mUsage = aUsage;
- mFileUsage = aFileUsage;
- mLimit = aLimit;
+ mResult = aResult;
+
mHaveResultOrErrorCode = true;
FireCallback();
@@ -149,43 +155,18 @@ NS_IMPL_ADDREF_INHERITED(UsageRequest, RequestBase)
NS_IMPL_RELEASE_INHERITED(UsageRequest, RequestBase)
NS_IMETHODIMP
-UsageRequest::GetUsage(uint64_t* aUsage)
+UsageRequest::GetResult(nsIVariant** aResult)
{
AssertIsOnOwningThread();
+ MOZ_ASSERT(aResult);
if (!mHaveResultOrErrorCode) {
return NS_ERROR_FAILURE;
}
- *aUsage = mUsage;
- return NS_OK;
-}
+ MOZ_ASSERT(mResult);
-NS_IMETHODIMP
-UsageRequest::GetFileUsage(uint64_t* aFileUsage)
-{
- AssertIsOnOwningThread();
- MOZ_ASSERT(aFileUsage);
-
- if (!mHaveResultOrErrorCode) {
- return NS_ERROR_FAILURE;
- }
-
- *aFileUsage = mFileUsage;
- return NS_OK;
-}
-
-NS_IMETHODIMP
-UsageRequest::GetLimit(uint64_t* aLimit)
-{
- AssertIsOnOwningThread();
- MOZ_ASSERT(aLimit);
-
- if (!mHaveResultOrErrorCode) {
- return NS_ERROR_FAILURE;
- }
-
- *aLimit = mLimit;
+ NS_ADDREF(*aResult = mResult);
return NS_OK;
}
diff --git a/dom/quota/QuotaRequests.h b/dom/quota/QuotaRequests.h
index 37c276039278..9a51a382085b 100644
--- a/dom/quota/QuotaRequests.h
+++ b/dom/quota/QuotaRequests.h
@@ -72,17 +72,15 @@ class UsageRequest final
{
nsCOMPtr mCallback;
- uint64_t mUsage;
- uint64_t mFileUsage;
-
- // Group Limit.
- uint64_t mLimit;
+ nsCOMPtr mResult;
QuotaUsageRequestChild* mBackgroundActor;
bool mCanceled;
public:
+ explicit UsageRequest(nsIQuotaUsageCallback* aCallback);
+
UsageRequest(nsIPrincipal* aPrincipal,
nsIQuotaUsageCallback* aCallback);
@@ -98,7 +96,7 @@ public:
}
void
- SetResult(uint64_t aUsage, uint64_t aFileUsage, uint64_t aLimit);
+ SetResult(nsIVariant* aResult);
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_NSIQUOTAREQUESTBASE(RequestBase::)
diff --git a/dom/quota/QuotaResults.cpp b/dom/quota/QuotaResults.cpp
new file mode 100644
index 000000000000..f5dbbd657e2a
--- /dev/null
+++ b/dom/quota/QuotaResults.cpp
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "QuotaResults.h"
+
+namespace mozilla {
+namespace dom {
+namespace quota {
+
+UsageResult::UsageResult(const nsACString& aOrigin,
+ bool aPersisted,
+ uint64_t aUsage)
+ : mOrigin(aOrigin)
+ , mUsage(aUsage)
+ , mPersisted(aPersisted)
+{
+}
+
+NS_IMPL_ISUPPORTS(UsageResult,
+ nsIQuotaUsageResult)
+
+NS_IMETHODIMP
+UsageResult::GetOrigin(nsACString& aOrigin)
+{
+ aOrigin = mOrigin;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+UsageResult::GetPersisted(bool* aPersisted)
+{
+ MOZ_ASSERT(aPersisted);
+
+ *aPersisted = mPersisted;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+UsageResult::GetUsage(uint64_t* aUsage)
+{
+ MOZ_ASSERT(aUsage);
+
+ *aUsage = mUsage;
+ return NS_OK;
+}
+
+OriginUsageResult::OriginUsageResult(uint64_t aUsage,
+ uint64_t aFileUsage,
+ uint64_t aLimit)
+ : mUsage(aUsage)
+ , mFileUsage(aFileUsage)
+ , mLimit(aLimit)
+{
+}
+
+NS_IMPL_ISUPPORTS(OriginUsageResult,
+ nsIQuotaOriginUsageResult)
+
+NS_IMETHODIMP
+OriginUsageResult::GetUsage(uint64_t* aUsage)
+{
+ MOZ_ASSERT(aUsage);
+
+ *aUsage = mUsage;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+OriginUsageResult::GetFileUsage(uint64_t* aFileUsage)
+{
+ MOZ_ASSERT(aFileUsage);
+
+ *aFileUsage = mFileUsage;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+OriginUsageResult::GetLimit(uint64_t* aLimit)
+{
+ MOZ_ASSERT(aLimit);
+
+ *aLimit = mLimit;
+ return NS_OK;
+}
+
+} // namespace quota
+} // namespace dom
+} // namespace mozilla
diff --git a/dom/quota/QuotaResults.h b/dom/quota/QuotaResults.h
new file mode 100644
index 000000000000..73fe6b790174
--- /dev/null
+++ b/dom/quota/QuotaResults.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_quota_QuotaResults_h
+#define mozilla_dom_quota_QuotaResults_h
+
+#include "nsIQuotaResults.h"
+
+namespace mozilla {
+namespace dom {
+namespace quota {
+
+class UsageResult
+ : public nsIQuotaUsageResult
+{
+ nsCString mOrigin;
+ uint64_t mUsage;
+ bool mPersisted;
+
+public:
+ UsageResult(const nsACString& aOrigin,
+ bool aPersisted,
+ uint64_t aUsage);
+
+private:
+ virtual ~UsageResult()
+ { }
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIQUOTAUSAGERESULT
+};
+
+class OriginUsageResult
+ : public nsIQuotaOriginUsageResult
+{
+ uint64_t mUsage;
+ uint64_t mFileUsage;
+ uint64_t mLimit;
+
+public:
+ OriginUsageResult(uint64_t aUsage,
+ uint64_t aFileUsage,
+ uint64_t aLimit);
+
+private:
+ virtual ~OriginUsageResult()
+ { }
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIQUOTAORIGINUSAGERESULT
+};
+
+} // namespace quota
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_quota_QuotaResults_h
diff --git a/dom/quota/StorageManager.cpp b/dom/quota/StorageManager.cpp
index 988fac57409c..4e9f0cf8c6b2 100644
--- a/dom/quota/StorageManager.cpp
+++ b/dom/quota/StorageManager.cpp
@@ -133,20 +133,31 @@ GetStorageEstimate(nsIQuotaUsageRequest* aRequest,
{
MOZ_ASSERT(aRequest);
- uint64_t usage;
- nsresult rv = aRequest->GetUsage(&usage);
+ nsCOMPtr result;
+ nsresult rv = aRequest->GetResult(getter_AddRefs(result));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
- uint64_t limit;
- rv = aRequest->GetLimit(&limit);
+ nsID* iid;
+ nsCOMPtr supports;
+ rv = result->GetAsInterface(&iid, getter_AddRefs(supports));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
- aStorageEstimate.mUsage.Construct() = usage;
- aStorageEstimate.mQuota.Construct() = limit;
+ free(iid);
+
+ nsCOMPtr originUsageResult =
+ do_QueryInterface(supports);
+ MOZ_ASSERT(originUsageResult);
+
+ MOZ_ALWAYS_SUCCEEDS(
+ originUsageResult->GetUsage(&aStorageEstimate.mUsage.Construct()));
+
+ MOZ_ALWAYS_SUCCEEDS(
+ originUsageResult->GetLimit(&aStorageEstimate.mQuota.Construct()));
+
return NS_OK;
}
diff --git a/dom/quota/UsageInfo.h b/dom/quota/UsageInfo.h
index 688e168707fa..9d34f1bff61e 100644
--- a/dom/quota/UsageInfo.h
+++ b/dom/quota/UsageInfo.h
@@ -18,26 +18,19 @@ class UsageInfo
{
public:
UsageInfo()
- : mCanceled(false), mDatabaseUsage(0), mFileUsage(0), mLimit(0)
+ : mDatabaseUsage(0)
+ , mFileUsage(0)
+ , mLimit(0)
{ }
virtual ~UsageInfo()
{ }
- bool
- Canceled()
+ void
+ Append(const UsageInfo& aUsageInfo)
{
- return mCanceled;
- }
-
- nsresult
- Cancel()
- {
- if (mCanceled.exchange(true)) {
- NS_WARNING("Canceled more than once?!");
- return NS_ERROR_UNEXPECTED;
- }
- return NS_OK;
+ IncrementUsage(&mDatabaseUsage, aUsageInfo.mDatabaseUsage);
+ IncrementUsage(&mFileUsage, aUsageInfo.mFileUsage);
}
void
@@ -104,9 +97,6 @@ public:
}
}
-protected:
- mozilla::Atomic mCanceled;
-
private:
uint64_t mDatabaseUsage;
uint64_t mFileUsage;
diff --git a/dom/quota/moz.build b/dom/quota/moz.build
index dca28101d3db..33c465666d4b 100644
--- a/dom/quota/moz.build
+++ b/dom/quota/moz.build
@@ -15,6 +15,7 @@ XPIDL_SOURCES += [
'nsIQuotaCallbacks.idl',
'nsIQuotaManagerService.idl',
'nsIQuotaRequests.idl',
+ 'nsIQuotaResults.idl',
]
XPIDL_MODULE = 'dom_quota'
@@ -43,6 +44,7 @@ UNIFIED_SOURCES += [
'FileStreams.cpp',
'QuotaManagerService.cpp',
'QuotaRequests.cpp',
+ 'QuotaResults.cpp',
'StorageManager.cpp',
]
diff --git a/dom/quota/nsIQuotaManagerService.idl b/dom/quota/nsIQuotaManagerService.idl
index 99a44476c6ec..b5c1869a9b68 100644
--- a/dom/quota/nsIQuotaManagerService.idl
+++ b/dom/quota/nsIQuotaManagerService.idl
@@ -41,6 +41,21 @@ interface nsIQuotaManagerService : nsISupports
initStoragesForPrincipal(in nsIPrincipal aPrincipal,
in ACString aPersistenceType);
+ /**
+ * Schedules an asynchronous callback that will inspect all origins and
+ * return the total amount of disk space being used by storages for each
+ * origin separately.
+ *
+ * @param aCallback
+ * The callback that will be called when the usage is available.
+ * @param aGetAll
+ * An optional boolean to indicate inspection of all origins,
+ * including internal ones.
+ */
+ [must_use] nsIQuotaUsageRequest
+ getUsage(in nsIQuotaUsageCallback aCallback,
+ [optional] in boolean aGetAll);
+
/**
* Schedules an asynchronous callback that will return the total amount of
* disk space being used by storages for the given origin.
diff --git a/dom/quota/nsIQuotaRequests.idl b/dom/quota/nsIQuotaRequests.idl
index 4a3d8547ae11..5d7cff3b9350 100644
--- a/dom/quota/nsIQuotaRequests.idl
+++ b/dom/quota/nsIQuotaRequests.idl
@@ -22,11 +22,10 @@ interface nsIQuotaRequestBase : nsISupports
[scriptable, uuid(166e28e6-cf6d-4927-a6d7-b51bca9d3469)]
interface nsIQuotaUsageRequest : nsIQuotaRequestBase
{
- [must_use] readonly attribute unsigned long long usage;
-
- [must_use] readonly attribute unsigned long long fileUsage;
-
- [must_use] readonly attribute unsigned long long limit;
+ // The result can contain one of these types:
+ // array of nsIQuotaUsageResult
+ // nsIQuotaOriginUsageResult
+ [must_use] readonly attribute nsIVariant result;
attribute nsIQuotaUsageCallback callback;
@@ -37,6 +36,9 @@ interface nsIQuotaUsageRequest : nsIQuotaRequestBase
[scriptable, uuid(22890e3e-ff25-4372-9684-d901060e2f6c)]
interface nsIQuotaRequest : nsIQuotaRequestBase
{
+ // The result can contain one of these types:
+ // void
+ // bool
[must_use] readonly attribute nsIVariant result;
attribute nsIQuotaCallback callback;
diff --git a/dom/quota/nsIQuotaResults.idl b/dom/quota/nsIQuotaResults.idl
new file mode 100644
index 000000000000..cd7ffd3a02c6
--- /dev/null
+++ b/dom/quota/nsIQuotaResults.idl
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+[scriptable, function, uuid(d8c9328b-9aa8-4f5d-90e6-482de4a6d5b8)]
+interface nsIQuotaUsageResult : nsISupports
+{
+ readonly attribute ACString origin;
+
+ readonly attribute boolean persisted;
+
+ readonly attribute unsigned long long usage;
+};
+
+[scriptable, function, uuid(96df03d2-116a-493f-bb0b-118c212a6b32)]
+interface nsIQuotaOriginUsageResult : nsISupports
+{
+ readonly attribute unsigned long long usage;
+
+ readonly attribute unsigned long long fileUsage;
+
+ readonly attribute unsigned long long limit;
+};
diff --git a/dom/quota/test/unit/getUsage_profile.zip b/dom/quota/test/unit/getUsage_profile.zip
new file mode 100644
index 000000000000..5144112bde35
Binary files /dev/null and b/dom/quota/test/unit/getUsage_profile.zip differ
diff --git a/dom/quota/test/unit/head.js b/dom/quota/test/unit/head.js
index e3606c47dece..8413ffc9efb3 100644
--- a/dom/quota/test/unit/head.js
+++ b/dom/quota/test/unit/head.js
@@ -261,12 +261,24 @@ function getPersistedFromMetadata(readBuffer)
return !!view[persistedPosition];
}
-function grabUsageAndContinueHandler(request)
+function grabResultAndContinueHandler(request)
{
- testGenerator.next(request.usage);
+ testGenerator.next(request.result);
}
-function getUsage(usageHandler)
+function grabUsageAndContinueHandler(request)
+{
+ testGenerator.next(request.result.usage);
+}
+
+function getUsage(usageHandler, getAll)
+{
+ let request = SpecialPowers._getQuotaManager().getUsage(usageHandler, getAll);
+
+ return request;
+}
+
+function getCurrentUsage(usageHandler)
{
let principal = Cc["@mozilla.org/systemprincipal;1"]
.createInstance(Ci.nsIPrincipal);
diff --git a/dom/quota/test/unit/test_basics.js b/dom/quota/test/unit/test_basics.js
index f23898c45abc..29aadf1fe11c 100644
--- a/dom/quota/test/unit/test_basics.js
+++ b/dom/quota/test/unit/test_basics.js
@@ -38,7 +38,7 @@ function* testSteps()
info("Getting usage");
- getUsage(grabUsageAndContinueHandler);
+ getCurrentUsage(grabUsageAndContinueHandler);
let usage = yield undefined;
ok(usage == 0, "Usage is zero");
@@ -53,7 +53,7 @@ function* testSteps()
info("Getting usage");
- getUsage(grabUsageAndContinueHandler);
+ getCurrentUsage(grabUsageAndContinueHandler);
usage = yield undefined;
ok(usage > 0, "Usage is not zero");
diff --git a/dom/quota/test/unit/test_getUsage.js b/dom/quota/test/unit/test_getUsage.js
new file mode 100644
index 000000000000..37d9d197a47b
--- /dev/null
+++ b/dom/quota/test/unit/test_getUsage.js
@@ -0,0 +1,127 @@
+/**
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var testGenerator = testSteps();
+
+function* testSteps()
+{
+ const origins = [
+ {
+ origin: "http://example.com",
+ persisted: false,
+ usage: 49152
+ },
+
+ {
+ origin: "http://localhost",
+ persisted: false,
+ usage: 147456
+ },
+
+ {
+ origin: "http://www.mozilla.org",
+ persisted: true,
+ usage: 98304
+ }
+ ];
+
+ const allOrigins = [
+ {
+ origin: "chrome",
+ persisted: false,
+ usage: 147456
+ },
+
+ {
+ origin: "http://example.com",
+ persisted: false,
+ usage: 49152
+ },
+
+ {
+ origin: "http://localhost",
+ persisted: false,
+ usage: 147456
+ },
+
+ {
+ origin: "http://www.mozilla.org",
+ persisted: true,
+ usage: 98304
+ }
+ ];
+
+ function verifyResult(result, origins) {
+ ok(result instanceof Array, "Got an array object");
+ ok(result.length == origins.length, "Correct number of elements");
+
+ info("Sorting elements");
+
+ result.sort(function(a, b) {
+ let originA = a.origin
+ let originB = b.origin
+
+ if (originA < originB) {
+ return -1;
+ }
+ if (originA > originB) {
+ return 1;
+ }
+ return 0;
+ });
+
+ info("Verifying elements");
+
+ for (let i = 0; i < result.length; i++) {
+ let a = result[i];
+ let b = origins[i];
+ ok(a.origin == b.origin, "Origin equals");
+ ok(a.persisted == b.persisted, "Persisted equals");
+ ok(a.usage == b.usage, "Usage equals");
+ }
+ }
+
+ info("Clearing");
+
+ clear(continueToNextStepSync);
+ yield undefined;
+
+ info("Getting usage");
+
+ getUsage(grabResultAndContinueHandler, /* getAll */ true);
+ let result = yield undefined;
+
+ info("Verifying result");
+
+ verifyResult(result, []);
+
+ info("Installing package");
+
+ // The profile contains IndexedDB databases placed across the repositories.
+ // The file create_db.js in the package was run locally, specifically it was
+ // temporarily added to xpcshell.ini and then executed:
+ // mach xpcshell-test --interactive dom/quota/test/unit/create_db.js
+ installPackage("getUsage_profile");
+
+ info("Getting usage");
+
+ getUsage(grabResultAndContinueHandler, /* getAll */ false);
+ result = yield undefined;
+
+ info("Verifying result");
+
+ verifyResult(result, origins);
+
+ info("Getting usage");
+
+ getUsage(grabResultAndContinueHandler, /* getAll */ true);
+ result = yield undefined;
+
+ info("Verifying result");
+
+ verifyResult(result, allOrigins);
+
+ finishTest();
+}
diff --git a/dom/quota/test/unit/test_unknownFiles.js b/dom/quota/test/unit/test_unknownFiles.js
index 8eef05b83024..e14af9695cdf 100644
--- a/dom/quota/test/unit/test_unknownFiles.js
+++ b/dom/quota/test/unit/test_unknownFiles.js
@@ -131,7 +131,7 @@ function* testSteps()
info("Getting usage");
- request = getUsage(continueToNextStepSync);
+ request = getCurrentUsage(continueToNextStepSync);
yield undefined;
ok(request.resultCode == NS_ERROR_UNEXPECTED, "Get usage failed");
@@ -140,7 +140,7 @@ function* testSteps()
info("Getting usage");
- request = getUsage(continueToNextStepSync);
+ request = getCurrentUsage(continueToNextStepSync);
yield undefined;
ok(request.resultCode == NS_OK, "Get usage succeeded");
@@ -156,7 +156,7 @@ function* testSteps()
info("Getting usage");
- request = getUsage(continueToNextStepSync);
+ request = getCurrentUsage(continueToNextStepSync);
yield undefined;
ok(request.resultCode == NS_OK, "Get usage succeeded");
diff --git a/dom/quota/test/unit/xpcshell.ini b/dom/quota/test/unit/xpcshell.ini
index 1ad1b8ff0edb..fc825a035c30 100644
--- a/dom/quota/test/unit/xpcshell.ini
+++ b/dom/quota/test/unit/xpcshell.ini
@@ -7,6 +7,7 @@ head = head.js
support-files =
basics_profile.zip
defaultStorageUpgrade_profile.zip
+ getUsage_profile.zip
idbSubdirUpgrade1_profile.zip
idbSubdirUpgrade2_profile.zip
morgueCleanup_profile.zip
@@ -18,6 +19,7 @@ support-files =
[test_basics.js]
[test_defaultStorageUpgrade.js]
+[test_getUsage.js]
[test_idbSubdirUpgrade.js]
[test_morgueCleanup.js]
[test_obsoleteOriginAttributesUpgrade.js]
diff --git a/dom/security/nsCSPService.cpp b/dom/security/nsCSPService.cpp
index b5bb2109f28e..3aa3e0ed0e38 100644
--- a/dom/security/nsCSPService.cpp
+++ b/dom/security/nsCSPService.cpp
@@ -20,7 +20,6 @@
#include "nsIScriptError.h"
#include "nsContentUtils.h"
#include "nsContentPolicyUtils.h"
-#include "nsPrincipal.h"
using namespace mozilla;
diff --git a/dom/security/test/csp/file_upgrade_insecure.html b/dom/security/test/csp/file_upgrade_insecure.html
index 0daaa853ebb2..e3243c1bbe9c 100644
--- a/dom/security/test/csp/file_upgrade_insecure.html
+++ b/dom/security/test/csp/file_upgrade_insecure.html
@@ -57,6 +57,7 @@
else {
window.parent.postMessage({result: "websocket-error"}, "*");
}
+ mySocket.close();
};
mySocket.onerror = function(e) {
// debug information for Bug 1316305
diff --git a/dom/security/test/csp/file_upgrade_insecure_meta.html b/dom/security/test/csp/file_upgrade_insecure_meta.html
index 5f65e78ec30b..15f565a6b8a7 100644
--- a/dom/security/test/csp/file_upgrade_insecure_meta.html
+++ b/dom/security/test/csp/file_upgrade_insecure_meta.html
@@ -58,6 +58,7 @@
else {
window.parent.postMessage({result: "websocket-error"}, "*");
}
+ mySocket.close();
};
mySocket.onerror = function(e) {
window.parent.postMessage({result: "websocket-unexpected-error"}, "*");
diff --git a/dom/worklet/Worklet.cpp b/dom/worklet/Worklet.cpp
index 133ad8cf9224..77b8a9647ba6 100644
--- a/dom/worklet/Worklet.cpp
+++ b/dom/worklet/Worklet.cpp
@@ -205,9 +205,6 @@ public:
compileOptions.setFileAndLine(NS_ConvertUTF16toUTF8(mURL).get(), 0);
compileOptions.setVersion(JSVERSION_DEFAULT);
compileOptions.setIsRunOnce(true);
-
- // We only need the setNoScriptRval bit when compiling off-thread here,
- // since otherwise nsJSUtils::EvaluateString will set it up for us.
compileOptions.setNoScriptRval(true);
JSAutoCompartment comp(cx, globalObj);
diff --git a/dom/xbl/nsXBLProtoImplField.cpp b/dom/xbl/nsXBLProtoImplField.cpp
index cc4d0c7591d8..8860deec1019 100644
--- a/dom/xbl/nsXBLProtoImplField.cpp
+++ b/dom/xbl/nsXBLProtoImplField.cpp
@@ -427,14 +427,19 @@ nsXBLProtoImplField::InstallField(JS::Handle aBoundNode,
JS::CompileOptions options(cx);
options.setFileAndLine(uriSpec.get(), mLineNumber)
.setVersion(JSVERSION_LATEST);
- nsJSUtils::EvaluateOptions evalOptions(cx);
- if (!nsJSUtils::GetScopeChainForElement(cx, boundElement,
- evalOptions.scopeChain)) {
+ JS::AutoObjectVector scopeChain(cx);
+ if (!nsJSUtils::GetScopeChainForElement(cx, boundElement, scopeChain)) {
return NS_ERROR_OUT_OF_MEMORY;
}
- rv = nsJSUtils::EvaluateString(cx, nsDependentString(mFieldText,
- mFieldTextLength),
- scopeObject, options, evalOptions, &result);
+ rv = NS_OK;
+ {
+ nsJSUtils::ExecutionContext exec(cx, scopeObject);
+ exec.SetScopeChain(scopeChain);
+ exec.CompileAndExec(options, nsDependentString(mFieldText,
+ mFieldTextLength));
+ rv = exec.ExtractReturnValue(&result);
+ }
+
if (NS_FAILED(rv)) {
return rv;
}
diff --git a/dom/xslt/xslt/txExecutionState.cpp b/dom/xslt/xslt/txExecutionState.cpp
index ed57c79351dd..a32fdb0b8065 100644
--- a/dom/xslt/xslt/txExecutionState.cpp
+++ b/dom/xslt/xslt/txExecutionState.cpp
@@ -87,7 +87,10 @@ txExecutionState::~txExecutionState()
txStackIterator handlerIter(&mResultHandlerStack);
while (handlerIter.hasNext()) {
- delete (txAXMLEventHandler*)handlerIter.next();
+ txAXMLEventHandler* handler = (txAXMLEventHandler*)handlerIter.next();
+ if (handler != mObsoleteHandler) {
+ delete handler;
+ }
}
txStackIterator paramIter(&mParamStack);
@@ -159,6 +162,17 @@ txExecutionState::end(nsresult aResult)
return mOutputHandler->endDocument(aResult);
}
+void
+txExecutionState::popAndDeleteEvalContext()
+{
+ if (!mEvalContextStack.isEmpty()) {
+ auto ctx = popEvalContext();
+ if (ctx != mInitialEvalContext) {
+ delete ctx;
+ }
+ }
+}
+
void
txExecutionState::popAndDeleteEvalContextUntil(txIEvalContext* aContext)
{
diff --git a/dom/xslt/xslt/txExecutionState.h b/dom/xslt/xslt/txExecutionState.h
index 44f1918c86b0..3aa6d5a660bf 100644
--- a/dom/xslt/xslt/txExecutionState.h
+++ b/dom/xslt/xslt/txExecutionState.h
@@ -95,6 +95,8 @@ public:
nsresult pushEvalContext(txIEvalContext* aContext);
txIEvalContext* popEvalContext();
+ void popAndDeleteEvalContext();
+
/**
* Helper that deletes all entries before |aContext| and then
* pops it off the stack. The caller must delete |aContext| if
diff --git a/dom/xslt/xslt/txInstructions.cpp b/dom/xslt/xslt/txInstructions.cpp
index 38253e0cb332..f769680474f3 100644
--- a/dom/xslt/xslt/txInstructions.cpp
+++ b/dom/xslt/xslt/txInstructions.cpp
@@ -37,16 +37,7 @@ txApplyDefaultElementTemplate::execute(txExecutionState& aEs)
}
nsresult
-txApplyImportsEnd::execute(txExecutionState& aEs)
-{
- aEs.popTemplateRule();
- aEs.popParamMap();
-
- return NS_OK;
-}
-
-nsresult
-txApplyImportsStart::execute(txExecutionState& aEs)
+txApplyImports::execute(txExecutionState& aEs)
{
txExecutionState::TemplateRule* rule = aEs.getCurrentTemplateRule();
// The frame is set to null when there is no current template rule, or
@@ -68,7 +59,12 @@ txApplyImportsStart::execute(txExecutionState& aEs)
aEs.pushTemplateRule(frame, mode, rule->mParams);
- return aEs.runTemplate(templ);
+ rv = aEs.runTemplate(templ);
+
+ aEs.popTemplateRule();
+ aEs.popParamMap();
+
+ return rv;
}
txApplyTemplates::txApplyTemplates(const txExpandedName& aMode)
@@ -474,7 +470,7 @@ txLoopNodeSet::execute(txExecutionState& aEs)
txNodeSetContext* context =
static_cast(aEs.getEvalContext());
if (!context->hasNext()) {
- delete aEs.popEvalContext();
+ aEs.popAndDeleteEvalContext();
return NS_OK;
}
diff --git a/dom/xslt/xslt/txInstructions.h b/dom/xslt/xslt/txInstructions.h
index 55138a600a54..d363400e868c 100644
--- a/dom/xslt/xslt/txInstructions.h
+++ b/dom/xslt/xslt/txInstructions.h
@@ -47,13 +47,7 @@ public:
TX_DECL_TXINSTRUCTION
};
-class txApplyImportsEnd : public txInstruction
-{
-public:
- TX_DECL_TXINSTRUCTION
-};
-
-class txApplyImportsStart : public txInstruction
+class txApplyImports : public txInstruction
{
public:
TX_DECL_TXINSTRUCTION
diff --git a/dom/xslt/xslt/txStylesheetCompileHandlers.cpp b/dom/xslt/xslt/txStylesheetCompileHandlers.cpp
index f447df7cfc46..4d451e3c303f 100644
--- a/dom/xslt/xslt/txStylesheetCompileHandlers.cpp
+++ b/dom/xslt/xslt/txStylesheetCompileHandlers.cpp
@@ -1312,8 +1312,7 @@ txFnText(const nsAString& aStr, txStylesheetCompilerState& aState)
/*
xsl:apply-imports
- txApplyImportsStart
- txApplyImportsEnd
+ txApplyImports
*/
static nsresult
txFnStartApplyImports(int32_t aNamespaceID,
@@ -1325,11 +1324,7 @@ txFnStartApplyImports(int32_t aNamespaceID,
{
nsresult rv = NS_OK;
- nsAutoPtr instr(new txApplyImportsStart);
- rv = aState.addInstruction(Move(instr));
- NS_ENSURE_SUCCESS(rv, rv);
-
- instr = new txApplyImportsEnd;
+ nsAutoPtr instr(new txApplyImports);
rv = aState.addInstruction(Move(instr));
NS_ENSURE_SUCCESS(rv, rv);
diff --git a/extensions/gio/nsGIOProtocolHandler.cpp b/extensions/gio/nsGIOProtocolHandler.cpp
index 793f80267014..eae6e1da0fe5 100644
--- a/extensions/gio/nsGIOProtocolHandler.cpp
+++ b/extensions/gio/nsGIOProtocolHandler.cpp
@@ -24,7 +24,7 @@
#include "nsIChannel.h"
#include "nsIInputStream.h"
#include "nsIProtocolHandler.h"
-#include "nsNullPrincipal.h"
+#include "NullPrincipal.h"
#include "mozilla/Monitor.h"
#include "plstr.h"
#include "prtime.h"
diff --git a/gfx/2d/RecordedEvent.cpp b/gfx/2d/RecordedEvent.cpp
index 6d3688ac05f3..370ac98d1ffe 100644
--- a/gfx/2d/RecordedEvent.cpp
+++ b/gfx/2d/RecordedEvent.cpp
@@ -1299,6 +1299,10 @@ RecordedSourceSurfaceCreation::~RecordedSourceSurfaceCreation()
bool
RecordedSourceSurfaceCreation::PlayEvent(Translator *aTranslator) const
{
+ if (!mData) {
+ return false;
+ }
+
RefPtr src = aTranslator->GetReferenceDrawTarget()->
CreateSourceSurfaceFromData(mData, mSize, mSize.width * BytesPerPixel(mFormat), mFormat);
aTranslator->AddSourceSurface(mRefPtr, src);
@@ -1311,6 +1315,7 @@ RecordedSourceSurfaceCreation::RecordToStream(ostream &aStream) const
WriteElement(aStream, mRefPtr);
WriteElement(aStream, mSize);
WriteElement(aStream, mFormat);
+ MOZ_ASSERT(mData);
for (int y = 0; y < mSize.height; y++) {
aStream.write((const char*)mData + y * mStride, BytesPerPixel(mFormat) * mSize.width);
}
@@ -1322,8 +1327,12 @@ RecordedSourceSurfaceCreation::RecordedSourceSurfaceCreation(istream &aStream)
ReadElement(aStream, mRefPtr);
ReadElement(aStream, mSize);
ReadElement(aStream, mFormat);
- mData = (uint8_t*)new char[mSize.width * mSize.height * BytesPerPixel(mFormat)];
- aStream.read((char*)mData, mSize.width * mSize.height * BytesPerPixel(mFormat));
+ mData = (uint8_t*)new (fallible) char[mSize.width * mSize.height * BytesPerPixel(mFormat)];
+ if (!mData) {
+ gfxWarning() << "RecordedSourceSurfaceCreation failed to allocate data";
+ } else {
+ aStream.read((char*)mData, mSize.width * mSize.height * BytesPerPixel(mFormat));
+ }
}
void
diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp
index 6cfcf9797ff7..c502f9f0827e 100644
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -154,7 +154,7 @@ IsAccelAngleSupported(const nsCOMPtr& gfxInfo,
if (CompositorThreadHolder::IsInCompositorThread()) {
// We can only enter here with WebRender, so assert that this is a
// WebRender-enabled build.
-#ifndef MOZ_ENABLE_WEBRENDER
+#ifndef MOZ_BUILD_WEBRENDER
MOZ_ASSERT(false);
#endif
return true;
diff --git a/gfx/layers/LayersTypes.h b/gfx/layers/LayersTypes.h
index f9ac335c1c9b..adc70fefb9f3 100644
--- a/gfx/layers/LayersTypes.h
+++ b/gfx/layers/LayersTypes.h
@@ -46,7 +46,6 @@ enum class LayersBackend : int8_t {
LAYERS_NONE = 0,
LAYERS_BASIC,
LAYERS_OPENGL,
- LAYERS_D3D9,
LAYERS_D3D11,
LAYERS_CLIENT,
LAYERS_WR,
diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp
index 19683a6c82b3..03d406b5b924 100644
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -336,9 +336,7 @@ TexClientFromReadback(SharedSurface* src, CompositableForwarder* allocator,
// RB_SWAPPED doesn't work with D3D11. (bug 1051010)
// RB_SWAPPED doesn't work with Basic. (bug ???????)
- // RB_SWAPPED doesn't work with D3D9. (bug ???????)
bool layersNeedsManualSwap = layersBackend == LayersBackend::LAYERS_BASIC ||
- layersBackend == LayersBackend::LAYERS_D3D9 ||
layersBackend == LayersBackend::LAYERS_D3D11;
if (texClient->HasFlags(TextureFlags::RB_SWAPPED) &&
layersNeedsManualSwap)
diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp
index 9a57682b0b5f..08fe6c4d2b13 100644
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -826,7 +826,6 @@ ClientLayerManager::GetBackendName(nsAString& aName)
case LayersBackend::LAYERS_NONE: aName.AssignLiteral("None"); return;
case LayersBackend::LAYERS_BASIC: aName.AssignLiteral("Basic"); return;
case LayersBackend::LAYERS_OPENGL: aName.AssignLiteral("OpenGL"); return;
- case LayersBackend::LAYERS_D3D9: aName.AssignLiteral("Direct3D 9"); return;
case LayersBackend::LAYERS_D3D11: {
#ifdef XP_WIN
if (DeviceManagerDx::Get()->IsWARP()) {
diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp
index 69384ae7ebde..1d2840920d84 100644
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -61,7 +61,6 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
{
LayersBackend backend = aForwarder->GetCompositorBackendType();
if (backend != LayersBackend::LAYERS_OPENGL &&
- backend != LayersBackend::LAYERS_D3D9 &&
backend != LayersBackend::LAYERS_D3D11 &&
backend != LayersBackend::LAYERS_WR &&
backend != LayersBackend::LAYERS_BASIC) {
diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp
index b30b9405e04f..812f126319a0 100644
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1579,7 +1579,7 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel
TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint32_t* aIdNamespace)
{
-#ifndef MOZ_ENABLE_WEBRENDER
+#ifndef MOZ_BUILD_WEBRENDER
// Extra guard since this in the parent process and we don't want a malicious
// child process invoking this codepath before it's ready
MOZ_RELEASE_ASSERT(false);
@@ -1614,7 +1614,7 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel
bool
CompositorBridgeParent::DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor)
{
-#ifndef MOZ_ENABLE_WEBRENDER
+#ifndef MOZ_BUILD_WEBRENDER
// Extra guard since this in the parent process and we don't want a malicious
// child process invoking this codepath before it's ready
MOZ_RELEASE_ASSERT(false);
diff --git a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
index 3f5d968589aa..9369d7317acf 100644
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
@@ -203,7 +203,7 @@ CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::Pipeli
TextureFactoryIdentifier* aTextureFactoryIdentifier,
uint32_t *aIdNamespace)
{
-#ifndef MOZ_ENABLE_WEBRENDER
+#ifndef MOZ_BUILD_WEBRENDER
// Extra guard since this in the parent process and we don't want a malicious
// child process invoking this codepath before it's ready
MOZ_RELEASE_ASSERT(false);
@@ -238,7 +238,7 @@ CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::Pipeli
bool
CrossProcessCompositorBridgeParent::DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor)
{
-#ifndef MOZ_ENABLE_WEBRENDER
+#ifndef MOZ_BUILD_WEBRENDER
// Extra guard since this in the parent process and we don't want a malicious
// child process invoking this codepath before it's ready
MOZ_RELEASE_ASSERT(false);
diff --git a/gfx/skia/skia/src/core/SkScan_Path.cpp b/gfx/skia/skia/src/core/SkScan_Path.cpp
index a3116bb92922..5b80492cfa28 100644
--- a/gfx/skia/skia/src/core/SkScan_Path.cpp
+++ b/gfx/skia/skia/src/core/SkScan_Path.cpp
@@ -592,29 +592,35 @@ static bool clip_to_limit(const SkRegion& orig, SkRegion* reduced) {
}
/**
- * Variant of SkScalarRoundToInt, identical to SkDScalarRoundToInt except when the input fraction
- * is 0.5. In this case only, round the value down. This is used to round the top and left
- * of a rectangle, and corresponds to the way the scan converter treats the top and left edges.
+ * Variants of SkScalarRoundToInt, identical to SkDScalarRoundToInt except when the input fraction
+ * is 0.5. When SK_RASTERIZE_EVEN_ROUNDING is enabled, we must bias the result before rounding to
+ * account for potential FDot6 rounding edge-cases.
+ */
+#ifdef SK_RASTERIZE_EVEN_ROUNDING
+static const double kRoundBias = 0.5 / SK_FDot6One;
+#else
+static const double kRoundBias = 0.0;
+#endif
+
+/**
+ * Round the value down. This is used to round the top and left of a rectangle,
+ * and corresponds to the way the scan converter treats the top and left edges.
*/
static inline int round_down_to_int(SkScalar x) {
double xx = x;
- xx += 0.5;
- double floorXX = floor(xx);
- return (int)floorXX - (xx == floorXX);
+ xx -= 0.5 + kRoundBias;
+ return (int)ceil(xx);
}
-#ifdef SK_RASTERIZE_EVEN_ROUNDING
/**
- * Variant of SkDScalarRoundToInt that allows offseting the input by a small fraction
- * while trying to preserve intermediate double-precision (rather than directly adding
- * the bias to the input at lower single-precision).
+ * Round the value up. This is used to round the bottom and right of a rectangle,
+ * and corresponds to the way the scan converter treats the bottom and right edges.
*/
-static inline int round_biased_to_int(SkScalar x, SkScalar bias) {
+static inline int round_up_to_int(SkScalar x) {
double xx = x;
- xx += 0.5 + bias;
+ xx += 0.5 + kRoundBias;
return (int)floor(xx);
}
-#endif
/**
* Variant of SkRect::round() that explicitly performs the rounding step (i.e. floor(x + 0.5))
@@ -635,26 +641,21 @@ static inline int round_biased_to_int(SkScalar x, SkScalar bias) {
* SkASSERT(0 == iright); // <--- succeeds
*
*
- * If using SK_RASTERIZE_EVEN_ROUNDING, we need to ensure that bottom and right account for
- * edges bounded by this rect being rounded to FDot6 format before being later rounded to an
- * integer. For example, a value like 0.499 can be below 0.5, but round to 0.5 as FDot6, which
- * would finally round to the integer 1, instead of just rounding to 0.
+ * If using SK_RASTERIZE_EVEN_ROUNDING, we need to ensure we account for edges bounded by this
+ * rect being rounded to FDot6 format before being later rounded to an integer. For example, a
+ * value like 0.499 can be below 0.5, but round to 0.5 as FDot6, which would finally round to
+ * the integer 1, instead of just rounding to 0.
*
* To handle this, a small bias of half an FDot6 increment is added before actually rounding to
* an integer value. This simulates the rounding of SkScalarRoundToFDot6 without incurring the
* range loss of converting to FDot6 format first, preserving the integer range for the SkIRect.
- * Thus, bottom and right are rounded in this manner (biased up), ensuring the rect is large enough.
- * Top and left can round as normal since they will round (biased down) to values less or equal
- * to the desired rect origin.
+ * Thus, bottom and right are rounded in this manner (biased up), ensuring the rect is large
+ * enough.
*/
static void round_asymmetric_to_int(const SkRect& src, SkIRect* dst) {
SkASSERT(dst);
dst->set(round_down_to_int(src.fLeft), round_down_to_int(src.fTop),
-#ifdef SK_RASTERIZE_EVEN_ROUNDING
- round_biased_to_int(src.fRight, 0.5f / SK_FDot6One), round_biased_to_int(src.fBottom, 0.5f / SK_FDot6One));
-#else
- SkDScalarRoundToInt(src.fRight), SkDScalarRoundToInt(src.fBottom));
-#endif
+ round_up_to_int(src.fRight), round_up_to_int(src.fBottom));
}
void SkScan::FillPath(const SkPath& path, const SkRegion& origClip,
diff --git a/gfx/tests/gtest/TestCompositor.cpp b/gfx/tests/gtest/TestCompositor.cpp
index 816c0d011aee..0a8498bb6988 100644
--- a/gfx/tests/gtest/TestCompositor.cpp
+++ b/gfx/tests/gtest/TestCompositor.cpp
@@ -63,9 +63,6 @@ static already_AddRefed CreateTestCompositor(LayersBackend backend,
} else if (backend == LayersBackend::LAYERS_D3D11) {
//compositor = new CompositorD3D11();
MOZ_CRASH(); // No support yet
- } else if (backend == LayersBackend::LAYERS_D3D9) {
- //compositor = new CompositorD3D9(this, mWidget);
- MOZ_CRASH(); // No support yet
#endif
}
nsCString failureReason;
diff --git a/gfx/thebes/gfxFontconfigFonts.cpp b/gfx/thebes/gfxFontconfigFonts.cpp
deleted file mode 100644
index bbcbbabf9159..000000000000
--- a/gfx/thebes/gfxFontconfigFonts.cpp
+++ /dev/null
@@ -1,2262 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * 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 "prlink.h"
-#include "gfxTypes.h"
-
-#include "nsTArray.h"
-
-#include "gfxContext.h"
-#ifdef MOZ_WIDGET_GTK
-#include "gfxPlatformGtk.h"
-#endif
-#include "gfxFontconfigFonts.h"
-#include "gfxFT2FontBase.h"
-#include "gfxFT2Utils.h"
-#include "harfbuzz/hb.h"
-#include "harfbuzz/hb-glib.h"
-#include "harfbuzz/hb-ot.h"
-#include "nsUnicodeProperties.h"
-#include "nsUnicodeScriptCodes.h"
-#include "gfxFontconfigUtils.h"
-#include "gfxUserFontSet.h"
-#include "gfxFontConstants.h"
-#include "nsGkAtoms.h"
-#include "nsILanguageAtomService.h"
-#include "nsServiceManagerUtils.h"
-
-#include
-#include
-#include "mozilla/gfx/HelpersCairo.h"
-
-#include
-#include
-
-#include FT_TRUETYPE_TABLES_H
-
-#ifdef MOZ_WIDGET_GTK
-#include
-#endif
-
-#include
-
-using namespace mozilla;
-using namespace mozilla::unicode;
-
-#define PRINTING_FC_PROPERTY "gfx.printing"
-
-static PangoLanguage *GuessPangoLanguage(nsIAtom *aLanguage);
-
-static cairo_scaled_font_t *
-CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace);
-
-static FT_Library gFTLibrary;
-
-// FC_FAMILYLANG and FC_FULLNAME were introduced in fontconfig-2.2.97
-// and so fontconfig-2.3.0 (2005).
-#ifndef FC_FAMILYLANG
-#define FC_FAMILYLANG "familylang"
-#endif
-#ifndef FC_FULLNAME
-#define FC_FULLNAME "fullname"
-#endif
-
-static PRFuncPtr
-FindFunctionSymbol(const char *name)
-{
- PRLibrary *lib = nullptr;
- PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(name, &lib);
- if (lib) {
- PR_UnloadLibrary(lib);
- }
-
- return result;
-}
-
-static bool HasChar(FcPattern *aFont, FcChar32 wc)
-{
- FcCharSet *charset = nullptr;
- FcPatternGetCharSet(aFont, FC_CHARSET, 0, &charset);
-
- return charset && FcCharSetHasChar(charset, wc);
-}
-
-/**
- * gfxFcFontEntry:
- *
- * An abstract base class of for gfxFontEntry implementations used by
- * gfxFcFont and gfxUserFontSet.
- */
-
-class gfxFcFontEntry : public gfxFontEntry {
-public:
- // For all FontEntrys attached to gfxFcFonts, there will be only one
- // pattern in this array. This is always a font pattern, not a fully
- // resolved pattern. gfxFcFont only uses this to construct a PangoFont.
- //
- // FontEntrys for src:local() fonts in gfxUserFontSet may return more than
- // one pattern. (See comment in gfxUserFcFontEntry.)
- const nsTArray< nsCountedRef >& GetPatterns()
- {
- return mPatterns;
- }
-
- static gfxFcFontEntry *LookupFontEntry(cairo_font_face_t *aFace)
- {
- return static_cast
- (cairo_font_face_get_user_data(aFace, &sFontEntryKey));
- }
-
- // override the gfxFontEntry impl to read the name from fontconfig
- // instead of trying to get the 'name' table, as we don't implement
- // GetFontTable() here
- virtual nsString RealFaceName();
-
- // This is needed to make gfxFontEntry::HasCharacter(aCh) work.
- virtual bool TestCharacterMap(uint32_t aCh)
- {
- for (uint32_t i = 0; i < mPatterns.Length(); ++i) {
- if (HasChar(mPatterns[i], aCh)) {
- return true;
- }
- }
- return false;
- }
-
-protected:
- explicit gfxFcFontEntry(const nsAString& aName)
- : gfxFontEntry(aName)
- {
- }
-
- // One pattern is the common case and some subclasses rely on successful
- // addition of the first element to the array.
- AutoTArray,1> mPatterns;
-
- static cairo_user_data_key_t sFontEntryKey;
-};
-
-cairo_user_data_key_t gfxFcFontEntry::sFontEntryKey;
-
-nsString
-gfxFcFontEntry::RealFaceName()
-{
- FcChar8 *name;
- if (!mPatterns.IsEmpty()) {
- if (FcPatternGetString(mPatterns[0],
- FC_FULLNAME, 0, &name) == FcResultMatch) {
- return NS_ConvertUTF8toUTF16((const char*)name);
- }
- if (FcPatternGetString(mPatterns[0],
- FC_FAMILY, 0, &name) == FcResultMatch) {
- NS_ConvertUTF8toUTF16 result((const char*)name);
- if (FcPatternGetString(mPatterns[0],
- FC_STYLE, 0, &name) == FcResultMatch) {
- result.Append(' ');
- AppendUTF8toUTF16((const char*)name, result);
- }
- return result;
- }
- }
- // fall back to gfxFontEntry implementation (only works for sfnt fonts)
- return gfxFontEntry::RealFaceName();
-}
-
-/**
- * gfxSystemFcFontEntry:
- *
- * An implementation of gfxFcFontEntry used by gfxFcFonts for system fonts,
- * including those from regular family-name based font selection as well as
- * those from src:local().
- *
- * All gfxFcFonts using the same cairo_font_face_t share the same FontEntry.
- */
-
-class gfxSystemFcFontEntry : public gfxFcFontEntry {
-public:
- // For memory efficiency, aFontPattern should be a font pattern,
- // not a fully resolved pattern.
- gfxSystemFcFontEntry(cairo_font_face_t *aFontFace,
- FcPattern *aFontPattern,
- const nsAString& aName)
- : gfxFcFontEntry(aName), mFontFace(aFontFace),
- mFTFace(nullptr), mFTFaceInitialized(false)
- {
- cairo_font_face_reference(mFontFace);
- cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, this, nullptr);
-
- // mPatterns is an AutoTArray with 1 space always available, so the
- // AppendElement always succeeds.
- // FIXME: Make this infallible after bug 968520 is done.
- MOZ_ALWAYS_TRUE(mPatterns.AppendElement(fallible));
- mPatterns[0] = aFontPattern;
-
- FcChar8 *name;
- if (FcPatternGetString(aFontPattern,
- FC_FAMILY, 0, &name) == FcResultMatch) {
- mFamilyName = NS_ConvertUTF8toUTF16((const char*)name);
- }
- }
-
- ~gfxSystemFcFontEntry()
- {
- cairo_font_face_set_user_data(mFontFace,
- &sFontEntryKey,
- nullptr,
- nullptr);
- cairo_font_face_destroy(mFontFace);
- }
-
- virtual void ForgetHBFace() override;
- virtual void ReleaseGrFace(gr_face* aFace) override;
-
-protected:
- virtual nsresult
- CopyFontTable(uint32_t aTableTag, nsTArray& aBuffer) override;
-
- void MaybeReleaseFTFace();
-
-private:
- cairo_font_face_t *mFontFace;
- FT_Face mFTFace;
- bool mFTFaceInitialized;
-};
-
-nsresult
-gfxSystemFcFontEntry::CopyFontTable(uint32_t aTableTag,
- nsTArray& aBuffer)
-{
- if (!mFTFaceInitialized) {
- mFTFaceInitialized = true;
- FcChar8 *filename;
- if (FcPatternGetString(mPatterns[0], FC_FILE, 0, &filename) != FcResultMatch) {
- return NS_ERROR_FAILURE;
- }
- int index;
- if (FcPatternGetInteger(mPatterns[0], FC_INDEX, 0, &index) != FcResultMatch) {
- index = 0; // default to 0 if not found in pattern
- }
- if (FT_New_Face(gfxPangoFontGroup::GetFTLibrary(),
- (const char*)filename, index, &mFTFace) != 0) {
- return NS_ERROR_FAILURE;
- }
- }
-
- if (!mFTFace) {
- return NS_ERROR_NOT_AVAILABLE;
- }
-
- FT_ULong length = 0;
- if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, nullptr, &length) != 0) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- if (!aBuffer.SetLength(length, fallible)) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, aBuffer.Elements(), &length) != 0) {
- aBuffer.Clear();
- return NS_ERROR_FAILURE;
- }
-
- return NS_OK;
-}
-
-void
-gfxSystemFcFontEntry::MaybeReleaseFTFace()
-{
- // don't release if either HB or Gr face still exists
- if (mHBFace || mGrFace) {
- return;
- }
- if (mFTFace) {
- FT_Done_Face(mFTFace);
- mFTFace = nullptr;
- }
- mFTFaceInitialized = false;
-}
-
-void
-gfxSystemFcFontEntry::ForgetHBFace()
-{
- gfxFontEntry::ForgetHBFace();
- MaybeReleaseFTFace();
-}
-
-void
-gfxSystemFcFontEntry::ReleaseGrFace(gr_face* aFace)
-{
- gfxFontEntry::ReleaseGrFace(aFace);
- MaybeReleaseFTFace();
-}
-
-// A namespace for @font-face family names in FcPatterns so that fontconfig
-// aliases do not pick up families from @font-face rules and so that
-// fontconfig rules can distinguish between web fonts and platform fonts.
-// http://lists.freedesktop.org/archives/fontconfig/2008-November/003037.html
-#define FONT_FACE_FAMILY_PREFIX "@font-face:"
-
-/**
- * gfxUserFcFontEntry:
- *
- * An abstract class for objects in a gfxUserFontSet that can provide
- * FcPattern* handles to fonts.
- *
- * Separate implementations of this class support local fonts from src:local()
- * and web fonts from src:url().
- */
-
-// There is a one-to-one correspondence between gfxUserFcFontEntry objects and
-// @font-face rules, but sometimes a one-to-many correspondence between font
-// entries and font patterns.
-//
-// http://www.w3.org/TR/2002/WD-css3-webfonts-20020802#font-descriptions
-// provided a font-size descriptor to specify the sizes supported by the face,
-// but the "Editor's Draft 27 June 2008"
-// http://dev.w3.org/csswg/css3-fonts/#font-resources does not provide such a
-// descriptor, and Mozilla does not recognize such a descriptor.
-//
-// Font face names used in src:local() also do not usually specify a size.
-//
-// PCF format fonts have each size in a different file, and each of these
-// files is referenced by its own pattern, but really these are each
-// different sizes of one face with one name.
-//
-// Multiple patterns in an entry also effectively deals with a set of
-// PostScript Type 1 font files that all have the same face name but are in
-// several files because of the limit on the number of glyphs in a Type 1 font
-// file. (e.g. Computer Modern.)
-
-class gfxUserFcFontEntry : public gfxFcFontEntry {
-protected:
- explicit gfxUserFcFontEntry(const nsAString& aFontName,
- uint16_t aWeight,
- int16_t aStretch,
- uint8_t aStyle)
- : gfxFcFontEntry(aFontName)
- {
- mStyle = aStyle;
- mWeight = aWeight;
- mStretch = aStretch;
- }
-
- // Helper function to change a pattern so that it matches the CSS style
- // descriptors and so gets properly sorted in font selection. This also
- // avoids synthetic style effects being added by the renderer when the
- // style of the font itself does not match the descriptor provided by the
- // author.
- void AdjustPatternToCSS(FcPattern *aPattern);
-};
-
-void
-gfxUserFcFontEntry::AdjustPatternToCSS(FcPattern *aPattern)
-{
- int fontWeight = -1;
- FcPatternGetInteger(aPattern, FC_WEIGHT, 0, &fontWeight);
- int cssWeight = gfxFontconfigUtils::FcWeightForBaseWeight(mWeight / 100);
- if (cssWeight != fontWeight) {
- FcPatternDel(aPattern, FC_WEIGHT);
- FcPatternAddInteger(aPattern, FC_WEIGHT, cssWeight);
- }
-
- int fontSlant;
- FcResult res = FcPatternGetInteger(aPattern, FC_SLANT, 0, &fontSlant);
- // gfxFontEntry doesn't understand the difference between oblique
- // and italic.
- if (res != FcResultMatch ||
- IsItalic() != (fontSlant != FC_SLANT_ROMAN)) {
- FcPatternDel(aPattern, FC_SLANT);
- FcPatternAddInteger(aPattern, FC_SLANT,
- IsItalic() ? FC_SLANT_OBLIQUE : FC_SLANT_ROMAN);
- }
-
- int fontWidth = -1;
- FcPatternGetInteger(aPattern, FC_WIDTH, 0, &fontWidth);
- int cssWidth = gfxFontconfigUtils::FcWidthForThebesStretch(mStretch);
- if (cssWidth != fontWidth) {
- FcPatternDel(aPattern, FC_WIDTH);
- FcPatternAddInteger(aPattern, FC_WIDTH, cssWidth);
- }
-
- // Ensure that there is a fullname property (if there is a family
- // property) so that fontconfig rules can identify the real name of the
- // font, because the family property will be replaced.
- FcChar8 *unused;
- if (FcPatternGetString(aPattern,
- FC_FULLNAME, 0, &unused) == FcResultNoMatch) {
- nsAutoCString fullname;
- if (gfxFontconfigUtils::GetFullnameFromFamilyAndStyle(aPattern,
- &fullname)) {
- FcPatternAddString(aPattern, FC_FULLNAME,
- gfxFontconfigUtils::ToFcChar8(fullname));
- }
- }
-
- nsAutoCString family;
- family.Append(FONT_FACE_FAMILY_PREFIX);
- AppendUTF16toUTF8(Name(), family);
-
- FcPatternDel(aPattern, FC_FAMILY);
- FcPatternDel(aPattern, FC_FAMILYLANG);
- FcPatternAddString(aPattern, FC_FAMILY,
- gfxFontconfigUtils::ToFcChar8(family));
-}
-
-/**
- * gfxLocalFcFontEntry:
- *
- * An implementation of gfxUserFcFontEntry for local fonts from src:local().
- *
- * This class is used only in gfxUserFontSet and for providing FcPattern*
- * handles to system fonts for font selection. gfxFcFonts created from these
- * patterns will use gfxSystemFcFontEntrys, which may be shared with
- * gfxFcFonts from regular family-name based font selection.
- */
-
-class gfxLocalFcFontEntry : public gfxUserFcFontEntry {
-public:
- gfxLocalFcFontEntry(const nsAString& aFontName,
- uint16_t aWeight,
- int16_t aStretch,
- uint8_t aStyle,
- const nsTArray< nsCountedRef >& aPatterns)
- : gfxUserFcFontEntry(aFontName, aWeight, aStretch, aStyle)
- {
- if (!mPatterns.SetCapacity(aPatterns.Length(), fallible))
- return; // OOM
-
- for (uint32_t i = 0; i < aPatterns.Length(); ++i) {
- FcPattern *pattern = FcPatternDuplicate(aPatterns.ElementAt(i));
- if (!pattern)
- return; // OOM
-
- AdjustPatternToCSS(pattern);
-
- // FIXME: Make this infallible after bug 968520 is done.
- MOZ_ALWAYS_TRUE(mPatterns.AppendElement(fallible));
- mPatterns[i].own(pattern);
- }
- mIsLocalUserFont = true;
- }
-};
-
-/**
- * gfxDownloadedFcFontEntry:
- *
- * An implementation of gfxFcFontEntry for web fonts from src:url().
- *
- * When a cairo_font_face_t is created for these fonts, the cairo_font_face_t
- * keeps a reference to the FontEntry to keep the font data alive.
- */
-
-class gfxDownloadedFcFontEntry : public gfxUserFcFontEntry {
-public:
- // This takes ownership of the face and its underlying data
- gfxDownloadedFcFontEntry(const nsAString& aFontName,
- uint16_t aWeight,
- int16_t aStretch,
- uint8_t aStyle,
- const uint8_t *aData, FT_Face aFace)
- : gfxUserFcFontEntry(aFontName, aWeight, aStretch, aStyle),
- mFontData(aData), mFace(aFace)
- {
- NS_PRECONDITION(aFace != nullptr, "aFace is NULL!");
- mIsDataUserFont = true;
- InitPattern();
- }
-
- virtual ~gfxDownloadedFcFontEntry();
-
- // Returns true on success
- bool SetCairoFace(cairo_font_face_t *aFace);
-
- virtual hb_blob_t* GetFontTable(uint32_t aTableTag) override;
-
-protected:
- void InitPattern();
-
- // mFontData holds the data used to instantiate the FT_Face;
- // this has to persist until we are finished with the face,
- // then be released with free().
- const uint8_t* mFontData;
-
- FT_Face mFace;
-};
-
-// A property for recording gfxDownloadedFcFontEntrys on FcPatterns.
-static const char *kFontEntryFcProp = "-moz-font-entry";
-
-static FcBool AddDownloadedFontEntry(FcPattern *aPattern,
- gfxDownloadedFcFontEntry *aFontEntry)
-{
- FcValue value;
- value.type = FcTypeFTFace; // void* field of union
- value.u.f = aFontEntry;
-
- return FcPatternAdd(aPattern, kFontEntryFcProp, value, FcFalse);
-}
-
-static FcBool DelDownloadedFontEntry(FcPattern *aPattern)
-{
- return FcPatternDel(aPattern, kFontEntryFcProp);
-}
-
-static gfxDownloadedFcFontEntry *GetDownloadedFontEntry(FcPattern *aPattern)
-{
- FcValue value;
- if (FcPatternGet(aPattern, kFontEntryFcProp, 0, &value) != FcResultMatch)
- return nullptr;
-
- if (value.type != FcTypeFTFace) {
- NS_NOTREACHED("Wrong type for -moz-font-entry font property");
- return nullptr;
- }
-
- return static_cast(value.u.f);
-}
-
-gfxDownloadedFcFontEntry::~gfxDownloadedFcFontEntry()
-{
- if (mPatterns.Length() != 0) {
- // Remove back reference to this font entry and the face in case
- // anyone holds a reference to the pattern.
- NS_ASSERTION(mPatterns.Length() == 1,
- "More than one pattern in gfxDownloadedFcFontEntry!");
- DelDownloadedFontEntry(mPatterns[0]);
- FcPatternDel(mPatterns[0], FC_FT_FACE);
- }
- FT_Done_Face(mFace);
- free((void*)mFontData);
-}
-
-typedef FcPattern* (*QueryFaceFunction)(const FT_Face face,
- const FcChar8 *file, int id,
- FcBlanks *blanks);
-
-void
-gfxDownloadedFcFontEntry::InitPattern()
-{
- static QueryFaceFunction sQueryFacePtr =
- reinterpret_cast
- (FindFunctionSymbol("FcFreeTypeQueryFace"));
- FcPattern *pattern;
-
- // FcFreeTypeQueryFace is the same function used to construct patterns for
- // system fonts and so is the preferred function to use for this purpose.
- // This will set up the langset property, which helps with sorting, and
- // the foundry, fullname, and fontversion properties, which properly
- // identify the font to fontconfig rules. However, FcFreeTypeQueryFace is
- // available only from fontconfig-2.4.2 (December 2006). (CentOS 5.0 has
- // fontconfig-2.4.1.)
- if (sQueryFacePtr) {
- // The "file" argument cannot be nullptr (in fontconfig-2.6.0 at
- // least). The dummy file passed here is removed below.
- //
- // When fontconfig scans the system fonts, FcConfigGetBlanks(nullptr)
- // is passed as the "blanks" argument, which provides that unexpectedly
- // blank glyphs are elided. Here, however, we pass nullptr for
- // "blanks", effectively assuming that, if the font has a blank glyph,
- // then the author intends any associated character to be rendered
- // blank.
- pattern =
- (*sQueryFacePtr)(mFace,
- gfxFontconfigUtils::ToFcChar8(""),
- 0,
- nullptr);
- if (!pattern)
- // Either OOM, or fontconfig chose to skip this font because it
- // has "no encoded characters", which I think means "BDF and PCF
- // fonts which are not in Unicode (or the effectively equivalent
- // ISO Latin-1) encoding".
- return;
-
- // These properties don't make sense for this face without a file.
- FcPatternDel(pattern, FC_FILE);
- FcPatternDel(pattern, FC_INDEX);
-
- } else {
- // Do the minimum necessary to construct a pattern for sorting.
-
- // FC_CHARSET is vital to determine which characters are supported.
- nsAutoRef charset(FcFreeTypeCharSet(mFace, nullptr));
- // If there are no characters then assume we don't know how to read
- // this font.
- if (!charset || FcCharSetCount(charset) == 0)
- return;
-
- pattern = FcPatternCreate();
- FcPatternAddCharSet(pattern, FC_CHARSET, charset);
-
- // FC_PIXEL_SIZE can be important for font selection of fixed-size
- // fonts.
- if (!(mFace->face_flags & FT_FACE_FLAG_SCALABLE)) {
- for (FT_Int i = 0; i < mFace->num_fixed_sizes; ++i) {
-#if HAVE_FT_BITMAP_SIZE_Y_PPEM
- double size = FLOAT_FROM_26_6(mFace->available_sizes[i].y_ppem);
-#else
- double size = mFace->available_sizes[i].height;
-#endif
- FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size);
- }
-
- // Not sure whether this is important;
- // imitating FcFreeTypeQueryFace:
- FcPatternAddBool (pattern, FC_ANTIALIAS, FcFalse);
- }
-
- // Setting up the FC_LANGSET property is very difficult with the APIs
- // available prior to FcFreeTypeQueryFace. Having no FC_LANGSET
- // property seems better than having a property with an empty LangSet.
- // With no FC_LANGSET property, fontconfig sort functions will
- // consider this face to have the same priority as (otherwise equal)
- // faces that have support for the primary requested language, but
- // will not consider any language to have been satisfied (and so will
- // continue to look for a face with language support in fallback
- // fonts).
- }
-
- AdjustPatternToCSS(pattern);
-
- FcPatternAddFTFace(pattern, FC_FT_FACE, mFace);
- AddDownloadedFontEntry(pattern, this);
-
- // There is never more than one pattern
- // FIXME: Make this infallible after bug 968520 is done.
- MOZ_ALWAYS_TRUE(mPatterns.AppendElement(fallible));
- mPatterns[0].own(pattern);
-}
-
-static void ReleaseDownloadedFontEntry(void *data)
-{
- gfxDownloadedFcFontEntry *downloadedFontEntry =
- static_cast(data);
- NS_RELEASE(downloadedFontEntry);
-}
-
-bool gfxDownloadedFcFontEntry::SetCairoFace(cairo_font_face_t *aFace)
-{
- if (CAIRO_STATUS_SUCCESS !=
- cairo_font_face_set_user_data(aFace, &sFontEntryKey, this,
- ReleaseDownloadedFontEntry))
- return false;
-
- // Hold a reference to this font entry to keep the font face data.
- NS_ADDREF(this);
- return true;
-}
-
-hb_blob_t *
-gfxDownloadedFcFontEntry::GetFontTable(uint32_t aTableTag)
-{
- // The entry already owns the (sanitized) sfnt data in mFontData,
- // so we can just return a blob that "wraps" the appropriate chunk of it.
- // The blob should not attempt to free its data, as the entire sfnt data
- // will be freed when the font entry is deleted.
- return gfxFontUtils::GetTableFromFontData(mFontData, aTableTag);
-}
-
-/*
- * gfxFcFont
- *
- * This is a gfxFont implementation using a CAIRO_FONT_TYPE_FT
- * cairo_scaled_font created from an FcPattern.
- */
-
-class gfxFcFont : public gfxFontconfigFontBase {
-public:
- virtual ~gfxFcFont();
- static already_AddRefed
- GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern,
- const gfxFontStyle *aFontStyle);
-
- // return a cloned font resized and offset to simulate sub/superscript glyphs
- virtual already_AddRefed
- GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel) override;
-
-protected:
- virtual already_AddRefed MakeScaledFont(gfxFontStyle *aFontStyle,
- gfxFloat aFontScale);
- virtual already_AddRefed GetSmallCapsFont() override;
-
-private:
- gfxFcFont(cairo_scaled_font_t *aCairoFont,
- FcPattern *aPattern,
- gfxFcFontEntry *aFontEntry,
- const gfxFontStyle *aFontStyle);
-
- // key for locating a gfxFcFont corresponding to a cairo_scaled_font
- static cairo_user_data_key_t sGfxFontKey;
-};
-
-/**
- * gfxFcFontSet:
- *
- * Translation from a desired FcPattern to a sorted set of font references
- * (fontconfig cache data) and (when needed) fonts.
- */
-
-class gfxFcFontSet final {
-public:
- NS_INLINE_DECL_REFCOUNTING(gfxFcFontSet)
-
- explicit gfxFcFontSet(FcPattern *aPattern,
- gfxUserFontSet *aUserFontSet)
- : mSortPattern(aPattern), mUserFontSet(aUserFontSet),
- mFcFontsTrimmed(0),
- mHaveFallbackFonts(false)
- {
- bool waitForUserFont;
- mFcFontSet = SortPreferredFonts(waitForUserFont);
- mWaitingForUserFont = waitForUserFont;
- }
-
- // A reference is held by the FontSet.
- // The caller may add a ref to keep the font alive longer than the FontSet.
- gfxFcFont *GetFontAt(uint32_t i, const gfxFontStyle *aFontStyle)
- {
- if (i >= mFonts.Length() || !mFonts[i].mFont) {
- // GetFontPatternAt sets up mFonts
- FcPattern *fontPattern = GetFontPatternAt(i);
- if (!fontPattern)
- return nullptr;
-
- mFonts[i].mFont =
- gfxFcFont::GetOrMakeFont(mSortPattern, fontPattern,
- aFontStyle);
- }
- return mFonts[i].mFont;
- }
-
- FcPattern *GetFontPatternAt(uint32_t i);
-
- bool WaitingForUserFont() const {
- return mWaitingForUserFont;
- }
-
-private:
- // Private destructor, to discourage deletion outside of Release():
- ~gfxFcFontSet()
- {
- }
-
- nsReturnRef SortPreferredFonts(bool& aWaitForUserFont);
- nsReturnRef SortFallbackFonts();
-
- struct FontEntry {
- explicit FontEntry(FcPattern *aPattern) : mPattern(aPattern) {}
- nsCountedRef mPattern;
- RefPtr mFont;
- };
-
- struct LangSupportEntry {
- LangSupportEntry(FcChar8 *aLang, FcLangResult aSupport) :
- mLang(aLang), mBestSupport(aSupport) {}
- FcChar8 *mLang;
- FcLangResult mBestSupport;
- };
-
-public:
- // public for nsTArray
- class LangComparator {
- public:
- bool Equals(const LangSupportEntry& a, const FcChar8 *b) const
- {
- return FcStrCmpIgnoreCase(a.mLang, b) == 0;
- }
- };
-
-private:
- // The requested pattern
- nsCountedRef mSortPattern;
- // Fonts from @font-face rules
- RefPtr mUserFontSet;
- // A (trimmed) list of font patterns and fonts that is built up as
- // required.
- nsTArray mFonts;
- // Holds a list of font patterns that will be trimmed. This is first set
- // to a list of preferred fonts. Then, if/when all the preferred fonts
- // have been trimmed and added to mFonts, this is set to a list of
- // fallback fonts.
- nsAutoRef mFcFontSet;
- // The set of characters supported by the fonts in mFonts.
- nsAutoRef mCharSet;
- // The index of the next font in mFcFontSet that has not yet been
- // considered for mFonts.
- int mFcFontsTrimmed;
- // True iff fallback fonts are either stored in mFcFontSet or have been
- // trimmed and added to mFonts (so that mFcFontSet is nullptr).
- bool mHaveFallbackFonts;
- // True iff there was a user font set with pending downloads,
- // so the set may be updated when downloads complete
- bool mWaitingForUserFont;
-};
-
-// Find the FcPattern for an @font-face font suitable for CSS family |aFamily|
-// and style |aStyle| properties.
-static const nsTArray< nsCountedRef >*
-FindFontPatterns(gfxUserFontSet *mUserFontSet,
- const nsACString &aFamily, uint8_t aStyle,
- uint16_t aWeight, int16_t aStretch,
- bool& aWaitForUserFont)
-{
- // Convert to UTF16
- NS_ConvertUTF8toUTF16 utf16Family(aFamily);
-
- // needsBold is not used here. Instead synthetic bold is enabled through
- // FcFontRenderPrepare when the weight in the requested pattern is
- // compared against the weight in the font pattern.
- bool needsBold;
-
- gfxFontStyle style;
- style.style = aStyle;
- style.weight = aWeight;
- style.stretch = aStretch;
-
- gfxUserFcFontEntry *fontEntry = nullptr;
- gfxFontFamily *family = mUserFontSet->LookupFamily(utf16Family);
- if (family) {
- gfxUserFontEntry* userFontEntry =
- mUserFontSet->FindUserFontEntryAndLoad(family, style, needsBold,
- aWaitForUserFont);
- if (userFontEntry) {
- fontEntry = static_cast
- (userFontEntry->GetPlatformFontEntry());
- }
-
- // Accept synthetic oblique for italic and oblique.
- // xxx - this isn't really ideal behavior, for docs that only use a
- // single italic face it will also pull down the normal face
- // and probably never use it
- if (!fontEntry && aStyle != NS_FONT_STYLE_NORMAL) {
- style.style = NS_FONT_STYLE_NORMAL;
- userFontEntry =
- mUserFontSet->FindUserFontEntryAndLoad(family, style,
- needsBold,
- aWaitForUserFont);
- if (userFontEntry) {
- fontEntry = static_cast
- (userFontEntry->GetPlatformFontEntry());
- }
- }
- }
-
- if (!fontEntry) {
- return nullptr;
- }
-
- return &fontEntry->GetPatterns();
-}
-
-typedef FcBool (*FcPatternRemoveFunction)(FcPattern *p, const char *object,
- int id);
-
-// FcPatternRemove is available in fontconfig-2.3.0 (2005)
-static FcBool
-moz_FcPatternRemove(FcPattern *p, const char *object, int id)
-{
- static FcPatternRemoveFunction sFcPatternRemovePtr =
- reinterpret_cast
- (FindFunctionSymbol("FcPatternRemove"));
-
- if (!sFcPatternRemovePtr)
- return FcFalse;
-
- return (*sFcPatternRemovePtr)(p, object, id);
-}
-
-// fontconfig prefers a matching family or lang to pixelsize of bitmap
-// fonts. CSS suggests a tolerance of 20% on pixelsize.
-static bool
-SizeIsAcceptable(FcPattern *aFont, double aRequestedSize)
-{
- double size;
- int v = 0;
- while (FcPatternGetDouble(aFont,
- FC_PIXEL_SIZE, v, &size) == FcResultMatch) {
- ++v;
- if (5.0 * fabs(size - aRequestedSize) < aRequestedSize)
- return true;
- }
-
- // No size means scalable
- return v == 0;
-}
-
-// Sorting only the preferred fonts first usually saves having to sort through
-// every font on the system.
-nsReturnRef
-gfxFcFontSet::SortPreferredFonts(bool &aWaitForUserFont)
-{
- aWaitForUserFont = false;
-
- gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils();
- if (!utils)
- return nsReturnRef();
-
- // The list of families in mSortPattern has values with both weak and
- // strong bindings. Values with strong bindings should be preferred.
- // Values with weak bindings are default fonts that should be considered
- // only when the font provides the best support for a requested language
- // or after other fonts have satisfied all the requested languages.
- //
- // There are no direct fontconfig APIs to get the binding type. The
- // binding only takes effect in the sort and match functions.
-
- // |requiredLangs| is a list of requested languages that have not yet been
- // satisfied. gfxFontconfigUtils only sets one FC_LANG property value,
- // but FcConfigSubstitute may add more values (e.g. prepending "en" to
- // "ja" will use western fonts to render Latin/Arabic numerals in Japanese
- // text.)
- AutoTArray requiredLangs;
- for (int v = 0; ; ++v) {
- FcChar8 *lang;
- FcResult result = FcPatternGetString(mSortPattern, FC_LANG, v, &lang);
- if (result != FcResultMatch) {
- // No need to check FcPatternGetLangSet() because
- // gfxFontconfigUtils sets only a string value for FC_LANG and
- // FcConfigSubstitute cannot add LangSets.
- NS_ASSERTION(result != FcResultTypeMismatch,
- "Expected a string for FC_LANG");
- break;
- }
-
- if (!requiredLangs.Contains(lang, LangComparator())) {
- FcLangResult bestLangSupport = utils->GetBestLangSupport(lang);
- if (bestLangSupport != FcLangDifferentLang) {
- requiredLangs.
- AppendElement(LangSupportEntry(lang, bestLangSupport));
- }
- }
- }
-
- nsAutoRef fontSet(FcFontSetCreate());
- if (!fontSet)
- return fontSet.out();
-
- // FcDefaultSubstitute() ensures a slant on mSortPattern, but, if that ever
- // doesn't happen, Roman will be used.
- int requestedSlant = FC_SLANT_ROMAN;
- FcPatternGetInteger(mSortPattern, FC_SLANT, 0, &requestedSlant);
- double requestedSize = -1.0;
- FcPatternGetDouble(mSortPattern, FC_PIXEL_SIZE, 0, &requestedSize);
-
- nsTHashtable existingFamilies(32);
- FcChar8 *family;
- for (int v = 0;
- FcPatternGetString(mSortPattern,
- FC_FAMILY, v, &family) == FcResultMatch; ++v) {
- const nsTArray< nsCountedRef