Bug 1610775 [wpt PR 21336] - Update urllib3 to 1.25.8, a=testonly
[gecko.git] / dom / canvas / OffscreenCanvas.cpp
blob091cc61b015e7bcb7fd5cadb508ad8560f1fa033
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "OffscreenCanvas.h"
9 #include "mozilla/dom/OffscreenCanvasBinding.h"
10 #include "mozilla/dom/WorkerPrivate.h"
11 #include "mozilla/dom/WorkerScope.h"
12 #include "mozilla/layers/AsyncCanvasRenderer.h"
13 #include "mozilla/layers/CanvasClient.h"
14 #include "mozilla/layers/ImageBridgeChild.h"
15 #include "mozilla/Telemetry.h"
16 #include "CanvasRenderingContext2D.h"
17 #include "CanvasUtils.h"
18 #include "GLContext.h"
19 #include "GLScreenBuffer.h"
21 namespace mozilla {
22 namespace dom {
24 OffscreenCanvasCloneData::OffscreenCanvasCloneData(
25 layers::AsyncCanvasRenderer* aRenderer, uint32_t aWidth, uint32_t aHeight,
26 layers::LayersBackend aCompositorBackend, bool aNeutered, bool aIsWriteOnly)
27 : mRenderer(aRenderer),
28 mWidth(aWidth),
29 mHeight(aHeight),
30 mCompositorBackendType(aCompositorBackend),
31 mNeutered(aNeutered),
32 mIsWriteOnly(aIsWriteOnly) {}
34 OffscreenCanvasCloneData::~OffscreenCanvasCloneData() {}
36 OffscreenCanvas::OffscreenCanvas(nsIGlobalObject* aGlobal, uint32_t aWidth,
37 uint32_t aHeight,
38 layers::LayersBackend aCompositorBackend,
39 layers::AsyncCanvasRenderer* aRenderer)
40 : DOMEventTargetHelper(aGlobal),
41 mAttrDirty(false),
42 mNeutered(false),
43 mIsWriteOnly(false),
44 mWidth(aWidth),
45 mHeight(aHeight),
46 mCompositorBackendType(aCompositorBackend),
47 mCanvasRenderer(aRenderer) {}
49 OffscreenCanvas::~OffscreenCanvas() { ClearResources(); }
51 JSObject* OffscreenCanvas::WrapObject(JSContext* aCx,
52 JS::Handle<JSObject*> aGivenProto) {
53 return OffscreenCanvas_Binding::Wrap(aCx, this, aGivenProto);
56 /* static */
57 already_AddRefed<OffscreenCanvas> OffscreenCanvas::Constructor(
58 const GlobalObject& aGlobal, uint32_t aWidth, uint32_t aHeight) {
59 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
60 RefPtr<OffscreenCanvas> offscreenCanvas = new OffscreenCanvas(
61 global, aWidth, aHeight, layers::LayersBackend::LAYERS_NONE, nullptr);
62 return offscreenCanvas.forget();
65 void OffscreenCanvas::ClearResources() {
66 if (mCanvasClient) {
67 mCanvasClient->Clear();
69 if (mCanvasRenderer) {
70 nsCOMPtr<nsISerialEventTarget> activeTarget =
71 mCanvasRenderer->GetActiveEventTarget();
72 MOZ_RELEASE_ASSERT(activeTarget,
73 "GFX: failed to get active event target.");
74 bool current;
75 activeTarget->IsOnCurrentThread(&current);
76 MOZ_RELEASE_ASSERT(current, "GFX: active thread is not current thread.");
77 mCanvasRenderer->SetCanvasClient(nullptr);
78 mCanvasRenderer->mContext = nullptr;
79 mCanvasRenderer->mGLContext = nullptr;
80 mCanvasRenderer->ResetActiveEventTarget();
83 mCanvasClient = nullptr;
87 already_AddRefed<nsISupports> OffscreenCanvas::GetContext(
88 JSContext* aCx, const nsAString& aContextId,
89 JS::Handle<JS::Value> aContextOptions, ErrorResult& aRv) {
90 if (mNeutered) {
91 aRv.Throw(NS_ERROR_FAILURE);
92 return nullptr;
95 // We only support WebGL in workers for now
96 CanvasContextType contextType;
97 if (!CanvasUtils::GetCanvasContextType(aContextId, &contextType)) {
98 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
99 return nullptr;
102 if (!(contextType == CanvasContextType::WebGL1 ||
103 contextType == CanvasContextType::WebGL2 ||
104 contextType == CanvasContextType::ImageBitmap)) {
105 aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
106 return nullptr;
109 RefPtr<nsISupports> result = CanvasRenderingContextHelper::GetContext(
110 aCx, aContextId, aContextOptions, aRv);
112 if (!mCurrentContext) {
113 return nullptr;
116 if (mCanvasRenderer) {
117 mCanvasRenderer->SetContextType(contextType);
118 if (contextType == CanvasContextType::WebGL1 ||
119 contextType == CanvasContextType::WebGL2) {
120 MOZ_ASSERT_UNREACHABLE("WebGL OffscreenCanvas not yet supported.");
121 return nullptr;
125 return result.forget();
128 ImageContainer* OffscreenCanvas::GetImageContainer() {
129 if (!mCanvasRenderer) {
130 return nullptr;
132 return mCanvasRenderer->GetImageContainer();
135 already_AddRefed<nsICanvasRenderingContextInternal>
136 OffscreenCanvas::CreateContext(CanvasContextType aContextType) {
137 RefPtr<nsICanvasRenderingContextInternal> ret =
138 CanvasRenderingContextHelper::CreateContext(aContextType);
140 ret->SetOffscreenCanvas(this);
141 return ret.forget();
144 void OffscreenCanvas::CommitFrameToCompositor() {
145 if (!mCanvasRenderer) {
146 // This offscreen canvas doesn't associate to any HTML canvas element.
147 // So, just bail out.
148 return;
151 // The attributes has changed, we have to notify main
152 // thread to change canvas size.
153 if (mAttrDirty) {
154 if (mCanvasRenderer) {
155 mCanvasRenderer->SetWidth(mWidth);
156 mCanvasRenderer->SetHeight(mHeight);
157 mCanvasRenderer->NotifyElementAboutAttributesChanged();
159 mAttrDirty = false;
162 CanvasContextType contentType = mCanvasRenderer->GetContextType();
163 if (mCurrentContext && (contentType == CanvasContextType::WebGL1 ||
164 contentType == CanvasContextType::WebGL2)) {
165 MOZ_ASSERT_UNREACHABLE("WebGL OffscreenCanvas not yet supported.");
166 return;
169 if (mCanvasRenderer && mCanvasRenderer->mGLContext) {
170 mCanvasRenderer->NotifyElementAboutInvalidation();
171 ImageBridgeChild::GetSingleton()->UpdateAsyncCanvasRenderer(
172 mCanvasRenderer);
176 OffscreenCanvasCloneData* OffscreenCanvas::ToCloneData() {
177 return new OffscreenCanvasCloneData(mCanvasRenderer, mWidth, mHeight,
178 mCompositorBackendType, mNeutered,
179 mIsWriteOnly);
182 already_AddRefed<ImageBitmap> OffscreenCanvas::TransferToImageBitmap(
183 ErrorResult& aRv) {
184 nsCOMPtr<nsIGlobalObject> globalObject = GetGlobalObject();
185 RefPtr<ImageBitmap> result =
186 ImageBitmap::CreateFromOffscreenCanvas(globalObject, *this, aRv);
187 if (aRv.Failed()) {
188 return nullptr;
191 // TODO: Clear the content?
192 return result.forget();
195 already_AddRefed<Promise> OffscreenCanvas::ToBlob(JSContext* aCx,
196 const nsAString& aType,
197 JS::Handle<JS::Value> aParams,
198 ErrorResult& aRv) {
199 // do a trust check if this is a write-only canvas
200 if (mIsWriteOnly) {
201 aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
202 return nullptr;
205 nsCOMPtr<nsIGlobalObject> global = GetGlobalObject();
207 RefPtr<Promise> promise = Promise::Create(global, aRv);
208 if (aRv.Failed()) {
209 return nullptr;
212 // Encoder callback when encoding is complete.
213 class EncodeCallback : public EncodeCompleteCallback {
214 public:
215 EncodeCallback(nsIGlobalObject* aGlobal, Promise* aPromise)
216 : mGlobal(aGlobal), mPromise(aPromise) {}
218 // This is called on main thread.
219 nsresult ReceiveBlobImpl(already_AddRefed<BlobImpl> aBlobImpl) override {
220 RefPtr<BlobImpl> blobImpl = aBlobImpl;
222 if (mPromise) {
223 RefPtr<Blob> blob = Blob::Create(mGlobal, blobImpl);
224 if (NS_WARN_IF(!blob)) {
225 mPromise->MaybeReject(NS_ERROR_FAILURE);
226 } else {
227 mPromise->MaybeResolve(blob);
231 mGlobal = nullptr;
232 mPromise = nullptr;
234 return NS_OK;
237 nsCOMPtr<nsIGlobalObject> mGlobal;
238 RefPtr<Promise> mPromise;
241 RefPtr<EncodeCompleteCallback> callback = new EncodeCallback(global, promise);
243 bool usePlaceholder;
244 if (NS_IsMainThread()) {
245 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetGlobalObject());
246 Document* doc = window->GetExtantDoc();
247 usePlaceholder =
248 doc ? nsContentUtils::ShouldResistFingerprinting(doc) : false;
249 } else {
250 dom::WorkerPrivate* workerPrivate = dom::GetCurrentThreadWorkerPrivate();
251 usePlaceholder = nsContentUtils::ShouldResistFingerprinting(workerPrivate);
253 CanvasRenderingContextHelper::ToBlob(aCx, global, callback, aType, aParams,
254 usePlaceholder, aRv);
256 return promise.forget();
259 already_AddRefed<gfx::SourceSurface> OffscreenCanvas::GetSurfaceSnapshot(
260 gfxAlphaType* const aOutAlphaType) {
261 if (!mCurrentContext) {
262 return nullptr;
265 return mCurrentContext->GetSurfaceSnapshot(aOutAlphaType);
268 nsCOMPtr<nsIGlobalObject> OffscreenCanvas::GetGlobalObject() {
269 if (NS_IsMainThread()) {
270 return GetParentObject();
273 dom::WorkerPrivate* workerPrivate = dom::GetCurrentThreadWorkerPrivate();
274 return workerPrivate->GlobalScope();
277 /* static */
278 already_AddRefed<OffscreenCanvas> OffscreenCanvas::CreateFromCloneData(
279 nsIGlobalObject* aGlobal, OffscreenCanvasCloneData* aData) {
280 MOZ_ASSERT(aData);
281 RefPtr<OffscreenCanvas> wc =
282 new OffscreenCanvas(aGlobal, aData->mWidth, aData->mHeight,
283 aData->mCompositorBackendType, aData->mRenderer);
284 if (aData->mNeutered) {
285 wc->SetNeutered();
287 return wc.forget();
290 /* static */
291 bool OffscreenCanvas::PrefEnabledOnWorkerThread(JSContext* aCx,
292 JSObject* aObj) {
293 if (NS_IsMainThread()) {
294 return true;
297 return StaticPrefs::gfx_offscreencanvas_enabled();
300 NS_IMPL_CYCLE_COLLECTION_INHERITED(OffscreenCanvas, DOMEventTargetHelper,
301 mCurrentContext)
303 NS_IMPL_ADDREF_INHERITED(OffscreenCanvas, DOMEventTargetHelper)
304 NS_IMPL_RELEASE_INHERITED(OffscreenCanvas, DOMEventTargetHelper)
306 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(OffscreenCanvas)
307 NS_INTERFACE_MAP_ENTRY(nsISupports)
308 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
310 } // namespace dom
311 } // namespace mozilla