diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index a3ffe7d356d9..f9bfedd7d984 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -4224,8 +4224,7 @@ TextMetrics* CanvasRenderingContext2D::DrawOrMeasureText( GetAppUnitsValues(&processor.mAppUnitsPerDevPixel, nullptr); processor.mPt = gfx::Point(aX, aY); - processor.mDrawTarget = - gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); + processor.mDrawTarget = gfxPlatform::ThreadLocalScreenReferenceDrawTarget(); // If we don't have a target then we don't have a transform. A target won't // be needed in the case where we're measuring the text size. This allows @@ -5985,17 +5984,15 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CanvasPath, Release) NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CanvasPath, mParent) CanvasPath::CanvasPath(nsISupports* aParent) : mParent(aParent) { - mPathBuilder = gfxPlatform::GetPlatform() - ->ScreenReferenceDrawTarget() - ->CreatePathBuilder(); + mPathBuilder = + gfxPlatform::ThreadLocalScreenReferenceDrawTarget()->CreatePathBuilder(); } CanvasPath::CanvasPath(nsISupports* aParent, already_AddRefed aPathBuilder) : mParent(aParent), mPathBuilder(aPathBuilder) { if (!mPathBuilder) { - mPathBuilder = gfxPlatform::GetPlatform() - ->ScreenReferenceDrawTarget() + mPathBuilder = gfxPlatform::ThreadLocalScreenReferenceDrawTarget() ->CreatePathBuilder(); } } @@ -6013,9 +6010,10 @@ already_AddRefed CanvasPath::Constructor( already_AddRefed CanvasPath::Constructor( const GlobalObject& aGlobal, CanvasPath& aCanvasPath) { - RefPtr tempPath = aCanvasPath.GetPath( - CanvasWindingRule::Nonzero, - gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget().get()); + RefPtr drawTarget = + gfxPlatform::ThreadLocalScreenReferenceDrawTarget(); + RefPtr tempPath = + aCanvasPath.GetPath(CanvasWindingRule::Nonzero, drawTarget.get()); RefPtr path = new CanvasPath(aGlobal.GetAsSupports(), tempPath->CopyToBuilder()); @@ -6177,9 +6175,10 @@ void CanvasPath::BezierTo(const gfx::Point& aCP1, const gfx::Point& aCP2, void CanvasPath::AddPath(CanvasPath& aCanvasPath, const DOMMatrix2DInit& aInit, ErrorResult& aError) { - RefPtr tempPath = aCanvasPath.GetPath( - CanvasWindingRule::Nonzero, - gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget().get()); + RefPtr drawTarget = + gfxPlatform::ThreadLocalScreenReferenceDrawTarget(); + RefPtr tempPath = + aCanvasPath.GetPath(CanvasWindingRule::Nonzero, drawTarget.get()); RefPtr matrix = DOMMatrixReadOnly::FromMatrix(GetParentObject(), aInit, aError); diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 58c078c69aa7..a041bcb146a6 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -50,6 +50,7 @@ #include "gfxCrashReporterUtils.h" #include "gfxPlatform.h" +#include "gfxPlatformWorker.h" #include "gfxBlur.h" #include "gfxEnv.h" @@ -2262,12 +2263,28 @@ mozilla::LogModule* gfxPlatform::GetLog(eGfxLog aWhichLog) { } RefPtr gfxPlatform::ScreenReferenceDrawTarget() { + MOZ_ASSERT_IF(XRE_IsContentProcess(), NS_IsMainThread()); return (mScreenReferenceDrawTarget) ? mScreenReferenceDrawTarget : gPlatform->CreateOffscreenContentDrawTarget( IntSize(1, 1), SurfaceFormat::B8G8R8A8, true); } +/* static */ RefPtr +gfxPlatform::ThreadLocalScreenReferenceDrawTarget() { + if (NS_IsMainThread() && gPlatform) { + return gPlatform->ScreenReferenceDrawTarget(); + } + + gfxPlatformWorker* platformWorker = gfxPlatformWorker::Get(); + if (platformWorker) { + return platformWorker->ScreenReferenceDrawTarget(); + } + + return Factory::CreateDrawTarget(BackendType::SKIA, IntSize(1, 1), + SurfaceFormat::B8G8R8A8); +} + mozilla::gfx::SurfaceFormat gfxPlatform::Optimal2DFormatForContent( gfxContentType aContent) { switch (aContent) { diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index e56ab49aa952..57410bd4a48e 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -636,6 +636,9 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener { */ RefPtr ScreenReferenceDrawTarget(); + static RefPtr + ThreadLocalScreenReferenceDrawTarget(); + virtual mozilla::gfx::SurfaceFormat Optimal2DFormatForContent( gfxContentType aContent); diff --git a/gfx/thebes/gfxPlatformWorker.cpp b/gfx/thebes/gfxPlatformWorker.cpp new file mode 100644 index 000000000000..1a6183236eec --- /dev/null +++ b/gfx/thebes/gfxPlatformWorker.cpp @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gfxPlatformWorker.h" +#include "mozilla/dom/WorkerCommon.h" +#include "mozilla/dom/WorkerRef.h" +#include "mozilla/gfx/2D.h" +#include "mozilla/ThreadLocal.h" + +using namespace mozilla; +using namespace mozilla::dom; +using namespace mozilla::gfx; + +MOZ_THREAD_LOCAL(gfxPlatformWorker*) gfxPlatformWorker::sInstance; + +/* static */ gfxPlatformWorker* gfxPlatformWorker::Get() { + if (!sInstance.init()) { + return nullptr; + } + + gfxPlatformWorker* instance = sInstance.get(); + if (instance) { + return instance; + } + + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + if (!workerPrivate) { + return nullptr; + } + + RefPtr workerRef = WeakWorkerRef::Create( + workerPrivate, []() { gfxPlatformWorker::Shutdown(); }); + if (!workerRef) { + return nullptr; + } + + instance = new gfxPlatformWorker(std::move(workerRef)); + sInstance.set(instance); + return instance; +} + +/* static */ void gfxPlatformWorker::Shutdown() { + if (!sInstance.init()) { + return; + } + + gfxPlatformWorker* instance = sInstance.get(); + if (!instance) { + return; + } + + sInstance.set(nullptr); + delete instance; +} + +gfxPlatformWorker::gfxPlatformWorker(RefPtr&& aWorkerRef) + : mWorkerRef(std::move(aWorkerRef)) {} + +gfxPlatformWorker::~gfxPlatformWorker() = default; + +RefPtr +gfxPlatformWorker::ScreenReferenceDrawTarget() { + if (!mScreenReferenceDrawTarget) { + mScreenReferenceDrawTarget = Factory::CreateDrawTarget( + BackendType::SKIA, IntSize(1, 1), SurfaceFormat::B8G8R8A8); + } + return mScreenReferenceDrawTarget; +} diff --git a/gfx/thebes/gfxPlatformWorker.h b/gfx/thebes/gfxPlatformWorker.h new file mode 100644 index 000000000000..bf9336e77d11 --- /dev/null +++ b/gfx/thebes/gfxPlatformWorker.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GFX_PLATFORM_WORKER_H +#define GFX_PLATFORM_WORKER_H + +#include "mozilla/ThreadLocal.h" + +namespace mozilla { +namespace dom { +class WeakWorkerRef; +} // namespace dom + +namespace gfx { +class DrawTarget; +} // namespace gfx +} // namespace mozilla + +/** + * Threadlocal instance of gfxPlatform data that may be used/shared on a DOM + * worker thread. + */ +class gfxPlatformWorker final { + public: + static gfxPlatformWorker* Get(); + static void Shutdown(); + + RefPtr ScreenReferenceDrawTarget(); + + private: + explicit gfxPlatformWorker(RefPtr&& aWorkerRef); + ~gfxPlatformWorker(); + + static MOZ_THREAD_LOCAL(gfxPlatformWorker*) sInstance; + + RefPtr mWorkerRef; + + RefPtr mScreenReferenceDrawTarget; +}; + +#endif // GFX_PLATFORM_WORKER_H diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index be85c44845fe..c2d47afdb2e9 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -47,6 +47,7 @@ EXPORTS += [ "gfxPattern.h", "gfxPlatform.h", "gfxPlatformFontList.h", + "gfxPlatformWorker.h", "gfxPoint.h", "gfxQuad.h", "gfxQuaternion.h", @@ -213,6 +214,7 @@ UNIFIED_SOURCES += [ "gfxMathTable.cpp", "gfxPattern.cpp", "gfxPlatformFontList.cpp", + "gfxPlatformWorker.cpp", "gfxScriptItemizer.cpp", "gfxSkipChars.cpp", "gfxSVGGlyphs.cpp", diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 08a38aef4cb0..d4aead98a924 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -7086,7 +7086,7 @@ SurfaceFromElementResult nsLayoutUtils::SurfaceFromOffscreenCanvas( result.mAlphaType = gfxAlphaType::Opaque; RefPtr ref = aTarget ? aTarget - : gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); + : gfxPlatform::ThreadLocalScreenReferenceDrawTarget(); if (ref->CanCreateSimilarDrawTarget(size, SurfaceFormat::B8G8R8A8)) { RefPtr dt = ref->CreateSimilarDrawTarget(size, SurfaceFormat::B8G8R8A8);