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
9 # include "mozilla/Attributes.h"
10 # include "mozilla/StateWatching.h"
11 # include "mozilla/WeakPtr.h"
12 # include "nsIDOMEventListener.h"
13 # include "nsIObserver.h"
14 # include "nsGenericHTMLElement.h"
15 # include "nsGkAtoms.h"
19 # include "mozilla/dom/CanvasRenderingContextHelper.h"
20 # include "mozilla/gfx/Rect.h"
21 # include "mozilla/layers/LayersTypes.h"
23 class nsICanvasRenderingContextInternal
;
25 class nsITimerCallback
;
26 enum class gfxAlphaType
;
27 enum class FrameCaptureState
: uint8_t;
31 class nsDisplayListBuilder
;
32 class ClientWebGLContext
;
40 class OOPCanvasRenderer
;
41 class SharedSurfaceTextureClient
;
42 class WebRenderCanvasData
;
55 class CanvasCaptureMediaStream
;
57 class HTMLCanvasPrintState
;
58 class OffscreenCanvas
;
59 class OffscreenCanvasDisplayHelper
;
62 class RequestedFrameRefreshObserver
;
64 // Listen visibilitychange and memory-pressure event and inform
65 // context when event is fired.
66 class HTMLCanvasElementObserver final
: public nsIObserver
{
71 explicit HTMLCanvasElementObserver(HTMLCanvasElement
* aElement
);
74 void RegisterObserverEvents();
75 void UnregisterObserverEvents();
78 ~HTMLCanvasElementObserver();
80 HTMLCanvasElement
* mElement
;
84 * FrameCaptureListener is used by captureStream() as a way of getting video
85 * frames from the canvas. On a refresh driver tick after something has been
86 * drawn to the canvas since the last such tick, all registered
87 * FrameCaptureListeners that report true for FrameCaptureRequested() will be
88 * given a copy of the just-painted canvas.
89 * All FrameCaptureListeners get the same copy.
91 class FrameCaptureListener
: public SupportsWeakPtr
{
93 FrameCaptureListener() = default;
96 * Indicates to the canvas whether or not this listener has requested a frame.
98 virtual bool FrameCaptureRequested(const TimeStamp
& aTime
) const = 0;
101 * Interface through which new video frames will be provided while
102 * `mFrameCaptureRequested` is `true`.
104 virtual void NewFrame(already_AddRefed
<layers::Image
> aImage
,
105 const TimeStamp
& aTime
) = 0;
108 virtual ~FrameCaptureListener() = default;
111 class HTMLCanvasElement final
: public nsGenericHTMLElement
,
112 public CanvasRenderingContextHelper
,
113 public SupportsWeakPtr
{
114 enum { DEFAULT_CANVAS_WIDTH
= 300, DEFAULT_CANVAS_HEIGHT
= 150 };
116 typedef layers::CanvasRenderer CanvasRenderer
;
117 typedef layers::LayerManager LayerManager
;
118 typedef layers::WebRenderCanvasData WebRenderCanvasData
;
121 explicit HTMLCanvasElement(
122 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
);
124 NS_IMPL_FROMNODE_HTML_WITH_TAG(HTMLCanvasElement
, canvas
)
127 NS_DECL_ISUPPORTS_INHERITED
130 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLCanvasElement
,
131 nsGenericHTMLElement
)
135 return GetUnsignedIntAttr(nsGkAtoms::height
, DEFAULT_CANVAS_HEIGHT
);
138 return GetUnsignedIntAttr(nsGkAtoms::width
, DEFAULT_CANVAS_WIDTH
);
140 void SetHeight(uint32_t aHeight
, ErrorResult
& aRv
);
141 void SetWidth(uint32_t aWidth
, ErrorResult
& aRv
);
143 already_AddRefed
<nsISupports
> GetContext(
144 JSContext
* aCx
, const nsAString
& aContextId
,
145 JS::Handle
<JS::Value
> aContextOptions
, ErrorResult
& aRv
);
147 void ToDataURL(JSContext
* aCx
, const nsAString
& aType
,
148 JS::Handle
<JS::Value
> aParams
, nsAString
& aDataURL
,
149 nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
);
151 void ToBlob(JSContext
* aCx
, BlobCallback
& aCallback
, const nsAString
& aType
,
152 JS::Handle
<JS::Value
> aParams
, nsIPrincipal
& aSubjectPrincipal
,
155 OffscreenCanvas
* TransferControlToOffscreen(ErrorResult
& aRv
);
157 bool MozOpaque() const { return GetBoolAttr(nsGkAtoms::moz_opaque
); }
158 void SetMozOpaque(bool aValue
, ErrorResult
& aRv
) {
159 if (mOffscreenCanvas
) {
160 aRv
.Throw(NS_ERROR_FAILURE
);
164 SetHTMLBoolAttr(nsGkAtoms::moz_opaque
, aValue
, aRv
);
166 PrintCallback
* GetMozPrintCallback() const;
167 void SetMozPrintCallback(PrintCallback
* aCallback
);
169 already_AddRefed
<CanvasCaptureMediaStream
> CaptureStream(
170 const Optional
<double>& aFrameRate
, nsIPrincipal
& aSubjectPrincipal
,
174 * Get the size in pixels of this canvas element
179 * Set the size in pixels of this canvas element.
181 void SetSize(const nsIntSize
& aSize
, ErrorResult
& aRv
);
184 * Determine whether the canvas is write-only.
186 bool IsWriteOnly() const;
189 * Force the canvas to be write-only, except for readers from
190 * a specific extension's content script expanded principal, if
193 void SetWriteOnly(nsIPrincipal
* aExpandedReader
= nullptr);
196 * Notify the placeholder offscreen canvas of an updated size.
198 void InvalidateCanvasPlaceholder(uint32_t aWidth
, uint32_t aHeight
);
201 * Notify that some canvas content has changed and the window may
202 * need to be updated. aDamageRect is in canvas coordinates.
204 void InvalidateCanvasContent(const mozilla::gfx::Rect
* aDamageRect
);
206 * Notify that we need to repaint the entire canvas, including updating of
209 void InvalidateCanvas();
211 nsICanvasRenderingContextInternal
* GetCurrentContext() {
212 return mCurrentContext
;
216 * Returns true if the canvas context content is guaranteed to be opaque
217 * across its entire area.
220 virtual bool GetOpaqueAttr() override
;
223 * Retrieve a snapshot of the internal surface, returning the alpha type if
224 * requested. An optional target may be supplied for which the snapshot will
225 * be optimized for, if possible.
227 virtual already_AddRefed
<gfx::SourceSurface
> GetSurfaceSnapshot(
228 gfxAlphaType
* aOutAlphaType
= nullptr,
229 gfx::DrawTarget
* aTarget
= nullptr);
232 * Register a FrameCaptureListener with this canvas.
233 * The canvas hooks into the RefreshDriver while there are
234 * FrameCaptureListeners registered.
235 * The registered FrameCaptureListeners are stored as WeakPtrs, thus it's the
236 * caller's responsibility to keep them alive. Once a registered
237 * FrameCaptureListener is destroyed it will be automatically deregistered.
239 nsresult
RegisterFrameCaptureListener(FrameCaptureListener
* aListener
,
240 bool aReturnPlaceholderData
);
243 * Returns true when there is at least one registered FrameCaptureListener
244 * that has requested a frame capture.
246 bool IsFrameCaptureRequested(const TimeStamp
& aTime
) const;
249 * Processes destroyed FrameCaptureListeners and removes them if necessary.
250 * Should there be none left, the FrameRefreshObserver will be unregistered.
252 void ProcessDestroyedFrameListeners();
255 * Called by the RefreshDriver hook when a frame has been captured.
256 * Makes a copy of the provided surface and hands it to all
257 * FrameCaptureListeners having requested frame capture.
259 void SetFrameCapture(already_AddRefed
<gfx::SourceSurface
> aSurface
,
260 const TimeStamp
& aTime
);
262 virtual bool ParseAttribute(int32_t aNamespaceID
, nsAtom
* aAttribute
,
263 const nsAString
& aValue
,
264 nsIPrincipal
* aMaybeScriptedPrincipal
,
265 nsAttrValue
& aResult
) override
;
266 NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom
* aAttribute
) const override
;
267 nsChangeHint
GetAttributeChangeHint(const nsAtom
* aAttribute
,
268 int32_t aModType
) const override
;
269 nsMapRuleToAttributesFunc
GetAttributeMappingFunction() const override
;
271 virtual nsresult
Clone(dom::NodeInfo
*, nsINode
** aResult
) const override
;
272 nsresult
CopyInnerTo(HTMLCanvasElement
* aDest
);
274 static void MapAttributesIntoRule(MappedDeclarationsBuilder
&);
277 * Helpers called by various users of Canvas
280 already_AddRefed
<layers::Image
> GetAsImage();
281 bool UpdateWebRenderCanvasData(nsDisplayListBuilder
* aBuilder
,
282 WebRenderCanvasData
* aCanvasData
);
283 bool InitializeCanvasRenderer(nsDisplayListBuilder
* aBuilder
,
284 CanvasRenderer
* aRenderer
);
286 // Call this whenever we need future changes to the canvas
287 // to trigger fresh invalidation requests. This needs to be called
288 // whenever we render the canvas contents to the screen, or whenever we
289 // take a snapshot of the canvas that needs to be "live" (e.g. -moz-element).
290 void MarkContextClean();
292 // Call this after capturing a frame, so we can avoid unnecessary surface
293 // copies for future frames when no drawing has occurred.
294 void MarkContextCleanForFrameCapture();
296 // Returns non-null when the current context supports captureStream().
297 // The FrameCaptureState gets set to DIRTY when something is drawn.
298 Watchable
<FrameCaptureState
>* GetFrameCaptureState();
300 nsresult
GetContext(const nsAString
& aContextId
, nsISupports
** aContext
);
302 layers::LayersBackend
GetCompositorBackendType() const;
304 void OnMemoryPressure();
305 void OnDeviceReset();
307 already_AddRefed
<layers::SharedSurfaceTextureClient
> GetVRFrame();
310 bool MaybeModified() const { return mMaybeModified
; };
313 virtual ~HTMLCanvasElement();
316 virtual JSObject
* WrapNode(JSContext
* aCx
,
317 JS::Handle
<JSObject
*> aGivenProto
) override
;
319 virtual nsIntSize
GetWidthHeight() override
;
321 virtual already_AddRefed
<nsICanvasRenderingContextInternal
> CreateContext(
322 CanvasContextType aContextType
) override
;
324 nsresult
UpdateContext(JSContext
* aCx
,
325 JS::Handle
<JS::Value
> aNewContextOptions
,
326 ErrorResult
& aRvForDictionaryInit
) override
;
328 nsresult
ExtractData(JSContext
* aCx
, nsIPrincipal
& aSubjectPrincipal
,
329 nsAString
& aType
, const nsAString
& aOptions
,
330 nsIInputStream
** aStream
);
331 nsresult
ToDataURLImpl(JSContext
* aCx
, nsIPrincipal
& aSubjectPrincipal
,
332 const nsAString
& aMimeType
,
333 const JS::Value
& aEncoderOptions
, nsAString
& aDataURL
);
335 UniquePtr
<uint8_t[]> GetImageBuffer(int32_t* aOutFormat
,
336 gfx::IntSize
* aOutImageSize
) override
;
338 MOZ_CAN_RUN_SCRIPT
void CallPrintCallback();
340 virtual void AfterSetAttr(int32_t aNamespaceID
, nsAtom
* aName
,
341 const nsAttrValue
* aValue
,
342 const nsAttrValue
* aOldValue
,
343 nsIPrincipal
* aSubjectPrincipal
,
344 bool aNotify
) override
;
345 virtual void OnAttrSetButNotChanged(int32_t aNamespaceID
, nsAtom
* aName
,
346 const nsAttrValueOrString
& aValue
,
347 bool aNotify
) override
;
350 ClientWebGLContext
* GetWebGLContext();
351 webgpu::CanvasContext
* GetWebGPUContext();
353 bool IsOffscreen() const { return !!mOffscreenCanvas
; }
354 OffscreenCanvas
* GetOffscreenCanvas() const { return mOffscreenCanvas
; }
355 void FlushOffscreenCanvas();
357 layers::ImageContainer
* GetImageContainer() const { return mImageContainer
; }
359 bool UsingCaptureStream() const { return !!mRequestedFrameRefreshObserver
; }
363 bool mMaybeModified
; // we fetched the context, so we may have written to the
365 RefPtr
<HTMLCanvasElement
> mOriginalCanvas
;
366 RefPtr
<PrintCallback
> mPrintCallback
;
367 RefPtr
<HTMLCanvasPrintState
> mPrintState
;
368 nsTArray
<WeakPtr
<FrameCaptureListener
>> mRequestedFrameListeners
;
369 RefPtr
<RequestedFrameRefreshObserver
> mRequestedFrameRefreshObserver
;
370 RefPtr
<OffscreenCanvas
> mOffscreenCanvas
;
371 RefPtr
<OffscreenCanvasDisplayHelper
> mOffscreenDisplay
;
372 RefPtr
<layers::ImageContainer
> mImageContainer
;
373 RefPtr
<HTMLCanvasElementObserver
> mContextObserver
;
376 // Record whether this canvas should be write-only or not.
377 // We set this when script paints an image from a different origin.
378 // We also transitively set it when script paints a canvas which
379 // is itself write-only.
382 // When this canvas is (only) tainted by an image from an extension
383 // content script, allow reads from the same extension afterwards.
384 RefPtr
<nsIPrincipal
> mExpandedReader
;
386 // Determines if the caller should be able to read the content.
387 bool CallerCanRead(nsIPrincipal
& aPrincipal
) const;
389 bool IsPrintCallbackDone();
391 void HandlePrintCallback(nsPresContext
*);
393 nsresult
DispatchPrintCallback(nsITimerCallback
* aCallback
);
395 void ResetPrintCallback();
397 HTMLCanvasElement
* GetOriginalCanvas();
399 CanvasContextType
GetCurrentContextType();
403 * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
404 * This function will be called by AfterSetAttr whether the attribute is being
407 * @param aNamespaceID the namespace of the attr being set
408 * @param aName the localname of the attribute being set
409 * @param aNotify Whether we plan to notify document observers.
411 void AfterMaybeChangeAttr(int32_t aNamespaceID
, nsAtom
* aName
, bool aNotify
);
414 class HTMLCanvasPrintState final
: public nsWrapperCache
{
416 HTMLCanvasPrintState(HTMLCanvasElement
* aCanvas
,
417 nsICanvasRenderingContextInternal
* aContext
,
418 nsITimerCallback
* aCallback
);
420 nsISupports
* Context() const;
428 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(HTMLCanvasPrintState
)
429 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(HTMLCanvasPrintState
)
431 virtual JSObject
* WrapObject(JSContext
* cx
,
432 JS::Handle
<JSObject
*> aGivenProto
) override
;
434 HTMLCanvasElement
* GetParentObject() { return mCanvas
; }
437 ~HTMLCanvasPrintState();
441 RefPtr
<HTMLCanvasElement
> mCanvas
;
442 nsCOMPtr
<nsICanvasRenderingContextInternal
> mContext
;
443 nsCOMPtr
<nsITimerCallback
> mCallback
;
447 } // namespace mozilla
449 #endif /* mozilla_dom_HTMLCanvasElement_h */