HTMLCanvasElement.h (15246B)
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 #ifndef mozilla_dom_HTMLCanvasElement_h 7 #define mozilla_dom_HTMLCanvasElement_h 8 9 #include "LayoutConstants.h" 10 #include "mozilla/Attributes.h" 11 #include "mozilla/StateWatching.h" 12 #include "mozilla/WeakPtr.h" 13 #include "mozilla/dom/CanvasRenderingContextHelper.h" 14 #include "mozilla/gfx/Rect.h" 15 #include "mozilla/layers/LayersTypes.h" 16 #include "nsError.h" 17 #include "nsGenericHTMLElement.h" 18 #include "nsGkAtoms.h" 19 #include "nsIObserver.h" 20 #include "nsSize.h" 21 22 class nsICanvasRenderingContextInternal; 23 class nsIInputStream; 24 class nsITimerCallback; 25 enum class gfxAlphaType; 26 enum class FrameCaptureState : uint8_t; 27 28 namespace mozilla { 29 30 class nsDisplayListBuilder; 31 class ClientWebGLContext; 32 33 namespace layers { 34 class CanvasRenderer; 35 class Image; 36 class ImageContainer; 37 class Layer; 38 class LayerManager; 39 class OOPCanvasRenderer; 40 class SharedSurfaceTextureClient; 41 class WebRenderCanvasData; 42 } // namespace layers 43 namespace gfx { 44 class DrawTarget; 45 class SourceSurface; 46 class VRLayerChild; 47 } // namespace gfx 48 namespace webgpu { 49 class CanvasContext; 50 } // namespace webgpu 51 52 namespace dom { 53 class BlobCallback; 54 class CanvasCaptureMediaStream; 55 class File; 56 class HTMLCanvasPrintState; 57 class OffscreenCanvas; 58 class OffscreenCanvasDisplayHelper; 59 class PrintCallback; 60 class PWebGLChild; 61 class RequestedFrameRefreshObserver; 62 63 // Listen visibilitychange and memory-pressure event and inform 64 // context when event is fired. 65 class HTMLCanvasElementObserver final : public nsIObserver { 66 public: 67 NS_DECL_ISUPPORTS 68 NS_DECL_NSIOBSERVER 69 70 explicit HTMLCanvasElementObserver(HTMLCanvasElement* aElement); 71 void Destroy(); 72 73 void RegisterObserverEvents(); 74 void UnregisterObserverEvents(); 75 76 private: 77 ~HTMLCanvasElementObserver(); 78 79 HTMLCanvasElement* mElement; 80 }; 81 82 /* 83 * FrameCaptureListener is used by captureStream() as a way of getting video 84 * frames from the canvas. On a refresh driver tick after something has been 85 * drawn to the canvas since the last such tick, all registered 86 * FrameCaptureListeners that report true for FrameCaptureRequested() will be 87 * given a copy of the just-painted canvas. 88 * All FrameCaptureListeners get the same copy. 89 */ 90 class FrameCaptureListener : public SupportsWeakPtr { 91 public: 92 FrameCaptureListener() = default; 93 94 /* 95 * Indicates to the canvas whether or not this listener has requested a frame. 96 */ 97 virtual bool FrameCaptureRequested(const TimeStamp& aTime) const = 0; 98 99 /* 100 * Interface through which new video frames will be provided while 101 * `mFrameCaptureRequested` is `true`. 102 */ 103 virtual void NewFrame(already_AddRefed<layers::Image> aImage, 104 const TimeStamp& aTime) = 0; 105 106 protected: 107 virtual ~FrameCaptureListener() = default; 108 }; 109 110 class HTMLCanvasElement final : public nsGenericHTMLElement, 111 public CanvasRenderingContextHelper, 112 public SupportsWeakPtr { 113 typedef layers::CanvasRenderer CanvasRenderer; 114 typedef layers::LayerManager LayerManager; 115 typedef layers::WebRenderCanvasData WebRenderCanvasData; 116 117 public: 118 explicit HTMLCanvasElement( 119 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo); 120 121 NS_IMPL_FROMNODE_HTML_WITH_TAG(HTMLCanvasElement, canvas) 122 123 // nsISupports 124 NS_DECL_ISUPPORTS_INHERITED 125 126 // CC 127 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLCanvasElement, 128 nsGenericHTMLElement) 129 130 // WebIDL 131 uint32_t Height() { 132 return GetUnsignedIntAttr(nsGkAtoms::height, 133 kFallbackIntrinsicHeightInPixels); 134 } 135 uint32_t Width() { 136 return GetUnsignedIntAttr(nsGkAtoms::width, 137 kFallbackIntrinsicWidthInPixels); 138 } 139 void SetHeight(uint32_t aHeight, ErrorResult& aRv); 140 void SetWidth(uint32_t aWidth, ErrorResult& aRv); 141 142 already_AddRefed<nsISupports> GetContext( 143 JSContext* aCx, const nsAString& aContextId, 144 JS::Handle<JS::Value> aContextOptions, ErrorResult& aRv); 145 146 void ToDataURL(JSContext* aCx, const nsAString& aType, 147 JS::Handle<JS::Value> aParams, nsAString& aDataURL, 148 nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv); 149 150 void ToBlob(JSContext* aCx, BlobCallback& aCallback, const nsAString& aType, 151 JS::Handle<JS::Value> aParams, nsIPrincipal& aSubjectPrincipal, 152 ErrorResult& aRv); 153 154 OffscreenCanvas* TransferControlToOffscreen(ErrorResult& aRv); 155 156 bool MozOpaque() const { return GetBoolAttr(nsGkAtoms::moz_opaque); } 157 void SetMozOpaque(bool aValue, ErrorResult& aRv) { 158 if (mOffscreenCanvas) { 159 aRv.Throw(NS_ERROR_FAILURE); 160 return; 161 } 162 163 SetHTMLBoolAttr(nsGkAtoms::moz_opaque, aValue, aRv); 164 } 165 PrintCallback* GetMozPrintCallback() const; 166 void SetMozPrintCallback(PrintCallback* aCallback); 167 168 already_AddRefed<CanvasCaptureMediaStream> CaptureStream( 169 const Optional<double>& aFrameRate, nsIPrincipal& aSubjectPrincipal, 170 ErrorResult& aRv); 171 172 /** 173 * Get the size in pixels of this canvas element 174 */ 175 CSSIntSize GetSize(); 176 177 /** 178 * Set the size in pixels of this canvas element. 179 */ 180 void SetSize(const nsIntSize& aSize, ErrorResult& aRv); 181 182 /** 183 * Determine whether the canvas is write-only. 184 */ 185 bool IsWriteOnly() const; 186 187 /** 188 * Force the canvas to be write-only, except for readers from 189 * a specific extension's content script expanded principal, if 190 * available. 191 */ 192 void SetWriteOnly(nsIPrincipal* aExpandedReader = nullptr); 193 194 /** 195 * Notify the placeholder offscreen canvas of an updated size. 196 */ 197 void InvalidateCanvasPlaceholder(uint32_t aWidth, uint32_t aHeight); 198 199 /** 200 * Notify that some canvas content has changed and the window may 201 * need to be updated. aDamageRect is in canvas coordinates. 202 */ 203 void InvalidateCanvasContent(const mozilla::gfx::Rect* aDamageRect); 204 /* 205 * Notify that we need to repaint the entire canvas, including updating of 206 * the layer tree. 207 */ 208 void InvalidateCanvas(); 209 210 nsICanvasRenderingContextInternal* GetCurrentContext() { 211 return mCurrentContext; 212 } 213 214 /* 215 * Returns true if the canvas context content is guaranteed to be opaque 216 * across its entire area. 217 */ 218 bool GetIsOpaque(); 219 virtual bool GetOpaqueAttr() override; 220 221 /** 222 * Retrieve a snapshot of the internal surface, returning the alpha type if 223 * requested. An optional target may be supplied for which the snapshot will 224 * be optimized for, if possible. 225 */ 226 virtual already_AddRefed<gfx::SourceSurface> GetSurfaceSnapshot( 227 gfxAlphaType* aOutAlphaType = nullptr, 228 gfx::DrawTarget* aTarget = nullptr); 229 230 /* 231 * Register a FrameCaptureListener with this canvas. 232 * The canvas hooks into the RefreshDriver while there are 233 * FrameCaptureListeners registered. 234 * The registered FrameCaptureListeners are stored as WeakPtrs, thus it's the 235 * caller's responsibility to keep them alive. Once a registered 236 * FrameCaptureListener is destroyed it will be automatically deregistered. 237 */ 238 nsresult RegisterFrameCaptureListener(FrameCaptureListener* aListener, 239 bool aReturnPlaceholderData); 240 241 /* 242 * Returns true when there is at least one registered FrameCaptureListener 243 * that has requested a frame capture. 244 */ 245 bool IsFrameCaptureRequested(const TimeStamp& aTime) const; 246 247 /* 248 * Processes destroyed FrameCaptureListeners and removes them if necessary. 249 * Should there be none left, the FrameRefreshObserver will be unregistered. 250 */ 251 void ProcessDestroyedFrameListeners(); 252 253 /* 254 * Called by the RefreshDriver hook when a frame has been captured. 255 * Makes a copy of the provided surface and hands it to all 256 * FrameCaptureListeners having requested frame capture. 257 */ 258 void SetFrameCapture(already_AddRefed<gfx::SourceSurface> aSurface, 259 const TimeStamp& aTime); 260 261 virtual bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute, 262 const nsAString& aValue, 263 nsIPrincipal* aMaybeScriptedPrincipal, 264 nsAttrValue& aResult) override; 265 NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override; 266 nsChangeHint GetAttributeChangeHint(const nsAtom* aAttribute, 267 AttrModType aModType) const override; 268 nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override; 269 270 virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override; 271 nsresult CopyInnerTo(HTMLCanvasElement* aDest); 272 273 static void MapAttributesIntoRule(MappedDeclarationsBuilder&); 274 275 /* 276 * Helpers called by various users of Canvas 277 */ 278 279 already_AddRefed<layers::Image> GetAsImage(); 280 bool UpdateWebRenderCanvasData(nsDisplayListBuilder* aBuilder, 281 WebRenderCanvasData* aCanvasData); 282 bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder, 283 CanvasRenderer* aRenderer); 284 285 // Call this whenever we need future changes to the canvas 286 // to trigger fresh invalidation requests. This needs to be called 287 // whenever we render the canvas contents to the screen, or whenever we 288 // take a snapshot of the canvas that needs to be "live" (e.g. -moz-element). 289 void MarkContextClean(); 290 291 // Call this after capturing a frame, so we can avoid unnecessary surface 292 // copies for future frames when no drawing has occurred. 293 void MarkContextCleanForFrameCapture(); 294 295 // Returns non-null when the current context supports captureStream(). 296 // The FrameCaptureState gets set to DIRTY when something is drawn. 297 Watchable<FrameCaptureState>* GetFrameCaptureState(); 298 299 nsresult GetContext(const nsAString& aContextId, nsISupports** aContext); 300 301 layers::LayersBackend GetCompositorBackendType() const; 302 303 void OnMemoryPressure(); 304 void OnDeviceReset(); 305 306 already_AddRefed<layers::SharedSurfaceTextureClient> GetVRFrame(); 307 void ClearVRFrame(); 308 309 bool MaybeModified() const { return mMaybeModified; }; 310 311 protected: 312 virtual ~HTMLCanvasElement(); 313 void Destroy(); 314 315 virtual JSObject* WrapNode(JSContext* aCx, 316 JS::Handle<JSObject*> aGivenProto) override; 317 318 CSSIntSize GetWidthHeight() override; 319 320 virtual already_AddRefed<nsICanvasRenderingContextInternal> CreateContext( 321 CanvasContextType aContextType) override; 322 323 nsresult UpdateContext(JSContext* aCx, 324 JS::Handle<JS::Value> aNewContextOptions, 325 ErrorResult& aRvForDictionaryInit) override; 326 327 nsresult ExtractData(JSContext* aCx, nsIPrincipal& aSubjectPrincipal, 328 nsAString& aType, const nsAString& aOptions, 329 nsIInputStream** aStream); 330 nsresult ToDataURLImpl(JSContext* aCx, nsIPrincipal& aSubjectPrincipal, 331 const nsAString& aMimeType, 332 const JS::Value& aEncoderOptions, nsAString& aDataURL); 333 334 UniquePtr<uint8_t[]> GetImageBuffer( 335 CanvasUtils::ImageExtraction aExtractionBehavior, int32_t* aOutFormat, 336 gfx::IntSize* aOutImageSize) override; 337 338 MOZ_CAN_RUN_SCRIPT void CallPrintCallback(); 339 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; 348 349 public: 350 ClientWebGLContext* GetWebGLContext(); 351 webgpu::CanvasContext* GetWebGPUContext(); 352 353 bool IsOffscreen() const { return !!mOffscreenCanvas; } 354 OffscreenCanvas* GetOffscreenCanvas() const { return mOffscreenCanvas; } 355 void FlushOffscreenCanvas(); 356 357 layers::ImageContainer* GetImageContainer() const { return mImageContainer; } 358 359 bool UsingCaptureStream() const { return !!mRequestedFrameRefreshObserver; } 360 361 protected: 362 bool mResetLayer; 363 bool mMaybeModified; // we fetched the context, so we may have written to the 364 // canvas 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; 374 375 // Record whether this canvas should be write-only or not. 376 // We set this when script paints an image from a different origin. 377 // We also transitively set it when script paints a canvas which 378 // is itself write-only. 379 bool mWriteOnly; 380 381 public: 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; 385 386 // Determines if the caller should be able to read the content. 387 bool CallerCanRead(nsIPrincipal& aPrincipal) const; 388 389 bool IsPrintCallbackDone(); 390 391 void HandlePrintCallback(nsPresContext*); 392 393 nsresult DispatchPrintCallback(nsITimerCallback* aCallback); 394 395 void ResetPrintCallback(); 396 397 HTMLCanvasElement* GetOriginalCanvas(); 398 399 CanvasContextType GetCurrentContextType(); 400 401 private: 402 /** 403 * This function is called by AfterSetAttr and OnAttrSetButNotChanged. 404 * This function will be called by AfterSetAttr whether the attribute is being 405 * set or unset. 406 * 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. 410 */ 411 void AfterMaybeChangeAttr(int32_t aNamespaceID, nsAtom* aName, bool aNotify); 412 }; 413 414 class HTMLCanvasPrintState final : public nsWrapperCache { 415 public: 416 HTMLCanvasPrintState(HTMLCanvasElement* aCanvas, 417 nsICanvasRenderingContextInternal* aContext, 418 nsITimerCallback* aCallback); 419 420 nsISupports* Context() const; 421 422 void Done(); 423 424 void NotifyDone(); 425 426 bool mIsDone; 427 428 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(HTMLCanvasPrintState) 429 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(HTMLCanvasPrintState) 430 431 virtual JSObject* WrapObject(JSContext* cx, 432 JS::Handle<JSObject*> aGivenProto) override; 433 434 HTMLCanvasElement* GetParentObject() { return mCanvas; } 435 436 private: 437 ~HTMLCanvasPrintState(); 438 bool mPendingNotify; 439 440 protected: 441 RefPtr<HTMLCanvasElement> mCanvas; 442 nsCOMPtr<nsICanvasRenderingContextInternal> mContext; 443 nsCOMPtr<nsITimerCallback> mCallback; 444 }; 445 446 } // namespace dom 447 } // namespace mozilla 448 449 #endif /* mozilla_dom_HTMLCanvasElement_h */