Bug 1887729 - Implement context lost/restored support for CanvasRenderingContext2D. r=webidl,gfx-reviewers,smaug,lsalzman

Remote canvas can run in the GPU process, and if the GPU process
crashes, we need to notify the application using canvas. Historically we
just failed, and the application may have been able to continue drawing
but with the contents prior to the crash lost. Later we regressed to
prevent the canvas from being used at all.

This patch makes it so that we can restore functionality to any
application that supports the contextlost/contextrestored events. This
will allow for a theoretical complete graceful recovery for the user
with minimal disruption.

Differential Revision: https://phabricator.services.mozilla.com/D205608
This commit is contained in:
Andrew Osmond 2024-03-28 14:50:20 +00:00
Родитель ec53092a1a
Коммит 503fb4c624
26 изменённых файлов: 365 добавлений и 171 удалений

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

@ -1229,6 +1229,64 @@ void CanvasRenderingContext2D::RemoveShutdownObserver() {
canvasManager->RemoveShutdownObserver(this);
}
void CanvasRenderingContext2D::OnRemoteCanvasLost() {
// We only lose context / data if we are using remote canvas, which is only
// for accelerated targets.
if (!mBufferProvider || !mBufferProvider->IsAccelerated() || mIsContextLost) {
return;
}
// 2. Set context's context lost to true.
mIsContextLost = mAllowContextRestore = true;
// 3. Reset the rendering context to its default state given context.
ClearTarget();
// We dispatch because it isn't safe to call into the script event handlers,
// and we don't want to mutate our state in CanvasShutdownManager.
NS_DispatchToCurrentThread(NS_NewCancelableRunnableFunction(
"CanvasRenderingContext2D::OnRemoteCanvasLost", [self = RefPtr{this}] {
// 4. Let shouldRestore be the result of firing an event named
// contextlost at canvas, with the cancelable attribute initialized to
// true.
self->mAllowContextRestore = self->DispatchEvent(
u"contextlost"_ns, CanBubble::eNo, Cancelable::eYes);
}));
}
void CanvasRenderingContext2D::OnRemoteCanvasRestored() {
// We never lost our context if it was not a remote canvas, nor can we restore
// if we have already shutdown.
if (mHasShutdown || !mIsContextLost || !mAllowContextRestore) {
return;
}
// We dispatch because it isn't safe to call into the script event handlers,
// and we don't want to mutate our state in CanvasShutdownManager.
NS_DispatchToCurrentThread(NS_NewCancelableRunnableFunction(
"CanvasRenderingContext2D::OnRemoteCanvasRestored",
[self = RefPtr{this}] {
// 5. If shouldRestore is false, then abort these steps.
if (!self->mHasShutdown && self->mIsContextLost &&
self->mAllowContextRestore) {
// 7. Set context's context lost to false.
self->mIsContextLost = false;
// 6. Attempt to restore context by creating a backing storage using
// context's attributes and associating them with context. If this
// fails, then abort these steps.
if (!self->EnsureTarget()) {
self->mIsContextLost = true;
return;
}
// 8. Fire an event named contextrestored at canvas.
self->DispatchEvent(u"contextrestored"_ns, CanBubble::eNo,
Cancelable::eNo);
}
}));
}
void CanvasRenderingContext2D::SetStyleFromString(const nsACString& aStr,
Style aWhichStyle) {
MOZ_ASSERT(!aStr.IsVoid());
@ -1456,6 +1514,17 @@ bool CanvasRenderingContext2D::EnsureTarget(ErrorResult& aError,
return false;
}
// The spec doesn't say what to do in this case, but Chrome silently fails
// without throwing an error. We should at least throw if the canvas is
// permanently disabled.
if (NS_WARN_IF(mIsContextLost)) {
if (!mAllowContextRestore) {
aError.ThrowInvalidStateError(
"Cannot use canvas as context is lost forever.");
}
return false;
}
if (mTarget) {
if (mTarget == sErrorTarget.get()) {
aError.ThrowInvalidStateError("Canvas is already in error state.");
@ -2028,7 +2097,7 @@ CanvasRenderingContext2D::GetOptimizedSnapshot(DrawTarget* aTarget,
// already exists, otherwise we get performance issues. See bug 1567054.
if (!EnsureTarget()) {
MOZ_ASSERT(
mTarget == sErrorTarget.get(),
mTarget == sErrorTarget.get() || mIsContextLost,
"On EnsureTarget failure mTarget should be set to sErrorTarget.");
// In rare circumstances we may have failed to create an error target.
return mTarget ? mTarget->Snapshot() : nullptr;

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

@ -570,6 +570,10 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
void OnShutdown();
bool IsContextLost() const { return mIsContextLost; }
void OnRemoteCanvasLost();
void OnRemoteCanvasRestored();
/**
* Update CurrentState().filter with the filter description for
* CurrentState().filterChain.
@ -762,7 +766,7 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
* Check if the target is valid after calling EnsureTarget.
*/
bool IsTargetValid() const {
return !!mTarget && mTarget != sErrorTarget.get();
return !!mTarget && mTarget != sErrorTarget.get() && !mIsContextLost;
}
/**
@ -845,6 +849,10 @@ class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
bool mWillReadFrequently = false;
// Whether or not we have already shutdown.
bool mHasShutdown = false;
// Whether or not remote canvas is currently unavailable.
bool mIsContextLost = false;
// Whether or not we can restore the context after restoration.
bool mAllowContextRestore = true;
bool AddShutdownObserver();
void RemoveShutdownObserver();

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

@ -7,9 +7,12 @@
#include "mozilla/dom/CanvasUtils.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/WorkerCommon.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/PresShell.h"
#include "nsContentUtils.h"
#include "nsPIDOMWindow.h"
#include "nsRefreshDriver.h"
@ -116,3 +119,24 @@ bool nsICanvasRenderingContextInternal::ShouldResistFingerprinting(
// Last resort, just check the global preference
return nsContentUtils::ShouldResistFingerprinting("Fallback", aTarget);
}
bool nsICanvasRenderingContextInternal::DispatchEvent(
const nsAString& eventName, mozilla::CanBubble aCanBubble,
mozilla::Cancelable aIsCancelable) const {
bool useDefaultHandler = true;
if (mCanvasElement) {
nsContentUtils::DispatchTrustedEvent(mCanvasElement->OwnerDoc(),
mCanvasElement, eventName, aCanBubble,
aIsCancelable, &useDefaultHandler);
} else if (mOffscreenCanvas) {
// OffscreenCanvas case
auto event = mozilla::MakeRefPtr<mozilla::dom::Event>(mOffscreenCanvas,
nullptr, nullptr);
event->InitEvent(eventName, aCanBubble, aIsCancelable);
event->SetTrusted(true);
useDefaultHandler = mOffscreenCanvas->DispatchEvent(
*event, mozilla::dom::CallerType::System, mozilla::IgnoreErrors());
}
return useDefaultHandler;
}

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

@ -15,6 +15,7 @@
#include "nsRFPService.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/dom/OffscreenCanvas.h"
#include "mozilla/EventForwards.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefPtr.h"
#include "mozilla/StateWatching.h"
@ -225,6 +226,9 @@ class nsICanvasRenderingContextInternal : public nsISupports,
// Checking if fingerprinting protection is enable for the given target.
bool ShouldResistFingerprinting(mozilla::RFPTarget aTarget) const;
bool DispatchEvent(const nsAString& eventName, mozilla::CanBubble aCanBubble,
mozilla::Cancelable aIsCancelable) const;
protected:
RefPtr<mozilla::dom::HTMLCanvasElement> mCanvasElement;
RefPtr<mozilla::dom::OffscreenCanvas> mOffscreenCanvas;

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

@ -185,6 +185,10 @@ support-files = [
["test_ImageData_ctor.html"]
["test_accelerated_canvas_context_loss.html"]
subsuite = "gpu"
skip-if = ["verify || (os == 'win' && debug)"]
["test_bitmaprenderer.html"]
["test_bug232227.html"]

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

@ -0,0 +1,121 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Check for contextlost/restored events after GPU process restart</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<canvas id="c" width="512" height="512"></canvas>
<script type="application/javascript">
function waitRAF() {
return new Promise((resolve, reject) => {
window.requestAnimationFrame(resolve);
});
}
async function restartGPUProcess() {
return await SpecialPowers.spawnChrome([], async () => {
const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
if (gfxInfo.usingGPUProcess) {
const { TestUtils } = ChromeUtils.importESModule(
"resource://testing-common/TestUtils.sys.mjs"
);
let promise = TestUtils.topicObserved("compositor-reinitialized");
const remoteCanvas = gfxInfo.usingRemoteCanvas;
const acceleratedCanvas = gfxInfo.usingAcceleratedCanvas;
ok(true, "Restarting GPU process, remote canvas " + remoteCanvas + ", accelerated canvas " + acceleratedCanvas);
gfxInfo.killGPUProcessForTests();
await promise;
return remoteCanvas || acceleratedCanvas;
}
ok(true, "Not using GPU process");
return false;
});
}
const canvas = document.getElementById("c");
const context = canvas.getContext("2d");
let restoredPromiseResolve;
let restoredPromiseReject;
const restoredPromise = new Promise((resolve, reject) => {
restoredPromiseResolve = resolve;
restoredPromiseReject = reject;
});
let countLostEvents = 0;
let countRestoredEvents = 0;
function onContextLost() {
ok(context.isContextLost(), "Canvas context should be lost during contextlost event");
countLostEvents += 1;
}
function onContextRestored() {
ok(!context.isContextLost(), "Canvas context should not be lost during contextrestored event");
countRestoredEvents += 1;
restoredPromiseResolve(true);
}
function waitContextRestored() {
let timeoutId = window.setTimeout(restoredPromiseReject, 5000);
return restoredPromise.then(() => {
window.clearTimeout(timeoutId);
});
}
async function start() {
try {
canvas.addEventListener("contextlost", onContextLost);
canvas.addEventListener("contextrestored", onContextRestored);
ok(!context.isContextLost(), "Canvas context should not be lost before initial fill");
context.fillStyle = 'red';
context.fill();
await waitRAF();
ok(!context.isContextLost(), "Canvas context should not be lost after initial fill");
const restarted = await restartGPUProcess();
const expectedEvents = restarted ? 1 : 0;
if (expectedEvents) {
await waitContextRestored();
}
await waitRAF();
is(countLostEvents, expectedEvents, "Should have fired " + expectedEvents + " contextlost events");
is(countRestoredEvents, expectedEvents, "Should have fired " + expectedEvents + " contextrestored events");
ok(!context.isContextLost(), "Canvas context should not be lost after restoration");
context.fillStyle = 'green';
context.fill();
await waitRAF();
ok(!context.isContextLost(), "Canvas context should not be lost at completion");
} catch (err) {
ok(false, "Caught exception " + err);
} finally {
SimpleTest.finish();
}
}
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("Wait for failure condition");
start();
</script>
</body>
</html>

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

@ -228,6 +228,9 @@ EVENT(lostpointercapture, ePointerLostCapture, EventNameType_All,
ePointerEventClass)
EVENT(selectstart, eSelectStart, EventNameType_HTMLXUL, eBasicEventClass)
EVENT(contextlost, eContextLost, EventNameType_HTML, eBasicEventClass)
EVENT(contextrestored, eContextRestored, EventNameType_HTML, eBasicEventClass)
// Not supported yet; probably never because "wheel" is a better idea.
// EVENT(mousewheel)
EVENT(pause, ePause, EventNameType_HTML, eBasicEventClass)

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

@ -1669,8 +1669,12 @@ let interfaceNamesInGlobalScope = [
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "onclose", insecureContext: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "oncontextlost", insecureContext: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "oncontextmenu", insecureContext: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "oncontextrestored", insecureContext: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "oncopy", insecureContext: true },
// IMPORTANT: Do not change this list without review from a DOM peer!
{ name: "oncuechange", insecureContext: true },

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

@ -151,6 +151,7 @@ interface mixin CanvasState {
undefined save(); // push state on state stack
undefined restore(); // pop state stack and restore state
undefined reset(); // reset the rendering context to its default state
boolean isContextLost(); // return whether context is lost
};
interface mixin CanvasTransform {

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

@ -39,7 +39,9 @@ interface mixin GlobalEventHandlers {
attribute EventHandler onchange;
attribute EventHandler onclick;
attribute EventHandler onclose;
attribute EventHandler oncontextlost;
attribute EventHandler oncontextmenu;
attribute EventHandler oncontextrestored;
attribute EventHandler oncopy;
attribute EventHandler oncuechange;
attribute EventHandler oncut;

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

@ -55,6 +55,10 @@ void CanvasManagerChild::DestroyInternal() {
mCanvasChild->Destroy();
mCanvasChild = nullptr;
}
if (auto* shutdownManager = CanvasShutdownManager::Get()) {
shutdownManager->OnRemoteCanvasLost();
}
}
void CanvasManagerChild::Destroy() {
@ -140,6 +144,7 @@ void CanvasManagerChild::Destroy() {
}
manager->SendInitialize(manager->Id());
shutdownManager->OnRemoteCanvasRestored();
sLocalManager.set(manager);
return manager;
}

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

@ -9,12 +9,16 @@
#include "mozilla/dom/CanvasRenderingContext2D.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRef.h"
#include "mozilla/dom/WorkerRunnable.h"
#include "mozilla/gfx/CanvasManagerChild.h"
using namespace mozilla::dom;
namespace mozilla::gfx {
StaticMutex CanvasShutdownManager::sManagersMutex;
std::set<CanvasShutdownManager*> CanvasShutdownManager::sManagers;
// The owning thread will tell us to close when it is shutdown, either via
// CanvasShutdownManager::Shutdown for the main thread, or via a shutdown
// callback from ThreadSafeWorkerRef for worker threads.
@ -42,6 +46,11 @@ void CanvasShutdownManager::Destroy() {
return;
}
{
StaticMutexAutoLock lock(sManagersMutex);
sManagers.erase(manager);
}
sLocalManager.set(nullptr);
manager->Destroy();
delete manager;
@ -77,6 +86,9 @@ void CanvasShutdownManager::Destroy() {
CanvasShutdownManager* manager = new CanvasShutdownManager(workerRef);
sLocalManager.set(manager);
StaticMutexAutoLock lock(sManagersMutex);
sManagers.insert(manager);
return manager;
}
@ -88,6 +100,9 @@ void CanvasShutdownManager::Destroy() {
CanvasShutdownManager* manager = new CanvasShutdownManager();
sLocalManager.set(manager);
StaticMutexAutoLock lock(sManagersMutex);
sManagers.insert(manager);
return manager;
}
@ -105,4 +120,60 @@ void CanvasShutdownManager::RemoveShutdownObserver(
mActiveCanvas.erase(aCanvas);
}
void CanvasShutdownManager::OnRemoteCanvasLost() {
// Note that the canvas cannot do anything that mutates our state. It will
// dispatch for anything that risks re-entrancy.
for (const auto& canvas : mActiveCanvas) {
canvas->OnRemoteCanvasLost();
}
}
void CanvasShutdownManager::OnRemoteCanvasRestored() {
// Note that the canvas cannot do anything that mutates our state. It will
// dispatch for anything that risks re-entrancy.
for (const auto& canvas : mActiveCanvas) {
canvas->OnRemoteCanvasRestored();
}
}
/* static */ void CanvasShutdownManager::MaybeRestoreRemoteCanvas() {
// Calling Get will recreate the CanvasManagerChild, which in turn will
// cause us to call OnRemoteCanvasRestore upon success.
if (CanvasShutdownManager* manager = MaybeGet()) {
if (!manager->mActiveCanvas.empty()) {
CanvasManagerChild::Get();
}
}
}
/* static */ void CanvasShutdownManager::OnCompositorManagerRestored() {
MOZ_ASSERT(NS_IsMainThread());
class RestoreRunnable final : public WorkerRunnable {
public:
explicit RestoreRunnable(WorkerPrivate* aWorkerPrivate)
: WorkerRunnable(aWorkerPrivate,
"CanvasShutdownManager::RestoreRunnable") {}
bool WorkerRun(JSContext*, WorkerPrivate*) override {
MaybeRestoreRemoteCanvas();
return true;
}
};
// We can restore the main thread canvases immediately.
MaybeRestoreRemoteCanvas();
// And dispatch to restore any DOM worker canvases. This is safe because we
// remove the manager from sManagers before clearing mWorkerRef during DOM
// worker shutdown.
StaticMutexAutoLock lock(sManagersMutex);
for (const auto& manager : sManagers) {
if (manager->mWorkerRef) {
auto task = MakeRefPtr<RestoreRunnable>(manager->mWorkerRef->Private());
task->Dispatch();
}
}
}
} // namespace mozilla::gfx

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

@ -7,6 +7,7 @@
#define _include_gfx_ipc_CanvasShutdownManager_h__
#include "mozilla/RefPtr.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/ThreadLocal.h"
#include <set>
@ -29,15 +30,25 @@ class CanvasShutdownManager final {
void AddShutdownObserver(dom::CanvasRenderingContext2D* aCanvas);
void RemoveShutdownObserver(dom::CanvasRenderingContext2D* aCanvas);
static void OnCompositorManagerRestored();
void OnRemoteCanvasLost();
void OnRemoteCanvasRestored();
private:
explicit CanvasShutdownManager(dom::StrongWorkerRef* aWorkerRef);
CanvasShutdownManager();
~CanvasShutdownManager();
void Destroy();
static void MaybeRestoreRemoteCanvas();
RefPtr<dom::ThreadSafeWorkerRef> mWorkerRef;
std::set<dom::CanvasRenderingContext2D*> mActiveCanvas;
static MOZ_THREAD_LOCAL(CanvasShutdownManager*) sLocalManager;
static StaticMutex sManagersMutex;
static std::set<CanvasShutdownManager*> sManagers;
};
} // namespace gfx

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

@ -10,6 +10,7 @@
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/CompositorManagerParent.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/gfx/CanvasShutdownManager.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/dom/ContentChild.h" // for ContentChild
@ -67,7 +68,15 @@ bool CompositorManagerChild::Init(Endpoint<PCompositorManagerChild>&& aEndpoint,
sInstance = new CompositorManagerChild(std::move(aEndpoint), aProcessToken,
aNamespace);
sOtherPid = sInstance->OtherPid();
return sInstance->CanSend();
if (!sInstance->CanSend()) {
return false;
}
// If there are any canvases waiting on the recreation of the GPUProcess or
// CompositorManagerChild, then we need to notify them so that they can
// restore their contexts.
gfx::CanvasShutdownManager::OnCompositorManagerRestored();
return true;
}
/* static */

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

@ -159,6 +159,12 @@ class MockGfxInfo final : public nsIGfxInfo {
NS_IMETHOD GetUsingGPUProcess(bool* aOutValue) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetUsingRemoteCanvas(bool* aOutValue) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetUsingAcceleratedCanvas(bool* aOutValue) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD GetIsHeadless(bool* aIsHeadless) override {
return NS_ERROR_NOT_IMPLEMENTED;
}

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

@ -282,21 +282,6 @@ prefs: [dom.security.featurePolicy.experimental.enabled:true, dom.security.featu
[ImageData interface: new ImageData(10, 10) must inherit property "colorSpace" with the proper type]
expected: FAIL
[CanvasRenderingContext2D interface: operation isContextLost()]
expected: FAIL
[CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "isContextLost()" with the proper type]
expected: FAIL
[OffscreenCanvasRenderingContext2D interface: operation isContextLost()]
expected: FAIL
[SVGElement interface: attribute oncontextlost]
expected: FAIL
[SVGElement interface: attribute oncontextrestored]
expected: FAIL
[SVGElement interface: attribute onbeforematch]
expected: FAIL
@ -770,42 +755,6 @@ prefs: [dom.security.featurePolicy.experimental.enabled:true, dom.security.featu
[Window interface: attribute originAgentCluster]
expected: FAIL
[Window interface: attribute oncontextlost]
expected: FAIL
[Window interface: attribute oncontextrestored]
expected: FAIL
[Window interface: window must inherit property "oncontextlost" with the proper type]
expected: FAIL
[Window interface: window must inherit property "oncontextrestored" with the proper type]
expected: FAIL
[Document interface: attribute oncontextlost]
expected: FAIL
[Document interface: attribute oncontextrestored]
expected: FAIL
[Document interface: iframe.contentDocument must inherit property "oncontextlost" with the proper type]
expected: FAIL
[Document interface: iframe.contentDocument must inherit property "oncontextrestored" with the proper type]
expected: FAIL
[Document interface: new Document() must inherit property "oncontextlost" with the proper type]
expected: FAIL
[Document interface: new Document() must inherit property "oncontextrestored" with the proper type]
expected: FAIL
[Document interface: documentWithHandlers must inherit property "oncontextlost" with the proper type]
expected: FAIL
[Document interface: documentWithHandlers must inherit property "oncontextrestored" with the proper type]
expected: FAIL
[Window interface: attribute onbeforematch]
expected: FAIL
@ -892,18 +841,6 @@ prefs: [dom.security.featurePolicy.experimental.enabled:true, dom.security.featu
[HTMLMediaElement interface: document.createElement("audio") must inherit property "getStartDate()" with the proper type]
expected: FAIL
[HTMLElement interface: attribute oncontextlost]
expected: FAIL
[HTMLElement interface: attribute oncontextrestored]
expected: FAIL
[HTMLElement interface: document.createElement("noscript") must inherit property "oncontextlost" with the proper type]
expected: FAIL
[HTMLElement interface: document.createElement("noscript") must inherit property "oncontextrestored" with the proper type]
expected: FAIL
[HTMLLinkElement interface: attribute blocking]
expected: FAIL

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

@ -5,9 +5,6 @@
[ImageData interface: attribute colorSpace]
expected: FAIL
[OffscreenCanvasRenderingContext2D interface: operation isContextLost()]
expected: FAIL
[PromiseRejectionEvent interface: attribute promise]
expected: FAIL

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

@ -1,28 +1,4 @@
[event-handler-all-global-events.html]
[oncontextlost: must be on the appropriate locations for GlobalEventHandlers]
expected: FAIL
[oncontextlost: the default value must be null]
expected: FAIL
[oncontextlost: the content attribute must be compiled into a function as the corresponding property]
expected: FAIL
[oncontextlost: the content attribute must execute when an event is dispatched]
expected: FAIL
[oncontextrestored: must be on the appropriate locations for GlobalEventHandlers]
expected: FAIL
[oncontextrestored: the default value must be null]
expected: FAIL
[oncontextrestored: the content attribute must be compiled into a function as the corresponding property]
expected: FAIL
[oncontextrestored: the content attribute must execute when an event is dispatched]
expected: FAIL
[onbeforematch: must be on the appropriate locations for GlobalEventHandlers]
expected: FAIL

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

@ -20,24 +20,6 @@
if not debug and (os == "mac"): FAIL
if not debug and (os == "win") and (version == "6.1.7601"): FAIL
[not shadowed contextrestored (document.body)]
expected: FAIL
[not shadowed contextlost (window)]
expected: FAIL
[not shadowed contextlost (document.createElement("body"))]
expected: FAIL
[not shadowed contextlost (document.body)]
expected: FAIL
[not shadowed contextrestored (window)]
expected: FAIL
[not shadowed contextrestored (document.createElement("body"))]
expected: FAIL
[not shadowed beforematch (window)]
expected: FAIL

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

@ -8,24 +8,6 @@
[shadowed unload removal (document.createElement("frameset"))]
disabled: Bug 1485887
[not shadowed contextrestored (document.body)]
expected: FAIL
[not shadowed contextlost (window)]
expected: FAIL
[not shadowed contextlost (document.createElement("frameset"))]
expected: FAIL
[not shadowed contextrestored (document.createElement("frameset"))]
expected: FAIL
[not shadowed contextlost (document.body)]
expected: FAIL
[not shadowed contextrestored (window)]
expected: FAIL
[not shadowed beforematch (document.createElement("frameset"))]
expected: FAIL

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

@ -1,16 +1,4 @@
[event-handler-attributes-windowless-body.html]
[contextlost is unaffected on a windowless body]
expected: FAIL
[contextlost is unaffected on a windowless frameset]
expected: FAIL
[contextrestored is unaffected on a windowless body]
expected: FAIL
[contextrestored is unaffected on a windowless frameset]
expected: FAIL
[beforematch is unaffected on a windowless body]
expected: FAIL

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

@ -1,36 +1,6 @@
[math-global-event-handlers.tentative.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[oncontextlost: must be on the appropriate locations for GlobalEventHandlers]
expected: FAIL
[oncontextlost: the default value must be null]
expected: FAIL
[oncontextlost: the content attribute must be compiled into a function as the corresponding property]
expected: FAIL
[oncontextlost: dynamic changes on the attribute]
expected: FAIL
[oncontextlost: dispatching an Event at a <math> element must trigger element.oncontextlost]
expected: FAIL
[oncontextrestored: must be on the appropriate locations for GlobalEventHandlers]
expected: FAIL
[oncontextrestored: the default value must be null]
expected: FAIL
[oncontextrestored: the content attribute must be compiled into a function as the corresponding property]
expected: FAIL
[oncontextrestored: dynamic changes on the attribute]
expected: FAIL
[oncontextrestored: dispatching an Event at a <math> element must trigger element.oncontextrestored]
expected: FAIL
[onbeforematch: must be on the appropriate locations for GlobalEventHandlers]
expected: FAIL

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

@ -209,6 +209,10 @@ NS_EVENT_MESSAGE(eLegacyDOMFocusOut)
NS_EVENT_MESSAGE(ePageShow)
NS_EVENT_MESSAGE(ePageHide)
// Canvas events
NS_EVENT_MESSAGE(eContextLost)
NS_EVENT_MESSAGE(eContextRestored)
// SVG events
NS_EVENT_MESSAGE(eSVGLoad)
NS_EVENT_MESSAGE(eSVGScroll)

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

@ -2161,6 +2161,18 @@ GfxInfoBase::GetUsingGPUProcess(bool* aOutValue) {
return NS_OK;
}
NS_IMETHODIMP
GfxInfoBase::GetUsingRemoteCanvas(bool* aOutValue) {
*aOutValue = gfx::gfxVars::RemoteCanvasEnabled();
return NS_OK;
}
NS_IMETHODIMP
GfxInfoBase::GetUsingAcceleratedCanvas(bool* aOutValue) {
*aOutValue = gfx::gfxVars::UseAcceleratedCanvas2D();
return NS_OK;
}
NS_IMETHODIMP_(int32_t)
GfxInfoBase::GetMaxRefreshRate(bool* aMixed) {
if (aMixed) {

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

@ -73,6 +73,8 @@ class GfxInfoBase : public nsIGfxInfo,
NS_IMETHOD GetAzureCanvasBackend(nsAString& aBackend) override;
NS_IMETHOD GetAzureContentBackend(nsAString& aBackend) override;
NS_IMETHOD GetUsingGPUProcess(bool* aOutValue) override;
NS_IMETHOD GetUsingRemoteCanvas(bool* aOutValue) override;
NS_IMETHOD GetUsingAcceleratedCanvas(bool* aOutValue) override;
NS_IMETHOD GetIsHeadless(bool* aIsHeadless) override;
NS_IMETHOD GetTargetFrameRate(uint32_t* aTargetFrameRate) override;
NS_IMETHOD GetCodecSupportInfo(nsACString& aCodecSupportInfo) override;

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

@ -19,6 +19,8 @@ interface nsIGfxInfo : nsISupports
readonly attribute AString AzureCanvasBackend;
readonly attribute AString AzureContentBackend;
readonly attribute boolean usingGPUProcess;
readonly attribute boolean usingRemoteCanvas;
readonly attribute boolean usingAcceleratedCanvas;
readonly attribute boolean hasBattery;
readonly attribute AString DWriteVersion;
readonly attribute AString cleartypeParameters;