summaryrefslogtreecommitdiffstats
path: root/dom/html/HTMLCanvasElement.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/html/HTMLCanvasElement.h')
-rw-r--r--dom/html/HTMLCanvasElement.h447
1 files changed, 447 insertions, 0 deletions
diff --git a/dom/html/HTMLCanvasElement.h b/dom/html/HTMLCanvasElement.h
new file mode 100644
index 0000000000..586a43fedc
--- /dev/null
+++ b/dom/html/HTMLCanvasElement.h
@@ -0,0 +1,447 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#if !defined(mozilla_dom_HTMLCanvasElement_h)
+# define mozilla_dom_HTMLCanvasElement_h
+
+# include "mozilla/Attributes.h"
+# include "mozilla/StateWatching.h"
+# include "mozilla/WeakPtr.h"
+# include "nsIDOMEventListener.h"
+# include "nsIObserver.h"
+# include "nsGenericHTMLElement.h"
+# include "nsGkAtoms.h"
+# include "nsSize.h"
+# include "nsError.h"
+
+# include "mozilla/dom/CanvasRenderingContextHelper.h"
+# include "mozilla/gfx/Rect.h"
+# include "mozilla/layers/LayersTypes.h"
+
+class nsICanvasRenderingContextInternal;
+class nsIInputStream;
+class nsITimerCallback;
+enum class gfxAlphaType;
+enum class FrameCaptureState : uint8_t;
+
+namespace mozilla {
+
+class nsDisplayListBuilder;
+class ClientWebGLContext;
+
+namespace layers {
+class CanvasRenderer;
+class Image;
+class ImageContainer;
+class Layer;
+class LayerManager;
+class OOPCanvasRenderer;
+class SharedSurfaceTextureClient;
+class WebRenderCanvasData;
+} // namespace layers
+namespace gfx {
+class DrawTarget;
+class SourceSurface;
+class VRLayerChild;
+} // namespace gfx
+namespace webgpu {
+class CanvasContext;
+} // namespace webgpu
+
+namespace dom {
+class BlobCallback;
+class CanvasCaptureMediaStream;
+class File;
+class HTMLCanvasPrintState;
+class OffscreenCanvas;
+class OffscreenCanvasDisplayHelper;
+class PrintCallback;
+class PWebGLChild;
+class RequestedFrameRefreshObserver;
+
+// Listen visibilitychange and memory-pressure event and inform
+// context when event is fired.
+class HTMLCanvasElementObserver final : public nsIObserver {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+
+ explicit HTMLCanvasElementObserver(HTMLCanvasElement* aElement);
+ void Destroy();
+
+ void RegisterObserverEvents();
+ void UnregisterObserverEvents();
+
+ private:
+ ~HTMLCanvasElementObserver();
+
+ HTMLCanvasElement* mElement;
+};
+
+/*
+ * FrameCaptureListener is used by captureStream() as a way of getting video
+ * frames from the canvas. On a refresh driver tick after something has been
+ * drawn to the canvas since the last such tick, all registered
+ * FrameCaptureListeners that report true for FrameCaptureRequested() will be
+ * given a copy of the just-painted canvas.
+ * All FrameCaptureListeners get the same copy.
+ */
+class FrameCaptureListener : public SupportsWeakPtr {
+ public:
+ FrameCaptureListener() = default;
+
+ /*
+ * Indicates to the canvas whether or not this listener has requested a frame.
+ */
+ virtual bool FrameCaptureRequested(const TimeStamp& aTime) const = 0;
+
+ /*
+ * Interface through which new video frames will be provided while
+ * `mFrameCaptureRequested` is `true`.
+ */
+ virtual void NewFrame(already_AddRefed<layers::Image> aImage,
+ const TimeStamp& aTime) = 0;
+
+ protected:
+ virtual ~FrameCaptureListener() = default;
+};
+
+class HTMLCanvasElement final : public nsGenericHTMLElement,
+ public CanvasRenderingContextHelper,
+ public SupportsWeakPtr {
+ enum { DEFAULT_CANVAS_WIDTH = 300, DEFAULT_CANVAS_HEIGHT = 150 };
+
+ typedef layers::CanvasRenderer CanvasRenderer;
+ typedef layers::LayerManager LayerManager;
+ typedef layers::WebRenderCanvasData WebRenderCanvasData;
+
+ public:
+ explicit HTMLCanvasElement(
+ already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
+
+ NS_IMPL_FROMNODE_HTML_WITH_TAG(HTMLCanvasElement, canvas)
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+
+ // CC
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLCanvasElement,
+ nsGenericHTMLElement)
+
+ // WebIDL
+ uint32_t Height() {
+ return GetUnsignedIntAttr(nsGkAtoms::height, DEFAULT_CANVAS_HEIGHT);
+ }
+ uint32_t Width() {
+ return GetUnsignedIntAttr(nsGkAtoms::width, DEFAULT_CANVAS_WIDTH);
+ }
+ void SetHeight(uint32_t aHeight, ErrorResult& aRv);
+ void SetWidth(uint32_t aWidth, ErrorResult& aRv);
+
+ already_AddRefed<nsISupports> GetContext(
+ JSContext* aCx, const nsAString& aContextId,
+ JS::Handle<JS::Value> aContextOptions, ErrorResult& aRv);
+
+ void ToDataURL(JSContext* aCx, const nsAString& aType,
+ JS::Handle<JS::Value> aParams, nsAString& aDataURL,
+ nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv);
+
+ void ToBlob(JSContext* aCx, BlobCallback& aCallback, const nsAString& aType,
+ JS::Handle<JS::Value> aParams, nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv);
+
+ OffscreenCanvas* TransferControlToOffscreen(ErrorResult& aRv);
+
+ bool MozOpaque() const { return GetBoolAttr(nsGkAtoms::moz_opaque); }
+ void SetMozOpaque(bool aValue, ErrorResult& aRv) {
+ if (mOffscreenCanvas) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return;
+ }
+
+ SetHTMLBoolAttr(nsGkAtoms::moz_opaque, aValue, aRv);
+ }
+ PrintCallback* GetMozPrintCallback() const;
+ void SetMozPrintCallback(PrintCallback* aCallback);
+
+ already_AddRefed<CanvasCaptureMediaStream> CaptureStream(
+ const Optional<double>& aFrameRate, nsIPrincipal& aSubjectPrincipal,
+ ErrorResult& aRv);
+
+ /**
+ * Get the size in pixels of this canvas element
+ */
+ nsIntSize GetSize();
+
+ /**
+ * Set the size in pixels of this canvas element.
+ */
+ void SetSize(const nsIntSize& aSize, ErrorResult& aRv);
+
+ /**
+ * Determine whether the canvas is write-only.
+ */
+ bool IsWriteOnly() const;
+
+ /**
+ * Force the canvas to be write-only, except for readers from
+ * a specific extension's content script expanded principal, if
+ * available.
+ */
+ void SetWriteOnly(nsIPrincipal* aExpandedReader = nullptr);
+
+ /**
+ * Notify the placeholder offscreen canvas of an updated size.
+ */
+ void InvalidateCanvasPlaceholder(uint32_t aWidth, uint32_t aHeight);
+
+ /**
+ * Notify that some canvas content has changed and the window may
+ * need to be updated. aDamageRect is in canvas coordinates.
+ */
+ void InvalidateCanvasContent(const mozilla::gfx::Rect* aDamageRect);
+ /*
+ * Notify that we need to repaint the entire canvas, including updating of
+ * the layer tree.
+ */
+ void InvalidateCanvas();
+
+ nsICanvasRenderingContextInternal* GetCurrentContext() {
+ return mCurrentContext;
+ }
+
+ /*
+ * Returns true if the canvas context content is guaranteed to be opaque
+ * across its entire area.
+ */
+ bool GetIsOpaque();
+ virtual bool GetOpaqueAttr() override;
+
+ /**
+ * Retrieve a snapshot of the internal surface, returning the alpha type if
+ * requested. An optional target may be supplied for which the snapshot will
+ * be optimized for, if possible.
+ */
+ virtual already_AddRefed<gfx::SourceSurface> GetSurfaceSnapshot(
+ gfxAlphaType* aOutAlphaType = nullptr,
+ gfx::DrawTarget* aTarget = nullptr);
+
+ /*
+ * Register a FrameCaptureListener with this canvas.
+ * The canvas hooks into the RefreshDriver while there are
+ * FrameCaptureListeners registered.
+ * The registered FrameCaptureListeners are stored as WeakPtrs, thus it's the
+ * caller's responsibility to keep them alive. Once a registered
+ * FrameCaptureListener is destroyed it will be automatically deregistered.
+ */
+ nsresult RegisterFrameCaptureListener(FrameCaptureListener* aListener,
+ bool aReturnPlaceholderData);
+
+ /*
+ * Returns true when there is at least one registered FrameCaptureListener
+ * that has requested a frame capture.
+ */
+ bool IsFrameCaptureRequested(const TimeStamp& aTime) const;
+
+ /*
+ * Processes destroyed FrameCaptureListeners and removes them if necessary.
+ * Should there be none left, the FrameRefreshObserver will be unregistered.
+ */
+ void ProcessDestroyedFrameListeners();
+
+ /*
+ * Called by the RefreshDriver hook when a frame has been captured.
+ * Makes a copy of the provided surface and hands it to all
+ * FrameCaptureListeners having requested frame capture.
+ */
+ void SetFrameCapture(already_AddRefed<gfx::SourceSurface> aSurface,
+ const TimeStamp& aTime);
+
+ virtual bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
+ const nsAString& aValue,
+ nsIPrincipal* aMaybeScriptedPrincipal,
+ nsAttrValue& aResult) override;
+ NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
+ nsChangeHint GetAttributeChangeHint(const nsAtom* aAttribute,
+ int32_t aModType) const override;
+ nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
+
+ virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
+ nsresult CopyInnerTo(HTMLCanvasElement* aDest);
+
+ static void MapAttributesIntoRule(MappedDeclarationsBuilder&);
+
+ /*
+ * Helpers called by various users of Canvas
+ */
+
+ already_AddRefed<layers::Image> GetAsImage();
+ bool UpdateWebRenderCanvasData(nsDisplayListBuilder* aBuilder,
+ WebRenderCanvasData* aCanvasData);
+ bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+ CanvasRenderer* aRenderer);
+
+ // Call this whenever we need future changes to the canvas
+ // to trigger fresh invalidation requests. This needs to be called
+ // whenever we render the canvas contents to the screen, or whenever we
+ // take a snapshot of the canvas that needs to be "live" (e.g. -moz-element).
+ void MarkContextClean();
+
+ // Call this after capturing a frame, so we can avoid unnecessary surface
+ // copies for future frames when no drawing has occurred.
+ void MarkContextCleanForFrameCapture();
+
+ // Returns non-null when the current context supports captureStream().
+ // The FrameCaptureState gets set to DIRTY when something is drawn.
+ Watchable<FrameCaptureState>* GetFrameCaptureState();
+
+ nsresult GetContext(const nsAString& aContextId, nsISupports** aContext);
+
+ layers::LayersBackend GetCompositorBackendType() const;
+
+ void OnMemoryPressure();
+ void OnDeviceReset();
+
+ already_AddRefed<layers::SharedSurfaceTextureClient> GetVRFrame();
+ void ClearVRFrame();
+
+ bool MaybeModified() const { return mMaybeModified; };
+
+ protected:
+ virtual ~HTMLCanvasElement();
+ void Destroy();
+
+ virtual JSObject* WrapNode(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) override;
+
+ virtual nsIntSize GetWidthHeight() override;
+
+ virtual already_AddRefed<nsICanvasRenderingContextInternal> CreateContext(
+ CanvasContextType aContextType) override;
+
+ nsresult UpdateContext(JSContext* aCx,
+ JS::Handle<JS::Value> aNewContextOptions,
+ ErrorResult& aRvForDictionaryInit) override;
+
+ nsresult ExtractData(JSContext* aCx, nsIPrincipal& aSubjectPrincipal,
+ nsAString& aType, const nsAString& aOptions,
+ nsIInputStream** aStream);
+ nsresult ToDataURLImpl(JSContext* aCx, nsIPrincipal& aSubjectPrincipal,
+ const nsAString& aMimeType,
+ const JS::Value& aEncoderOptions, nsAString& aDataURL);
+
+ UniquePtr<uint8_t[]> GetImageBuffer(int32_t* aOutFormat,
+ gfx::IntSize* aOutImageSize) override;
+
+ MOZ_CAN_RUN_SCRIPT void CallPrintCallback();
+
+ virtual void AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
+ const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue,
+ nsIPrincipal* aSubjectPrincipal,
+ bool aNotify) override;
+ virtual void OnAttrSetButNotChanged(int32_t aNamespaceID, nsAtom* aName,
+ const nsAttrValueOrString& aValue,
+ bool aNotify) override;
+
+ public:
+ ClientWebGLContext* GetWebGLContext();
+ webgpu::CanvasContext* GetWebGPUContext();
+
+ bool IsOffscreen() const { return !!mOffscreenCanvas; }
+ OffscreenCanvas* GetOffscreenCanvas() const { return mOffscreenCanvas; }
+ void FlushOffscreenCanvas();
+
+ layers::ImageContainer* GetImageContainer() const { return mImageContainer; }
+
+ protected:
+ bool mResetLayer;
+ bool mMaybeModified; // we fetched the context, so we may have written to the
+ // canvas
+ RefPtr<HTMLCanvasElement> mOriginalCanvas;
+ RefPtr<PrintCallback> mPrintCallback;
+ RefPtr<HTMLCanvasPrintState> mPrintState;
+ nsTArray<WeakPtr<FrameCaptureListener>> mRequestedFrameListeners;
+ RefPtr<RequestedFrameRefreshObserver> mRequestedFrameRefreshObserver;
+ RefPtr<OffscreenCanvas> mOffscreenCanvas;
+ RefPtr<OffscreenCanvasDisplayHelper> mOffscreenDisplay;
+ RefPtr<layers::ImageContainer> mImageContainer;
+ RefPtr<HTMLCanvasElementObserver> mContextObserver;
+
+ public:
+ // Record whether this canvas should be write-only or not.
+ // We set this when script paints an image from a different origin.
+ // We also transitively set it when script paints a canvas which
+ // is itself write-only.
+ bool mWriteOnly;
+
+ // When this canvas is (only) tainted by an image from an extension
+ // content script, allow reads from the same extension afterwards.
+ RefPtr<nsIPrincipal> mExpandedReader;
+
+ // Determines if the caller should be able to read the content.
+ bool CallerCanRead(nsIPrincipal& aPrincipal) const;
+
+ bool IsPrintCallbackDone();
+
+ void HandlePrintCallback(nsPresContext*);
+
+ nsresult DispatchPrintCallback(nsITimerCallback* aCallback);
+
+ void ResetPrintCallback();
+
+ HTMLCanvasElement* GetOriginalCanvas();
+
+ CanvasContextType GetCurrentContextType();
+
+ private:
+ /**
+ * This function is called by AfterSetAttr and OnAttrSetButNotChanged.
+ * This function will be called by AfterSetAttr whether the attribute is being
+ * set or unset.
+ *
+ * @param aNamespaceID the namespace of the attr being set
+ * @param aName the localname of the attribute being set
+ * @param aNotify Whether we plan to notify document observers.
+ */
+ void AfterMaybeChangeAttr(int32_t aNamespaceID, nsAtom* aName, bool aNotify);
+};
+
+class HTMLCanvasPrintState final : public nsWrapperCache {
+ public:
+ HTMLCanvasPrintState(HTMLCanvasElement* aCanvas,
+ nsICanvasRenderingContextInternal* aContext,
+ nsITimerCallback* aCallback);
+
+ nsISupports* Context() const;
+
+ void Done();
+
+ void NotifyDone();
+
+ bool mIsDone;
+
+ NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(HTMLCanvasPrintState)
+ NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(HTMLCanvasPrintState)
+
+ virtual JSObject* WrapObject(JSContext* cx,
+ JS::Handle<JSObject*> aGivenProto) override;
+
+ HTMLCanvasElement* GetParentObject() { return mCanvas; }
+
+ private:
+ ~HTMLCanvasPrintState();
+ bool mPendingNotify;
+
+ protected:
+ RefPtr<HTMLCanvasElement> mCanvas;
+ nsCOMPtr<nsICanvasRenderingContextInternal> mContext;
+ nsCOMPtr<nsITimerCallback> mCallback;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif /* mozilla_dom_HTMLCanvasElement_h */