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 * Determine whether the canvas is write-only.
181 bool IsWriteOnly() const;
184 * Force the canvas to be write-only, except for readers from
185 * a specific extension's content script expanded principal, if
188 void SetWriteOnly(nsIPrincipal
* aExpandedReader
= nullptr);
191 * Notify the placeholder offscreen canvas of an updated size.
193 void InvalidateCanvasPlaceholder(uint32_t aWidth
, uint32_t aHeight
);
196 * Notify that some canvas content has changed and the window may
197 * need to be updated. aDamageRect is in canvas coordinates.
199 void InvalidateCanvasContent(const mozilla::gfx::Rect
* aDamageRect
);
201 * Notify that we need to repaint the entire canvas, including updating of
204 void InvalidateCanvas();
206 nsICanvasRenderingContextInternal
* GetCurrentContext() {
207 return mCurrentContext
;
211 * Returns true if the canvas context content is guaranteed to be opaque
212 * across its entire area.
215 virtual bool GetOpaqueAttr() override
;
218 * Retrieve a snapshot of the internal surface, returning the alpha type if
219 * requested. An optional target may be supplied for which the snapshot will
220 * be optimized for, if possible.
222 virtual already_AddRefed
<gfx::SourceSurface
> GetSurfaceSnapshot(
223 gfxAlphaType
* aOutAlphaType
= nullptr,
224 gfx::DrawTarget
* aTarget
= nullptr);
227 * Register a FrameCaptureListener with this canvas.
228 * The canvas hooks into the RefreshDriver while there are
229 * FrameCaptureListeners registered.
230 * The registered FrameCaptureListeners are stored as WeakPtrs, thus it's the
231 * caller's responsibility to keep them alive. Once a registered
232 * FrameCaptureListener is destroyed it will be automatically deregistered.
234 nsresult
RegisterFrameCaptureListener(FrameCaptureListener
* aListener
,
235 bool aReturnPlaceholderData
);
238 * Returns true when there is at least one registered FrameCaptureListener
239 * that has requested a frame capture.
241 bool IsFrameCaptureRequested(const TimeStamp
& aTime
) const;
244 * Processes destroyed FrameCaptureListeners and removes them if necessary.
245 * Should there be none left, the FrameRefreshObserver will be unregistered.
247 void ProcessDestroyedFrameListeners();
250 * Called by the RefreshDriver hook when a frame has been captured.
251 * Makes a copy of the provided surface and hands it to all
252 * FrameCaptureListeners having requested frame capture.
254 void SetFrameCapture(already_AddRefed
<gfx::SourceSurface
> aSurface
,
255 const TimeStamp
& aTime
);
257 virtual bool ParseAttribute(int32_t aNamespaceID
, nsAtom
* aAttribute
,
258 const nsAString
& aValue
,
259 nsIPrincipal
* aMaybeScriptedPrincipal
,
260 nsAttrValue
& aResult
) override
;
261 NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom
* aAttribute
) const override
;
262 nsChangeHint
GetAttributeChangeHint(const nsAtom
* aAttribute
,
263 int32_t aModType
) const override
;
264 nsMapRuleToAttributesFunc
GetAttributeMappingFunction() const override
;
266 virtual nsresult
Clone(dom::NodeInfo
*, nsINode
** aResult
) const override
;
267 nsresult
CopyInnerTo(HTMLCanvasElement
* aDest
);
269 static void MapAttributesIntoRule(MappedDeclarationsBuilder
&);
272 * Helpers called by various users of Canvas
275 already_AddRefed
<layers::Image
> GetAsImage();
276 bool UpdateWebRenderCanvasData(nsDisplayListBuilder
* aBuilder
,
277 WebRenderCanvasData
* aCanvasData
);
278 bool InitializeCanvasRenderer(nsDisplayListBuilder
* aBuilder
,
279 CanvasRenderer
* aRenderer
);
281 // Call this whenever we need future changes to the canvas
282 // to trigger fresh invalidation requests. This needs to be called
283 // whenever we render the canvas contents to the screen, or whenever we
284 // take a snapshot of the canvas that needs to be "live" (e.g. -moz-element).
285 void MarkContextClean();
287 // Call this after capturing a frame, so we can avoid unnecessary surface
288 // copies for future frames when no drawing has occurred.
289 void MarkContextCleanForFrameCapture();
291 // Returns non-null when the current context supports captureStream().
292 // The FrameCaptureState gets set to DIRTY when something is drawn.
293 Watchable
<FrameCaptureState
>* GetFrameCaptureState();
295 nsresult
GetContext(const nsAString
& aContextId
, nsISupports
** aContext
);
297 layers::LayersBackend
GetCompositorBackendType() const;
299 void OnMemoryPressure();
300 void OnDeviceReset();
302 already_AddRefed
<layers::SharedSurfaceTextureClient
> GetVRFrame();
305 bool MaybeModified() const { return mMaybeModified
; };
308 virtual ~HTMLCanvasElement();
311 virtual JSObject
* WrapNode(JSContext
* aCx
,
312 JS::Handle
<JSObject
*> aGivenProto
) override
;
314 virtual nsIntSize
GetWidthHeight() override
;
316 virtual already_AddRefed
<nsICanvasRenderingContextInternal
> CreateContext(
317 CanvasContextType aContextType
) override
;
319 nsresult
UpdateContext(JSContext
* aCx
,
320 JS::Handle
<JS::Value
> aNewContextOptions
,
321 ErrorResult
& aRvForDictionaryInit
) override
;
323 nsresult
ExtractData(JSContext
* aCx
, nsIPrincipal
& aSubjectPrincipal
,
324 nsAString
& aType
, const nsAString
& aOptions
,
325 nsIInputStream
** aStream
);
326 nsresult
ToDataURLImpl(JSContext
* aCx
, nsIPrincipal
& aSubjectPrincipal
,
327 const nsAString
& aMimeType
,
328 const JS::Value
& aEncoderOptions
, nsAString
& aDataURL
);
330 UniquePtr
<uint8_t[]> GetImageBuffer(int32_t* aOutFormat
,
331 gfx::IntSize
* aOutImageSize
) override
;
333 MOZ_CAN_RUN_SCRIPT
void CallPrintCallback();
335 virtual void AfterSetAttr(int32_t aNamespaceID
, nsAtom
* aName
,
336 const nsAttrValue
* aValue
,
337 const nsAttrValue
* aOldValue
,
338 nsIPrincipal
* aSubjectPrincipal
,
339 bool aNotify
) override
;
340 virtual void OnAttrSetButNotChanged(int32_t aNamespaceID
, nsAtom
* aName
,
341 const nsAttrValueOrString
& aValue
,
342 bool aNotify
) override
;
345 ClientWebGLContext
* GetWebGLContext();
346 webgpu::CanvasContext
* GetWebGPUContext();
348 bool IsOffscreen() const { return !!mOffscreenCanvas
; }
349 OffscreenCanvas
* GetOffscreenCanvas() const { return mOffscreenCanvas
; }
350 void FlushOffscreenCanvas();
352 layers::ImageContainer
* GetImageContainer() const { return mImageContainer
; }
356 bool mMaybeModified
; // we fetched the context, so we may have written to the
358 RefPtr
<HTMLCanvasElement
> mOriginalCanvas
;
359 RefPtr
<PrintCallback
> mPrintCallback
;
360 RefPtr
<HTMLCanvasPrintState
> mPrintState
;
361 nsTArray
<WeakPtr
<FrameCaptureListener
>> mRequestedFrameListeners
;
362 RefPtr
<RequestedFrameRefreshObserver
> mRequestedFrameRefreshObserver
;
363 RefPtr
<OffscreenCanvas
> mOffscreenCanvas
;
364 RefPtr
<OffscreenCanvasDisplayHelper
> mOffscreenDisplay
;
365 RefPtr
<layers::ImageContainer
> mImageContainer
;
366 RefPtr
<HTMLCanvasElementObserver
> mContextObserver
;
369 // Record whether this canvas should be write-only or not.
370 // We set this when script paints an image from a different origin.
371 // We also transitively set it when script paints a canvas which
372 // is itself write-only.
375 // When this canvas is (only) tainted by an image from an extension
376 // content script, allow reads from the same extension afterwards.
377 RefPtr
<nsIPrincipal
> mExpandedReader
;
379 // Determines if the caller should be able to read the content.
380 bool CallerCanRead(nsIPrincipal
& aPrincipal
) const;
382 bool IsPrintCallbackDone();
384 void HandlePrintCallback(nsPresContext
*);
386 nsresult
DispatchPrintCallback(nsITimerCallback
* aCallback
);
388 void ResetPrintCallback();
390 HTMLCanvasElement
* GetOriginalCanvas();
392 CanvasContextType
GetCurrentContextType();
396 * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
397 * This function will be called by AfterSetAttr whether the attribute is being
400 * @param aNamespaceID the namespace of the attr being set
401 * @param aName the localname of the attribute being set
402 * @param aNotify Whether we plan to notify document observers.
404 void AfterMaybeChangeAttr(int32_t aNamespaceID
, nsAtom
* aName
, bool aNotify
);
407 class HTMLCanvasPrintState final
: public nsWrapperCache
{
409 HTMLCanvasPrintState(HTMLCanvasElement
* aCanvas
,
410 nsICanvasRenderingContextInternal
* aContext
,
411 nsITimerCallback
* aCallback
);
413 nsISupports
* Context() const;
421 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(HTMLCanvasPrintState
)
422 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(HTMLCanvasPrintState
)
424 virtual JSObject
* WrapObject(JSContext
* cx
,
425 JS::Handle
<JSObject
*> aGivenProto
) override
;
427 HTMLCanvasElement
* GetParentObject() { return mCanvas
; }
430 ~HTMLCanvasPrintState();
434 RefPtr
<HTMLCanvasElement
> mCanvas
;
435 nsCOMPtr
<nsICanvasRenderingContextInternal
> mContext
;
436 nsCOMPtr
<nsITimerCallback
> mCallback
;
440 } // namespace mozilla
442 #endif /* mozilla_dom_HTMLCanvasElement_h */