Merge mozilla-central to mozilla-autoland. r=merge a=merge CLOSED TREE

This commit is contained in:
btara 2017-11-12 12:48:22 +02:00
Родитель 48bd0d4658 fe75164c55
Коммит 7a9dcc4806
21 изменённых файлов: 460 добавлений и 105 удалений

Просмотреть файл

@ -27,7 +27,6 @@
#include "nsIURI.h"
#include "nsTextFormatter.h"
#include "OuterDocAccessible.h"
#include "Platform.h"
#include "Role.h"
#ifdef MOZ_ACCESSIBILITY_ATK
#include "RootAccessibleWrap.h"
@ -96,6 +95,15 @@ using namespace mozilla;
using namespace mozilla::a11y;
using namespace mozilla::dom;
/**
* Accessibility service force enable/disable preference.
* Supported values:
* Accessibility is force enabled (accessibility should always be enabled): -1
* Accessibility is enabled (will be started upon a request, default value): 0
* Accessibility is force disabled (never enable accessibility): 1
*/
#define PREF_ACCESSIBILITY_FORCE_DISABLED "accessibility.force_disabled"
////////////////////////////////////////////////////////////////////////////////
// Statics
////////////////////////////////////////////////////////////////////////////////
@ -269,6 +277,11 @@ New_MaybeImageOrToolbarButtonAccessible(nsIContent* aContent,
}
#endif
/**
* Cached value of the PREF_ACCESSIBILITY_FORCE_DISABLED preference.
*/
static int32_t sPlatformDisabledState = 0;
////////////////////////////////////////////////////////////////////////////////
// Markup maps array.
@ -1970,17 +1983,39 @@ XPCApplicationAcc()
EPlatformDisabledState
PlatformDisabledState()
{
static int disabledState = 0xff;
if (disabledState == 0xff) {
disabledState = Preferences::GetInt("accessibility.force_disabled", 0);
if (disabledState < ePlatformIsForceEnabled)
disabledState = ePlatformIsForceEnabled;
else if (disabledState > ePlatformIsDisabled)
disabledState = ePlatformIsDisabled;
static bool platformDisabledStateCached = false;
if (platformDisabledStateCached) {
return static_cast<EPlatformDisabledState>(sPlatformDisabledState);
}
return (EPlatformDisabledState)disabledState;
platformDisabledStateCached = true;
Preferences::RegisterCallback(PrefChanged, PREF_ACCESSIBILITY_FORCE_DISABLED);
return ReadPlatformDisabledState();
}
EPlatformDisabledState
ReadPlatformDisabledState()
{
sPlatformDisabledState = Preferences::GetInt(PREF_ACCESSIBILITY_FORCE_DISABLED, 0);
if (sPlatformDisabledState < ePlatformIsForceEnabled) {
sPlatformDisabledState = ePlatformIsForceEnabled;
} else if (sPlatformDisabledState > ePlatformIsDisabled){
sPlatformDisabledState = ePlatformIsDisabled;
}
return static_cast<EPlatformDisabledState>(sPlatformDisabledState);
}
void
PrefChanged(const char* aPref, void* aClosure)
{
if (ReadPlatformDisabledState() == ePlatformIsDisabled) {
// Force shut down accessibility.
nsAccessibilityService* accService = nsAccessibilityService::gAccessibilityService;
if (accService && !accService->IsShutdown()) {
accService->Shutdown();
}
}
}
}

Просмотреть файл

@ -8,6 +8,7 @@
#include "mozilla/a11y/DocManager.h"
#include "mozilla/a11y/FocusManager.h"
#include "mozilla/a11y/Platform.h"
#include "mozilla/a11y/Role.h"
#include "mozilla/a11y/SelectionManager.h"
#include "mozilla/Preferences.h"
@ -74,6 +75,16 @@ struct XULMarkupMapInfo {
};
#endif
/**
* PREF_ACCESSIBILITY_FORCE_DISABLED preference change callback.
*/
void PrefChanged(const char* aPref, void* aClosure);
/**
* Read and normalize PREF_ACCESSIBILITY_FORCE_DISABLED preference.
*/
EPlatformDisabledState ReadPlatformDisabledState();
} // namespace a11y
} // namespace mozilla
@ -340,6 +351,7 @@ private:
friend nsAccessibilityService* GetAccService();
friend nsAccessibilityService* GetOrCreateAccService(uint32_t);
friend void MaybeShutdownAccService(uint32_t);
friend void mozilla::a11y::PrefChanged(const char*, void*);
friend mozilla::a11y::FocusManager* mozilla::a11y::FocusMgr();
friend mozilla::a11y::SelectionManager* mozilla::a11y::SelectionMgr();
friend mozilla::a11y::ApplicationAccessible* mozilla::a11y::ApplicationAcc();

Просмотреть файл

@ -12,6 +12,7 @@ support-files =
[browser_shutdown_multi_reference.js]
[browser_shutdown_parent_own_reference.js]
skip-if = !e10s || (os == 'win' && os_version == '5.1') # e10s specific test for a11y start/shutdown between parent and content.
[browser_shutdown_pref.js]
[browser_shutdown_proxy_acc_reference.js]
skip-if = !e10s || (os == 'win') # e10s specific test for a11y start/shutdown between parent and content.
[browser_shutdown_proxy_doc_acc_reference.js]

Просмотреть файл

@ -0,0 +1,55 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const PREF_ACCESSIBILITY_FORCE_DISABLED = "accessibility.force_disabled";
add_task(async function testForceDisable() {
ok(!Services.appinfo.accessibilityEnabled, "Accessibility is disabled by default");
info("Reset force disabled preference");
Services.prefs.clearUserPref(PREF_ACCESSIBILITY_FORCE_DISABLED);
info("Enable accessibility service via XPCOM");
let a11yInit = initPromise();
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
await a11yInit;
ok(Services.appinfo.accessibilityEnabled, "Accessibility is enabled");
info("Force disable a11y service via preference");
let a11yShutdown = shutdownPromise();
Services.prefs.setIntPref(PREF_ACCESSIBILITY_FORCE_DISABLED, 1);
await a11yShutdown;
ok(!Services.appinfo.accessibilityEnabled, "Accessibility is disabled");
info("Attempt to get an instance of a11y service and call its method.");
accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
try {
accService.getAccesssibleFor(document);
ok(false, "getAccesssibleFor should've triggered an exception.");
} catch (e) {
ok(true, "getAccesssibleFor triggers an exception as a11y service is shutdown.");
}
ok(!Services.appinfo.accessibilityEnabled, "Accessibility is disabled");
info("Reset force disabled preference");
Services.prefs.clearUserPref(PREF_ACCESSIBILITY_FORCE_DISABLED);
info("Create a11y service again");
a11yInit = initPromise();
accService = Cc["@mozilla.org/accessibilityService;1"].getService(
Ci.nsIAccessibilityService);
await a11yInit;
ok(Services.appinfo.accessibilityEnabled, "Accessibility is enabled");
info("Remove all references to a11y service");
a11yShutdown = shutdownPromise();
accService = null;
forceGC();
await a11yShutdown;
ok(!Services.appinfo.accessibilityEnabled, "Accessibility is disabled");
});

Просмотреть файл

@ -6,6 +6,7 @@
#include "nsAccessiblePivot.h"
#include "nsAccessibilityService.h"
#include "Platform.h"
#ifdef A11Y_LOG
#include "Logging.h"
@ -43,7 +44,9 @@ xpcAccessibilityService::AddRef(void)
nsrefcnt count = ++mRefCnt;
NS_LOG_ADDREF(this, count, "xpcAccessibilityService", sizeof(*this));
if (mRefCnt > 1) {
// We want refcount to be > 1 because one reference is added in the XPCOM
// accessibility service getter.
if (mRefCnt > 1 && PlatformDisabledState() != ePlatformIsDisabled) {
GetOrCreateAccService(nsAccessibilityService::eXPCOM);
}
@ -114,7 +117,12 @@ xpcAccessibilityService::GetAccessibleFor(nsIDOMNode *aNode,
return NS_ERROR_INVALID_ARG;
}
DocAccessible* document = GetAccService()->GetDocAccessible(node->OwnerDoc());
nsAccessibilityService* accService = GetAccService();
if (!accService) {
return NS_ERROR_SERVICE_NOT_AVAILABLE;
}
DocAccessible* document = accService->GetDocAccessible(node->OwnerDoc());
if (document) {
NS_IF_ADDREF(*aAccessible = ToXPC(document->GetAccessible(node)));
}
@ -125,7 +133,12 @@ xpcAccessibilityService::GetAccessibleFor(nsIDOMNode *aNode,
NS_IMETHODIMP
xpcAccessibilityService::GetStringRole(uint32_t aRole, nsAString& aString)
{
GetAccService()->GetStringRole(aRole, aString);
nsAccessibilityService* accService = GetAccService();
if (!accService) {
return NS_ERROR_SERVICE_NOT_AVAILABLE;
}
accService->GetStringRole(aRole, aString);
return NS_OK;
}
@ -133,7 +146,12 @@ NS_IMETHODIMP
xpcAccessibilityService::GetStringStates(uint32_t aState, uint32_t aExtraState,
nsISupports **aStringStates)
{
GetAccService()->GetStringStates(aState, aExtraState, aStringStates);
nsAccessibilityService* accService = GetAccService();
if (!accService) {
return NS_ERROR_SERVICE_NOT_AVAILABLE;
}
accService->GetStringStates(aState, aExtraState, aStringStates);
return NS_OK;
}
@ -141,7 +159,12 @@ NS_IMETHODIMP
xpcAccessibilityService::GetStringEventType(uint32_t aEventType,
nsAString& aString)
{
GetAccService()->GetStringEventType(aEventType, aString);
nsAccessibilityService* accService = GetAccService();
if (!accService) {
return NS_ERROR_SERVICE_NOT_AVAILABLE;
}
accService->GetStringEventType(aEventType, aString);
return NS_OK;
}
@ -149,7 +172,12 @@ NS_IMETHODIMP
xpcAccessibilityService::GetStringRelationType(uint32_t aRelationType,
nsAString& aString)
{
GetAccService()->GetStringRelationType(aRelationType, aString);
nsAccessibilityService* accService = GetAccService();
if (!accService) {
return NS_ERROR_SERVICE_NOT_AVAILABLE;
}
accService->GetStringRelationType(aRelationType, aString);
return NS_OK;
}
@ -168,13 +196,18 @@ xpcAccessibilityService::GetAccessibleFromCache(nsIDOMNode* aNode,
return NS_ERROR_INVALID_ARG;
}
nsAccessibilityService* accService = GetAccService();
if (!accService) {
return NS_ERROR_SERVICE_NOT_AVAILABLE;
}
// Search for an accessible in each of our per document accessible object
// caches. If we don't find it, and the given node is itself a document, check
// our cache of document accessibles (document cache). Note usually shutdown
// document accessibles are not stored in the document cache, however an
// "unofficially" shutdown document (i.e. not from DocManager) can still
// exist in the document cache.
Accessible* accessible = GetAccService()->FindAccessibleInCache(node);
Accessible* accessible = accService->FindAccessibleInCache(node);
if (!accessible) {
nsCOMPtr<nsIDocument> document(do_QueryInterface(node));
if (document) {
@ -235,6 +268,11 @@ NS_GetAccessibilityService(nsIAccessibilityService** aResult)
NS_ENSURE_TRUE(aResult, NS_ERROR_NULL_POINTER);
*aResult = nullptr;
// Do not initialize accessibility if it is force disabled.
if (PlatformDisabledState() == ePlatformIsDisabled) {
return NS_ERROR_SERVICE_NOT_AVAILABLE;
}
GetOrCreateAccService(nsAccessibilityService::eXPCOM);
xpcAccessibilityService* service = new xpcAccessibilityService();

Просмотреть файл

@ -2590,7 +2590,12 @@ CustomizeMode.prototype = {
function updatePlayers() {
if (keydown) {
p1 += (keydown == 37 ? -1 : 1) * 10 * keydownAdj;
let p1Adj = 1;
if ((keydown == 37 && !isRTL) ||
(keydown == 39 && isRTL)) {
p1Adj = -1;
}
p1 += p1Adj * 10 * keydownAdj;
}
let sign = Math.sign(ballDxDy[0]);
@ -2622,15 +2627,16 @@ CustomizeMode.prototype = {
}
function draw() {
elements.player1.style.transform = "translate(" + p1 + "px, -37px)";
elements.player2.style.transform = "translate(" + p2 + "px, 300px)";
elements.ball.style.transform = "translate(" + ball[0] + "px, " + ball[1] + "px)";
elements.score.textContent = score;
elements.lives.setAttribute("lives", lives);
let xAdj = isRTL ? -1 : 1;
elements["wp-player1"].style.transform = "translate(" + (xAdj * p1) + "px, -37px)";
elements["wp-player2"].style.transform = "translate(" + (xAdj * p2) + "px, " + gameSide + "px)";
elements["wp-ball"].style.transform = "translate(" + (xAdj * ball[0]) + "px, " + ball[1] + "px)";
elements["wp-score"].textContent = score;
elements["wp-lives"].setAttribute("lives", lives);
if (score >= winScore) {
let arena = elements.arena;
let image = "url(chrome://browser/skin/customizableui/whimsy.png)";
let position = `${ball[0] - 10}px ${ball[1] - 10}px`;
let position = `${(isRTL ? gameSide : 0) + (xAdj * ball[0]) - 10}px ${ball[1] - 10}px`;
let repeat = "no-repeat";
let size = "20px";
if (arena.style.backgroundImage) {
@ -2651,6 +2657,22 @@ CustomizeMode.prototype = {
}
function onkeydown(event) {
keys.push(event.which);
if (keys.length > 10) {
keys.shift();
let codeEntered = true;
for (let i = 0; i < keys.length; i++) {
if (keys[i] != keysCode[i]) {
codeEntered = false;
break;
}
}
if (codeEntered) {
elements.arena.setAttribute("kcode", "true");
let spacer = document.querySelector("#customization-palette > toolbarpaletteitem");
spacer.setAttribute("kcode", "true");
}
}
if (event.which == 37 /* left */ ||
event.which == 39 /* right */) {
keydown = event.which;
@ -2677,10 +2699,13 @@ CustomizeMode.prototype = {
}
arena.removeAttribute("score");
arena.removeAttribute("lives");
arena.removeAttribute("kcode");
arena.style.removeProperty("background-image");
arena.style.removeProperty("background-position");
arena.style.removeProperty("background-repeat");
arena.style.removeProperty("background-size");
let spacer = document.querySelector("#customization-palette > toolbarpaletteitem");
spacer.removeAttribute("kcode");
elements = null;
document = null;
quit = true;
@ -2702,6 +2727,8 @@ CustomizeMode.prototype = {
let paddleWidth = 84;
let keydownAdj = 1;
let keydown = 0;
let keys = [];
let keysCode = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65];
let lives = 5;
let winScore = 11;
let quit = false;
@ -2710,18 +2737,19 @@ CustomizeMode.prototype = {
let elements = {
arena: document.getElementById("customization-pong-arena")
};
let isRTL = document.documentElement.matches(":-moz-locale-dir(rtl)");
document.addEventListener("keydown", onkeydown);
document.addEventListener("keyup", onkeyup);
for (let id of ["player1", "player2", "ball", "score", "lives"]) {
let el = document.createElement("box");
el.id = id;
elements[id] = elements.arena.appendChild(el);
el.id = "wp-" + id;
elements[el.id] = elements.arena.appendChild(el);
}
let spacer = this.visiblePalette.querySelector("toolbarpaletteitem");
for (let player of ["#player1", "#player2"]) {
for (let player of ["#wp-player1", "#wp-player2"]) {
let val = "-moz-element(#" + spacer.id + ") no-repeat";
elements.arena.querySelector(player).style.background = val;
}
@ -2731,8 +2759,8 @@ CustomizeMode.prototype = {
update();
draw();
if (quit) {
elements.score.textContent = score;
elements.lives && elements.lives.setAttribute("lives", lives);
elements["wp-score"].textContent = score;
elements["wp-lives"] && elements["wp-lives"].setAttribute("lives", lives);
elements.arena.setAttribute("score", score);
elements.arena.setAttribute("lives", lives);
} else {

Просмотреть файл

@ -580,8 +580,8 @@ toolbarpaletteitem[place=toolbar] > toolbarspring {
margin: 0 -7px;
}
#lives,
#ball {
#wp-lives,
#wp-ball {
/* Don't need HiDPI versions since the size used will be scaled down to 20x20. */
background-image: url("chrome://browser/skin/customizableui/whimsy.png");
background-size: contain;
@ -594,57 +594,73 @@ toolbarpaletteitem[place=toolbar] > toolbarspring {
border-left: 1px solid currentColor;
border-right: 1px solid currentColor;
margin: 16px auto 0;
box-sizing: content-box;
}
#ball {
margin-left: -10px;
#customization-palette[whimsypong] > toolbarpaletteitem[kcode],
#customization-pong-arena[kcode] {
animation-name: kcode;
animation-timing-function: steps(5);
animation-duration: 1s;
animation-iteration-count: infinite;
}
#wp-ball {
margin-inline-start: -10px;
margin-top: -10px;
height: 20px;
}
#player1,
#player2 {
#wp-player1,
#wp-player2 {
width: 84px;
height: calc(39px + 3em);
background-color: rgba(255,255,0,.5);
}
#player1,
#player2,
#ball,
#score {
#wp-player1,
#wp-player2,
#wp-ball,
#wp-score {
position: fixed;
}
#score {
#wp-score {
transform: translateX(-4ch);
}
#lives {
#wp-score:-moz-locale-dir(rtl) {
transform: translateX(4ch);
}
#wp-lives {
transform: translate(-4ch, 1ch);
}
#lives[lives="5"] {
#wp-lives:-moz-locale-dir(rtl) {
transform: translate(4ch, 1ch);
}
#wp-lives[lives="5"] {
height: 100px;
}
#lives[lives="4"] {
#wp-lives[lives="4"] {
height: 80px;
}
#lives[lives="3"] {
#wp-lives[lives="3"] {
height: 60px;
}
#lives[lives="2"] {
#wp-lives[lives="2"] {
height: 40px;
}
#lives[lives="1"] {
#wp-lives[lives="1"] {
height: 20px;
}
#customization-pong-arena[lives="0"] > #ball {
#customization-pong-arena[lives="0"] > #wp-ball {
animation: game-over 4s forwards ease;
}
@ -663,3 +679,12 @@ toolbarpaletteitem[place=toolbar] > toolbarspring {
opacity: 0;
}
}
@keyframes kcode {
0% { border-color: rgb(195,17,206); color: rgb(195,17,206); }
20% { border-color: rgb(252,82,27); color: rgb(252,82,27); }
40% { border-color: rgb(251,179,0); color: rgb(251,179,0); }
60% { border-color: rgb(105,211,0); color: rgb(105,211,0); }
80% { border-color: rgb(20,155,249); color: rgb(20,155,249); }
100% { border-color: rgb(195,17,206); color: rgb(195,17,206); }
}

Просмотреть файл

@ -35,25 +35,34 @@ try {
let prefix = msg.data.prefix;
let addonId = msg.data.addonId;
let conn = DebuggerServer.connectToParent(prefix, mm);
conn.parentMessageManager = mm;
connections.set(prefix, conn);
// Using the JS debugger causes problems when we're trying to
// schedule those zone groups across different threads. Calling
// blockThreadedExecution causes Gecko to switch to a simpler
// single-threaded model until unblockThreadedExecution is
// called later. We cannot start the debugger until the callback
// passed to blockThreadedExecution has run, signaling that
// we're running single-threaded.
Cu.blockThreadedExecution(() => {
let conn = DebuggerServer.connectToParent(prefix, mm);
conn.parentMessageManager = mm;
connections.set(prefix, conn);
let actor;
let actor;
if (addonId) {
const { WebExtensionChildActor } = require("devtools/server/actors/webextension");
actor = new WebExtensionChildActor(conn, chromeGlobal, prefix, addonId);
} else {
const { ContentActor } = require("devtools/server/actors/childtab");
actor = new ContentActor(conn, chromeGlobal, prefix);
}
if (addonId) {
const { WebExtensionChildActor } = require("devtools/server/actors/webextension");
actor = new WebExtensionChildActor(conn, chromeGlobal, prefix, addonId);
} else {
const { ContentActor } = require("devtools/server/actors/childtab");
actor = new ContentActor(conn, chromeGlobal, prefix);
}
let actorPool = new ActorPool(conn);
actorPool.addActor(actor);
conn.addActorPool(actorPool);
let actorPool = new ActorPool(conn);
actorPool.addActor(actor);
conn.addActorPool(actorPool);
sendAsyncMessage("debug:actor", {actor: actor.form(), prefix: prefix});
sendAsyncMessage("debug:actor", {actor: actor.form(), prefix: prefix});
});
});
addMessageListener("debug:connect", onConnect);
@ -100,6 +109,8 @@ try {
return;
}
Cu.unblockThreadedExecution();
removeMessageListener("debug:disconnect", onDisconnect);
// Call DebuggerServerConnection.close to destroy all child actors. It should end up
// calling DebuggerServerConnection.onClosed that would actually cleanup all actor

Просмотреть файл

@ -41,6 +41,8 @@ function setupServer(mm) {
mm.addMessageListener("debug:content-process-destroy", function onDestroy() {
mm.removeMessageListener("debug:content-process-destroy", onDestroy);
Cu.unblockThreadedExecution();
DebuggerServer.destroy();
gLoader.destroy();
gLoader = null;
@ -54,23 +56,32 @@ function init(msg) {
mm.QueryInterface(Ci.nsISyncMessageSender);
let prefix = msg.data.prefix;
// Setup a server if none started yet
let loader = setupServer(mm);
// Using the JS debugger causes problems when we're trying to
// schedule those zone groups across different threads. Calling
// blockThreadedExecution causes Gecko to switch to a simpler
// single-threaded model until unblockThreadedExecution is called
// later. We cannot start the debugger until the callback passed to
// blockThreadedExecution has run, signaling that we're running
// single-threaded.
Cu.blockThreadedExecution(() => {
// Setup a server if none started yet
let loader = setupServer(mm);
// Connect both parent/child processes debugger servers RDP via message
// managers
let { DebuggerServer } = loader.require("devtools/server/main");
let conn = DebuggerServer.connectToParent(prefix, mm);
conn.parentMessageManager = mm;
// Connect both parent/child processes debugger servers RDP via message
// managers
let { DebuggerServer } = loader.require("devtools/server/main");
let conn = DebuggerServer.connectToParent(prefix, mm);
conn.parentMessageManager = mm;
let { ChildProcessActor } =
loader.require("devtools/server/actors/child-process");
let { ActorPool } = loader.require("devtools/server/main");
let actor = new ChildProcessActor(conn);
let actorPool = new ActorPool(conn);
actorPool.addActor(actor);
conn.addActorPool(actorPool);
let { ChildProcessActor } =
loader.require("devtools/server/actors/child-process");
let { ActorPool } = loader.require("devtools/server/main");
let actor = new ChildProcessActor(conn);
let actorPool = new ActorPool(conn);
actorPool.addActor(actor);
conn.addActorPool(actorPool);
let response = { actor: actor.form() };
mm.sendAsyncMessage("debug:content-process-actor", response);
let response = { actor: actor.form() };
mm.sendAsyncMessage("debug:content-process-actor", response);
});
}

Просмотреть файл

@ -6335,6 +6335,10 @@ nsDocShell::SetIsActive(bool aIsActive)
// Keep track ourselves.
mIsActive = aIsActive;
if (TabChild* tc = TabChild::GetFrom(this)) {
tc->OnDocShellActivated(aIsActive);
}
// Clear prerender flag if necessary.
if (mIsPrerendered && aIsActive) {
MOZ_ASSERT(mPrerenderGlobalHistory.get());

Просмотреть файл

@ -2668,6 +2668,23 @@ TabChild::RemovePendingDocShellBlocker()
}
}
void
TabChild::OnDocShellActivated(bool aIsActive)
{
if (aIsActive) {
if (!sActiveTabs) {
sActiveTabs = new nsTHashtable<nsPtrHashKey<TabChild>>();
}
sActiveTabs->PutEntry(this);
} else {
if (sActiveTabs) {
sActiveTabs->RemoveEntry(this);
// We don't delete sActiveTabs here when it's empty since that
// could cause a lot of churn. Instead, we wait until ~TabChild.
}
}
}
void
TabChild::InternalSetDocShellIsActive(bool aIsActive, bool aPreserveLayers)
{
@ -2712,19 +2729,6 @@ TabChild::InternalSetDocShellIsActive(bool aIsActive, bool aPreserveLayers)
docShell->SetIsActive(aIsActive);
}
if (aIsActive) {
if (!sActiveTabs) {
sActiveTabs = new nsTHashtable<nsPtrHashKey<TabChild>>();
}
sActiveTabs->PutEntry(this);
} else {
if (sActiveTabs) {
sActiveTabs->RemoveEntry(this);
// We don't delete sActiveTabs here when it's empty since that
// could cause a lot of churn. Instead, we wait until ~TabChild.
}
}
if (aIsActive) {
MakeVisible();

Просмотреть файл

@ -580,6 +580,8 @@ public:
void MakeVisible();
void MakeHidden();
void OnDocShellActivated(bool aIsActive);
nsIContentChild* Manager() const { return mManager; }
static inline TabChild*

Просмотреть файл

@ -516,7 +516,8 @@
gczeal(Number(properties.gczeal));
}
document.write(`<title>${ properties.test }<\/title>`);
// Display the test path in the title.
document.title = properties.test;
// Output script tags for shell.js, then browser.js, at each level of the
// test path hierarchy.
@ -537,10 +538,6 @@
scripts.push({src: "js-test-driver-end.js", module: false});
if (!moduleTest) {
// XXX bc - the first document.written script is ignored if the protocol
// is file:. insert an empty script tag, to work around it.
document.write("<script></script>");
var key, value;
if (properties.language !== "type") {
key = "language";

Просмотреть файл

@ -441,7 +441,7 @@ ProfileEntry::script() const
// AutoSuppressProfilerSampling prohibits the runtime's active context from
// being changed while it exists.
JSContext* cx = script->runtimeFromAnyThread()->activeContext();
if (!cx->isProfilerSamplingEnabled())
if (!cx || !cx->isProfilerSamplingEnabled())
return nullptr;
MOZ_ASSERT(!IsForwarded(script));

Просмотреть файл

@ -124,6 +124,15 @@ interface ScheduledGCCallback : nsISupports
void callback();
};
/**
* Interface for callback to be passed to Cu.blockThreadedExecution.
*/
[scriptable, function, uuid(c3b85a5c-c328-47d4-aaaf-384c4ff9d77d)]
interface nsIBlockThreadedExecutionCallback : nsISupports
{
void callback();
};
/**
* interface of Components.utils
*/
@ -708,6 +717,21 @@ interface nsIXPCComponents_Utils : nsISupports
* same semantics of readFile.
*/
ACString readURI(in nsIURI url);
/**
* If the main thread is using any kind of fancy cooperative
* scheduling (e.g., Quantum DOM scheduling),
* blockThreadedExecution disables it temporarily. The
* aBlockedCallback is called when it has been completely disabled
* and events are back to running sequentially on a single main
* thread. Calling unblockThreadedExecution will re-enable thread
* scheduling of the main thread. Multiple calls to
* blockThreadedExecution will require the same number of calls to
* unblockThreadedExecution in order to resume cooperative
* scheduling.
*/
void blockThreadedExecution(in nsIBlockThreadedExecutionCallback aBlockedCallback);
void unblockThreadedExecution();
};
/**

Просмотреть файл

@ -29,6 +29,7 @@
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/StructuredCloneTags.h"
#include "mozilla/dom/WindowBinding.h"
#include "mozilla/Scheduler.h"
#include "nsZipArchive.h"
#include "nsIDOMFileList.h"
#include "nsWindowMemoryReporter.h"
@ -3212,6 +3213,20 @@ nsXPCComponents_Utils::Now(double* aRetval)
return NS_OK;
}
NS_IMETHODIMP
nsXPCComponents_Utils::BlockThreadedExecution(nsIBlockThreadedExecutionCallback* aCallback)
{
Scheduler::BlockThreadedExecution(aCallback);
return NS_OK;
}
NS_IMETHODIMP
nsXPCComponents_Utils::UnblockThreadedExecution()
{
Scheduler::UnblockThreadedExecution();
return NS_OK;
}
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/

Просмотреть файл

@ -3103,7 +3103,9 @@ nsChildView::GetDocumentAccessible()
if (!mozilla::a11y::ShouldA11yBeEnabled())
return nullptr;
if (mAccessible) {
// mAccessible might be dead if accessibility was previously disabled and is
// now being enabled again.
if (mAccessible && mAccessible->IsAlive()) {
RefPtr<a11y::Accessible> ret;
CallQueryReferent(mAccessible.get(),
static_cast<a11y::Accessible**>(getter_AddRefs(ret)));

Просмотреть файл

@ -31,7 +31,7 @@ CooperativeThreadPool::CooperativeThreadPool(size_t aNumThreads,
, mController(aController)
, mSelectedThread(size_t(0))
{
MOZ_ASSERT(aNumThreads < kMaxThreads);
MOZ_ASSERT(aNumThreads <= kMaxThreads);
gCooperativeSchedulingEnabled = true;
sTlsCurrentThread.infallibleInit();

Просмотреть файл

@ -124,8 +124,10 @@ PrioritizedEventQueue<InnerQueueT>::SelectQueue(bool aUpdateState,
bool normalPending = !mNormalQueue->IsEmpty(aProofOfLock);
size_t inputCount = mInputQueue->Count(aProofOfLock);
if (mInputQueueState == STATE_ENABLED &&
mInputHandlingStartTime.IsNull() && inputCount > 0) {
if (aUpdateState &&
mInputQueueState == STATE_ENABLED &&
mInputHandlingStartTime.IsNull() &&
inputCount > 0) {
mInputHandlingStartTime =
InputEventStatistics::Get()
.GetInputHandlingStartTime(inputCount);
@ -156,6 +158,7 @@ PrioritizedEventQueue<InnerQueueT>::SelectQueue(bool aUpdateState,
queue = EventPriority::High;
} else if (inputCount > 0 && (mInputQueueState == STATE_FLUSHING ||
(mInputQueueState == STATE_ENABLED &&
!mInputHandlingStartTime.IsNull() &&
TimeStamp::Now() > mInputHandlingStartTime))) {
queue = EventPriority::Input;
} else if (normalPending) {

Просмотреть файл

@ -21,6 +21,7 @@
#include "nsThreadManager.h"
#include "PrioritizedEventQueue.h"
#include "xpcpublic.h"
#include "xpccomponents.h"
// Windows silliness. winbase.h defines an empty no-argument Yield macro.
#undef Yield
@ -93,6 +94,7 @@ public:
explicit SchedulerImpl(SchedulerEventQueue* aQueue);
void Start();
void Stop(already_AddRefed<nsIRunnable> aStoppedCallback);
void Shutdown();
void Dispatch(already_AddRefed<nsIRunnable> aEvent);
@ -118,6 +120,9 @@ public:
static bool UnlabeledEventRunning() { return sUnlabeledEventRunning; }
static bool AnyEventRunning() { return sNumThreadsRunning > 0; }
void BlockThreadedExecution(nsIBlockThreadedExecutionCallback* aCallback);
void UnblockThreadedExecution();
CooperativeThreadPool::Resource* GetQueueResource() { return &mQueueResource; }
bool UseCooperativeScheduling() const { return mQueue->UseCooperativeScheduling(); }
@ -143,6 +148,9 @@ private:
bool mShuttingDown;
// Runnable to call when the scheduler has finished shutting down.
nsTArray<nsCOMPtr<nsIRunnable>> mShutdownCallbacks;
UniquePtr<CooperativeThreadPool> mThreadPool;
RefPtr<SchedulerEventQueue> mQueue;
@ -202,6 +210,11 @@ private:
static size_t sNumThreadsRunning;
static bool sUnlabeledEventRunning;
// Number of times that BlockThreadedExecution has been called without
// corresponding calls to UnblockThreadedExecution. If this is non-zero,
// scheduling is disabled.
size_t mNumSchedulerBlocks = 0;
JSContext* mContexts[CooperativeThreadPool::kMaxThreads];
};
@ -443,6 +456,8 @@ SchedulerImpl::SwitcherThread(void* aData)
void
SchedulerImpl::Start()
{
MOZ_ASSERT(mNumSchedulerBlocks == 0);
NS_DispatchToMainThread(NS_NewRunnableFunction("Scheduler::Start", [this]() -> void {
// Let's pretend the runnable here isn't actually running.
MOZ_ASSERT(sUnlabeledEventRunning);
@ -492,16 +507,40 @@ SchedulerImpl::Start()
MOZ_ASSERT(sNumThreadsRunning == 0);
sNumThreadsRunning = 1;
// Delete the SchedulerImpl. Don't use it after this point.
Scheduler::sScheduler = nullptr;
mShuttingDown = false;
nsTArray<nsCOMPtr<nsIRunnable>> callbacks = Move(mShutdownCallbacks);
for (nsIRunnable* runnable : callbacks) {
runnable->Run();
}
}));
}
void
SchedulerImpl::Stop(already_AddRefed<nsIRunnable> aStoppedCallback)
{
MOZ_ASSERT(mNumSchedulerBlocks > 0);
// Note that this may be called when mShuttingDown is already true. We still
// want to invoke the callback in that case.
MutexAutoLock lock(mLock);
mShuttingDown = true;
mShutdownCallbacks.AppendElement(aStoppedCallback);
mShutdownCondVar.Notify();
}
void
SchedulerImpl::Shutdown()
{
MOZ_ASSERT(mNumSchedulerBlocks == 0);
MutexAutoLock lock(mLock);
mShuttingDown = true;
// Delete the SchedulerImpl once shutdown is complete.
mShutdownCallbacks.AppendElement(NS_NewRunnableFunction("SchedulerImpl::Shutdown",
[] { Scheduler::sScheduler = nullptr; }));
mShutdownCondVar.Notify();
}
@ -519,7 +558,9 @@ SchedulerImpl::SystemZoneResource::IsAvailable(const MutexAutoLock& aProofOfLock
{
mScheduler->mLock.AssertCurrentThreadOwns();
JSContext* cx = dom::danger::GetJSContext();
// It doesn't matter which context we pick; we really just some main-thread
// JSContext.
JSContext* cx = mScheduler->mContexts[0];
return js::SystemZoneAvailable(cx);
}
@ -681,6 +722,27 @@ SchedulerImpl::Yield()
CooperativeThreadPool::Yield(nullptr, lock);
}
void
SchedulerImpl::BlockThreadedExecution(nsIBlockThreadedExecutionCallback* aCallback)
{
if (mNumSchedulerBlocks++ == 0 || mShuttingDown) {
Stop(NewRunnableMethod("BlockThreadedExecution", aCallback,
&nsIBlockThreadedExecutionCallback::Callback));
} else {
// The scheduler is already blocked.
nsCOMPtr<nsIBlockThreadedExecutionCallback> kungFuDeathGrip(aCallback);
aCallback->Callback();
}
}
void
SchedulerImpl::UnblockThreadedExecution()
{
if (--mNumSchedulerBlocks == 0) {
Start();
}
}
/* static */ already_AddRefed<nsThread>
Scheduler::Init(nsIIdlePeriod* aIdlePeriod)
{
@ -789,3 +851,25 @@ Scheduler::AnyEventRunning()
{
return SchedulerImpl::AnyEventRunning();
}
/* static */ void
Scheduler::BlockThreadedExecution(nsIBlockThreadedExecutionCallback* aCallback)
{
if (!sScheduler) {
nsCOMPtr<nsIBlockThreadedExecutionCallback> kungFuDeathGrip(aCallback);
aCallback->Callback();
return;
}
sScheduler->BlockThreadedExecution(aCallback);
}
/* static */ void
Scheduler::UnblockThreadedExecution()
{
if (!sScheduler) {
return;
}
sScheduler->UnblockThreadedExecution();
}

Просмотреть файл

@ -18,6 +18,7 @@
// Windows silliness. winbase.h defines an empty no-argument Yield macro.
#undef Yield
class nsIBlockThreadedExecutionCallback;
class nsIIdlePeriod;
class nsThread;
@ -74,6 +75,9 @@ public:
static bool UnlabeledEventRunning();
static bool AnyEventRunning();
static void BlockThreadedExecution(nsIBlockThreadedExecutionCallback* aCallback);
static void UnblockThreadedExecution();
class MOZ_RAII EventLoopActivation
{
public: