зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
a4a2be52e8
|
@ -23,21 +23,16 @@ var gSafeBrowsing = {
|
|||
document.getElementById("menu_HelpPopup_reportPhishingErrortoolmenu")
|
||||
.hidden = !isPhishingPage;
|
||||
|
||||
var broadcasterId = isPhishingPage
|
||||
? "reportPhishingErrorBroadcaster"
|
||||
: "reportPhishingBroadcaster";
|
||||
|
||||
var broadcaster = document.getElementById(broadcasterId);
|
||||
if (!broadcaster)
|
||||
return;
|
||||
|
||||
// Now look at the currentURI to learn which page we were trying
|
||||
// to browse to.
|
||||
let uri = gBrowser.currentURI;
|
||||
if (uri && (uri.schemeIs("http") || uri.schemeIs("https")))
|
||||
broadcaster.removeAttribute("disabled");
|
||||
else
|
||||
broadcaster.setAttribute("disabled", true);
|
||||
const uri = gBrowser.currentURI;
|
||||
const isReportablePage = uri && (uri.schemeIs("http") || uri.schemeIs("https"));
|
||||
|
||||
const disabledByPolicy = !Services.policies.isAllowed("feedbackCommands");
|
||||
document.getElementById("reportPhishingBroadcaster")
|
||||
.disabled = disabledByPolicy || isPhishingPage || !isReportablePage;
|
||||
document.getElementById("reportPhishingErrorBroadcaster")
|
||||
.disabled = disabledByPolicy || !isPhishingPage || !isReportablePage;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -831,6 +831,12 @@ function openTourPage() {
|
|||
}
|
||||
|
||||
function buildHelpMenu() {
|
||||
document.getElementById("feedbackPage")
|
||||
.disabled = !Services.policies.isAllowed("feedbackCommands");
|
||||
|
||||
document.getElementById("helpSafeMode")
|
||||
.disabled = !Services.policies.isAllowed("safeMode");
|
||||
|
||||
// Enable/disable the "Report Web Forgery" menu item.
|
||||
if (typeof gSafeBrowsing != "undefined") {
|
||||
gSafeBrowsing.setReportPhishingMenu();
|
||||
|
|
|
@ -135,6 +135,14 @@ var Policies = {
|
|||
}
|
||||
},
|
||||
|
||||
"DisableBuiltinPDFViewer": {
|
||||
onBeforeUIStartup(manager, param) {
|
||||
if (param) {
|
||||
manager.disallowFeature("PDF.js");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"DisableDeveloperTools": {
|
||||
onBeforeAddons(manager, param) {
|
||||
if (param) {
|
||||
|
@ -149,6 +157,14 @@ var Policies = {
|
|||
}
|
||||
},
|
||||
|
||||
"DisableFeedbackCommands": {
|
||||
onBeforeUIStartup(manager, param) {
|
||||
if (param) {
|
||||
manager.disallowFeature("feedbackCommands");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"DisableFirefoxAccounts": {
|
||||
onBeforeAddons(manager, param) {
|
||||
if (param) {
|
||||
|
@ -199,6 +215,14 @@ var Policies = {
|
|||
}
|
||||
},
|
||||
|
||||
"DisableSafeMode": {
|
||||
onBeforeUIStartup(manager, param) {
|
||||
if (param) {
|
||||
manager.disallowFeature("safeMode");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"DisableSysAddonUpdate": {
|
||||
onBeforeAddons(manager, param) {
|
||||
if (param) {
|
||||
|
|
|
@ -107,6 +107,13 @@
|
|||
"type": "boolean"
|
||||
},
|
||||
|
||||
"DisableBuiltinPDFViewer": {
|
||||
"description": "Disables PDF.js, which displays PDFs within Firefox.",
|
||||
"first_available": "60.0",
|
||||
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
"DisableDeveloperTools": {
|
||||
"description": "Prevents access to developer tools.",
|
||||
"first_available": "60.0",
|
||||
|
@ -114,6 +121,13 @@
|
|||
"type": "boolean"
|
||||
},
|
||||
|
||||
"DisableFeedbackCommands": {
|
||||
"description": "Prevents ability to send feedback from the help menu (\"Submit Feedback\" and \"Report Deceptive Site\").",
|
||||
"first_available": "60.0",
|
||||
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
"DisableFirefoxAccounts": {
|
||||
"description": "Disables Firefox Account based services, including Sync.",
|
||||
"first_available": "60.0",
|
||||
|
@ -156,6 +170,13 @@
|
|||
"type": "boolean"
|
||||
},
|
||||
|
||||
"DisableSafeMode": {
|
||||
"description": "Prevents ability to restart in safe mode.",
|
||||
"first_available": "60.0",
|
||||
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
"DisableSysAddonUpdate": {
|
||||
"description": "Prevent the browser from installing and updating system addons.",
|
||||
"first_available": "60.0",
|
||||
|
|
|
@ -24,12 +24,15 @@ support-files =
|
|||
[browser_policy_bookmarks.js]
|
||||
[browser_policy_clear_blocked_cookies.js]
|
||||
[browser_policy_default_browser_check.js]
|
||||
[browser_policy_disable_feedback_commands.js]
|
||||
[browser_policy_disable_formhistory.js]
|
||||
[browser_policy_disable_fxaccounts.js]
|
||||
[browser_policy_disable_fxscreenshots.js]
|
||||
[browser_policy_disable_masterpassword.js]
|
||||
[browser_policy_disable_pdfjs.js]
|
||||
[browser_policy_disable_pocket.js]
|
||||
[browser_policy_disable_privatebrowsing.js]
|
||||
[browser_policy_disable_safemode.js]
|
||||
[browser_policy_disable_shield.js]
|
||||
[browser_policy_display_bookmarks.js]
|
||||
[browser_policy_display_menu.js]
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* the buidHelpMenu() function comes from browser/base/content/utilityOverlay.js */
|
||||
|
||||
const NORMAL_PAGE = "http://example.com";
|
||||
const PHISH_PAGE = "http://www.itisatrap.org/firefox/its-a-trap.html";
|
||||
|
||||
async function checkItemsAreDisabled(url) {
|
||||
await BrowserTestUtils.withNewTab({
|
||||
gBrowser,
|
||||
url,
|
||||
// The phishing page doesn't send a load notification
|
||||
waitForLoad: false,
|
||||
waitForStateStop: true,
|
||||
}, async function checkItems() {
|
||||
buildHelpMenu();
|
||||
|
||||
let reportMenu = document.getElementById("menu_HelpPopup_reportPhishingtoolmenu");
|
||||
is(reportMenu.getAttribute("disabled"), "true",
|
||||
"The `Report Deceptive Site` item should be disabled");
|
||||
|
||||
let errorMenu = document.getElementById("menu_HelpPopup_reportPhishingErrortoolmenu");
|
||||
is(errorMenu.getAttribute("disabled"), "true",
|
||||
"The `This isn’t a deceptive site` item should be disabled");
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function test_policy_feedback_commands() {
|
||||
await setupPolicyEngineWithJson({
|
||||
"policies": {
|
||||
"DisableFeedbackCommands": true
|
||||
}
|
||||
});
|
||||
|
||||
/* from browser/base/content/utilityOverlay.js */
|
||||
buildHelpMenu();
|
||||
|
||||
let feedbackPageMenu = document.getElementById("feedbackPage");
|
||||
is(feedbackPageMenu.getAttribute("disabled"), "true",
|
||||
"The `Submit Feedback...` item should be disabled");
|
||||
|
||||
await checkItemsAreDisabled(NORMAL_PAGE);
|
||||
await checkItemsAreDisabled(PHISH_PAGE);
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
const {PdfJs} = ChromeUtils.import("resource://pdf.js/PdfJs.jsm", {});
|
||||
|
||||
add_task(async function test_disable_pdfjs() {
|
||||
is(PdfJs.enabled, true, "PDFjs should be enabled before policy runs");
|
||||
|
||||
await setupPolicyEngineWithJson({
|
||||
"policies": {
|
||||
"DisableBuiltinPDFViewer": true
|
||||
}
|
||||
});
|
||||
|
||||
is(PdfJs.enabled, false, "PDFjs should be disabled after policy runs");
|
||||
});
|
|
@ -0,0 +1,42 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
add_task(async function setup() {
|
||||
await setupPolicyEngineWithJson({
|
||||
"policies": {
|
||||
"DisableSafeMode": true
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_help_menu() {
|
||||
buildHelpMenu();
|
||||
let safeModeMenu = document.getElementById("helpSafeMode");
|
||||
is(safeModeMenu.getAttribute("disabled"), "true",
|
||||
"The `Restart with Add-ons Disabled...` item should be disabled");
|
||||
});
|
||||
|
||||
add_task(async function test_safemode_from_about_support() {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:support");
|
||||
|
||||
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
|
||||
let button = content.document.getElementById("restart-in-safe-mode-button");
|
||||
is(button.getAttribute("disabled"), "true",
|
||||
"The `Restart with Add-ons Disabled...` button should be disabled");
|
||||
});
|
||||
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(async function test_safemode_from_about_profiles() {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:profiles");
|
||||
|
||||
await ContentTask.spawn(tab.linkedBrowser, null, async function() {
|
||||
let button = content.document.getElementById("restart-in-safe-mode-button");
|
||||
is(button.getAttribute("disabled"), "true",
|
||||
"The `Restart with Add-ons Disabled...` button should be disabled");
|
||||
});
|
||||
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
});
|
|
@ -51,6 +51,7 @@ skip-if = os == 'linux'
|
|||
[browser_ext_browserAction_pageAction_icon_permissions.js]
|
||||
[browser_ext_browserAction_popup.js]
|
||||
skip-if = (debug && os == 'linux' && bits == 32) || (os == 'win' && !debug) # Bug 1313372, win: Bug 1285500
|
||||
[browser_ext_browserAction_popup_port.js]
|
||||
[browser_ext_browserAction_popup_preload.js]
|
||||
skip-if = (os == 'win' && !debug) # bug 1352668
|
||||
[browser_ext_browserAction_popup_resize.js]
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
let scriptPage = url => `<html><head><meta charset="utf-8"><script src="${url}"></script></head><body>${url}</body></html>`;
|
||||
|
||||
// Tests that message ports still function correctly after a browserAction popup
|
||||
// <browser> has been reparented.
|
||||
add_task(async function test_browserActionPort() {
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"browser_action": {
|
||||
"default_popup": "popup.html",
|
||||
"browser_style": true,
|
||||
},
|
||||
},
|
||||
|
||||
background() {
|
||||
new Promise(resolve => {
|
||||
browser.runtime.onConnect.addListener(port => {
|
||||
resolve(Promise.all([
|
||||
new Promise(r => port.onMessage.addListener(r)),
|
||||
new Promise(r => port.onDisconnect.addListener(r)),
|
||||
]));
|
||||
});
|
||||
}).then(([msg]) => {
|
||||
browser.test.assertEq("Hallo.", msg, "Got expected message");
|
||||
browser.test.notifyPass("browserAction-popup-port");
|
||||
});
|
||||
},
|
||||
|
||||
files: {
|
||||
"popup.html": scriptPage("popup.js"),
|
||||
"popup.js"() {
|
||||
let port = browser.runtime.connect();
|
||||
window.onload = () => {
|
||||
setTimeout(() => {
|
||||
port.postMessage("Hallo.");
|
||||
window.close();
|
||||
}, 0);
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
|
||||
await clickBrowserAction(extension);
|
||||
|
||||
await extension.awaitFinish("browserAction-popup-port");
|
||||
await extension.unload();
|
||||
});
|
|
@ -0,0 +1,48 @@
|
|||
.. _browsererrorreporter:
|
||||
|
||||
=======================
|
||||
Browser Error Reporter
|
||||
=======================
|
||||
|
||||
The `BrowserErrorReporter.jsm <https://dxr.mozilla.org/mozilla-central/source/browser/modules/BrowserErrorReporter.jsm>`_ module collects errors logged to the Browser Console and sends them to a remote error aggregation service.
|
||||
|
||||
.. note::
|
||||
This module and the related service is a prototype and will be removed from Firefox in later 2018.
|
||||
|
||||
Opt-out
|
||||
=======
|
||||
Collection is enabled by default in the Nightly channel, except for local builds, where it is disabled. It is not available outside of the Nightly channel.
|
||||
|
||||
To opt-out of collection:
|
||||
|
||||
1. Open ``about:preferences``.
|
||||
2. Select the Privacy and Security panel and go to the Nightly Data Collection and Use section.
|
||||
3. Uncheck "Allow Nightly to send browser error reports (including error messages) to Mozilla".
|
||||
|
||||
Collected Error Data
|
||||
====================
|
||||
Errors are first sampled at the rate specified by the ``browser.chrome.errorReporter.sampleRate`` preference.
|
||||
|
||||
The payload sent to the remote collection service contains the following info:
|
||||
|
||||
- Firefox version number
|
||||
- Firefox update channel (usually "Nightly")
|
||||
- Firefox build ID
|
||||
- Revision used to build Firefox
|
||||
- Timestamp when the error occurred
|
||||
- A project ID specified by the ``browser.chrome.errorReporter.projectId`` preference
|
||||
- The error message
|
||||
- The filename that the error was thrown from
|
||||
- A stacktrace, if available, of the code being executed when the error was thrown
|
||||
|
||||
Privacy-sensitive info
|
||||
======================
|
||||
Error reports may contain sensitive information about the user:
|
||||
|
||||
- Error messages may inadvertently contain personal info depending on the code that generated the error.
|
||||
- Filenames in the stack trace may contain add-on IDs of currently-installed add-ons. They may also contain local filesystem paths.
|
||||
|
||||
.. seealso::
|
||||
|
||||
`Browser Error Collection wiki page <https://wiki.mozilla.org/Firefox/BrowserErrorCollection>`_
|
||||
Wiki page with up-to-date information on error collection and how we restrict access to the collected data.
|
|
@ -9,3 +9,4 @@ This is the nascent documentation of the Firefox front-end code.
|
|||
|
||||
UITelemetry
|
||||
BrowserUsageTelemetry
|
||||
BrowserErrorReporter
|
||||
|
|
|
@ -337,6 +337,10 @@ var PdfJs = {
|
|||
* @return {boolean} Whether or not it's enabled.
|
||||
*/
|
||||
get enabled() {
|
||||
if (!Services.policies.isAllowed("PDF.js")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Services.prefs.getBoolPref(PREF_ENABLED_CACHE_INITIALIZED, false)) {
|
||||
// If we just updated, and the cache hasn't been initialized, then we
|
||||
// can't assume a default state, and need to synchronously initialize
|
||||
|
|
|
@ -55,9 +55,10 @@ const REPORTED_CATEGORIES = new Set([
|
|||
* traces; see bug 1426482 for privacy review and server-side mitigation.
|
||||
*/
|
||||
class BrowserErrorReporter {
|
||||
constructor(fetchMethod = this._defaultFetch) {
|
||||
// A fake fetch is passed by the tests to avoid network connections
|
||||
constructor(fetchMethod = this._defaultFetch, chromeOnly = true) {
|
||||
// Test arguments for mocks and changing behavior
|
||||
this.fetch = fetchMethod;
|
||||
this.chromeOnly = chromeOnly;
|
||||
|
||||
// Values that don't change between error reports.
|
||||
this.requestBodyTemplate = {
|
||||
|
@ -133,7 +134,7 @@ class BrowserErrorReporter {
|
|||
|
||||
const isWarning = message.flags & message.warningFlag;
|
||||
const isFromChrome = REPORTED_CATEGORIES.has(message.category);
|
||||
if (!isFromChrome || isWarning) {
|
||||
if ((this.chromeOnly && !isFromChrome) || isWarning) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -143,6 +144,22 @@ class BrowserErrorReporter {
|
|||
return;
|
||||
}
|
||||
|
||||
const extensions = new Map();
|
||||
for (let extension of WebExtensionPolicy.getActiveExtensions()) {
|
||||
extensions.set(extension.mozExtensionHostname, extension);
|
||||
}
|
||||
|
||||
// Replaces any instances of moz-extension:// URLs with internal UUIDs to use
|
||||
// the add-on ID instead.
|
||||
function mangleExtURL(string, anchored = true) {
|
||||
let re = new RegExp(`${anchored ? "^" : ""}moz-extension://([^/]+)/`, "g");
|
||||
|
||||
return string.replace(re, (m0, m1) => {
|
||||
let id = extensions.has(m1) ? extensions.get(m1).id : m1;
|
||||
return `moz-extension://${id}/`;
|
||||
});
|
||||
}
|
||||
|
||||
// Parse the error type from the message if present (e.g. "TypeError: Whoops").
|
||||
let errorMessage = message.errorMessage;
|
||||
let errorName = "Error";
|
||||
|
@ -156,7 +173,9 @@ class BrowserErrorReporter {
|
|||
let frame = message.stack;
|
||||
// Avoid an infinite loop by limiting traces to 100 frames.
|
||||
while (frame && frames.length < 100) {
|
||||
frames.push(await this.normalizeStackFrame(frame));
|
||||
const normalizedFrame = await this.normalizeStackFrame(frame);
|
||||
normalizedFrame.module = mangleExtURL(normalizedFrame.module, false);
|
||||
frames.push(normalizedFrame);
|
||||
frame = frame.parent;
|
||||
}
|
||||
// Frames are sent in order from oldest to newest.
|
||||
|
@ -169,7 +188,7 @@ class BrowserErrorReporter {
|
|||
values: [
|
||||
{
|
||||
type: errorName,
|
||||
value: errorMessage,
|
||||
value: mangleExtURL(errorMessage),
|
||||
module: message.sourceName,
|
||||
stacktrace: {
|
||||
frames,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm", this);
|
||||
ChromeUtils.import("resource:///modules/BrowserErrorReporter.jsm", this);
|
||||
|
||||
/* global sinon */
|
||||
|
@ -406,3 +407,45 @@ add_task(async function testFetchArguments() {
|
|||
reporter.uninit();
|
||||
resetConsole();
|
||||
});
|
||||
|
||||
add_task(async function testAddonIDMangle() {
|
||||
const fetchSpy = sinon.spy();
|
||||
// Passing false here disables category checks on errors, which would
|
||||
// otherwise block errors directly from extensions.
|
||||
const reporter = new BrowserErrorReporter(fetchSpy, false);
|
||||
await SpecialPowers.pushPrefEnv({set: [
|
||||
[PREF_ENABLED, true],
|
||||
[PREF_SAMPLE_RATE, "1.0"],
|
||||
]});
|
||||
reporter.init();
|
||||
|
||||
// Create and install test add-on
|
||||
const id = "browsererrorcollection@example.com";
|
||||
const extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
applications: {
|
||||
gecko: { id },
|
||||
},
|
||||
},
|
||||
background() {
|
||||
throw new Error("testAddonIDMangle error");
|
||||
},
|
||||
});
|
||||
await extension.startup();
|
||||
|
||||
// Just in case the error hasn't been thrown before add-on startup.
|
||||
const call = await TestUtils.waitForCondition(
|
||||
() => fetchCallForMessage(fetchSpy, "testAddonIDMangle error"),
|
||||
`Wait for error from ${id} to be logged`,
|
||||
);
|
||||
const body = JSON.parse(call.args[1].body);
|
||||
const stackFrame = body.exception.values[0].stacktrace.frames[0];
|
||||
ok(
|
||||
stackFrame.module.startsWith(`moz-extension://${id}/`),
|
||||
"Stack frame filenames use the proper add-on ID instead of internal UUIDs.",
|
||||
);
|
||||
|
||||
await extension.unload();
|
||||
reporter.uninit();
|
||||
resetConsole();
|
||||
});
|
||||
|
|
|
@ -217,7 +217,7 @@ BrowserAddonActor.prototype = {
|
|||
}
|
||||
|
||||
if (global instanceof Ci.nsIDOMWindow) {
|
||||
return global.document.nodePrincipal.addonId;
|
||||
return global.document.nodePrincipal.addonId == this.id;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "mozilla/dom/MessageEventBinding.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/dom/WorkerRef.h"
|
||||
#include "mozilla/dom/WorkerRunnable.h"
|
||||
#include "mozilla/dom/WorkerScope.h"
|
||||
#include "mozilla/UniquePtrExtensions.h"
|
||||
|
@ -143,8 +144,8 @@ public:
|
|||
void AddRefObject();
|
||||
void ReleaseObject();
|
||||
|
||||
bool RegisterWorkerHolder();
|
||||
void UnregisterWorkerHolder();
|
||||
bool CreateWorkerRef(WorkerPrivate* aWorkerPrivate);
|
||||
void ReleaseWorkerRef();
|
||||
|
||||
void AssertIsOnTargetThread() const
|
||||
{
|
||||
|
@ -282,11 +283,8 @@ public:
|
|||
nsString mLastFieldValue;
|
||||
|
||||
// EventSourceImpl internal states.
|
||||
// The worker private where the EventSource is created. nullptr if created on
|
||||
// main thread. (accessed on worker thread only)
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
// Holder to worker to keep worker alive. (accessed on worker thread only)
|
||||
nsAutoPtr<WorkerHolder> mWorkerHolder;
|
||||
// WorkerRef to keep the worker alive. (accessed on worker thread only)
|
||||
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
|
||||
// This mutex protects mFrozen and mEventSource->mReadyState that are used in
|
||||
// different threads.
|
||||
mozilla::Mutex mMutex;
|
||||
|
@ -353,8 +351,6 @@ EventSourceImpl::EventSourceImpl(EventSource* aEventSource)
|
|||
{
|
||||
MOZ_ASSERT(mEventSource);
|
||||
if (!mIsMainThread) {
|
||||
mWorkerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mEventSource->mIsMainThread = false;
|
||||
}
|
||||
SetReadyState(CONNECTING);
|
||||
|
@ -364,11 +360,11 @@ class CleanupRunnable final : public WorkerMainThreadRunnable
|
|||
{
|
||||
public:
|
||||
explicit CleanupRunnable(EventSourceImpl* aEventSourceImpl)
|
||||
: WorkerMainThreadRunnable(aEventSourceImpl->mWorkerPrivate,
|
||||
: WorkerMainThreadRunnable(GetCurrentThreadWorkerPrivate(),
|
||||
NS_LITERAL_CSTRING("EventSource :: Cleanup"))
|
||||
, mImpl(aEventSourceImpl)
|
||||
{
|
||||
mImpl->mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
bool MainThreadRun() override
|
||||
|
@ -413,7 +409,7 @@ EventSourceImpl::CloseInternal()
|
|||
RefPtr<CleanupRunnable> runnable = new CleanupRunnable(this);
|
||||
runnable->Dispatch(Killing, rv);
|
||||
MOZ_ASSERT(!rv.Failed());
|
||||
UnregisterWorkerHolder();
|
||||
ReleaseWorkerRef();
|
||||
}
|
||||
|
||||
while (mMessagesToDispatch.GetSize() != 0) {
|
||||
|
@ -452,20 +448,22 @@ void EventSourceImpl::CleanupOnMainThread()
|
|||
class InitRunnable final : public WorkerMainThreadRunnable
|
||||
{
|
||||
public:
|
||||
explicit InitRunnable(EventSourceImpl* aEventSourceImpl,
|
||||
const nsAString& aURL)
|
||||
: WorkerMainThreadRunnable(aEventSourceImpl->mWorkerPrivate,
|
||||
InitRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
EventSourceImpl* aEventSourceImpl,
|
||||
const nsAString& aURL)
|
||||
: WorkerMainThreadRunnable(aWorkerPrivate,
|
||||
NS_LITERAL_CSTRING("EventSource :: Init"))
|
||||
, mImpl(aEventSourceImpl)
|
||||
, mURL(aURL)
|
||||
{
|
||||
mImpl->mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
bool MainThreadRun() override
|
||||
{
|
||||
// Get principal from worker's owner document or from worker.
|
||||
WorkerPrivate* wp = mImpl->mWorkerPrivate;
|
||||
WorkerPrivate* wp = mWorkerPrivate;
|
||||
while (wp->GetParent()) {
|
||||
wp = wp->GetParent();
|
||||
}
|
||||
|
@ -485,13 +483,36 @@ public:
|
|||
|
||||
nsresult ErrorCode() const { return mRv; }
|
||||
|
||||
protected:
|
||||
private:
|
||||
// Raw pointer because this runnable is sync.
|
||||
EventSourceImpl* mImpl;
|
||||
const nsAString& mURL;
|
||||
nsresult mRv;
|
||||
};
|
||||
|
||||
class ConnectRunnable final : public WorkerMainThreadRunnable
|
||||
{
|
||||
public:
|
||||
explicit ConnectRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
EventSourceImpl* aEventSourceImpl)
|
||||
: WorkerMainThreadRunnable(aWorkerPrivate,
|
||||
NS_LITERAL_CSTRING("EventSource :: Connect"))
|
||||
, mImpl(aEventSourceImpl)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
bool MainThreadRun() override
|
||||
{
|
||||
mImpl->InitChannelAndRequestEventSource();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<EventSourceImpl> mImpl;
|
||||
};
|
||||
|
||||
nsresult
|
||||
EventSourceImpl::ParseURL(const nsAString& aURL)
|
||||
{
|
||||
|
@ -585,11 +606,6 @@ EventSourceImpl::Init(nsIPrincipal* aPrincipal,
|
|||
DEFAULT_RECONNECTION_TIME_VALUE);
|
||||
|
||||
mUnicodeDecoder = UTF_8_ENCODING->NewDecoderWithBOMRemoval();
|
||||
|
||||
// the constructor should throw a SYNTAX_ERROR only if it fails resolving the
|
||||
// url parameter, so we don't care about the InitChannelAndRequestEventSource
|
||||
// result.
|
||||
InitChannelAndRequestEventSource();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -1131,11 +1147,11 @@ class CallRestartConnection final : public WorkerMainThreadRunnable
|
|||
public:
|
||||
explicit CallRestartConnection(EventSourceImpl* aEventSourceImpl)
|
||||
: WorkerMainThreadRunnable(
|
||||
aEventSourceImpl->mWorkerPrivate,
|
||||
aEventSourceImpl->mWorkerRef->Private(),
|
||||
NS_LITERAL_CSTRING("EventSource :: RestartConnection"))
|
||||
, mImpl(aEventSourceImpl)
|
||||
{
|
||||
mImpl->mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
bool MainThreadRun() override
|
||||
|
@ -1476,8 +1492,8 @@ EventSourceImpl::DispatchAllMessageEvents()
|
|||
return;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
if (NS_WARN_IF(!jsapi.Init(mWorkerPrivate->GlobalScope()))) {
|
||||
MOZ_ASSERT(mWorkerRef);
|
||||
if (NS_WARN_IF(!jsapi.Init(mWorkerRef->Private()->GlobalScope()))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1777,28 +1793,6 @@ EventSourceImpl::ReleaseObject()
|
|||
}
|
||||
|
||||
namespace {
|
||||
class EventSourceWorkerHolder final : public WorkerHolder
|
||||
{
|
||||
public:
|
||||
explicit EventSourceWorkerHolder(EventSourceImpl* aEventSourceImpl)
|
||||
: WorkerHolder("EventSourceWorkerHolder")
|
||||
, mEventSourceImpl(aEventSourceImpl)
|
||||
{
|
||||
}
|
||||
|
||||
bool Notify(WorkerStatus aStatus) override
|
||||
{
|
||||
MOZ_ASSERT(aStatus > Running);
|
||||
if (aStatus >= Canceling) {
|
||||
mEventSourceImpl->Close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Raw pointer because the EventSourceImpl object keeps alive the holder.
|
||||
EventSourceImpl* mEventSourceImpl;
|
||||
};
|
||||
|
||||
class WorkerRunnableDispatcher final : public WorkerRunnable
|
||||
{
|
||||
|
@ -1849,30 +1843,32 @@ private:
|
|||
|
||||
} // namespace
|
||||
|
||||
bool EventSourceImpl::RegisterWorkerHolder()
|
||||
bool EventSourceImpl::CreateWorkerRef(WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(!IsShutDown());
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(!mWorkerHolder);
|
||||
mWorkerHolder = new EventSourceWorkerHolder(this);
|
||||
if (NS_WARN_IF(!mWorkerHolder->HoldWorker(mWorkerPrivate, Canceling))) {
|
||||
mWorkerHolder = nullptr;
|
||||
MOZ_ASSERT(!mWorkerRef);
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
RefPtr<EventSourceImpl> self = this;
|
||||
RefPtr<StrongWorkerRef> workerRef =
|
||||
StrongWorkerRef::Create(aWorkerPrivate, "EventSource", [self]() {
|
||||
self->Close();
|
||||
});
|
||||
|
||||
if (NS_WARN_IF(!workerRef)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mWorkerRef = new ThreadSafeWorkerRef(workerRef);
|
||||
return true;
|
||||
}
|
||||
|
||||
void EventSourceImpl::UnregisterWorkerHolder()
|
||||
void EventSourceImpl::ReleaseWorkerRef()
|
||||
{
|
||||
// RegisterWorkerHolder fail will destroy EventSourceImpl and invoke
|
||||
// UnregisterWorkerHolder.
|
||||
MOZ_ASSERT(IsClosed());
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
// The DTOR of this WorkerHolder will release the worker for us.
|
||||
mWorkerHolder = nullptr;
|
||||
mWorkerPrivate = nullptr;
|
||||
MOZ_ASSERT(IsCurrentThreadRunningWorker());
|
||||
mWorkerRef = nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -1896,11 +1892,11 @@ EventSourceImpl::Dispatch(already_AddRefed<nsIRunnable> aEvent, uint32_t aFlags)
|
|||
if (IsShutDown()) {
|
||||
return NS_OK;
|
||||
}
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
|
||||
// If the target is a worker, we have to use a custom WorkerRunnableDispatcher
|
||||
// runnable.
|
||||
RefPtr<WorkerRunnableDispatcher> event =
|
||||
new WorkerRunnableDispatcher(this, mWorkerPrivate, event_ref.forget());
|
||||
new WorkerRunnableDispatcher(this, mWorkerRef->Private(), event_ref.forget());
|
||||
|
||||
if (!event->Dispatch()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -1982,23 +1978,53 @@ EventSource::Constructor(const GlobalObject& aGlobal, const nsAString& aURL,
|
|||
return nullptr;
|
||||
}
|
||||
eventSourceImp->Init(principal, aURL, aRv);
|
||||
} else {
|
||||
// In workers we have to keep the worker alive using a WorkerHolder in order
|
||||
// to dispatch messages correctly.
|
||||
if (!eventSourceImp->RegisterWorkerHolder()) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<InitRunnable> runnable = new InitRunnable(eventSourceImp, aURL);
|
||||
runnable->Dispatch(Terminating, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
aRv = runnable->ErrorCode();
|
||||
|
||||
eventSourceImp->InitChannelAndRequestEventSource();
|
||||
return eventSource.forget();
|
||||
}
|
||||
|
||||
// Worker side.
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
RefPtr<InitRunnable> initRunnable =
|
||||
new InitRunnable(workerPrivate, eventSourceImp, aURL);
|
||||
initRunnable->Dispatch(Terminating, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aRv = initRunnable->ErrorCode();
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// In workers we have to keep the worker alive using a WorkerRef in order
|
||||
// to dispatch messages correctly.
|
||||
if (!eventSourceImp->CreateWorkerRef(workerPrivate)) {
|
||||
// The worker is already shutting down. Let's return an already closed
|
||||
// object, but marked as Connecting.
|
||||
eventSource->Close();
|
||||
|
||||
// EventSourceImpl must be released before returning the object, otherwise
|
||||
// it will set EventSource to a CLOSED state in its DTOR.
|
||||
eventSourceImp = nullptr;
|
||||
|
||||
eventSource->mReadyState = EventSourceImpl::CONNECTING;
|
||||
return eventSource.forget();
|
||||
}
|
||||
|
||||
// Let's connect to the server.
|
||||
RefPtr<ConnectRunnable> connectRunnable =
|
||||
new ConnectRunnable(workerPrivate, eventSourceImp);
|
||||
connectRunnable->Dispatch(Terminating, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return eventSource.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ struct LinkedProgramInfo final
|
|||
: public RefCounted<LinkedProgramInfo>
|
||||
, public SupportsWeakPtr<LinkedProgramInfo>
|
||||
{
|
||||
friend class WebGLProgram;
|
||||
friend class mozilla::WebGLProgram;
|
||||
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(LinkedProgramInfo)
|
||||
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(LinkedProgramInfo)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
52547
|
||||
52568
|
||||
0/nm
|
||||
0th/pt
|
||||
1/n1
|
||||
|
@ -14713,6 +14713,7 @@ anticyclonic
|
|||
antidemocratic
|
||||
antidepressant/MS
|
||||
antidote/MS
|
||||
antifa
|
||||
antifascist/MS
|
||||
antifreeze/M
|
||||
antigen/SM
|
||||
|
@ -16936,6 +16937,7 @@ blockader/M
|
|||
blockage/MS
|
||||
blockbuster/SM
|
||||
blockbusting/M
|
||||
blockchain/S
|
||||
blocker/MS
|
||||
blockhead/SM
|
||||
blockhouse/MS
|
||||
|
@ -22428,6 +22430,7 @@ demonstration/M
|
|||
demonstrative/MYSP
|
||||
demonstrativeness/M
|
||||
demonstrator/MS
|
||||
demonym/S
|
||||
demote/GD
|
||||
demotic
|
||||
demount
|
||||
|
@ -24433,6 +24436,7 @@ ember/SM
|
|||
embezzle/ZGLDRS
|
||||
embezzlement/M
|
||||
embezzler/M
|
||||
embiggen
|
||||
embitter/GLDS
|
||||
embitterment/M
|
||||
emblazon/GDLS
|
||||
|
@ -27921,6 +27925,7 @@ glamorization/M
|
|||
glamorize/DSG
|
||||
glamorous/Y
|
||||
glamour/GMDS
|
||||
glamping
|
||||
glance/DSMG
|
||||
gland/SM
|
||||
glandes
|
||||
|
@ -28761,6 +28766,7 @@ hacktivist/MS
|
|||
hackwork/M
|
||||
had
|
||||
haddock/SM
|
||||
hadith/S
|
||||
hadn't
|
||||
hadst
|
||||
hafnium/M
|
||||
|
@ -28996,6 +29002,7 @@ harelip/SM
|
|||
harelipped
|
||||
harem/SM
|
||||
haricot/S
|
||||
harissa
|
||||
hark/DGS
|
||||
harlequin/SM
|
||||
harlot/SM
|
||||
|
@ -29634,6 +29641,7 @@ hobnobbed
|
|||
hobnobbing
|
||||
hobo/MS
|
||||
hoboes
|
||||
hoc
|
||||
hock/MDSG
|
||||
hockey/M
|
||||
hockshop/MS
|
||||
|
@ -32138,6 +32146,7 @@ kWh
|
|||
kabbala
|
||||
kabbalah
|
||||
kabob/SM
|
||||
kabocha
|
||||
kaboom
|
||||
kabuki/M
|
||||
kaddish/MS
|
||||
|
@ -32422,6 +32431,7 @@ kohl
|
|||
kohlrabi/M
|
||||
kohlrabies
|
||||
kola/MS
|
||||
kombucha
|
||||
kook/MS
|
||||
kookaburra/SM
|
||||
kookiness/M
|
||||
|
@ -34727,6 +34737,7 @@ microcode
|
|||
microcomputer/MS
|
||||
microcosm/MS
|
||||
microcosmic
|
||||
microcredit
|
||||
microdot/SM
|
||||
microeconomics/M
|
||||
microelectronic/S
|
||||
|
@ -34734,6 +34745,7 @@ microelectronics/M
|
|||
microfiber/MS
|
||||
microfiche/M
|
||||
microfilm/GMDS
|
||||
microfinance
|
||||
microfloppies
|
||||
microgroove/SM
|
||||
microlight/MS
|
||||
|
@ -35258,6 +35270,7 @@ moistness/M
|
|||
moisture/M
|
||||
moisturize/ZGDRS
|
||||
moisturizer/M
|
||||
mojo/S
|
||||
molar/SM
|
||||
molasses/M
|
||||
mold/MDRJSZG
|
||||
|
@ -36143,6 +36156,7 @@ nelson/SM
|
|||
nematode/SM
|
||||
nemeses
|
||||
nemesis/M
|
||||
neoadjuvant
|
||||
neoclassic
|
||||
neoclassical
|
||||
neoclassicism/M
|
||||
|
@ -37995,6 +38009,7 @@ oxygenate/DSGN
|
|||
oxygenation/M
|
||||
oxymora
|
||||
oxymoron/M
|
||||
oy
|
||||
oyes
|
||||
oyez
|
||||
oyster/SM
|
||||
|
@ -42412,6 +42427,7 @@ respectful/EY
|
|||
respectfulness/M
|
||||
respective/Y
|
||||
respell/SGD
|
||||
respellings
|
||||
respiration/M
|
||||
respirator/SM
|
||||
respiratory
|
||||
|
@ -44946,6 +44962,7 @@ site/MGDS
|
|||
sitemap/SM
|
||||
sitter/SM
|
||||
sitting/SM
|
||||
situ
|
||||
situate/DSXGN
|
||||
situation/M
|
||||
situational
|
||||
|
@ -45404,7 +45421,7 @@ snarly/TR
|
|||
snatch/ZGMDRS
|
||||
snatcher/M
|
||||
snazzily
|
||||
snazzy/TR
|
||||
snazzy/TRP
|
||||
sneak/SMDRZG
|
||||
sneaker/M
|
||||
sneakily
|
||||
|
@ -47117,6 +47134,7 @@ subtrahend/SM
|
|||
subtropic/S
|
||||
subtropical
|
||||
subtropics/M
|
||||
subtweet/S
|
||||
suburb/MS
|
||||
suburban/SM
|
||||
suburbanite/SM
|
||||
|
@ -49875,6 +49893,7 @@ tyrannous
|
|||
tyranny/SM
|
||||
tyrant/SM
|
||||
tyro/MS
|
||||
tzatziki
|
||||
u/S
|
||||
ubiquitous/Y
|
||||
ubiquity/M
|
||||
|
@ -51565,6 +51584,7 @@ wellington/MS
|
|||
wellness/M
|
||||
wellspring/MS
|
||||
welly/S
|
||||
welp
|
||||
welsh/ZGDRS
|
||||
welsher/M
|
||||
welt/MDRSZG
|
||||
|
@ -52104,6 +52124,7 @@ word's
|
|||
word/ADSG
|
||||
wordage/M
|
||||
wordbook/SM
|
||||
wordie/S
|
||||
wordily
|
||||
wordiness/M
|
||||
wording/SM
|
||||
|
|
|
@ -195,7 +195,7 @@ struct nsGridContainerFrame::TrackSize
|
|||
eMaxContentMinSizing = 0x4,
|
||||
eMinOrMaxContentMinSizing = eMinContentMinSizing | eMaxContentMinSizing,
|
||||
eIntrinsicMinSizing = eMinOrMaxContentMinSizing | eAutoMinSizing,
|
||||
// 0x8 is unused, feel free to take it!
|
||||
eModified = 0x8,
|
||||
eAutoMaxSizing = 0x10,
|
||||
eMinContentMaxSizing = 0x20,
|
||||
eMaxContentMaxSizing = 0x40,
|
||||
|
@ -208,6 +208,7 @@ struct nsGridContainerFrame::TrackSize
|
|||
eSkipGrowUnlimited = eSkipGrowUnlimited1 | eSkipGrowUnlimited2,
|
||||
eBreakBefore = 0x800,
|
||||
eFitContent = 0x1000,
|
||||
eInfinitelyGrowable = 0x2000,
|
||||
};
|
||||
|
||||
StateBits Initialize(nscoord aPercentageBasis,
|
||||
|
@ -1139,6 +1140,61 @@ struct nsGridContainerFrame::Tracks
|
|||
*/
|
||||
void AlignBaselineSubtree(const GridItemInfo& aGridItem) const;
|
||||
|
||||
enum class TrackSizingPhase
|
||||
{
|
||||
eIntrinsicMinimums,
|
||||
eContentBasedMinimums,
|
||||
eMaxContentMinimums,
|
||||
eIntrinsicMaximums,
|
||||
eMaxContentMaximums,
|
||||
};
|
||||
|
||||
// Some data we collect on each item for Step 2 of the Track Sizing Algorithm
|
||||
// in ResolveIntrinsicSize below.
|
||||
struct Step2ItemData final
|
||||
{
|
||||
uint32_t mSpan;
|
||||
TrackSize::StateBits mState;
|
||||
LineRange mLineRange;
|
||||
nscoord mMinSize;
|
||||
nscoord mMinContentContribution;
|
||||
nscoord mMaxContentContribution;
|
||||
nsIFrame* mFrame;
|
||||
static bool IsSpanLessThan(const Step2ItemData& a, const Step2ItemData& b)
|
||||
{
|
||||
return a.mSpan < b.mSpan;
|
||||
}
|
||||
|
||||
template<TrackSizingPhase phase>
|
||||
nscoord SizeContributionForPhase() const
|
||||
{
|
||||
switch (phase) {
|
||||
case TrackSizingPhase::eIntrinsicMinimums:
|
||||
case TrackSizingPhase::eIntrinsicMaximums:
|
||||
return mMinSize;
|
||||
case TrackSizingPhase::eContentBasedMinimums:
|
||||
return mMinContentContribution;
|
||||
case TrackSizingPhase::eMaxContentMinimums:
|
||||
case TrackSizingPhase::eMaxContentMaximums:
|
||||
return mMaxContentContribution;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected phase");
|
||||
}
|
||||
};
|
||||
|
||||
using FitContentClamper =
|
||||
std::function<bool(uint32_t aTrack, nscoord aMinSize, nscoord* aSize)>;
|
||||
|
||||
// Helper method for ResolveIntrinsicSize.
|
||||
template<TrackSizingPhase phase>
|
||||
bool GrowSizeForSpanningItems(nsTArray<Step2ItemData>::iterator aIter,
|
||||
const nsTArray<Step2ItemData>::iterator aEnd,
|
||||
nsTArray<uint32_t>& aTracks,
|
||||
nsTArray<TrackSize>& aPlan,
|
||||
nsTArray<TrackSize>& aItemPlan,
|
||||
TrackSize::StateBits aSelector,
|
||||
const FitContentClamper& aClamper = nullptr,
|
||||
bool aNeedInfinitelyGrowableFlag = false);
|
||||
/**
|
||||
* Resolve Intrinsic Track Sizes.
|
||||
* http://dev.w3.org/csswg/css-grid/#algo-content
|
||||
|
@ -1161,66 +1217,117 @@ struct nsGridContainerFrame::Tracks
|
|||
SizingConstraint aConstraint,
|
||||
const LineRange& aRange,
|
||||
const GridItemInfo& aGridItem);
|
||||
|
||||
// Helper method that returns the track size to use in §11.5.1.2
|
||||
// https://drafts.csswg.org/css-grid/#extra-space
|
||||
template<TrackSizingPhase phase> static
|
||||
nscoord StartSizeInDistribution(const TrackSize& aSize)
|
||||
{
|
||||
switch (phase) {
|
||||
case TrackSizingPhase::eIntrinsicMinimums:
|
||||
case TrackSizingPhase::eContentBasedMinimums:
|
||||
case TrackSizingPhase::eMaxContentMinimums:
|
||||
return aSize.mBase;
|
||||
case TrackSizingPhase::eIntrinsicMaximums:
|
||||
case TrackSizingPhase::eMaxContentMaximums:
|
||||
if (aSize.mLimit == NS_UNCONSTRAINEDSIZE) {
|
||||
return aSize.mBase;
|
||||
}
|
||||
return aSize.mLimit;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected phase");
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the tracks which are growable (matching aSelector) into
|
||||
* aGrowableTracks, and return the amount of space that can be used
|
||||
* to grow those tracks. Specifically, we return aAvailableSpace minus
|
||||
* the sum of mBase's (and corresponding grid gaps) in aPlan (clamped to 0)
|
||||
* for the tracks in aRange, or zero when there are no growable tracks.
|
||||
* @note aPlan[*].mBase represents a planned new base or limit.
|
||||
* to grow those tracks. This method implements CSS Grid §11.5.1.2.
|
||||
* https://drafts.csswg.org/css-grid/#extra-space
|
||||
*/
|
||||
nscoord CollectGrowable(nscoord aAvailableSpace,
|
||||
const nsTArray<TrackSize>& aPlan,
|
||||
const LineRange& aRange,
|
||||
TrackSize::StateBits aSelector,
|
||||
nsTArray<uint32_t>& aGrowableTracks) const
|
||||
template<TrackSizingPhase phase>
|
||||
nscoord CollectGrowable(nscoord aAvailableSpace,
|
||||
const LineRange& aRange,
|
||||
TrackSize::StateBits aSelector,
|
||||
nsTArray<uint32_t>& aGrowableTracks) const
|
||||
{
|
||||
MOZ_ASSERT(aAvailableSpace > 0, "why call me?");
|
||||
nscoord space = aAvailableSpace - mGridGap * (aRange.Extent() - 1);
|
||||
const uint32_t start = aRange.mStart;
|
||||
const uint32_t end = aRange.mEnd;
|
||||
for (uint32_t i = start; i < end; ++i) {
|
||||
const TrackSize& sz = aPlan[i];
|
||||
space -= sz.mBase;
|
||||
const TrackSize& sz = mSizes[i];
|
||||
space -= StartSizeInDistribution<phase>(sz);
|
||||
if (space <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if ((sz.mState & aSelector) && !sz.IsFrozen()) {
|
||||
if (sz.mState & aSelector) {
|
||||
aGrowableTracks.AppendElement(i);
|
||||
}
|
||||
}
|
||||
return aGrowableTracks.IsEmpty() ? 0 : space;
|
||||
}
|
||||
|
||||
void SetupGrowthPlan(nsTArray<TrackSize>& aPlan,
|
||||
const nsTArray<uint32_t>& aTracks) const
|
||||
template<TrackSizingPhase phase>
|
||||
void InitializeItemPlan(nsTArray<TrackSize>& aItemPlan,
|
||||
const nsTArray<uint32_t>& aTracks) const
|
||||
{
|
||||
for (uint32_t track : aTracks) {
|
||||
aPlan[track] = mSizes[track];
|
||||
auto& plan = aItemPlan[track];
|
||||
const TrackSize& sz = mSizes[track];
|
||||
plan.mBase = StartSizeInDistribution<phase>(sz);
|
||||
bool unlimited = sz.mState & TrackSize::eInfinitelyGrowable;
|
||||
plan.mLimit = unlimited ? NS_UNCONSTRAINEDSIZE : sz.mLimit;
|
||||
plan.mState = sz.mState;
|
||||
}
|
||||
}
|
||||
|
||||
void CopyPlanToBase(const nsTArray<TrackSize>& aPlan,
|
||||
const nsTArray<uint32_t>& aTracks)
|
||||
template<TrackSizingPhase phase>
|
||||
void InitializePlan(nsTArray<TrackSize>& aPlan) const
|
||||
{
|
||||
for (uint32_t track : aTracks) {
|
||||
MOZ_ASSERT(mSizes[track].mBase <= aPlan[track].mBase);
|
||||
mSizes[track].mBase = aPlan[track].mBase;
|
||||
for (size_t i = 0, len = aPlan.Length(); i < len; ++i) {
|
||||
auto& plan = aPlan[i];
|
||||
const auto& sz = mSizes[i];
|
||||
plan.mBase = StartSizeInDistribution<phase>(sz);
|
||||
MOZ_ASSERT(phase == TrackSizingPhase::eMaxContentMaximums ||
|
||||
!(sz.mState & TrackSize::eInfinitelyGrowable),
|
||||
"forgot to reset the eInfinitelyGrowable bit?");
|
||||
plan.mState = sz.mState;
|
||||
}
|
||||
}
|
||||
|
||||
void CopyPlanToLimit(const nsTArray<TrackSize>& aPlan,
|
||||
const nsTArray<uint32_t>& aTracks)
|
||||
template<TrackSizingPhase phase>
|
||||
void CopyPlanToSize(const nsTArray<TrackSize>& aPlan,
|
||||
bool aNeedInfinitelyGrowableFlag = false)
|
||||
{
|
||||
for (uint32_t track : aTracks) {
|
||||
MOZ_ASSERT(mSizes[track].mLimit == NS_UNCONSTRAINEDSIZE ||
|
||||
mSizes[track].mLimit <= aPlan[track].mBase);
|
||||
mSizes[track].mLimit = aPlan[track].mBase;
|
||||
for (size_t i = 0, len = mSizes.Length(); i < len; ++i) {
|
||||
const auto& plan = aPlan[i];
|
||||
MOZ_ASSERT(plan.mBase >= 0);
|
||||
auto& sz = mSizes[i];
|
||||
switch (phase) {
|
||||
case TrackSizingPhase::eIntrinsicMinimums:
|
||||
case TrackSizingPhase::eContentBasedMinimums:
|
||||
case TrackSizingPhase::eMaxContentMinimums:
|
||||
sz.mBase = plan.mBase;
|
||||
break;
|
||||
case TrackSizingPhase::eIntrinsicMaximums:
|
||||
if (plan.mState & TrackSize::eModified) {
|
||||
if (sz.mLimit == NS_UNCONSTRAINEDSIZE &&
|
||||
aNeedInfinitelyGrowableFlag) {
|
||||
sz.mState |= TrackSize::eInfinitelyGrowable;
|
||||
}
|
||||
sz.mLimit = plan.mBase;
|
||||
}
|
||||
break;
|
||||
case TrackSizingPhase::eMaxContentMaximums:
|
||||
if (plan.mState & TrackSize::eModified) {
|
||||
sz.mLimit = plan.mBase;
|
||||
}
|
||||
sz.mState &= ~TrackSize::eInfinitelyGrowable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using FitContentClamper =
|
||||
std::function<bool(uint32_t aTrack, nscoord aMinSize, nscoord* aSize)>;
|
||||
/**
|
||||
* Grow the planned size for tracks in aGrowableTracks up to their limit
|
||||
* and then freeze them (all aGrowableTracks must be unfrozen on entry).
|
||||
|
@ -1280,12 +1387,13 @@ struct nsGridContainerFrame::Tracks
|
|||
* assumed that aPlan have no aSkipFlag set for tracks in aGrowableTracks
|
||||
* on entry to this method.
|
||||
*/
|
||||
uint32_t MarkExcludedTracks(nsTArray<TrackSize>& aPlan,
|
||||
uint32_t aNumGrowable,
|
||||
const nsTArray<uint32_t>& aGrowableTracks,
|
||||
TrackSize::StateBits aMinSizingSelector,
|
||||
TrackSize::StateBits aMaxSizingSelector,
|
||||
TrackSize::StateBits aSkipFlag) const
|
||||
static uint32_t
|
||||
MarkExcludedTracks(nsTArray<TrackSize>& aPlan,
|
||||
uint32_t aNumGrowable,
|
||||
const nsTArray<uint32_t>& aGrowableTracks,
|
||||
TrackSize::StateBits aMinSizingSelector,
|
||||
TrackSize::StateBits aMaxSizingSelector,
|
||||
TrackSize::StateBits aSkipFlag)
|
||||
{
|
||||
bool foundOneSelected = false;
|
||||
bool foundOneGrowable = false;
|
||||
|
@ -1315,41 +1423,60 @@ struct nsGridContainerFrame::Tracks
|
|||
}
|
||||
|
||||
/**
|
||||
* Increase the planned size for tracks in aGrowableTracks that match
|
||||
* aSelector (or all tracks if aSelector is zero) beyond their limit.
|
||||
* Mark all tracks in aGrowableTracks with an eSkipGrowUnlimited bit if
|
||||
* they *shouldn't* grow unlimited in §11.5.1.2.3 "Distribute space beyond
|
||||
* growth limits" https://drafts.csswg.org/css-grid/#extra-space
|
||||
* Return the number of tracks that are still growable.
|
||||
*/
|
||||
template<TrackSizingPhase phase>
|
||||
static uint32_t
|
||||
MarkExcludedTracks(nsTArray<TrackSize>& aPlan,
|
||||
const nsTArray<uint32_t>& aGrowableTracks,
|
||||
TrackSize::StateBits aSelector)
|
||||
{
|
||||
uint32_t numGrowable = aGrowableTracks.Length();
|
||||
if (phase == TrackSizingPhase::eIntrinsicMaximums ||
|
||||
phase == TrackSizingPhase::eMaxContentMaximums) {
|
||||
// "when handling any intrinsic growth limit: all affected tracks"
|
||||
return numGrowable;
|
||||
}
|
||||
MOZ_ASSERT(aSelector == (aSelector & TrackSize::eIntrinsicMinSizing) &&
|
||||
(aSelector & TrackSize::eMaxContentMinSizing),
|
||||
"Should only get here for track sizing steps 2.1 to 2.3");
|
||||
// Note that eMaxContentMinSizing is always included. We do those first:
|
||||
numGrowable = MarkExcludedTracks(aPlan, numGrowable, aGrowableTracks,
|
||||
TrackSize::eMaxContentMinSizing,
|
||||
TrackSize::eMaxContentMaxSizing,
|
||||
TrackSize::eSkipGrowUnlimited1);
|
||||
// Now mark min-content/auto min-sizing tracks if requested.
|
||||
auto minOrAutoSelector = aSelector & ~TrackSize::eMaxContentMinSizing;
|
||||
if (minOrAutoSelector) {
|
||||
numGrowable = MarkExcludedTracks(aPlan, numGrowable, aGrowableTracks,
|
||||
minOrAutoSelector,
|
||||
TrackSize::eIntrinsicMaxSizing,
|
||||
TrackSize::eSkipGrowUnlimited2);
|
||||
}
|
||||
return numGrowable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the planned size for tracks in aGrowableTracks that aren't
|
||||
* marked with a eSkipGrowUnlimited flag beyond their limit.
|
||||
* This implements the "Distribute space beyond growth limits" step in
|
||||
* https://drafts.csswg.org/css-grid/#distribute-extra-space
|
||||
*/
|
||||
void GrowSelectedTracksUnlimited(nscoord aAvailableSpace,
|
||||
nsTArray<TrackSize>& aPlan,
|
||||
const nsTArray<uint32_t>& aGrowableTracks,
|
||||
TrackSize::StateBits aSelector,
|
||||
uint32_t aNumGrowable,
|
||||
const FitContentClamper& aFitContentClamper) const
|
||||
{
|
||||
MOZ_ASSERT(aAvailableSpace > 0 && aGrowableTracks.Length() > 0);
|
||||
uint32_t numGrowable = aGrowableTracks.Length();
|
||||
if (aSelector) {
|
||||
MOZ_ASSERT(aSelector == (aSelector & TrackSize::eIntrinsicMinSizing) &&
|
||||
(aSelector & TrackSize::eMaxContentMinSizing),
|
||||
"Should only get here for track sizing steps 2.1 to 2.3");
|
||||
// Note that eMaxContentMinSizing is always included. We do those first:
|
||||
numGrowable = MarkExcludedTracks(aPlan, numGrowable, aGrowableTracks,
|
||||
TrackSize::eMaxContentMinSizing,
|
||||
TrackSize::eMaxContentMaxSizing,
|
||||
TrackSize::eSkipGrowUnlimited1);
|
||||
// Now mark min-content/auto min-sizing tracks if requested.
|
||||
auto minOrAutoSelector = aSelector & ~TrackSize::eMaxContentMinSizing;
|
||||
if (minOrAutoSelector) {
|
||||
numGrowable = MarkExcludedTracks(aPlan, numGrowable, aGrowableTracks,
|
||||
minOrAutoSelector,
|
||||
TrackSize::eIntrinsicMaxSizing,
|
||||
TrackSize::eSkipGrowUnlimited2);
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(aAvailableSpace > 0 && aGrowableTracks.Length() > 0 &&
|
||||
aNumGrowable <= aGrowableTracks.Length());
|
||||
nscoord space = aAvailableSpace;
|
||||
DebugOnly<bool> didClamp = false;
|
||||
while (numGrowable) {
|
||||
nscoord spacePerTrack = std::max<nscoord>(space / numGrowable, 1);
|
||||
while (aNumGrowable) {
|
||||
nscoord spacePerTrack = std::max<nscoord>(space / aNumGrowable, 1);
|
||||
for (uint32_t track : aGrowableTracks) {
|
||||
TrackSize& sz = aPlan[track];
|
||||
if (sz.mState & TrackSize::eSkipGrowUnlimited) {
|
||||
|
@ -1365,7 +1492,7 @@ struct nsGridContainerFrame::Tracks
|
|||
delta = newBase - sz.mBase;
|
||||
MOZ_ASSERT(delta >= 0, "track size shouldn't shrink");
|
||||
sz.mState |= TrackSize::eSkipGrowUnlimited1;
|
||||
--numGrowable;
|
||||
--aNumGrowable;
|
||||
}
|
||||
}
|
||||
sz.mBase = newBase;
|
||||
|
@ -1384,46 +1511,30 @@ struct nsGridContainerFrame::Tracks
|
|||
* Distribute aAvailableSpace to the planned base size for aGrowableTracks
|
||||
* up to their limits, then distribute the remaining space beyond the limits.
|
||||
*/
|
||||
void DistributeToTrackBases(nscoord aAvailableSpace,
|
||||
template<TrackSizingPhase phase>
|
||||
void DistributeToTrackSizes(nscoord aAvailableSpace,
|
||||
nsTArray<TrackSize>& aPlan,
|
||||
nsTArray<TrackSize>& aItemPlan,
|
||||
nsTArray<uint32_t>& aGrowableTracks,
|
||||
TrackSize::StateBits aSelector)
|
||||
TrackSize::StateBits aSelector,
|
||||
const FitContentClamper& aFitContentClamper)
|
||||
{
|
||||
SetupGrowthPlan(aPlan, aGrowableTracks);
|
||||
nscoord space = GrowTracksToLimit(aAvailableSpace, aPlan, aGrowableTracks, nullptr);
|
||||
InitializeItemPlan<phase>(aItemPlan, aGrowableTracks);
|
||||
nscoord space = GrowTracksToLimit(aAvailableSpace, aItemPlan, aGrowableTracks,
|
||||
aFitContentClamper);
|
||||
if (space > 0) {
|
||||
GrowSelectedTracksUnlimited(space, aPlan, aGrowableTracks, aSelector, nullptr);
|
||||
uint32_t numGrowable =
|
||||
MarkExcludedTracks<phase>(aItemPlan, aGrowableTracks, aSelector);
|
||||
GrowSelectedTracksUnlimited(space, aItemPlan, aGrowableTracks,
|
||||
numGrowable, aFitContentClamper);
|
||||
}
|
||||
CopyPlanToBase(aPlan, aGrowableTracks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Distribute aAvailableSpace to the planned limits for aGrowableTracks.
|
||||
*/
|
||||
void DistributeToTrackLimits(nscoord aAvailableSpace,
|
||||
nsTArray<TrackSize>& aPlan,
|
||||
nsTArray<uint32_t>& aGrowableTracks,
|
||||
const TrackSizingFunctions& aFunctions,
|
||||
nscoord aPercentageBasis)
|
||||
{
|
||||
auto fitContentClamper = [&aFunctions, aPercentageBasis] (uint32_t aTrack,
|
||||
nscoord aMinSize,
|
||||
nscoord* aSize) {
|
||||
nscoord fitContentLimit =
|
||||
::ResolveToDefiniteSize(aFunctions.MaxSizingFor(aTrack), aPercentageBasis);
|
||||
if (*aSize > fitContentLimit) {
|
||||
*aSize = std::max(aMinSize, fitContentLimit);
|
||||
return true;
|
||||
for (uint32_t track : aGrowableTracks) {
|
||||
nscoord& plannedSize = aPlan[track].mBase;
|
||||
nscoord itemIncurredSize = aItemPlan[track].mBase;
|
||||
if (plannedSize < itemIncurredSize) {
|
||||
plannedSize = itemIncurredSize;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
nscoord space = GrowTracksToLimit(aAvailableSpace, aPlan, aGrowableTracks,
|
||||
fitContentClamper);
|
||||
if (space > 0) {
|
||||
GrowSelectedTracksUnlimited(aAvailableSpace, aPlan, aGrowableTracks,
|
||||
TrackSize::StateBits(0), fitContentClamper);
|
||||
}
|
||||
CopyPlanToLimit(aPlan, aGrowableTracks);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4136,6 +4247,55 @@ nsGridContainerFrame::Tracks::AlignBaselineSubtree(
|
|||
}
|
||||
}
|
||||
|
||||
template<nsGridContainerFrame::Tracks::TrackSizingPhase phase>
|
||||
bool
|
||||
nsGridContainerFrame::Tracks::GrowSizeForSpanningItems(
|
||||
nsTArray<Step2ItemData>::iterator aIter,
|
||||
const nsTArray<Step2ItemData>::iterator aIterEnd,
|
||||
nsTArray<uint32_t>& aTracks,
|
||||
nsTArray<TrackSize>& aPlan,
|
||||
nsTArray<TrackSize>& aItemPlan,
|
||||
TrackSize::StateBits aSelector,
|
||||
const FitContentClamper& aFitContentClamper,
|
||||
bool aNeedInfinitelyGrowableFlag)
|
||||
{
|
||||
constexpr bool isMaxSizingPhase =
|
||||
phase == TrackSizingPhase::eIntrinsicMaximums ||
|
||||
phase == TrackSizingPhase::eMaxContentMaximums;
|
||||
bool needToUpdateSizes = false;
|
||||
InitializePlan<phase>(aPlan);
|
||||
for (; aIter != aIterEnd; ++aIter) {
|
||||
const Step2ItemData& item = *aIter;
|
||||
if (!(item.mState & aSelector)) {
|
||||
continue;
|
||||
}
|
||||
if (isMaxSizingPhase) {
|
||||
for (auto j = item.mLineRange.mStart, end = item.mLineRange.mEnd; j < end; ++j) {
|
||||
aPlan[j].mState |= TrackSize::eModified;
|
||||
}
|
||||
}
|
||||
nscoord space = item.SizeContributionForPhase<phase>();
|
||||
if (space <= 0) {
|
||||
continue;
|
||||
}
|
||||
aTracks.ClearAndRetainStorage();
|
||||
space = CollectGrowable<phase>(space, item.mLineRange, aSelector,
|
||||
aTracks);
|
||||
if (space > 0) {
|
||||
DistributeToTrackSizes<phase>(space, aPlan, aItemPlan, aTracks, aSelector,
|
||||
aFitContentClamper);
|
||||
needToUpdateSizes = true;
|
||||
}
|
||||
}
|
||||
if (isMaxSizingPhase) {
|
||||
needToUpdateSizes = true;
|
||||
}
|
||||
if (needToUpdateSizes) {
|
||||
CopyPlanToSize<phase>(aPlan, aNeedInfinitelyGrowableFlag);
|
||||
}
|
||||
return needToUpdateSizes;
|
||||
}
|
||||
|
||||
void
|
||||
nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
|
||||
GridReflowInput& aState,
|
||||
|
@ -4145,22 +4305,6 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
|
|||
nscoord aPercentageBasis,
|
||||
SizingConstraint aConstraint)
|
||||
{
|
||||
// Some data we collect on each item for Step 2 of the algorithm below.
|
||||
struct Step2ItemData
|
||||
{
|
||||
uint32_t mSpan;
|
||||
TrackSize::StateBits mState;
|
||||
LineRange mLineRange;
|
||||
nscoord mMinSize;
|
||||
nscoord mMinContentContribution;
|
||||
nscoord mMaxContentContribution;
|
||||
nsIFrame* mFrame;
|
||||
static bool IsSpanLessThan(const Step2ItemData& a, const Step2ItemData& b)
|
||||
{
|
||||
return a.mSpan < b.mSpan;
|
||||
}
|
||||
};
|
||||
|
||||
// Resolve Intrinsic Track Sizes
|
||||
// http://dev.w3.org/csswg/css-grid/#algo-content
|
||||
// We're also setting eIsFlexing on the item state here to speed up
|
||||
|
@ -4270,6 +4414,19 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
|
|||
|
||||
// Step 2.
|
||||
if (maxSpan) {
|
||||
auto fitContentClamper = [&aFunctions, aPercentageBasis] (uint32_t aTrack,
|
||||
nscoord aMinSize,
|
||||
nscoord* aSize)
|
||||
{
|
||||
nscoord fitContentLimit =
|
||||
::ResolveToDefiniteSize(aFunctions.MaxSizingFor(aTrack), aPercentageBasis);
|
||||
if (*aSize > fitContentLimit) {
|
||||
*aSize = std::max(aMinSize, fitContentLimit);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Sort the collected items on span length, shortest first.
|
||||
std::stable_sort(step2Items.begin(), step2Items.end(),
|
||||
Step2ItemData::IsSpanLessThan);
|
||||
|
@ -4277,85 +4434,44 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
|
|||
nsTArray<uint32_t> tracks(maxSpan);
|
||||
nsTArray<TrackSize> plan(mSizes.Length());
|
||||
plan.SetLength(mSizes.Length());
|
||||
for (uint32_t i = 0, len = step2Items.Length(); i < len; ) {
|
||||
// Start / end index for items of the same span length:
|
||||
const uint32_t spanGroupStartIndex = i;
|
||||
uint32_t spanGroupEndIndex = len;
|
||||
const uint32_t span = step2Items[i].mSpan;
|
||||
for (++i; i < len; ++i) {
|
||||
if (step2Items[i].mSpan != span) {
|
||||
spanGroupEndIndex = i;
|
||||
break;
|
||||
}
|
||||
nsTArray<TrackSize> itemPlan(mSizes.Length());
|
||||
itemPlan.SetLength(mSizes.Length());
|
||||
// Start / end iterator for items of the same span length:
|
||||
auto spanGroupStart = step2Items.begin();
|
||||
auto spanGroupEnd = spanGroupStart;
|
||||
const auto end = step2Items.end();
|
||||
for (; spanGroupStart != end; spanGroupStart = spanGroupEnd) {
|
||||
while (spanGroupEnd != end &&
|
||||
!Step2ItemData::IsSpanLessThan(*spanGroupStart, *spanGroupEnd)) {
|
||||
++spanGroupEnd;
|
||||
}
|
||||
|
||||
const uint32_t span = spanGroupStart->mSpan;
|
||||
bool updatedBase = false; // Did we update any mBase in step 2.1 - 2.3?
|
||||
TrackSize::StateBits selector(TrackSize::eIntrinsicMinSizing);
|
||||
if (stateBitsPerSpan[span] & selector) {
|
||||
// Step 2.1 MinSize to intrinsic min-sizing.
|
||||
for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
|
||||
Step2ItemData& item = step2Items[i];
|
||||
if (!(item.mState & selector)) {
|
||||
continue;
|
||||
}
|
||||
nscoord space = item.mMinSize;
|
||||
if (space <= 0) {
|
||||
continue;
|
||||
}
|
||||
tracks.ClearAndRetainStorage();
|
||||
space = CollectGrowable(space, mSizes, item.mLineRange, selector,
|
||||
tracks);
|
||||
if (space > 0) {
|
||||
DistributeToTrackBases(space, plan, tracks, selector);
|
||||
updatedBase = true;
|
||||
}
|
||||
}
|
||||
updatedBase =
|
||||
GrowSizeForSpanningItems<TrackSizingPhase::eIntrinsicMinimums>(
|
||||
spanGroupStart, spanGroupEnd, tracks, plan, itemPlan, selector);
|
||||
}
|
||||
|
||||
selector = contentBasedMinSelector;
|
||||
if (stateBitsPerSpan[span] & selector) {
|
||||
// Step 2.2 MinContentContribution to min-/max-content (and 'auto' when
|
||||
// sizing under a min-content constraint) min-sizing.
|
||||
for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
|
||||
Step2ItemData& item = step2Items[i];
|
||||
if (!(item.mState & selector)) {
|
||||
continue;
|
||||
}
|
||||
nscoord space = item.mMinContentContribution;
|
||||
if (space <= 0) {
|
||||
continue;
|
||||
}
|
||||
tracks.ClearAndRetainStorage();
|
||||
space = CollectGrowable(space, mSizes, item.mLineRange, selector,
|
||||
tracks);
|
||||
if (space > 0) {
|
||||
DistributeToTrackBases(space, plan, tracks, selector);
|
||||
updatedBase = true;
|
||||
}
|
||||
}
|
||||
updatedBase |=
|
||||
GrowSizeForSpanningItems<TrackSizingPhase::eContentBasedMinimums>(
|
||||
spanGroupStart, spanGroupEnd, tracks, plan, itemPlan, selector);
|
||||
}
|
||||
|
||||
selector = maxContentMinSelector;
|
||||
if (stateBitsPerSpan[span] & selector) {
|
||||
// Step 2.3 MaxContentContribution to max-content (and 'auto' when
|
||||
// sizing under a max-content constraint) min-sizing.
|
||||
for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
|
||||
Step2ItemData& item = step2Items[i];
|
||||
if (!(item.mState & selector)) {
|
||||
continue;
|
||||
}
|
||||
nscoord space = item.mMaxContentContribution;
|
||||
if (space <= 0) {
|
||||
continue;
|
||||
}
|
||||
tracks.ClearAndRetainStorage();
|
||||
space = CollectGrowable(space, mSizes, item.mLineRange, selector,
|
||||
tracks);
|
||||
if (space > 0) {
|
||||
DistributeToTrackBases(space, plan, tracks, selector);
|
||||
updatedBase = true;
|
||||
}
|
||||
}
|
||||
updatedBase |=
|
||||
GrowSizeForSpanningItems<TrackSizingPhase::eMaxContentMinimums>(
|
||||
spanGroupStart, spanGroupEnd, tracks, plan, itemPlan, selector);
|
||||
}
|
||||
|
||||
if (updatedBase) {
|
||||
|
@ -4366,63 +4482,22 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
|
|||
}
|
||||
}
|
||||
}
|
||||
if (stateBitsPerSpan[span] & TrackSize::eIntrinsicMaxSizing) {
|
||||
plan = mSizes;
|
||||
for (TrackSize& sz : plan) {
|
||||
if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
|
||||
// use mBase as the planned limit
|
||||
} else {
|
||||
sz.mBase = sz.mLimit;
|
||||
}
|
||||
}
|
||||
|
||||
selector = TrackSize::eIntrinsicMaxSizing;
|
||||
if (stateBitsPerSpan[span] & selector) {
|
||||
const bool willRunStep2_6 =
|
||||
stateBitsPerSpan[span] & TrackSize::eAutoOrMaxContentMaxSizing;
|
||||
// Step 2.5 MinSize to intrinsic max-sizing.
|
||||
for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
|
||||
Step2ItemData& item = step2Items[i];
|
||||
if (!(item.mState & TrackSize::eIntrinsicMaxSizing)) {
|
||||
continue;
|
||||
}
|
||||
nscoord space = item.mMinSize;
|
||||
if (space <= 0) {
|
||||
continue;
|
||||
}
|
||||
tracks.ClearAndRetainStorage();
|
||||
space = CollectGrowable(space, plan, item.mLineRange,
|
||||
TrackSize::eIntrinsicMaxSizing,
|
||||
tracks);
|
||||
if (space > 0) {
|
||||
DistributeToTrackLimits(space, plan, tracks, aFunctions,
|
||||
aPercentageBasis);
|
||||
}
|
||||
}
|
||||
for (size_t j = 0, len = mSizes.Length(); j < len; ++j) {
|
||||
TrackSize& sz = plan[j];
|
||||
sz.mState &= ~(TrackSize::eFrozen | TrackSize::eSkipGrowUnlimited);
|
||||
if (sz.mLimit != NS_UNCONSTRAINEDSIZE) {
|
||||
sz.mLimit = sz.mBase; // collect the results from 2.5
|
||||
}
|
||||
}
|
||||
GrowSizeForSpanningItems<TrackSizingPhase::eIntrinsicMaximums>(
|
||||
spanGroupStart, spanGroupEnd, tracks, plan, itemPlan, selector,
|
||||
fitContentClamper, willRunStep2_6);
|
||||
|
||||
if (stateBitsPerSpan[span] & TrackSize::eAutoOrMaxContentMaxSizing) {
|
||||
if (willRunStep2_6) {
|
||||
// Step 2.6 MaxContentContribution to max-content max-sizing.
|
||||
for (i = spanGroupStartIndex; i < spanGroupEndIndex; ++i) {
|
||||
Step2ItemData& item = step2Items[i];
|
||||
if (!(item.mState & TrackSize::eAutoOrMaxContentMaxSizing)) {
|
||||
continue;
|
||||
}
|
||||
nscoord space = item.mMaxContentContribution;
|
||||
if (space <= 0) {
|
||||
continue;
|
||||
}
|
||||
tracks.ClearAndRetainStorage();
|
||||
space = CollectGrowable(space, plan, item.mLineRange,
|
||||
TrackSize::eAutoOrMaxContentMaxSizing,
|
||||
tracks);
|
||||
if (space > 0) {
|
||||
DistributeToTrackLimits(space, plan, tracks, aFunctions,
|
||||
aPercentageBasis);
|
||||
}
|
||||
}
|
||||
selector = TrackSize::eAutoOrMaxContentMaxSizing;
|
||||
GrowSizeForSpanningItems<TrackSizingPhase::eMaxContentMaximums>(
|
||||
spanGroupStart, spanGroupEnd, tracks, plan, itemPlan, selector,
|
||||
fitContentClamper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6944,6 +7019,9 @@ nsGridContainerFrame::TrackSize::Dump() const
|
|||
if (mState & eFrozen) {
|
||||
printf("frozen ");
|
||||
}
|
||||
if (mState & eModified) {
|
||||
printf("modified ");
|
||||
}
|
||||
if (mState & eBreakBefore) {
|
||||
printf("break-before ");
|
||||
}
|
||||
|
|
|
@ -142,3 +142,7 @@ support-files = file_scroll_position_restore.html
|
|||
[test_scroll_position_restore_after_stop.html]
|
||||
[test_scroll_animation_restore.html]
|
||||
[test_scroll_position_iframe.html]
|
||||
[test_grid_track_sizing_algo_001.html]
|
||||
skip-if = debug == true # the test is slow
|
||||
[test_grid_track_sizing_algo_002.html]
|
||||
skip-if = debug == true # the test is slow
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -17,9 +17,9 @@ body,html { color:black; background:white; font-size:16px; padding:0; margin:0;
|
|||
clear:left;
|
||||
}
|
||||
|
||||
.c1 { min-width:40px; margin-bottom: 2px; margin-right: 47px; }
|
||||
.c1 { width:40px; margin-bottom: 2px; margin-right: 47px; }
|
||||
.r1 { min-width:70px; margin-left: 38px; margin-top: 2px; }
|
||||
.c3 { min-width:0; margin: 2px 18px 1px 85px; }
|
||||
.c3 { width:10px; margin: 2px 18px 1px 71px; }
|
||||
|
||||
span {
|
||||
display: block;
|
||||
|
@ -52,21 +52,22 @@ x { display:inline-block; width:10px; height:18px; }
|
|||
<span class="r1"><x> </x></span>
|
||||
<span class="r1"><x> </x></span>
|
||||
</div>
|
||||
|
||||
<div class="grid" style="width:436px">
|
||||
<span class="c1" style="margin-right:41px"><x> </x></span>
|
||||
<span class="c1" style="width:374px; margin-right:41px"><x> </x></span>
|
||||
<span class="r1" style="margin-left:5px"><x> </x></span>
|
||||
<span class="c3" style="margin-left:405px; float:left;margin-top:1px;"><x> </x></span>
|
||||
</div>
|
||||
|
||||
<div class="grid" style="width:500px;">
|
||||
<span class="c1" style="min-width:20px;margin-right:448px"><x> </x></span>
|
||||
<span class="c1" style="width:20px;margin-right:448px"><x> </x></span>
|
||||
<span class="r1" style="min-width:10px;margin-left:28px; margin-right:426px"><x> </x></span>
|
||||
<span class="r1" style="min-width:30px;margin-left:28px; margin-right:426px"><x> </x></span>
|
||||
<span class="r1" style="min-width:10px;margin-left:28px; margin-right:426px"><x> </x></span>
|
||||
</div>
|
||||
|
||||
<div class="grid" style="width:583px;">
|
||||
<span class="c1" style="margin-right:55px"><x> </x></span>
|
||||
<span class="c1" style="width:507px; margin-right:55px"><x> </x></span>
|
||||
<span class="r1"><x> </x></span>
|
||||
<span class="c3" style="margin-left:538px; float:left;margin-top:1px;"><x> </x></span>
|
||||
</div>
|
||||
|
@ -74,13 +75,13 @@ x { display:inline-block; width:10px; height:18px; }
|
|||
<div class="grid" style="width:389px;">
|
||||
<span class="c1" style="width:100px"><x> </x></span>
|
||||
<span class="r1" style="width:300px;margin-left:68px;"><x> </x></span>
|
||||
<span class="c3" style="margin-left:245px;float:left;margin-top:1px;"><x> </x></span>
|
||||
<span class="c3" style="margin-left:131px;float:left;margin-top:1px;"><x> </x></span>
|
||||
</div>
|
||||
|
||||
<div class="grid" style="width:389px;">
|
||||
<span class="c1" style="width:100px"><x> </x></span>
|
||||
<span class="r1" style="width:300px;margin-left:68px;"><x> </x></span>
|
||||
<span class="c3" style="margin-left:245px;float:left;margin-top:1px;"><x> </x></span>
|
||||
<span class="c3" style="margin-left:131px;float:left;margin-top:1px;"><x> </x></span>
|
||||
</div>
|
||||
|
||||
|
||||
|
|
|
@ -21,9 +21,9 @@ body,html { color:black; background:white; font-size:16px; padding:0; margin:0;
|
|||
clear:left;
|
||||
}
|
||||
|
||||
.c1 { min-width:40px; margin-bottom: 2px; margin-right: 47px; }
|
||||
.c1 { width:40px; margin-bottom: 2px; margin-right: 47px; }
|
||||
.r1 { min-width:70px; margin-left: 38px; margin-top: 2px; }
|
||||
.c3 { min-width:0; margin: 2px 18px 1px 85px; }
|
||||
.c3 { width:10px; margin: 2px 18px 1px 71px; }
|
||||
|
||||
span {
|
||||
display: block;
|
||||
|
@ -56,21 +56,22 @@ x { display:inline-block; width:10px; height:18px; }
|
|||
<span class="r1"><x> </x></span>
|
||||
<span class="r1"><x> </x></span>
|
||||
</div></div>
|
||||
|
||||
<div class="wrap"><div class="grid" style="width:436px">
|
||||
<span class="c1" style="margin-right:41px"><x> </x></span>
|
||||
<span class="c1" style="width:374px; margin-right:41px"><x> </x></span>
|
||||
<span class="r1" style="margin-left:5px"><x> </x></span>
|
||||
<span class="c3" style="margin-left:405px; float:left;margin-top:1px;"><x> </x></span>
|
||||
</div></div>
|
||||
|
||||
<div class="wrap" style="float:left;"><div class="grid" style="width:500px;">
|
||||
<span class="c1" style="min-width:20px;margin-right:448px"><x> </x></span>
|
||||
<span class="c1" style="width:20px;margin-right:448px"><x> </x></span>
|
||||
<span class="r1" style="min-width:10px;margin-left:28px; margin-right:426px"><x> </x></span>
|
||||
<span class="r1" style="min-width:30px;margin-left:28px; margin-right:426px"><x> </x></span>
|
||||
<span class="r1" style="min-width:10px;margin-left:28px; margin-right:426px"><x> </x></span>
|
||||
</div></div>
|
||||
|
||||
<div class="wrap"><div class="grid" style="width:583px;">
|
||||
<span class="c1" style="margin-right:55px"><x> </x></span>
|
||||
<span class="c1" style="width:507px; margin-right:55px"><x> </x></span>
|
||||
<span class="r1"><x> </x></span>
|
||||
<span class="c3" style="margin-left:538px; float:left;margin-top:1px;"><x> </x></span>
|
||||
</div></div>
|
||||
|
@ -78,13 +79,13 @@ x { display:inline-block; width:10px; height:18px; }
|
|||
<div class="wrap"><div class="grid" style="width:389px;">
|
||||
<span class="c1" style="width:100px"><x> </x></span>
|
||||
<span class="r1" style="width:300px;margin-left:68px;"><x> </x></span>
|
||||
<span class="c3" style="margin-left:245px;float:left;margin-top:1px;"><x> </x></span>
|
||||
<span class="c3" style="margin-left:131px;float:left;margin-top:1px;"><x> </x></span>
|
||||
</div></div>
|
||||
|
||||
<div class="wrap"><div class="grid" style="width:389px;">
|
||||
<span class="c1" style="width:100px"><x> </x></span>
|
||||
<span class="r1" style="width:300px;margin-left:68px;"><x> </x></span>
|
||||
<span class="c3" style="margin-left:245px;float:left;margin-top:1px;"><x> </x></span>
|
||||
<span class="c3" style="margin-left:131px;float:left;margin-top:1px;"><x> </x></span>
|
||||
</div></div>
|
||||
|
||||
|
||||
|
|
|
@ -127,10 +127,10 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
|||
}
|
||||
|
||||
.gF {
|
||||
grid-template-columns: 22px
|
||||
1px
|
||||
1px
|
||||
auto;
|
||||
grid-template-columns: 2px
|
||||
20px
|
||||
2px
|
||||
0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -51,8 +51,8 @@ x { display:inline-block; height:10px; width:18px; }
|
|||
<div class="grid flex" style="width:1px;height:1px;"><span class="c1" style="margin-top:1px"><x></x></span></div>
|
||||
-->
|
||||
|
||||
<div class="grid mm" style="width:0;height:0;"><span class="c1" style="min-width:23px;min-height:10px"><x></x></span><span class="c2" style="position:relative;left:14px;width:18px;min-width:0;z-index:-1"><x></x></span></div>
|
||||
<div class="grid mm" style="width:1px;height:1px;"><span class="c1" style="min-width:23px;min-height:10px"><x></x></span><span class="c2" style="position:relative;left:14px;width:18px;min-width:0;z-index:-1"><x></x></span></div>
|
||||
<div class="grid mm" style="width:0;height:0;"><span class="c1" style="min-width:18px;min-height:10px"><x></x></span><span class="c2" style="position:relative;left:14px;width:18px;min-width:0;z-index:-1"><x></x></span></div>
|
||||
<div class="grid mm" style="width:1px;height:1px;"><span class="c1" style="min-width:18px;min-height:10px"><x></x></span><span class="c2" style="position:relative;left:14px;width:18px;min-width:0;z-index:-1"><x></x></span></div>
|
||||
<!-- TODO: fails due to broken align:stretch
|
||||
<div class="grid zero" style="width:0;height:0;"><span class="c1"><x></x></span></div>
|
||||
<div class="grid zero" style="width:1px;height:1px;"><span class="c1"><x></x></span></div>
|
||||
|
|
|
@ -27,34 +27,34 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
|||
background: grey;
|
||||
}
|
||||
.g1 .d1 {
|
||||
width: 52px;
|
||||
width: 0px;
|
||||
}
|
||||
.g2 .d1 {
|
||||
width: 56px;
|
||||
width: 0px;
|
||||
}
|
||||
.g2f .d1 {
|
||||
width: 69px;
|
||||
width: 0px;
|
||||
}
|
||||
.g3 .d1 {
|
||||
width: 56px;
|
||||
width: 0px;
|
||||
}
|
||||
.g4 .d1 {
|
||||
width: 96px;
|
||||
width: 80px;
|
||||
}
|
||||
.g4f .d1 {
|
||||
width: 69px;
|
||||
width: 0px;
|
||||
}
|
||||
.g5 .d1 {
|
||||
width: 96px;
|
||||
width: 80px;
|
||||
}
|
||||
.g6 .d1 {
|
||||
width: 69px;
|
||||
width: 0px;
|
||||
}
|
||||
.g6f .d1 {
|
||||
width: 69px;
|
||||
width: 0px;
|
||||
}
|
||||
.g7 .d1 {
|
||||
width: 69px;
|
||||
width: 0px;
|
||||
}
|
||||
.g8 .t {
|
||||
width: 196px;
|
||||
|
@ -63,19 +63,19 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
|||
width: 200px;
|
||||
}
|
||||
.g9 .d1 {
|
||||
width: 69px;
|
||||
width: 0px;
|
||||
}
|
||||
.gA .d1 {
|
||||
width: 93px;
|
||||
width: 80px;
|
||||
}
|
||||
.gB .d1 {
|
||||
width: 93px;
|
||||
width: 80px;
|
||||
}
|
||||
.gC .d1 {
|
||||
width: 93px;
|
||||
width: 80px;
|
||||
}
|
||||
.gD .d1 {
|
||||
width: 93px;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.t { grid-column: span 1; border:2px solid; }
|
||||
|
|
|
@ -27,34 +27,34 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
|||
background: grey;
|
||||
}
|
||||
.g1 .d1 {
|
||||
width: 52px;
|
||||
width: 0px;
|
||||
}
|
||||
.g2 .d1 {
|
||||
width: 56px;
|
||||
width: 0px;
|
||||
}
|
||||
.g2f .d1 {
|
||||
width: 69px;
|
||||
}
|
||||
.g3 .d1 {
|
||||
width: 56px;
|
||||
width: 0px;
|
||||
}
|
||||
.g4 .d1 {
|
||||
width: 96px;
|
||||
width: 80px;
|
||||
}
|
||||
.g4f .d1 {
|
||||
width: 104px;
|
||||
}
|
||||
.g5 .d1 {
|
||||
width: 96px;
|
||||
width: 80px;
|
||||
}
|
||||
.g6 .d1 {
|
||||
width: 69px;
|
||||
width: 0px;
|
||||
}
|
||||
.g6f .d1 {
|
||||
width: 89px;
|
||||
}
|
||||
.g7 .d1 {
|
||||
width: 69px;
|
||||
width: 0px;
|
||||
}
|
||||
.g8 .t {
|
||||
width: 196px;
|
||||
|
@ -63,19 +63,19 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
|||
width: 200px;
|
||||
}
|
||||
.g9 .d1 {
|
||||
width: 69px;
|
||||
width: 0px;
|
||||
}
|
||||
.gA .d1 {
|
||||
width: 93px;
|
||||
width: 80px;
|
||||
}
|
||||
.gB .d1 {
|
||||
width: 93px;
|
||||
width: 80px;
|
||||
}
|
||||
.gC .d1 {
|
||||
width: 93px;
|
||||
width: 80px;
|
||||
}
|
||||
.gD .d1 {
|
||||
width: 93px;
|
||||
width: 80px;
|
||||
}
|
||||
.d2 {
|
||||
position: absolute;
|
||||
|
@ -84,10 +84,10 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
|||
background: blue;
|
||||
}
|
||||
.g1 .d2 {
|
||||
width: 448px;
|
||||
width: 500px;
|
||||
}
|
||||
.g2 .d2 {
|
||||
width: 444px;
|
||||
width: 500px;
|
||||
}
|
||||
.g2f .d2 {
|
||||
right: auto;
|
||||
|
@ -95,10 +95,10 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
|||
width: 35px;
|
||||
}
|
||||
.g3 .d2 {
|
||||
width: 444px;
|
||||
width: 500px;
|
||||
}
|
||||
.g4 .d2 {
|
||||
width: 404px;
|
||||
width: 420px;
|
||||
}
|
||||
.g4f .d2 {
|
||||
right: auto;
|
||||
|
@ -106,10 +106,10 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
|||
width: 35px;
|
||||
}
|
||||
.g5 .d2 {
|
||||
width: 404px;
|
||||
width: 420px;
|
||||
}
|
||||
.g6 .d2 {
|
||||
width: 431px;
|
||||
width: 500px;
|
||||
}
|
||||
.g6f .d2 {
|
||||
right: auto;
|
||||
|
@ -117,25 +117,25 @@ body,html { color:black; background:white; font-family:monospace; font-size:16px
|
|||
width: 35px;
|
||||
}
|
||||
.g7 .d2 {
|
||||
width: 431px;
|
||||
width: 500px;
|
||||
}
|
||||
.g8 .d2 {
|
||||
width: 300px;
|
||||
}
|
||||
.g9 .d2 {
|
||||
width: 431px;
|
||||
width: 500px;
|
||||
}
|
||||
.gA .d2 {
|
||||
width: 407px;
|
||||
width: 420px;
|
||||
}
|
||||
.gB .d2 {
|
||||
width: 407px;
|
||||
width: 420px;
|
||||
}
|
||||
.gC .d2 {
|
||||
width: 407px;
|
||||
width: 420px;
|
||||
}
|
||||
.gD .d2 {
|
||||
width: 407px;
|
||||
width: 420px;
|
||||
}
|
||||
|
||||
.t { grid-column: span 1; border:2px solid; }
|
||||
|
|
|
@ -65,7 +65,14 @@ static const uint32_t kGoldenRatioU32 = 0x9E3779B9U;
|
|||
|
||||
namespace detail {
|
||||
|
||||
inline uint32_t
|
||||
MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
|
||||
constexpr uint32_t
|
||||
RotateLeft5(uint32_t aValue)
|
||||
{
|
||||
return (aValue << 5) | (aValue >> 27);
|
||||
}
|
||||
|
||||
constexpr uint32_t
|
||||
AddU32ToHash(uint32_t aHash, uint32_t aValue)
|
||||
{
|
||||
/*
|
||||
|
@ -89,7 +96,7 @@ AddU32ToHash(uint32_t aHash, uint32_t aValue)
|
|||
* Otherwise, if |aHash| is 0 (as it often is for the beginning of a
|
||||
* message), the expression
|
||||
*
|
||||
* mozilla::WrappingMultiply(kGoldenRatioU32, RotateBitsLeft(aHash, 5))
|
||||
* mozilla::WrappingMultiply(kGoldenRatioU32, RotateLeft5(aHash))
|
||||
* |xor|
|
||||
* aValue
|
||||
*
|
||||
|
@ -110,14 +117,14 @@ AddU32ToHash(uint32_t aHash, uint32_t aValue)
|
|||
* more than enough for our purposes.)
|
||||
*/
|
||||
return mozilla::WrappingMultiply(kGoldenRatioU32,
|
||||
RotateLeft(aHash, 5) ^ aValue);
|
||||
RotateLeft5(aHash) ^ aValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* AddUintptrToHash takes sizeof(uintptr_t) as a template parameter.
|
||||
*/
|
||||
template<size_t PtrSize>
|
||||
inline uint32_t
|
||||
constexpr uint32_t
|
||||
AddUintptrToHash(uint32_t aHash, uintptr_t aValue)
|
||||
{
|
||||
return AddU32ToHash(aHash, static_cast<uint32_t>(aValue));
|
||||
|
@ -173,7 +180,7 @@ AddToHash(uint32_t aHash, A* aA)
|
|||
// implicitly converted to 32 bits and then passed to AddUintptrToHash() to be hashed.
|
||||
template<typename T,
|
||||
typename U = typename mozilla::EnableIf<mozilla::IsIntegral<T>::value>::Type>
|
||||
MOZ_MUST_USE inline uint32_t
|
||||
MOZ_MUST_USE constexpr uint32_t
|
||||
AddToHash(uint32_t aHash, T aA)
|
||||
{
|
||||
return detail::AddUintptrToHash<sizeof(T)>(aHash, aA);
|
||||
|
@ -213,6 +220,19 @@ HashUntilZero(const T* aStr)
|
|||
return hash;
|
||||
}
|
||||
|
||||
// This is a `constexpr` alternative to HashUntilZero(const T*). It should
|
||||
// only be used for compile-time computation because it uses recursion.
|
||||
// XXX: once support for GCC 4.9 is dropped, this function should be removed
|
||||
// and HashUntilZero(const T*) should be made `constexpr`.
|
||||
template<typename T>
|
||||
constexpr uint32_t
|
||||
ConstExprHashUntilZero(const T* aStr, uint32_t aHash)
|
||||
{
|
||||
return !*aStr
|
||||
? aHash
|
||||
: ConstExprHashUntilZero(aStr + 1, AddToHash(aHash, *aStr));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
uint32_t
|
||||
HashKnownLength(const T* aStr, size_t aLength)
|
||||
|
@ -257,6 +277,21 @@ HashString(const char16_t* aStr)
|
|||
return detail::HashUntilZero(aStr);
|
||||
}
|
||||
|
||||
// This is a `constexpr` alternative to HashString(const char16_t*). It should
|
||||
// only be used for compile-time computation because it uses recursion.
|
||||
//
|
||||
// You may need to use the
|
||||
// MOZ_{PUSH,POP}_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING macros if you use
|
||||
// this function. See the comment on those macros' definitions for more detail.
|
||||
//
|
||||
// XXX: once support for GCC 4.9 is dropped, this function should be removed
|
||||
// and HashString(const char16_t*) should be made `constexpr`.
|
||||
MOZ_MUST_USE constexpr uint32_t
|
||||
ConstExprHashString(const char16_t* aStr)
|
||||
{
|
||||
return detail::ConstExprHashUntilZero(aStr, 0);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE inline uint32_t
|
||||
HashString(const char16_t* aStr, size_t aLength)
|
||||
{
|
||||
|
|
|
@ -94,29 +94,16 @@ struct WrapToSignedHelper
|
|||
* happening.
|
||||
*/
|
||||
template<typename UnsignedType>
|
||||
inline constexpr typename detail::WrapToSignedHelper<UnsignedType>::SignedType
|
||||
constexpr typename detail::WrapToSignedHelper<UnsignedType>::SignedType
|
||||
WrapToSigned(UnsignedType aValue)
|
||||
{
|
||||
return detail::WrapToSignedHelper<UnsignedType>::compute(aValue);
|
||||
}
|
||||
|
||||
// The |mozilla::Wrapping*| functions aren't constexpr because MSVC warns about
|
||||
// well-defined unsigned integer overflows that may occur within the constexpr
|
||||
// math. If/when MSVC fix this bug, we should make them all constexpr.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/4kze989h.aspx (C4307)
|
||||
// https://developercommunity.visualstudio.com/content/problem/211134/unsigned-integer-overflows-in-constexpr-functionsa.html (bug report)
|
||||
//
|
||||
// For now there's no practical, readable way to avoid such overflows in pure
|
||||
// C++. And we can't add narrow #pragmas where overflow can occur to disable
|
||||
// the warnings, because constexpr apparently causes the warning to be emitted
|
||||
// at the outermost call *sites* (so every user of |mozilla::Wrapping*| would
|
||||
// have to add them).
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr T
|
||||
constexpr T
|
||||
ToResult(typename MakeUnsigned<T>::Type aUnsigned)
|
||||
{
|
||||
// We could *always* return WrapToSigned and rely on unsigned conversion to
|
||||
|
@ -132,7 +119,7 @@ private:
|
|||
|
||||
public:
|
||||
MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
|
||||
static T compute(T aX, T aY)
|
||||
static constexpr T compute(T aX, T aY)
|
||||
{
|
||||
return ToResult<T>(static_cast<UnsignedT>(aX) + static_cast<UnsignedT>(aY));
|
||||
}
|
||||
|
@ -165,7 +152,7 @@ public:
|
|||
* permissibly -- triggers different behavior.
|
||||
*/
|
||||
template<typename T>
|
||||
inline T
|
||||
constexpr T
|
||||
WrappingAdd(T aX, T aY)
|
||||
{
|
||||
return detail::WrappingAddHelper<T>::compute(aX, aY);
|
||||
|
@ -181,7 +168,7 @@ private:
|
|||
|
||||
public:
|
||||
MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
|
||||
static T compute(T aX, T aY)
|
||||
static constexpr T compute(T aX, T aY)
|
||||
{
|
||||
return ToResult<T>(static_cast<UnsignedT>(aX) - static_cast<UnsignedT>(aY));
|
||||
}
|
||||
|
@ -215,7 +202,7 @@ public:
|
|||
* permissibly -- triggers different behavior.
|
||||
*/
|
||||
template<typename T>
|
||||
inline T
|
||||
constexpr T
|
||||
WrappingSubtract(T aX, T aY)
|
||||
{
|
||||
return detail::WrappingSubtractHelper<T>::compute(aX, aY);
|
||||
|
@ -231,7 +218,7 @@ private:
|
|||
|
||||
public:
|
||||
MOZ_NO_SANITIZE_UNSIGNED_OVERFLOW
|
||||
static T compute(T aX, T aY)
|
||||
static constexpr T compute(T aX, T aY)
|
||||
{
|
||||
// Begin with |1U| to ensure the overall operation chain is never promoted
|
||||
// to signed integer operations that might have *signed* integer overflow.
|
||||
|
@ -277,12 +264,36 @@ public:
|
|||
* or similar -- quite permissibly -- triggers different behavior.
|
||||
*/
|
||||
template<typename T>
|
||||
inline T
|
||||
constexpr T
|
||||
WrappingMultiply(T aX, T aY)
|
||||
{
|
||||
return detail::WrappingMultiplyHelper<T>::compute(aX, aY);
|
||||
}
|
||||
|
||||
// The |mozilla::Wrapping*| functions are constexpr. Unfortunately, MSVC warns
|
||||
// about well-defined unsigned integer overflows that may occur within the
|
||||
// constexpr math.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/4kze989h.aspx (C4307)
|
||||
// https://developercommunity.visualstudio.com/content/problem/211134/unsigned-integer-overflows-in-constexpr-functionsa.html (bug report)
|
||||
//
|
||||
// So we need a way to suppress these warnings. Unfortunately, the warnings are
|
||||
// issued at the very top of the `constexpr` chain, which is often some
|
||||
// distance from the triggering Wrapping*() operation. So we can't suppress
|
||||
// them within this file. Instead, callers have to do it with these macros.
|
||||
//
|
||||
// If/when MSVC fix this bug, we should remove these macros.
|
||||
#ifdef _MSC_VER
|
||||
#define MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING \
|
||||
__pragma(warning(push)) \
|
||||
__pragma(warning(disable:4307))
|
||||
#define MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING \
|
||||
__pragma(warning(pop))
|
||||
#else
|
||||
#define MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
|
||||
#define MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
|
||||
#endif
|
||||
|
||||
} /* namespace mozilla */
|
||||
|
||||
#endif /* mozilla_WrappingOperations_h */
|
||||
|
|
|
@ -5,6 +5,14 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import copy
|
||||
import platform
|
||||
try:
|
||||
import winreg
|
||||
except ImportError:
|
||||
try:
|
||||
import _winreg as winreg
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
from marionette_harness import MarionetteTestCase
|
||||
|
||||
|
@ -34,9 +42,36 @@ class TestCommandLineArguments(MarionetteTestCase):
|
|||
|
||||
return Services.appinfo.inSafeMode;
|
||||
""")
|
||||
|
||||
self.assertTrue(safe_mode, "Safe Mode has not been enabled")
|
||||
|
||||
def test_safe_mode_blocked_by_policy(self):
|
||||
if platform.system() != 'Windows':
|
||||
return
|
||||
|
||||
reg_policies = winreg.OpenKeyEx(winreg.HKEY_CURRENT_USER, "SOFTWARE\\Policies", 0, winreg.KEY_WRITE)
|
||||
reg_mozilla = winreg.CreateKeyEx(reg_policies, "Mozilla", 0, winreg.KEY_WRITE)
|
||||
reg_firefox = winreg.CreateKeyEx(reg_mozilla, "Firefox", 0, winreg.KEY_WRITE)
|
||||
winreg.SetValueEx(reg_firefox, "DisableSafeMode", 0, winreg.REG_DWORD, 1)
|
||||
|
||||
self.marionette.instance.app_args.append("-safe-mode")
|
||||
|
||||
self.marionette.quit()
|
||||
self.marionette.start_session()
|
||||
|
||||
with self.marionette.using_context("chrome"):
|
||||
safe_mode = self.marionette.execute_script("""
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
return Services.appinfo.inSafeMode;
|
||||
""")
|
||||
self.assertFalse(safe_mode, "Safe Mode has been enabled")
|
||||
|
||||
winreg.CloseKey(reg_firefox)
|
||||
winreg.DeleteKey(reg_mozilla, "Firefox")
|
||||
winreg.CloseKey(reg_mozilla)
|
||||
winreg.DeleteKey(reg_policies, "Mozilla")
|
||||
winreg.CloseKey(reg_policies)
|
||||
|
||||
def test_startup_timeout(self):
|
||||
startup_timeout = self.marionette.startup_timeout
|
||||
|
||||
|
|
|
@ -319484,6 +319484,12 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"eventsource/dedicated-worker/eventsource-close2.htm": [
|
||||
[
|
||||
"/eventsource/dedicated-worker/eventsource-close2.htm",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"eventsource/dedicated-worker/eventsource-constructor-non-same-origin.htm": [
|
||||
[
|
||||
"/eventsource/dedicated-worker/eventsource-constructor-non-same-origin.htm",
|
||||
|
@ -390178,7 +390184,7 @@
|
|||
"manual"
|
||||
],
|
||||
"FileAPI/FileReader/workers.html": [
|
||||
"7e9f00c9af5bb982a1b549ebc9f5a3d0b5cf4387",
|
||||
"d7894a0abb064411d4811d8cfb9c3ce65f99babd",
|
||||
"testharness"
|
||||
],
|
||||
"FileAPI/FileReaderSync.worker.js": [
|
||||
|
@ -542317,6 +542323,10 @@
|
|||
"700107771158b22fa280f30a5a52d1aac617ff6e",
|
||||
"testharness"
|
||||
],
|
||||
"eventsource/dedicated-worker/eventsource-close2.htm": [
|
||||
"a3d13b0261b05eba56effb9ca3f6c31e312e777a",
|
||||
"testharness"
|
||||
],
|
||||
"eventsource/dedicated-worker/eventsource-constructor-non-same-origin.htm": [
|
||||
"9614ac5ce1967bbbcae6a1cc8d64465579f6410d",
|
||||
"testharness"
|
||||
|
@ -546826,7 +546836,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-height.html": [
|
||||
"caaede75e5c16cc78023ce410f48e37e612cffbb",
|
||||
"6da68164fdba8986d4dd217ad48198f675e83165",
|
||||
"testharness"
|
||||
],
|
||||
"html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-non-integer-innerheight.html": [
|
||||
|
@ -594606,7 +594616,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"websockets/Create-on-worker-shutdown.html": [
|
||||
"6c1e57e92b617fdb3d8dd86528af7073d21ece03",
|
||||
"e710493c0cd84630a1c853ada23c37908bece9cb",
|
||||
"testharness"
|
||||
],
|
||||
"websockets/Create-protocol-with-space.htm": [
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<!--
|
||||
self.close()
|
||||
var source = new EventSource("../resources/message.py")
|
||||
postMessage(source.readyState)
|
||||
/*-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>dedicated worker - EventSource created after: worker.close()</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
var test = async_test();
|
||||
test.step(function() {
|
||||
var worker = new Worker('#')
|
||||
worker.onmessage = function(e) {
|
||||
test.step(function() {
|
||||
assert_equals(e.data, EventSource.CONNECTING, 'this.readyState')
|
||||
})
|
||||
test.done()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<!--*/ //-->
|
|
@ -85,7 +85,11 @@ function refreshUI() {
|
|||
createButton.onclick = createProfileWizard;
|
||||
|
||||
let restartSafeModeButton = document.getElementById("restart-in-safe-mode-button");
|
||||
restartSafeModeButton.onclick = function() { restart(true); };
|
||||
if (!Services.policies || Services.policies.isAllowed("safeMode")) {
|
||||
restartSafeModeButton.onclick = function() { restart(true); };
|
||||
} else {
|
||||
restartSafeModeButton.setAttribute("disabled", "true");
|
||||
}
|
||||
|
||||
let restartNormalModeButton = document.getElementById("restart-button");
|
||||
restartNormalModeButton.onclick = function() { restart(false); };
|
||||
|
|
|
@ -1206,6 +1206,10 @@ function populateActionBox() {
|
|||
if (!Services.appinfo.inSafeMode && AppConstants.platform !== "android") {
|
||||
$("safe-mode-box").style.display = "block";
|
||||
$("action-box").style.display = "block";
|
||||
|
||||
if (Services.policies && !Services.policies.isAllowed("safeMode")) {
|
||||
$("restart-in-safe-mode-button").setAttribute("disabled", "true");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2778,17 +2778,12 @@ var gDetailView = {
|
|||
desc.textContent = aAddon.description;
|
||||
|
||||
var fullDesc = document.getElementById("detail-fulldesc");
|
||||
if (aAddon.fullDescription) {
|
||||
// The following is part of an awful hack to include the licenses for GMP
|
||||
// plugins without having bug 624602 fixed yet, and intentionally ignores
|
||||
// localisation.
|
||||
if (aAddon.isGMPlugin) {
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
fullDesc.unsafeSetInnerHTML(aAddon.fullDescription);
|
||||
} else {
|
||||
fullDesc.textContent = aAddon.fullDescription;
|
||||
}
|
||||
|
||||
if (aAddon.getFullDescription) {
|
||||
fullDesc.textContent = "";
|
||||
fullDesc.append(aAddon.getFullDescription(document));
|
||||
fullDesc.hidden = false;
|
||||
} else if (aAddon.fullDescription) {
|
||||
fullDesc.textContent = aAddon.fullDescription;
|
||||
fullDesc.hidden = false;
|
||||
} else {
|
||||
fullDesc.hidden = true;
|
||||
|
|
|
@ -29,6 +29,8 @@ const SEC_IN_A_DAY = 24 * 60 * 60;
|
|||
// How long to wait after a user enabled EME before attempting to download CDMs.
|
||||
const GMP_CHECK_DELAY = 10 * 1000; // milliseconds
|
||||
|
||||
const XHTML = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
const NS_GRE_DIR = "GreD";
|
||||
const CLEARKEY_PLUGIN_ID = "gmp-clearkey";
|
||||
const CLEARKEY_VERSION = "0.1";
|
||||
|
@ -95,8 +97,9 @@ function configureLogging() {
|
|||
* The GMPWrapper provides the info for the various GMP plugins to public
|
||||
* callers through the API.
|
||||
*/
|
||||
function GMPWrapper(aPluginInfo) {
|
||||
function GMPWrapper(aPluginInfo, aRawPluginInfo) {
|
||||
this._plugin = aPluginInfo;
|
||||
this._rawPlugin = aRawPluginInfo;
|
||||
this._log =
|
||||
Log.repository.getLoggerWithMessagePrefix("Toolkit.GMP",
|
||||
"GMPWrapper(" +
|
||||
|
@ -140,7 +143,31 @@ GMPWrapper.prototype = {
|
|||
get homepageURL() { return this._plugin.homepageURL; },
|
||||
|
||||
get description() { return this._plugin.description; },
|
||||
get fullDescription() { return this._plugin.fullDescription; },
|
||||
get fullDescription() { return null; },
|
||||
|
||||
getFullDescription(doc) {
|
||||
let plugin = this._rawPlugin;
|
||||
|
||||
let frag = doc.createDocumentFragment();
|
||||
for (let [urlProp, labelId] of [["learnMoreURL", GMP_LEARN_MORE],
|
||||
["licenseURL", this.id == WIDEVINE_ID ?
|
||||
GMP_PRIVACY_INFO : GMP_LICENSE_INFO]]) {
|
||||
if (plugin[urlProp]) {
|
||||
let a = doc.createElementNS(XHTML, "a");
|
||||
a.href = plugin[urlProp];
|
||||
a.target = "_blank";
|
||||
a.textContent = pluginsBundle.GetStringFromName(labelId);
|
||||
|
||||
if (frag.childElementCount) {
|
||||
frag.append(doc.createElementNS(XHTML, "br"),
|
||||
doc.createElementNS(XHTML, "br"));
|
||||
}
|
||||
frag.append(a);
|
||||
}
|
||||
}
|
||||
|
||||
return frag;
|
||||
},
|
||||
|
||||
get version() {
|
||||
return GMPPrefs.getString(GMPPrefs.KEY_PLUGIN_VERSION, null, this._plugin.id);
|
||||
|
@ -633,19 +660,6 @@ var GMPProvider = {
|
|||
return GMPPrefs.getBool(GMPPrefs.KEY_PROVIDER_ENABLED, false);
|
||||
},
|
||||
|
||||
generateFullDescription(aPlugin) {
|
||||
let rv = [];
|
||||
for (let [urlProp, labelId] of [["learnMoreURL", GMP_LEARN_MORE],
|
||||
["licenseURL", aPlugin.id == WIDEVINE_ID ?
|
||||
GMP_PRIVACY_INFO : GMP_LICENSE_INFO]]) {
|
||||
if (aPlugin[urlProp]) {
|
||||
let label = pluginsBundle.GetStringFromName(labelId);
|
||||
rv.push(`<xhtml:a href="${aPlugin[urlProp]}" target="_blank">${label}</xhtml:a>.`);
|
||||
}
|
||||
}
|
||||
return rv.length ? rv.join("<xhtml:br /><xhtml:br />") : undefined;
|
||||
},
|
||||
|
||||
buildPluginList() {
|
||||
this._plugins = new Map();
|
||||
for (let aPlugin of GMP_PLUGINS) {
|
||||
|
@ -658,8 +672,7 @@ var GMPProvider = {
|
|||
wrapper: null,
|
||||
isEME: aPlugin.isEME,
|
||||
};
|
||||
plugin.fullDescription = this.generateFullDescription(aPlugin);
|
||||
plugin.wrapper = new GMPWrapper(plugin);
|
||||
plugin.wrapper = new GMPWrapper(plugin, aPlugin);
|
||||
this._plugins.set(plugin.id, plugin);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -511,7 +511,10 @@ add_task(async function test_permissions_prompt() {
|
|||
return Promise.resolve();
|
||||
};
|
||||
|
||||
await promiseCompleteInstall(install);
|
||||
await Promise.all([
|
||||
promiseCompleteInstall(install),
|
||||
promiseWebExtensionStartup(),
|
||||
]);
|
||||
|
||||
notEqual(perminfo, undefined, "Permission handler was invoked");
|
||||
equal(perminfo.existingAddon, null, "Permission info does not include an existing addon");
|
||||
|
|
|
@ -3154,6 +3154,40 @@ public:
|
|||
#endif
|
||||
};
|
||||
|
||||
#ifdef XP_WIN
|
||||
namespace {
|
||||
|
||||
bool PolicyHasRegValue(HKEY aKey, LPCTSTR aName, DWORD* aValue)
|
||||
{
|
||||
HKEY hkey = NULL;
|
||||
LONG ret = RegOpenKeyExW(aKey,
|
||||
L"SOFTWARE\\Policies\\Mozilla\\Firefox", 0, KEY_READ, &hkey);
|
||||
if (ret != ERROR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
nsAutoRegKey key(hkey);
|
||||
DWORD len = sizeof(aValue);
|
||||
ret = RegQueryValueExW(hkey, aName, 0, NULL, (LPBYTE)aValue, &len);
|
||||
RegCloseKey(key);
|
||||
return ret == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool SafeModeBlockedByPolicy()
|
||||
{
|
||||
LPCTSTR policyName = L"DisableSafeMode";
|
||||
DWORD value;
|
||||
if (PolicyHasRegValue(HKEY_LOCAL_MACHINE, policyName, &value)) {
|
||||
return value == 1;
|
||||
}
|
||||
if (PolicyHasRegValue(HKEY_CURRENT_USER, policyName, &value)) {
|
||||
return value == 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
#endif // XP_WIN
|
||||
|
||||
/*
|
||||
* XRE_mainInit - Initial setup and command line parameter processing.
|
||||
* Main() will exit early if either return value != 0 or if aExitFlag is
|
||||
|
@ -3490,12 +3524,6 @@ XREMain::XRE_mainInit(bool* aExitFlag)
|
|||
gRestartArgv[gRestartArgc] = nullptr;
|
||||
|
||||
|
||||
if (EnvHasValue("MOZ_SAFE_MODE_RESTART")) {
|
||||
gSafeMode = true;
|
||||
// unset the env variable
|
||||
SaveToEnv("MOZ_SAFE_MODE_RESTART=");
|
||||
}
|
||||
|
||||
ar = CheckArg("safe-mode", true);
|
||||
if (ar == ARG_BAD) {
|
||||
PR_fprintf(PR_STDERR, "Error: argument --safe-mode is invalid when argument --osint is specified\n");
|
||||
|
@ -3525,6 +3553,20 @@ XREMain::XRE_mainInit(bool* aExitFlag)
|
|||
gSafeMode = true;
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
if (gSafeMode && SafeModeBlockedByPolicy()) {
|
||||
gSafeMode = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// The Safe Mode Policy should not be enforced for the env var case
|
||||
// (used by updater and crash-recovery).
|
||||
if (EnvHasValue("MOZ_SAFE_MODE_RESTART")) {
|
||||
gSafeMode = true;
|
||||
// unset the env variable
|
||||
SaveToEnv("MOZ_SAFE_MODE_RESTART=");
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
{
|
||||
// Add CPU microcode version to the crash report as "CPUMicrocodeVersion".
|
||||
|
|
Загрузка…
Ссылка в новой задаче