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/. */
6 
7 #ifndef MOZILLA_DOM_OFFSCREENCANVAS_H_
8 #define MOZILLA_DOM_OFFSCREENCANVAS_H_
9 
10 #include "gfxTypes.h"
11 #include "mozilla/DOMEventTargetHelper.h"
12 #include "mozilla/layers/LayersTypes.h"
13 #include "mozilla/RefPtr.h"
14 #include "CanvasRenderingContextHelper.h"
15 #include "nsCycleCollectionParticipant.h"
16 
17 struct JSContext;
18 
19 namespace mozilla {
20 
21 class ErrorResult;
22 
23 namespace layers {
24 class AsyncCanvasRenderer;
25 class CanvasClient;
26 class ImageContainer;
27 }  // namespace layers
28 
29 namespace dom {
30 class Blob;
31 class ImageBitmap;
32 
33 // This is helper class for transferring OffscreenCanvas to worker thread.
34 // Because OffscreenCanvas is not thread-safe. So we cannot pass Offscreen-
35 // Canvas to worker thread directly. Thus, we create this helper class and
36 // store necessary data in it then pass it to worker thread.
37 struct OffscreenCanvasCloneData final {
38   OffscreenCanvasCloneData(layers::AsyncCanvasRenderer* aRenderer,
39                            uint32_t aWidth, uint32_t aHeight,
40                            layers::LayersBackend aCompositorBackend,
41                            bool aNeutered, bool aIsWriteOnly);
42   ~OffscreenCanvasCloneData();
43 
44   RefPtr<layers::AsyncCanvasRenderer> mRenderer;
45   uint32_t mWidth;
46   uint32_t mHeight;
47   layers::LayersBackend mCompositorBackendType;
48   bool mNeutered;
49   bool mIsWriteOnly;
50 };
51 
52 class OffscreenCanvas final : public DOMEventTargetHelper,
53                               public CanvasRenderingContextHelper {
54  public:
55   NS_DECL_ISUPPORTS_INHERITED
56   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(OffscreenCanvas,
57                                            DOMEventTargetHelper)
58 
59   OffscreenCanvas(nsIGlobalObject* aGlobal, uint32_t aWidth, uint32_t aHeight,
60                   layers::LayersBackend aCompositorBackend,
61                   layers::AsyncCanvasRenderer* aRenderer);
62 
GetParentObject()63   nsCOMPtr<nsIGlobalObject> GetParentObject() const { return GetOwnerGlobal(); }
64 
65   virtual JSObject* WrapObject(JSContext* aCx,
66                                JS::Handle<JSObject*> aGivenProto) override;
67 
68   static already_AddRefed<OffscreenCanvas> Constructor(
69       const GlobalObject& aGlobal, uint32_t aWidth, uint32_t aHeight);
70 
71   void ClearResources();
72 
Width()73   uint32_t Width() const { return mWidth; }
74 
Height()75   uint32_t Height() const { return mHeight; }
76 
SetWidth(uint32_t aWidth,ErrorResult & aRv)77   void SetWidth(uint32_t aWidth, ErrorResult& aRv) {
78     if (mNeutered) {
79       aRv.Throw(NS_ERROR_FAILURE);
80       return;
81     }
82 
83     if (mWidth != aWidth) {
84       mWidth = aWidth;
85       CanvasAttrChanged();
86     }
87   }
88 
SetHeight(uint32_t aHeight,ErrorResult & aRv)89   void SetHeight(uint32_t aHeight, ErrorResult& aRv) {
90     if (mNeutered) {
91       aRv.Throw(NS_ERROR_FAILURE);
92       return;
93     }
94 
95     if (mHeight != aHeight) {
96       mHeight = aHeight;
97       CanvasAttrChanged();
98     }
99   }
100 
101   already_AddRefed<ImageBitmap> TransferToImageBitmap(ErrorResult& aRv);
102 
103   already_AddRefed<Promise> ToBlob(JSContext* aCx, const nsAString& aType,
104                                    JS::Handle<JS::Value> aParams,
105                                    ErrorResult& aRv);
106 
GetContext()107   nsICanvasRenderingContextInternal* GetContext() const {
108     return mCurrentContext;
109   }
110 
111   already_AddRefed<gfx::SourceSurface> GetSurfaceSnapshot(
112       gfxAlphaType* aOutAlphaType = nullptr);
113 
114   static already_AddRefed<OffscreenCanvas> CreateFromCloneData(
115       nsIGlobalObject* aGlobal, OffscreenCanvasCloneData* aData);
116 
117   // Return true on main-thread, and return gfx.offscreencanvas.enabled
118   // on worker thread.
119   static bool PrefEnabledOnWorkerThread(JSContext* aCx, JSObject* aObj);
120 
121   OffscreenCanvasCloneData* ToCloneData();
122 
123   void CommitFrameToCompositor();
124 
GetOpaqueAttr()125   virtual bool GetOpaqueAttr() override { return false; }
126 
GetWidthHeight()127   virtual nsIntSize GetWidthHeight() override {
128     return nsIntSize(mWidth, mHeight);
129   }
130 
131   virtual already_AddRefed<nsICanvasRenderingContextInternal> CreateContext(
132       CanvasContextType aContextType) override;
133 
134   virtual already_AddRefed<nsISupports> GetContext(
135       JSContext* aCx, const nsAString& aContextId,
136       JS::Handle<JS::Value> aContextOptions, ErrorResult& aRv) override;
137 
SetNeutered()138   void SetNeutered() { mNeutered = true; }
139 
IsNeutered()140   bool IsNeutered() const { return mNeutered; }
141 
SetWriteOnly()142   void SetWriteOnly() { mIsWriteOnly = true; }
143 
IsWriteOnly()144   bool IsWriteOnly() const { return mIsWriteOnly; }
145 
GetCompositorBackendType()146   layers::LayersBackend GetCompositorBackendType() const {
147     return mCompositorBackendType;
148   }
149 
150   layers::ImageContainer* GetImageContainer();
151 
152  private:
153   ~OffscreenCanvas();
154 
155   nsCOMPtr<nsIGlobalObject> GetGlobalObject();
156 
CanvasAttrChanged()157   void CanvasAttrChanged() {
158     mAttrDirty = true;
159     ErrorResult dummy;
160     UpdateContext(nullptr, JS::NullHandleValue, dummy);
161   }
162 
163   bool mAttrDirty;
164   bool mNeutered;
165   bool mIsWriteOnly;
166 
167   uint32_t mWidth;
168   uint32_t mHeight;
169 
170   layers::LayersBackend mCompositorBackendType;
171 
172   RefPtr<layers::CanvasClient> mCanvasClient;
173   RefPtr<layers::AsyncCanvasRenderer> mCanvasRenderer;
174 };
175 
176 }  // namespace dom
177 }  // namespace mozilla
178 
179 #endif  // MOZILLA_DOM_OFFSCREENCANVAS_H_
180