From 503fb4c624dde6acbb4c9fac612fb42175ff3e08 Mon Sep 17 00:00:00 2001 From: Andrew Osmond Date: Thu, 28 Mar 2024 14:50:20 +0000 Subject: [PATCH] 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 --- dom/canvas/CanvasRenderingContext2D.cpp | 71 +++++++++- dom/canvas/CanvasRenderingContext2D.h | 10 +- .../nsICanvasRenderingContextInternal.cpp | 24 ++++ .../nsICanvasRenderingContextInternal.h | 4 + dom/canvas/test/mochitest.toml | 4 + .../test_accelerated_canvas_context_loss.html | 121 ++++++++++++++++++ dom/events/EventNameList.h | 3 + .../mochitest/general/test_interfaces.js | 4 + dom/webidl/CanvasRenderingContext2D.webidl | 1 + dom/webidl/EventHandler.webidl | 2 + gfx/ipc/CanvasManagerChild.cpp | 5 + gfx/ipc/CanvasShutdownManager.cpp | 71 ++++++++++ gfx/ipc/CanvasShutdownManager.h | 11 ++ gfx/layers/ipc/CompositorManagerChild.cpp | 11 +- gfx/tests/gtest/TestConfigManager.cpp | 6 + .../meta/html/dom/idlharness.https.html.ini | 63 --------- .../meta/html/dom/idlharness.worker.js.ini | 3 - .../event-handler-all-global-events.html.ini | 24 ---- ...nt-handler-attributes-body-window.html.ini | 18 --- ...andler-attributes-frameset-window.html.ini | 18 --- ...andler-attributes-windowless-body.html.ini | 12 -- ...h-global-event-handlers.tentative.html.ini | 30 ----- widget/EventMessageList.h | 4 + widget/GfxInfoBase.cpp | 12 ++ widget/GfxInfoBase.h | 2 + widget/nsIGfxInfo.idl | 2 + 26 files changed, 365 insertions(+), 171 deletions(-) create mode 100644 dom/canvas/test/test_accelerated_canvas_context_loss.html diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index c6501226b098..3c8ee055b405 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -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; diff --git a/dom/canvas/CanvasRenderingContext2D.h b/dom/canvas/CanvasRenderingContext2D.h index c42a94778ac3..75a57ab14fac 100644 --- a/dom/canvas/CanvasRenderingContext2D.h +++ b/dom/canvas/CanvasRenderingContext2D.h @@ -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(); diff --git a/dom/canvas/nsICanvasRenderingContextInternal.cpp b/dom/canvas/nsICanvasRenderingContextInternal.cpp index c463a00a1aef..ca8e16136cab 100644 --- a/dom/canvas/nsICanvasRenderingContextInternal.cpp +++ b/dom/canvas/nsICanvasRenderingContextInternal.cpp @@ -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(mOffscreenCanvas, + nullptr, nullptr); + event->InitEvent(eventName, aCanBubble, aIsCancelable); + event->SetTrusted(true); + useDefaultHandler = mOffscreenCanvas->DispatchEvent( + *event, mozilla::dom::CallerType::System, mozilla::IgnoreErrors()); + } + return useDefaultHandler; +} diff --git a/dom/canvas/nsICanvasRenderingContextInternal.h b/dom/canvas/nsICanvasRenderingContextInternal.h index 580a9f07b311..deb642e9e8e3 100644 --- a/dom/canvas/nsICanvasRenderingContextInternal.h +++ b/dom/canvas/nsICanvasRenderingContextInternal.h @@ -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 mCanvasElement; RefPtr mOffscreenCanvas; diff --git a/dom/canvas/test/mochitest.toml b/dom/canvas/test/mochitest.toml index 86cf26b6323d..3e96fff26bc2 100644 --- a/dom/canvas/test/mochitest.toml +++ b/dom/canvas/test/mochitest.toml @@ -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"] diff --git a/dom/canvas/test/test_accelerated_canvas_context_loss.html b/dom/canvas/test/test_accelerated_canvas_context_loss.html new file mode 100644 index 000000000000..6172420bcb65 --- /dev/null +++ b/dom/canvas/test/test_accelerated_canvas_context_loss.html @@ -0,0 +1,121 @@ + + + + + Check for contextlost/restored events after GPU process restart + + + + + + + + + diff --git a/dom/events/EventNameList.h b/dom/events/EventNameList.h index 6c9119d5f9e2..92c76d000ec0 100644 --- a/dom/events/EventNameList.h +++ b/dom/events/EventNameList.h @@ -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) diff --git a/dom/tests/mochitest/general/test_interfaces.js b/dom/tests/mochitest/general/test_interfaces.js index 38530ca3653a..1222447240a1 100644 --- a/dom/tests/mochitest/general/test_interfaces.js +++ b/dom/tests/mochitest/general/test_interfaces.js @@ -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 }, diff --git a/dom/webidl/CanvasRenderingContext2D.webidl b/dom/webidl/CanvasRenderingContext2D.webidl index c89c09892890..d6c27d91b5d6 100644 --- a/dom/webidl/CanvasRenderingContext2D.webidl +++ b/dom/webidl/CanvasRenderingContext2D.webidl @@ -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 { diff --git a/dom/webidl/EventHandler.webidl b/dom/webidl/EventHandler.webidl index 439ac79e5ddd..c88e4f0422ce 100644 --- a/dom/webidl/EventHandler.webidl +++ b/dom/webidl/EventHandler.webidl @@ -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; diff --git a/gfx/ipc/CanvasManagerChild.cpp b/gfx/ipc/CanvasManagerChild.cpp index 493fde1013c6..dee232b6b111 100644 --- a/gfx/ipc/CanvasManagerChild.cpp +++ b/gfx/ipc/CanvasManagerChild.cpp @@ -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; } diff --git a/gfx/ipc/CanvasShutdownManager.cpp b/gfx/ipc/CanvasShutdownManager.cpp index 68839582469f..d7fc96d2557a 100644 --- a/gfx/ipc/CanvasShutdownManager.cpp +++ b/gfx/ipc/CanvasShutdownManager.cpp @@ -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::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(manager->mWorkerRef->Private()); + task->Dispatch(); + } + } +} + } // namespace mozilla::gfx diff --git a/gfx/ipc/CanvasShutdownManager.h b/gfx/ipc/CanvasShutdownManager.h index fbf3e982967e..803d6a1eb8af 100644 --- a/gfx/ipc/CanvasShutdownManager.h +++ b/gfx/ipc/CanvasShutdownManager.h @@ -7,6 +7,7 @@ #define _include_gfx_ipc_CanvasShutdownManager_h__ #include "mozilla/RefPtr.h" +#include "mozilla/StaticMutex.h" #include "mozilla/ThreadLocal.h" #include @@ -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 mWorkerRef; std::set mActiveCanvas; static MOZ_THREAD_LOCAL(CanvasShutdownManager*) sLocalManager; + + static StaticMutex sManagersMutex; + static std::set sManagers; }; } // namespace gfx diff --git a/gfx/layers/ipc/CompositorManagerChild.cpp b/gfx/layers/ipc/CompositorManagerChild.cpp index 0e553745d38d..8d8933937366 100644 --- a/gfx/layers/ipc/CompositorManagerChild.cpp +++ b/gfx/layers/ipc/CompositorManagerChild.cpp @@ -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&& 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 */ diff --git a/gfx/tests/gtest/TestConfigManager.cpp b/gfx/tests/gtest/TestConfigManager.cpp index d76dcfd2345a..825a995e98b6 100644 --- a/gfx/tests/gtest/TestConfigManager.cpp +++ b/gfx/tests/gtest/TestConfigManager.cpp @@ -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; } diff --git a/testing/web-platform/meta/html/dom/idlharness.https.html.ini b/testing/web-platform/meta/html/dom/idlharness.https.html.ini index 8e590ea15cf7..96e0cbbe3dfc 100644 --- a/testing/web-platform/meta/html/dom/idlharness.https.html.ini +++ b/testing/web-platform/meta/html/dom/idlharness.https.html.ini @@ -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 diff --git a/testing/web-platform/meta/html/dom/idlharness.worker.js.ini b/testing/web-platform/meta/html/dom/idlharness.worker.js.ini index a9ff03494676..69318290ce50 100644 --- a/testing/web-platform/meta/html/dom/idlharness.worker.js.ini +++ b/testing/web-platform/meta/html/dom/idlharness.worker.js.ini @@ -5,9 +5,6 @@ [ImageData interface: attribute colorSpace] expected: FAIL - [OffscreenCanvasRenderingContext2D interface: operation isContextLost()] - expected: FAIL - [PromiseRejectionEvent interface: attribute promise] expected: FAIL diff --git a/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-all-global-events.html.ini b/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-all-global-events.html.ini index 4f77d733b8cc..988d05f88ecc 100644 --- a/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-all-global-events.html.ini +++ b/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-all-global-events.html.ini @@ -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 diff --git a/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-attributes-body-window.html.ini b/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-attributes-body-window.html.ini index 0f5040e45d85..a1136eafc221 100644 --- a/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-attributes-body-window.html.ini +++ b/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-attributes-body-window.html.ini @@ -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 diff --git a/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-attributes-frameset-window.html.ini b/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-attributes-frameset-window.html.ini index 2496ac3a7b51..933782ca51c2 100644 --- a/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-attributes-frameset-window.html.ini +++ b/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-attributes-frameset-window.html.ini @@ -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 diff --git a/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-attributes-windowless-body.html.ini b/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-attributes-windowless-body.html.ini index 14071ddb1d15..a22c675c54bd 100644 --- a/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-attributes-windowless-body.html.ini +++ b/testing/web-platform/meta/html/webappapis/scripting/events/event-handler-attributes-windowless-body.html.ini @@ -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 diff --git a/testing/web-platform/meta/mathml/relations/html5-tree/math-global-event-handlers.tentative.html.ini b/testing/web-platform/meta/mathml/relations/html5-tree/math-global-event-handlers.tentative.html.ini index 35ff408d0993..4dfd835f5f40 100644 --- a/testing/web-platform/meta/mathml/relations/html5-tree/math-global-event-handlers.tentative.html.ini +++ b/testing/web-platform/meta/mathml/relations/html5-tree/math-global-event-handlers.tentative.html.ini @@ -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 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 element must trigger element.oncontextrestored] - expected: FAIL - [onbeforematch: must be on the appropriate locations for GlobalEventHandlers] expected: FAIL diff --git a/widget/EventMessageList.h b/widget/EventMessageList.h index ae02d04676af..f42c1e3b2c7f 100644 --- a/widget/EventMessageList.h +++ b/widget/EventMessageList.h @@ -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) diff --git a/widget/GfxInfoBase.cpp b/widget/GfxInfoBase.cpp index a7ed1aaad1d2..251b46ce661b 100644 --- a/widget/GfxInfoBase.cpp +++ b/widget/GfxInfoBase.cpp @@ -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) { diff --git a/widget/GfxInfoBase.h b/widget/GfxInfoBase.h index 4d4b1a2def20..c2bab664006d 100644 --- a/widget/GfxInfoBase.h +++ b/widget/GfxInfoBase.h @@ -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; diff --git a/widget/nsIGfxInfo.idl b/widget/nsIGfxInfo.idl index f518608e941d..0df8696da7a7 100644 --- a/widget/nsIGfxInfo.idl +++ b/widget/nsIGfxInfo.idl @@ -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;