Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 : #if !defined(mozilla_dom_HTMLCanvasElement_h)
7 : #define mozilla_dom_HTMLCanvasElement_h
8 :
9 : #include "mozilla/Attributes.h"
10 : #include "mozilla/WeakPtr.h"
11 : #include "nsIDOMEventListener.h"
12 : #include "nsIDOMHTMLCanvasElement.h"
13 : #include "nsIObserver.h"
14 : #include "nsGenericHTMLElement.h"
15 : #include "nsGkAtoms.h"
16 : #include "nsSize.h"
17 : #include "nsError.h"
18 :
19 : #include "mozilla/dom/BindingDeclarations.h"
20 : #include "mozilla/dom/CanvasRenderingContextHelper.h"
21 : #include "mozilla/gfx/Rect.h"
22 : #include "mozilla/layers/LayersTypes.h"
23 :
24 : class nsICanvasRenderingContextInternal;
25 : class nsITimerCallback;
26 :
27 : namespace mozilla {
28 :
29 : class WebGLContext;
30 :
31 : namespace layers {
32 : class AsyncCanvasRenderer;
33 : class CanvasLayer;
34 : class Image;
35 : class Layer;
36 : class LayerManager;
37 : class SharedSurfaceTextureClient;
38 : } // namespace layers
39 : namespace gfx {
40 : class SourceSurface;
41 : class VRLayerChild;
42 : } // namespace gfx
43 :
44 : namespace dom {
45 : class BlobCallback;
46 : class CanvasCaptureMediaStream;
47 : class File;
48 : class HTMLCanvasPrintState;
49 : class OffscreenCanvas;
50 : class PrintCallback;
51 : class RequestedFrameRefreshObserver;
52 :
53 : // Listen visibilitychange and memory-pressure event and inform
54 : // context when event is fired.
55 : class HTMLCanvasElementObserver final : public nsIObserver
56 : , public nsIDOMEventListener
57 : {
58 : public:
59 : NS_DECL_ISUPPORTS
60 : NS_DECL_NSIOBSERVER
61 : NS_DECL_NSIDOMEVENTLISTENER
62 :
63 : explicit HTMLCanvasElementObserver(HTMLCanvasElement* aElement);
64 : void Destroy();
65 :
66 : void RegisterVisibilityChangeEvent();
67 : void UnregisterVisibilityChangeEvent();
68 :
69 : void RegisterMemoryPressureEvent();
70 : void UnregisterMemoryPressureEvent();
71 :
72 : private:
73 : ~HTMLCanvasElementObserver();
74 :
75 : HTMLCanvasElement* mElement;
76 : };
77 :
78 : /*
79 : * FrameCaptureListener is used by captureStream() as a way of getting video
80 : * frames from the canvas. On a refresh driver tick after something has been
81 : * drawn to the canvas since the last such tick, all registered
82 : * FrameCaptureListeners whose `mFrameCaptureRequested` equals `true`,
83 : * will be given a copy of the just-painted canvas.
84 : * All FrameCaptureListeners get the same copy.
85 : */
86 : class FrameCaptureListener : public SupportsWeakPtr<FrameCaptureListener>
87 : {
88 : public:
89 0 : MOZ_DECLARE_WEAKREFERENCE_TYPENAME(FrameCaptureListener)
90 :
91 0 : FrameCaptureListener()
92 0 : : mFrameCaptureRequested(false) {}
93 :
94 : /*
95 : * Called when a frame capture is desired on next paint.
96 : */
97 0 : void RequestFrameCapture() { mFrameCaptureRequested = true; }
98 :
99 : /*
100 : * Indicates to the canvas whether or not this listener has requested a frame.
101 : */
102 0 : bool FrameCaptureRequested() const { return mFrameCaptureRequested; }
103 :
104 : /*
105 : * Interface through which new video frames will be provided while
106 : * `mFrameCaptureRequested` is `true`.
107 : */
108 : virtual void NewFrame(already_AddRefed<layers::Image> aImage,
109 : const TimeStamp& aTime) = 0;
110 :
111 : protected:
112 0 : virtual ~FrameCaptureListener() {}
113 :
114 : bool mFrameCaptureRequested;
115 : };
116 :
117 : class HTMLCanvasElement final : public nsGenericHTMLElement,
118 : public nsIDOMHTMLCanvasElement,
119 : public CanvasRenderingContextHelper
120 : {
121 : enum {
122 : DEFAULT_CANVAS_WIDTH = 300,
123 : DEFAULT_CANVAS_HEIGHT = 150
124 : };
125 :
126 : typedef layers::AsyncCanvasRenderer AsyncCanvasRenderer;
127 : typedef layers::CanvasLayer CanvasLayer;
128 : typedef layers::Layer Layer;
129 : typedef layers::LayerManager LayerManager;
130 :
131 : public:
132 : explicit HTMLCanvasElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
133 :
134 0 : NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLCanvasElement, canvas)
135 :
136 : // nsISupports
137 : NS_DECL_ISUPPORTS_INHERITED
138 :
139 : // nsIDOMHTMLCanvasElement
140 : NS_DECL_NSIDOMHTMLCANVASELEMENT
141 :
142 : // CC
143 0 : NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLCanvasElement,
144 : nsGenericHTMLElement)
145 :
146 : // WebIDL
147 0 : uint32_t Height()
148 : {
149 0 : return GetUnsignedIntAttr(nsGkAtoms::height, DEFAULT_CANVAS_HEIGHT);
150 : }
151 0 : void SetHeight(uint32_t aHeight, ErrorResult& aRv)
152 : {
153 0 : if (mOffscreenCanvas) {
154 0 : aRv.Throw(NS_ERROR_FAILURE);
155 0 : return;
156 : }
157 :
158 0 : SetUnsignedIntAttr(nsGkAtoms::height, aHeight, DEFAULT_CANVAS_HEIGHT, aRv);
159 : }
160 0 : uint32_t Width()
161 : {
162 0 : return GetUnsignedIntAttr(nsGkAtoms::width, DEFAULT_CANVAS_WIDTH);
163 : }
164 0 : void SetWidth(uint32_t aWidth, ErrorResult& aRv)
165 : {
166 0 : if (mOffscreenCanvas) {
167 0 : aRv.Throw(NS_ERROR_FAILURE);
168 0 : return;
169 : }
170 :
171 0 : SetUnsignedIntAttr(nsGkAtoms::width, aWidth, DEFAULT_CANVAS_WIDTH, aRv);
172 : }
173 :
174 : virtual already_AddRefed<nsISupports>
175 : GetContext(JSContext* aCx, const nsAString& aContextId,
176 : JS::Handle<JS::Value> aContextOptions,
177 : ErrorResult& aRv) override;
178 :
179 : void ToDataURL(JSContext* aCx, const nsAString& aType,
180 : JS::Handle<JS::Value> aParams,
181 : nsAString& aDataURL,
182 : ErrorResult& aRv);
183 :
184 : void ToBlob(JSContext* aCx,
185 : BlobCallback& aCallback,
186 : const nsAString& aType,
187 : JS::Handle<JS::Value> aParams,
188 : ErrorResult& aRv);
189 :
190 : OffscreenCanvas* TransferControlToOffscreen(ErrorResult& aRv);
191 :
192 0 : bool MozOpaque() const
193 : {
194 0 : return GetBoolAttr(nsGkAtoms::moz_opaque);
195 : }
196 0 : void SetMozOpaque(bool aValue, ErrorResult& aRv)
197 : {
198 0 : if (mOffscreenCanvas) {
199 0 : aRv.Throw(NS_ERROR_FAILURE);
200 0 : return;
201 : }
202 :
203 0 : SetHTMLBoolAttr(nsGkAtoms::moz_opaque, aValue, aRv);
204 : }
205 : already_AddRefed<File> MozGetAsFile(const nsAString& aName,
206 : const nsAString& aType,
207 : CallerType aCallerType,
208 : ErrorResult& aRv);
209 : already_AddRefed<nsISupports> MozGetIPCContext(const nsAString& aContextId,
210 : ErrorResult& aRv);
211 : PrintCallback* GetMozPrintCallback() const;
212 : void SetMozPrintCallback(PrintCallback* aCallback);
213 :
214 : already_AddRefed<CanvasCaptureMediaStream>
215 : CaptureStream(const Optional<double>& aFrameRate, ErrorResult& aRv);
216 :
217 : /**
218 : * Get the size in pixels of this canvas element
219 : */
220 : nsIntSize GetSize();
221 :
222 : /**
223 : * Determine whether the canvas is write-only.
224 : */
225 : bool IsWriteOnly();
226 :
227 : /**
228 : * Force the canvas to be write-only.
229 : */
230 : void SetWriteOnly();
231 :
232 : /**
233 : * Notify that some canvas content has changed and the window may
234 : * need to be updated. aDamageRect is in canvas coordinates.
235 : */
236 : void InvalidateCanvasContent(const mozilla::gfx::Rect* aDamageRect);
237 : /*
238 : * Notify that we need to repaint the entire canvas, including updating of
239 : * the layer tree.
240 : */
241 : void InvalidateCanvas();
242 :
243 : /*
244 : * Get the number of contexts in this canvas, and request a context at
245 : * an index.
246 : */
247 : int32_t CountContexts ();
248 : nsICanvasRenderingContextInternal *GetContextAtIndex (int32_t index);
249 :
250 : /*
251 : * Returns true if the canvas context content is guaranteed to be opaque
252 : * across its entire area.
253 : */
254 : bool GetIsOpaque();
255 : virtual bool GetOpaqueAttr() override;
256 :
257 : virtual already_AddRefed<gfx::SourceSurface>
258 : GetSurfaceSnapshot(gfxAlphaType* aOutAlphaType = nullptr);
259 :
260 : /*
261 : * Register a FrameCaptureListener with this canvas.
262 : * The canvas hooks into the RefreshDriver while there are
263 : * FrameCaptureListeners registered.
264 : * The registered FrameCaptureListeners are stored as WeakPtrs, thus it's the
265 : * caller's responsibility to keep them alive. Once a registered
266 : * FrameCaptureListener is destroyed it will be automatically deregistered.
267 : */
268 : nsresult RegisterFrameCaptureListener(FrameCaptureListener* aListener);
269 :
270 : /*
271 : * Returns true when there is at least one registered FrameCaptureListener
272 : * that has requested a frame capture.
273 : */
274 : bool IsFrameCaptureRequested() const;
275 :
276 : /*
277 : * Processes destroyed FrameCaptureListeners and removes them if necessary.
278 : * Should there be none left, the FrameRefreshObserver will be unregistered.
279 : */
280 : void ProcessDestroyedFrameListeners();
281 :
282 : /*
283 : * Called by the RefreshDriver hook when a frame has been captured.
284 : * Makes a copy of the provided surface and hands it to all
285 : * FrameCaptureListeners having requested frame capture.
286 : */
287 : void SetFrameCapture(already_AddRefed<gfx::SourceSurface> aSurface,
288 : const TimeStamp& aTime);
289 :
290 : virtual bool ParseAttribute(int32_t aNamespaceID,
291 : nsIAtom* aAttribute,
292 : const nsAString& aValue,
293 : nsAttrValue& aResult) override;
294 : nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, int32_t aModType) const override;
295 :
296 : virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
297 : bool aPreallocateChildren) const override;
298 : nsresult CopyInnerTo(mozilla::dom::Element* aDest,
299 : bool aPreallocateChildren);
300 :
301 : virtual nsresult GetEventTargetParent(
302 : mozilla::EventChainPreVisitor& aVisitor) override;
303 :
304 : /*
305 : * Helpers called by various users of Canvas
306 : */
307 :
308 : already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
309 : Layer *aOldLayer,
310 : LayerManager *aManager);
311 : // Should return true if the canvas layer should always be marked inactive.
312 : // We should return true here if we can't do accelerated compositing with
313 : // a non-BasicCanvasLayer.
314 : bool ShouldForceInactiveLayer(LayerManager *aManager);
315 :
316 : // Call this whenever we need future changes to the canvas
317 : // to trigger fresh invalidation requests. This needs to be called
318 : // whenever we render the canvas contents to the screen, or whenever we
319 : // take a snapshot of the canvas that needs to be "live" (e.g. -moz-element).
320 : void MarkContextClean();
321 :
322 : // Call this after capturing a frame, so we can avoid unnecessary surface
323 : // copies for future frames when no drawing has occurred.
324 : void MarkContextCleanForFrameCapture();
325 :
326 : // Starts returning false when something is drawn.
327 : bool IsContextCleanForFrameCapture();
328 :
329 : nsresult GetContext(const nsAString& aContextId, nsISupports** aContext);
330 :
331 : layers::LayersBackend GetCompositorBackendType() const;
332 :
333 : void OnVisibilityChange();
334 :
335 : void OnMemoryPressure();
336 :
337 : static void SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer);
338 : static void InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer);
339 :
340 : void StartVRPresentation();
341 : void StopVRPresentation();
342 : already_AddRefed<layers::SharedSurfaceTextureClient> GetVRFrame();
343 :
344 : protected:
345 : virtual ~HTMLCanvasElement();
346 :
347 : virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
348 :
349 : virtual nsIntSize GetWidthHeight() override;
350 :
351 : virtual already_AddRefed<nsICanvasRenderingContextInternal>
352 : CreateContext(CanvasContextType aContextType) override;
353 :
354 : nsresult ExtractData(nsAString& aType,
355 : const nsAString& aOptions,
356 : nsIInputStream** aStream);
357 : nsresult ToDataURLImpl(JSContext* aCx,
358 : const nsAString& aMimeType,
359 : const JS::Value& aEncoderOptions,
360 : nsAString& aDataURL);
361 : nsresult MozGetAsFileImpl(const nsAString& aName,
362 : const nsAString& aType,
363 : File** aResult);
364 : void CallPrintCallback();
365 :
366 : virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
367 : const nsAttrValue* aValue,
368 : const nsAttrValue* aOldValue,
369 : bool aNotify) override;
370 : virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
371 : const nsAttrValueOrString& aValue,
372 : bool aNotify) override;
373 :
374 : AsyncCanvasRenderer* GetAsyncCanvasRenderer();
375 :
376 : bool mResetLayer;
377 : RefPtr<HTMLCanvasElement> mOriginalCanvas;
378 : RefPtr<PrintCallback> mPrintCallback;
379 : RefPtr<HTMLCanvasPrintState> mPrintState;
380 : nsTArray<WeakPtr<FrameCaptureListener>> mRequestedFrameListeners;
381 : RefPtr<RequestedFrameRefreshObserver> mRequestedFrameRefreshObserver;
382 : RefPtr<AsyncCanvasRenderer> mAsyncCanvasRenderer;
383 : RefPtr<OffscreenCanvas> mOffscreenCanvas;
384 : RefPtr<HTMLCanvasElementObserver> mContextObserver;
385 : bool mVRPresentationActive;
386 :
387 : public:
388 : // Record whether this canvas should be write-only or not.
389 : // We set this when script paints an image from a different origin.
390 : // We also transitively set it when script paints a canvas which
391 : // is itself write-only.
392 : bool mWriteOnly;
393 :
394 : bool IsPrintCallbackDone();
395 :
396 : void HandlePrintCallback(nsPresContext::nsPresContextType aType);
397 :
398 : nsresult DispatchPrintCallback(nsITimerCallback* aCallback);
399 :
400 : void ResetPrintCallback();
401 :
402 : HTMLCanvasElement* GetOriginalCanvas();
403 :
404 0 : CanvasContextType GetCurrentContextType() {
405 0 : return mCurrentContextType;
406 : }
407 :
408 : private:
409 : /**
410 : * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
411 : * This function will be called by AfterSetAttr whether the attribute is being
412 : * set or unset.
413 : *
414 : * @param aNamespaceID the namespace of the attr being set
415 : * @param aName the localname of the attribute being set
416 : * @param aNotify Whether we plan to notify document observers.
417 : */
418 : void AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName, bool aNotify);
419 : };
420 :
421 : class HTMLCanvasPrintState final : public nsWrapperCache
422 : {
423 : public:
424 : HTMLCanvasPrintState(HTMLCanvasElement* aCanvas,
425 : nsICanvasRenderingContextInternal* aContext,
426 : nsITimerCallback* aCallback);
427 :
428 : nsISupports* Context() const;
429 :
430 : void Done();
431 :
432 : void NotifyDone();
433 :
434 : bool mIsDone;
435 :
436 0 : NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(HTMLCanvasPrintState)
437 0 : NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(HTMLCanvasPrintState)
438 :
439 : virtual JSObject* WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
440 :
441 0 : HTMLCanvasElement* GetParentObject()
442 : {
443 0 : return mCanvas;
444 : }
445 :
446 : private:
447 : ~HTMLCanvasPrintState();
448 : bool mPendingNotify;
449 :
450 : protected:
451 : RefPtr<HTMLCanvasElement> mCanvas;
452 : nsCOMPtr<nsICanvasRenderingContextInternal> mContext;
453 : nsCOMPtr<nsITimerCallback> mCallback;
454 : };
455 :
456 : } // namespace dom
457 : } // namespace mozilla
458 :
459 : #endif /* mozilla_dom_HTMLCanvasElement_h */
|