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/. */
7 #include "mozilla/dom/HTMLCanvasElement.h"
9 #include "ImageEncoder.h"
11 #include "jsfriendapi.h"
13 #include "MediaSegment.h"
14 #include "mozilla/Assertions.h"
15 #include "mozilla/Base64.h"
16 #include "mozilla/CheckedInt.h"
17 #include "mozilla/dom/CanvasCaptureMediaStream.h"
18 #include "mozilla/dom/CanvasRenderingContext2D.h"
19 #include "mozilla/dom/Event.h"
20 #include "mozilla/dom/File.h"
21 #include "mozilla/dom/HTMLCanvasElementBinding.h"
22 #include "mozilla/dom/MediaStreamTrack.h"
23 #include "mozilla/dom/MouseEvent.h"
24 #include "mozilla/dom/OffscreenCanvas.h"
25 #include "mozilla/EventDispatcher.h"
26 #include "mozilla/gfx/Rect.h"
27 #include "mozilla/layers/AsyncCanvasRenderer.h"
28 #include "mozilla/layers/WebRenderCanvasRenderer.h"
29 #include "mozilla/layers/WebRenderUserData.h"
30 #include "mozilla/MouseEvents.h"
31 #include "mozilla/Preferences.h"
32 #include "mozilla/Telemetry.h"
33 #include "nsAttrValueInlines.h"
34 #include "nsContentUtils.h"
35 #include "nsDisplayList.h"
36 #include "nsDOMJSUtils.h"
37 #include "nsIScriptSecurityManager.h"
39 #include "nsIWritablePropertyBag2.h"
40 #include "nsIXPConnect.h"
41 #include "nsJSUtils.h"
42 #include "nsLayoutUtils.h"
43 #include "nsMathUtils.h"
44 #include "nsNetUtil.h"
45 #include "nsRefreshDriver.h"
46 #include "nsStreamUtils.h"
47 #include "ActiveLayerTracker.h"
48 #include "CanvasUtils.h"
49 #include "VRManagerChild.h"
50 #include "WebGL1Context.h"
51 #include "WebGL2Context.h"
53 using namespace mozilla::layers
;
54 using namespace mozilla::gfx
;
56 NS_IMPL_NS_NEW_HTML_ELEMENT(Canvas
)
61 class RequestedFrameRefreshObserver
: public nsARefreshObserver
{
62 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RequestedFrameRefreshObserver
, override
)
65 RequestedFrameRefreshObserver(HTMLCanvasElement
* const aOwningElement
,
66 nsRefreshDriver
* aRefreshDriver
,
67 bool aReturnPlaceholderData
)
69 mReturnPlaceholderData(aReturnPlaceholderData
),
70 mOwningElement(aOwningElement
),
71 mRefreshDriver(aRefreshDriver
) {
72 MOZ_ASSERT(mOwningElement
);
75 static already_AddRefed
<DataSourceSurface
> CopySurface(
76 const RefPtr
<SourceSurface
>& aSurface
, bool aReturnPlaceholderData
) {
77 RefPtr
<DataSourceSurface
> data
= aSurface
->GetDataSurface();
82 DataSourceSurface::ScopedMap
read(data
, DataSourceSurface::READ
);
83 if (!read
.IsMapped()) {
87 RefPtr
<DataSourceSurface
> copy
= Factory::CreateDataSourceSurfaceWithStride(
88 data
->GetSize(), data
->GetFormat(), read
.GetStride());
93 DataSourceSurface::ScopedMap
write(copy
, DataSourceSurface::WRITE
);
94 if (!write
.IsMapped()) {
98 MOZ_ASSERT(read
.GetStride() == write
.GetStride());
99 MOZ_ASSERT(data
->GetSize() == copy
->GetSize());
100 MOZ_ASSERT(data
->GetFormat() == copy
->GetFormat());
102 if (aReturnPlaceholderData
) {
103 // If returning placeholder data, fill the frame copy with white pixels.
104 memset(write
.GetData(), 0xFF, write
.GetStride() * copy
->GetSize().height
);
106 memcpy(write
.GetData(), read
.GetData(),
107 write
.GetStride() * copy
->GetSize().height
);
110 return copy
.forget();
113 void SetReturnPlaceholderData(bool aReturnPlaceholderData
) {
114 mReturnPlaceholderData
= aReturnPlaceholderData
;
117 void WillRefresh(TimeStamp aTime
) override
{
118 MOZ_ASSERT(NS_IsMainThread());
120 AUTO_PROFILER_LABEL("RequestedFrameRefreshObserver::WillRefresh", OTHER
);
122 if (!mOwningElement
) {
126 if (mOwningElement
->IsWriteOnly()) {
130 if (mOwningElement
->IsContextCleanForFrameCapture()) {
134 mOwningElement
->ProcessDestroyedFrameListeners();
136 if (!mOwningElement
->IsFrameCaptureRequested()) {
140 RefPtr
<SourceSurface
> snapshot
;
143 "RequestedFrameRefreshObserver::WillRefresh:GetSnapshot", OTHER
);
144 snapshot
= mOwningElement
->GetSurfaceSnapshot(nullptr);
150 RefPtr
<DataSourceSurface
> copy
;
153 "RequestedFrameRefreshObserver::WillRefresh:CopySurface", OTHER
);
154 copy
= CopySurface(snapshot
, mReturnPlaceholderData
);
161 AUTO_PROFILER_LABEL("RequestedFrameRefreshObserver::WillRefresh:SetFrame",
163 mOwningElement
->SetFrameCapture(copy
.forget(), aTime
);
164 mOwningElement
->MarkContextCleanForFrameCapture();
168 void DetachFromRefreshDriver() {
169 MOZ_ASSERT(mOwningElement
);
170 MOZ_ASSERT(mRefreshDriver
);
173 mRefreshDriver
= nullptr;
181 MOZ_ASSERT(mRefreshDriver
);
182 if (mRefreshDriver
) {
183 mRefreshDriver
->AddRefreshObserver(this, FlushType::Display
);
193 MOZ_ASSERT(mRefreshDriver
);
194 if (mRefreshDriver
) {
195 mRefreshDriver
->RemoveRefreshObserver(this, FlushType::Display
);
201 virtual ~RequestedFrameRefreshObserver() {
202 MOZ_ASSERT(!mRefreshDriver
);
203 MOZ_ASSERT(!mRegistered
);
207 bool mReturnPlaceholderData
;
208 HTMLCanvasElement
* const mOwningElement
;
209 RefPtr
<nsRefreshDriver
> mRefreshDriver
;
212 // ---------------------------------------------------------------------------
214 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLCanvasPrintState
, mCanvas
, mContext
,
217 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(HTMLCanvasPrintState
, AddRef
)
218 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(HTMLCanvasPrintState
, Release
)
220 HTMLCanvasPrintState::HTMLCanvasPrintState(
221 HTMLCanvasElement
* aCanvas
, nsICanvasRenderingContextInternal
* aContext
,
222 nsITimerCallback
* aCallback
)
224 mPendingNotify(false),
227 mCallback(aCallback
) {}
229 HTMLCanvasPrintState::~HTMLCanvasPrintState() {}
232 JSObject
* HTMLCanvasPrintState::WrapObject(JSContext
* aCx
,
233 JS::Handle
<JSObject
*> aGivenProto
) {
234 return MozCanvasPrintState_Binding::Wrap(aCx
, this, aGivenProto
);
237 nsISupports
* HTMLCanvasPrintState::Context() const { return mContext
; }
239 void HTMLCanvasPrintState::Done() {
240 if (!mPendingNotify
&& !mIsDone
) {
241 // The canvas needs to be invalidated for printing reftests on linux to
244 mCanvas
->InvalidateCanvas();
246 RefPtr
<nsRunnableMethod
<HTMLCanvasPrintState
>> doneEvent
=
247 NewRunnableMethod("dom::HTMLCanvasPrintState::NotifyDone", this,
248 &HTMLCanvasPrintState::NotifyDone
);
249 if (NS_SUCCEEDED(NS_DispatchToCurrentThread(doneEvent
))) {
250 mPendingNotify
= true;
255 void HTMLCanvasPrintState::NotifyDone() {
257 mPendingNotify
= false;
259 mCallback
->Notify(nullptr);
263 // ---------------------------------------------------------------------------
265 HTMLCanvasElementObserver::HTMLCanvasElementObserver(
266 HTMLCanvasElement
* aElement
)
267 : mElement(aElement
) {
268 RegisterVisibilityChangeEvent();
269 RegisterMemoryPressureEvent();
272 HTMLCanvasElementObserver::~HTMLCanvasElementObserver() { Destroy(); }
274 void HTMLCanvasElementObserver::Destroy() {
275 UnregisterMemoryPressureEvent();
276 UnregisterVisibilityChangeEvent();
280 void HTMLCanvasElementObserver::RegisterVisibilityChangeEvent() {
285 Document
* document
= mElement
->OwnerDoc();
286 document
->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), this,
290 void HTMLCanvasElementObserver::UnregisterVisibilityChangeEvent() {
295 Document
* document
= mElement
->OwnerDoc();
296 document
->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
300 void HTMLCanvasElementObserver::RegisterMemoryPressureEvent() {
305 nsCOMPtr
<nsIObserverService
> observerService
=
306 mozilla::services::GetObserverService();
308 MOZ_ASSERT(observerService
);
311 observerService
->AddObserver(this, "memory-pressure", false);
314 void HTMLCanvasElementObserver::UnregisterMemoryPressureEvent() {
319 nsCOMPtr
<nsIObserverService
> observerService
=
320 mozilla::services::GetObserverService();
322 // Do not assert on observerService here. This might be triggered by
323 // the cycle collector at a late enough time, that XPCOM services are
324 // no longer available. See bug 1029504.
325 if (observerService
) observerService
->RemoveObserver(this, "memory-pressure");
329 HTMLCanvasElementObserver::Observe(nsISupports
*, const char* aTopic
,
331 if (!mElement
|| strcmp(aTopic
, "memory-pressure")) {
335 mElement
->OnMemoryPressure();
341 HTMLCanvasElementObserver::HandleEvent(Event
* aEvent
) {
343 aEvent
->GetType(type
);
344 if (!mElement
|| !type
.EqualsLiteral("visibilitychange")) {
348 mElement
->OnVisibilityChange();
353 NS_IMPL_ISUPPORTS(HTMLCanvasElementObserver
, nsIObserver
)
355 // ---------------------------------------------------------------------------
357 HTMLCanvasElement::HTMLCanvasElement(
358 already_AddRefed
<mozilla::dom::NodeInfo
>&& aNodeInfo
)
359 : nsGenericHTMLElement(std::move(aNodeInfo
)),
361 mMaybeModified(false),
364 HTMLCanvasElement::~HTMLCanvasElement() {
365 if (mContextObserver
) {
366 mContextObserver
->Destroy();
367 mContextObserver
= nullptr;
370 ResetPrintCallback();
371 if (mRequestedFrameRefreshObserver
) {
372 mRequestedFrameRefreshObserver
->DetachFromRefreshDriver();
375 if (mAsyncCanvasRenderer
) {
376 mAsyncCanvasRenderer
->mHTMLCanvasElement
= nullptr;
380 NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement
, nsGenericHTMLElement
,
381 mCurrentContext
, mPrintCallback
, mPrintState
,
382 mOriginalCanvas
, mOffscreenCanvas
)
384 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(HTMLCanvasElement
,
385 nsGenericHTMLElement
)
387 NS_IMPL_ELEMENT_CLONE(HTMLCanvasElement
)
390 JSObject
* HTMLCanvasElement::WrapNode(JSContext
* aCx
,
391 JS::Handle
<JSObject
*> aGivenProto
) {
392 return HTMLCanvasElement_Binding::Wrap(aCx
, this, aGivenProto
);
395 already_AddRefed
<nsICanvasRenderingContextInternal
>
396 HTMLCanvasElement::CreateContext(CanvasContextType aContextType
) {
397 // Note that the compositor backend will be LAYERS_NONE if there is no widget.
398 RefPtr
<nsICanvasRenderingContextInternal
> ret
=
399 CreateContextHelper(aContextType
, GetCompositorBackendType());
401 // Add Observer for webgl canvas.
402 if (aContextType
== CanvasContextType::WebGL1
||
403 aContextType
== CanvasContextType::WebGL2
) {
404 if (!mContextObserver
) {
405 mContextObserver
= new HTMLCanvasElementObserver(this);
409 ret
->SetCanvasElement(this);
413 nsIntSize
HTMLCanvasElement::GetWidthHeight() {
414 nsIntSize
size(DEFAULT_CANVAS_WIDTH
, DEFAULT_CANVAS_HEIGHT
);
415 const nsAttrValue
* value
;
417 if ((value
= GetParsedAttr(nsGkAtoms::width
)) &&
418 value
->Type() == nsAttrValue::eInteger
) {
419 size
.width
= value
->GetIntegerValue();
422 if ((value
= GetParsedAttr(nsGkAtoms::height
)) &&
423 value
->Type() == nsAttrValue::eInteger
) {
424 size
.height
= value
->GetIntegerValue();
427 MOZ_ASSERT(size
.width
>= 0 && size
.height
>= 0,
428 "we should've required <canvas> width/height attrs to be "
429 "unsigned (non-negative) values");
434 nsresult
HTMLCanvasElement::AfterSetAttr(int32_t aNamespaceID
, nsAtom
* aName
,
435 const nsAttrValue
* aValue
,
436 const nsAttrValue
* aOldValue
,
437 nsIPrincipal
* aSubjectPrincipal
,
439 AfterMaybeChangeAttr(aNamespaceID
, aName
, aNotify
);
441 return nsGenericHTMLElement::AfterSetAttr(
442 aNamespaceID
, aName
, aValue
, aOldValue
, aSubjectPrincipal
, aNotify
);
445 nsresult
HTMLCanvasElement::OnAttrSetButNotChanged(
446 int32_t aNamespaceID
, nsAtom
* aName
, const nsAttrValueOrString
& aValue
,
448 AfterMaybeChangeAttr(aNamespaceID
, aName
, aNotify
);
450 return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID
, aName
,
454 void HTMLCanvasElement::AfterMaybeChangeAttr(int32_t aNamespaceID
,
455 nsAtom
* aName
, bool aNotify
) {
456 if (mCurrentContext
&& aNamespaceID
== kNameSpaceID_None
&&
457 (aName
== nsGkAtoms::width
|| aName
== nsGkAtoms::height
||
458 aName
== nsGkAtoms::moz_opaque
)) {
460 UpdateContext(nullptr, JS::NullHandleValue
, dummy
);
464 void HTMLCanvasElement::HandlePrintCallback(
465 nsPresContext::nsPresContextType aType
) {
466 // Only call the print callback here if 1) we're in a print testing mode or
467 // print preview mode, 2) the canvas has a print callback and 3) the callback
468 // hasn't already been called. For real printing the callback is handled in
469 // nsSimplePageSequenceFrame::PrePrintNextPage.
470 if ((aType
== nsPresContext::eContext_PageLayout
||
471 aType
== nsPresContext::eContext_PrintPreview
) &&
472 !mPrintState
&& GetMozPrintCallback()) {
473 DispatchPrintCallback(nullptr);
477 nsresult
HTMLCanvasElement::DispatchPrintCallback(nsITimerCallback
* aCallback
) {
478 // For print reftests the context may not be initialized yet, so get a context
479 // so mCurrentContext is set.
480 if (!mCurrentContext
) {
482 nsCOMPtr
<nsISupports
> context
;
483 rv
= GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(context
));
484 NS_ENSURE_SUCCESS(rv
, rv
);
486 mPrintState
= new HTMLCanvasPrintState(this, mCurrentContext
, aCallback
);
488 RefPtr
<nsRunnableMethod
<HTMLCanvasElement
>> renderEvent
=
489 NewRunnableMethod("dom::HTMLCanvasElement::CallPrintCallback", this,
490 &HTMLCanvasElement::CallPrintCallback
);
491 return OwnerDoc()->Dispatch(TaskCategory::Other
, renderEvent
.forget());
495 void HTMLCanvasElement::CallPrintCallback() {
496 RefPtr
<PrintCallback
> callback
= GetMozPrintCallback();
497 RefPtr
<HTMLCanvasPrintState
> state
= mPrintState
;
498 callback
->Call(*state
);
501 void HTMLCanvasElement::ResetPrintCallback() {
503 mPrintState
= nullptr;
507 bool HTMLCanvasElement::IsPrintCallbackDone() {
508 if (mPrintState
== nullptr) {
512 return mPrintState
->mIsDone
;
515 HTMLCanvasElement
* HTMLCanvasElement::GetOriginalCanvas() {
516 return mOriginalCanvas
? mOriginalCanvas
.get() : this;
519 nsresult
HTMLCanvasElement::CopyInnerTo(HTMLCanvasElement
* aDest
) {
520 nsresult rv
= nsGenericHTMLElement::CopyInnerTo(aDest
);
521 NS_ENSURE_SUCCESS(rv
, rv
);
522 if (aDest
->OwnerDoc()->IsStaticDocument()) {
523 // The Firefox print preview code can create a static clone from an
524 // existing static clone, so we may not be the original 'canvas' element.
525 aDest
->mOriginalCanvas
= GetOriginalCanvas();
527 // We make sure that the canvas is not zero sized since that would cause
528 // the DrawImage call below to return an error, which would cause printing
530 nsIntSize size
= GetWidthHeight();
531 if (size
.height
> 0 && size
.width
> 0) {
532 nsCOMPtr
<nsISupports
> cxt
;
533 aDest
->GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(cxt
));
534 RefPtr
<CanvasRenderingContext2D
> context2d
=
535 static_cast<CanvasRenderingContext2D
*>(cxt
.get());
536 if (context2d
&& !mPrintCallback
) {
537 CanvasImageSource source
;
538 source
.SetAsHTMLCanvasElement() = this;
540 context2d
->DrawImage(source
, 0.0, 0.0, err
);
541 rv
= err
.StealNSResult();
548 void HTMLCanvasElement::GetEventTargetParent(EventChainPreVisitor
& aVisitor
) {
549 if (aVisitor
.mEvent
->mClass
== eMouseEventClass
) {
550 WidgetMouseEventBase
* evt
= (WidgetMouseEventBase
*)aVisitor
.mEvent
;
551 if (mCurrentContext
) {
552 nsIFrame
* frame
= GetPrimaryFrame();
557 nsLayoutUtils::GetEventCoordinatesRelativeTo(evt
, frame
);
558 nsRect paddingRect
= frame
->GetContentRectRelativeToSelf();
560 hitpoint
.x
= (ptInRoot
.x
- paddingRect
.x
) / AppUnitsPerCSSPixel();
561 hitpoint
.y
= (ptInRoot
.y
- paddingRect
.y
) / AppUnitsPerCSSPixel();
563 evt
->mRegion
= mCurrentContext
->GetHitRegion(hitpoint
);
564 aVisitor
.mCanHandle
= true;
567 nsGenericHTMLElement::GetEventTargetParent(aVisitor
);
570 nsChangeHint
HTMLCanvasElement::GetAttributeChangeHint(const nsAtom
* aAttribute
,
571 int32_t aModType
) const {
572 nsChangeHint retval
=
573 nsGenericHTMLElement::GetAttributeChangeHint(aAttribute
, aModType
);
574 if (aAttribute
== nsGkAtoms::width
|| aAttribute
== nsGkAtoms::height
) {
575 retval
|= NS_STYLE_HINT_REFLOW
;
576 } else if (aAttribute
== nsGkAtoms::moz_opaque
) {
577 retval
|= NS_STYLE_HINT_VISUAL
;
582 bool HTMLCanvasElement::ParseAttribute(int32_t aNamespaceID
, nsAtom
* aAttribute
,
583 const nsAString
& aValue
,
584 nsIPrincipal
* aMaybeScriptedPrincipal
,
585 nsAttrValue
& aResult
) {
586 if (aNamespaceID
== kNameSpaceID_None
&&
587 (aAttribute
== nsGkAtoms::width
|| aAttribute
== nsGkAtoms::height
)) {
588 return aResult
.ParseNonNegativeIntValue(aValue
);
591 return nsGenericHTMLElement::ParseAttribute(aNamespaceID
, aAttribute
, aValue
,
592 aMaybeScriptedPrincipal
, aResult
);
595 void HTMLCanvasElement::ToDataURL(JSContext
* aCx
, const nsAString
& aType
,
596 JS::Handle
<JS::Value
> aParams
,
598 nsIPrincipal
& aSubjectPrincipal
,
600 // mWriteOnly check is redundant, but optimizes for the common case.
601 if (mWriteOnly
&& !CallerCanRead(aCx
)) {
602 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
606 aRv
= ToDataURLImpl(aCx
, aSubjectPrincipal
, aType
, aParams
, aDataURL
);
609 void HTMLCanvasElement::SetMozPrintCallback(PrintCallback
* aCallback
) {
610 mPrintCallback
= aCallback
;
613 PrintCallback
* HTMLCanvasElement::GetMozPrintCallback() const {
614 if (mOriginalCanvas
) {
615 return mOriginalCanvas
->GetMozPrintCallback();
617 return mPrintCallback
;
620 class CanvasCaptureTrackSource
: public MediaStreamTrackSource
{
622 NS_DECL_ISUPPORTS_INHERITED
623 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CanvasCaptureTrackSource
,
624 MediaStreamTrackSource
)
626 CanvasCaptureTrackSource(nsIPrincipal
* aPrincipal
,
627 CanvasCaptureMediaStream
* aCaptureStream
)
628 : MediaStreamTrackSource(aPrincipal
, nsString()),
629 mCaptureStream(aCaptureStream
) {}
631 MediaSourceEnum
GetMediaSource() const override
{
632 return MediaSourceEnum::Other
;
635 void Stop() override
{
636 if (!mCaptureStream
) {
637 NS_ERROR("No stream");
641 mCaptureStream
->StopCapture();
644 void Disable() override
{}
646 void Enable() override
{}
649 virtual ~CanvasCaptureTrackSource() {}
651 RefPtr
<CanvasCaptureMediaStream
> mCaptureStream
;
654 NS_IMPL_ADDREF_INHERITED(CanvasCaptureTrackSource
, MediaStreamTrackSource
)
655 NS_IMPL_RELEASE_INHERITED(CanvasCaptureTrackSource
, MediaStreamTrackSource
)
656 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CanvasCaptureTrackSource
)
657 NS_INTERFACE_MAP_END_INHERITING(MediaStreamTrackSource
)
658 NS_IMPL_CYCLE_COLLECTION_INHERITED(CanvasCaptureTrackSource
,
659 MediaStreamTrackSource
, mCaptureStream
)
661 already_AddRefed
<CanvasCaptureMediaStream
> HTMLCanvasElement::CaptureStream(
662 const Optional
<double>& aFrameRate
, nsIPrincipal
& aSubjectPrincipal
,
665 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
669 nsPIDOMWindowInner
* window
= OwnerDoc()->GetInnerWindow();
671 aRv
.Throw(NS_ERROR_FAILURE
);
675 if (!mCurrentContext
) {
676 aRv
.Throw(NS_ERROR_NOT_INITIALIZED
);
680 RefPtr
<CanvasCaptureMediaStream
> stream
=
681 CanvasCaptureMediaStream::CreateSourceStream(window
, this);
683 aRv
.Throw(NS_ERROR_FAILURE
);
687 TrackID videoTrackId
= 1;
688 nsCOMPtr
<nsIPrincipal
> principal
= NodePrincipal();
689 nsresult rv
= stream
->Init(aFrameRate
, videoTrackId
, principal
);
695 RefPtr
<MediaStreamTrack
> track
=
696 stream
->CreateDOMTrack(videoTrackId
, MediaSegment::VIDEO
,
697 new CanvasCaptureTrackSource(principal
, stream
));
698 stream
->AddTrackInternal(track
);
700 // Check site-specific permission and display prompt if appropriate.
701 // If no permission, arrange for the frame capture listener to return
702 // all-white, opaque image data.
703 bool usePlaceholder
= !CanvasUtils::IsImageExtractionAllowed(
704 OwnerDoc(), nsContentUtils::GetCurrentJSContext(), aSubjectPrincipal
);
706 rv
= RegisterFrameCaptureListener(stream
->FrameCaptureListener(),
713 return stream
.forget();
716 nsresult
HTMLCanvasElement::ExtractData(JSContext
* aCx
,
717 nsIPrincipal
& aSubjectPrincipal
,
719 const nsAString
& aOptions
,
720 nsIInputStream
** aStream
) {
721 // Check site-specific permission and display prompt if appropriate.
722 // If no permission, return all-white, opaque image data.
723 bool usePlaceholder
= !CanvasUtils::IsImageExtractionAllowed(
724 OwnerDoc(), aCx
, aSubjectPrincipal
);
725 return ImageEncoder::ExtractData(aType
, aOptions
, GetSize(), usePlaceholder
,
726 mCurrentContext
, mAsyncCanvasRenderer
,
730 nsresult
HTMLCanvasElement::ToDataURLImpl(JSContext
* aCx
,
731 nsIPrincipal
& aSubjectPrincipal
,
732 const nsAString
& aMimeType
,
733 const JS::Value
& aEncoderOptions
,
734 nsAString
& aDataURL
) {
735 nsIntSize size
= GetWidthHeight();
736 if (size
.height
== 0 || size
.width
== 0) {
737 aDataURL
= NS_LITERAL_STRING("data:,");
742 nsContentUtils::ASCIIToLower(aMimeType
, type
);
745 bool usingCustomParseOptions
;
747 ParseParams(aCx
, type
, aEncoderOptions
, params
, &usingCustomParseOptions
);
752 nsCOMPtr
<nsIInputStream
> stream
;
754 ExtractData(aCx
, aSubjectPrincipal
, type
, params
, getter_AddRefs(stream
));
756 // If there are unrecognized custom parse options, we should fall back to
757 // the default values for the encoder without any options at all.
758 if (rv
== NS_ERROR_INVALID_ARG
&& usingCustomParseOptions
) {
759 rv
= ExtractData(aCx
, aSubjectPrincipal
, type
, EmptyString(),
760 getter_AddRefs(stream
));
763 NS_ENSURE_SUCCESS(rv
, rv
);
765 // build data URL string
766 aDataURL
= NS_LITERAL_STRING("data:") + type
+ NS_LITERAL_STRING(";base64,");
769 rv
= stream
->Available(&count
);
770 NS_ENSURE_SUCCESS(rv
, rv
);
771 NS_ENSURE_TRUE(count
<= UINT32_MAX
, NS_ERROR_FILE_TOO_BIG
);
773 return Base64EncodeInputStream(stream
, aDataURL
, (uint32_t)count
,
777 void HTMLCanvasElement::ToBlob(JSContext
* aCx
, BlobCallback
& aCallback
,
778 const nsAString
& aType
,
779 JS::Handle
<JS::Value
> aParams
,
780 nsIPrincipal
& aSubjectPrincipal
,
782 // mWriteOnly check is redundant, but optimizes for the common case.
783 if (mWriteOnly
&& !CallerCanRead(aCx
)) {
784 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
788 nsCOMPtr
<nsIGlobalObject
> global
= OwnerDoc()->GetScopeObject();
791 nsIntSize elemSize
= GetWidthHeight();
792 if (elemSize
.width
== 0 || elemSize
.height
== 0) {
793 // According to spec, blob should return null if either its horizontal
794 // dimension or its vertical dimension is zero. See link below.
795 // https://html.spec.whatwg.org/multipage/scripting.html#dom-canvas-toblob
796 OwnerDoc()->Dispatch(
798 NewRunnableMethod
<Blob
*, const char*>(
799 "dom::HTMLCanvasElement::ToBlob", &aCallback
,
800 static_cast<void (BlobCallback::*)(Blob
*, const char*)>(
801 &BlobCallback::Call
),
806 // Check site-specific permission and display prompt if appropriate.
807 // If no permission, return all-white, opaque image data.
808 bool usePlaceholder
= !CanvasUtils::IsImageExtractionAllowed(
809 OwnerDoc(), aCx
, aSubjectPrincipal
);
810 CanvasRenderingContextHelper::ToBlob(aCx
, global
, aCallback
, aType
, aParams
,
811 usePlaceholder
, aRv
);
814 OffscreenCanvas
* HTMLCanvasElement::TransferControlToOffscreen(
816 if (mCurrentContext
) {
817 aRv
.Throw(NS_ERROR_DOM_INVALID_STATE_ERR
);
821 if (!mOffscreenCanvas
) {
822 nsIntSize sz
= GetWidthHeight();
823 RefPtr
<AsyncCanvasRenderer
> renderer
= GetAsyncCanvasRenderer();
824 renderer
->SetWidth(sz
.width
);
825 renderer
->SetHeight(sz
.height
);
827 nsPIDOMWindowInner
* win
= OwnerDoc()->GetInnerWindow();
829 aRv
.Throw(NS_ERROR_DOM_INVALID_STATE_ERR
);
834 new OffscreenCanvas(win
->AsGlobal(), sz
.width
, sz
.height
,
835 GetCompositorBackendType(), renderer
);
837 mOffscreenCanvas
->SetWriteOnly();
840 if (!mContextObserver
) {
841 mContextObserver
= new HTMLCanvasElementObserver(this);
844 aRv
.Throw(NS_ERROR_DOM_INVALID_STATE_ERR
);
847 return mOffscreenCanvas
;
850 already_AddRefed
<File
> HTMLCanvasElement::MozGetAsFile(
851 const nsAString
& aName
, const nsAString
& aType
,
852 nsIPrincipal
& aSubjectPrincipal
, ErrorResult
& aRv
) {
853 OwnerDoc()->WarnOnceAbout(Document::eMozGetAsFile
);
855 // do a trust check if this is a write-only canvas
856 if (mWriteOnly
&& !nsContentUtils::IsSystemPrincipal(&aSubjectPrincipal
)) {
857 aRv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
862 aRv
= MozGetAsFileImpl(aName
, aType
, aSubjectPrincipal
, getter_AddRefs(file
));
863 if (NS_WARN_IF(aRv
.Failed())) {
866 return file
.forget();
869 nsresult
HTMLCanvasElement::MozGetAsFileImpl(const nsAString
& aName
,
870 const nsAString
& aType
,
871 nsIPrincipal
& aSubjectPrincipal
,
873 nsCOMPtr
<nsIInputStream
> stream
;
874 nsAutoString
type(aType
);
876 ExtractData(nsContentUtils::GetCurrentJSContext(), aSubjectPrincipal
,
877 type
, EmptyString(), getter_AddRefs(stream
));
878 NS_ENSURE_SUCCESS(rv
, rv
);
881 void* imgData
= nullptr;
882 rv
= NS_ReadInputStreamToBuffer(stream
, &imgData
, -1, &imgSize
);
883 NS_ENSURE_SUCCESS(rv
, rv
);
885 nsCOMPtr
<nsPIDOMWindowInner
> win
=
886 do_QueryInterface(OwnerDoc()->GetScopeObject());
888 // The File takes ownership of the buffer
890 File::CreateMemoryFile(win
, imgData
, imgSize
, aName
, type
, PR_Now());
892 file
.forget(aResult
);
896 nsresult
HTMLCanvasElement::GetContext(const nsAString
& aContextId
,
897 nsISupports
** aContext
) {
899 mMaybeModified
= true; // For FirstContentfulPaint
900 *aContext
= GetContext(nullptr, aContextId
, JS::NullHandleValue
, rv
).take();
901 return rv
.StealNSResult();
904 already_AddRefed
<nsISupports
> HTMLCanvasElement::GetContext(
905 JSContext
* aCx
, const nsAString
& aContextId
,
906 JS::Handle
<JS::Value
> aContextOptions
, ErrorResult
& aRv
) {
907 if (mOffscreenCanvas
) {
911 mMaybeModified
= true; // For FirstContentfulPaint
912 return CanvasRenderingContextHelper::GetContext(
914 aContextOptions
.isObject() ? aContextOptions
: JS::NullHandleValue
, aRv
);
917 already_AddRefed
<nsISupports
> HTMLCanvasElement::MozGetIPCContext(
918 const nsAString
& aContextId
, ErrorResult
& aRv
) {
919 // Note that we're a [ChromeOnly] method, so from JS we can only be called by
922 // We only support 2d shmem contexts for now.
923 if (!aContextId
.EqualsLiteral("2d")) {
924 aRv
.Throw(NS_ERROR_INVALID_ARG
);
928 CanvasContextType contextType
= CanvasContextType::Canvas2D
;
930 if (!mCurrentContext
) {
931 // This canvas doesn't have a context yet.
933 RefPtr
<nsICanvasRenderingContextInternal
> context
;
934 context
= CreateContext(contextType
);
939 mCurrentContext
= context
;
940 mCurrentContext
->SetIsIPC(true);
941 mCurrentContextType
= contextType
;
944 nsresult rv
= UpdateContext(nullptr, JS::NullHandleValue
, dummy
);
945 if (NS_WARN_IF(NS_FAILED(rv
))) {
950 // We already have a context of some type.
951 if (contextType
!= mCurrentContextType
) {
952 aRv
.Throw(NS_ERROR_INVALID_ARG
);
957 nsCOMPtr
<nsISupports
> context(mCurrentContext
);
958 return context
.forget();
961 nsIntSize
HTMLCanvasElement::GetSize() { return GetWidthHeight(); }
963 bool HTMLCanvasElement::IsWriteOnly() const { return mWriteOnly
; }
965 void HTMLCanvasElement::SetWriteOnly() {
966 mExpandedReader
= nullptr;
970 void HTMLCanvasElement::SetWriteOnly(nsIPrincipal
* aExpandedReader
) {
971 mExpandedReader
= aExpandedReader
;
975 bool HTMLCanvasElement::CallerCanRead(JSContext
* aCx
) {
980 nsIPrincipal
* prin
= nsContentUtils::SubjectPrincipal(aCx
);
982 // If mExpandedReader is set, this canvas was tainted only by
983 // mExpandedReader's resources. So allow reading if the subject
984 // principal subsumes mExpandedReader.
985 if (mExpandedReader
&& prin
->Subsumes(mExpandedReader
)) {
989 return nsContentUtils::PrincipalHasPermission(prin
,
990 nsGkAtoms::all_urlsPermission
);
993 void HTMLCanvasElement::InvalidateCanvasContent(const gfx::Rect
* damageRect
) {
994 // We don't need to flush anything here; if there's no frame or if
995 // we plan to reframe we don't need to invalidate it anyway.
996 nsIFrame
* frame
= GetPrimaryFrame();
999 ActiveLayerTracker::NotifyContentChange(frame
);
1001 // When using layers-free WebRender, we cannot invalidate the layer (because
1002 // there isn't one). Instead, we mark the CanvasRenderer dirty and scheduling
1003 // an empty transaction which is effectively equivalent.
1004 CanvasRenderer
* renderer
= nullptr;
1005 RefPtr
<WebRenderCanvasData
> data
= GetWebRenderUserData
<WebRenderCanvasData
>(
1006 frame
, static_cast<uint32_t>(DisplayItemType::TYPE_CANVAS
));
1008 renderer
= data
->GetCanvasRenderer();
1012 renderer
->SetDirty();
1013 frame
->SchedulePaint(nsIFrame::PAINT_COMPOSITE_ONLY
);
1015 Layer
* layer
= nullptr;
1017 nsIntSize size
= GetWidthHeight();
1018 if (size
.width
!= 0 && size
.height
!= 0) {
1019 gfx::IntRect invalRect
= gfx::IntRect::Truncate(*damageRect
);
1021 frame
->InvalidateLayer(DisplayItemType::TYPE_CANVAS
, &invalRect
);
1024 layer
= frame
->InvalidateLayer(DisplayItemType::TYPE_CANVAS
);
1028 static_cast<CanvasLayer
*>(layer
)->Updated();
1033 * Treat canvas invalidations as animation activity for JS. Frequently
1034 * invalidating a canvas will feed into heuristics and cause JIT code to be
1035 * kept around longer, for smoother animations.
1037 nsPIDOMWindowInner
* win
= OwnerDoc()->GetInnerWindow();
1040 if (JSObject
* obj
= win
->AsGlobal()->GetGlobalJSObject()) {
1041 js::NotifyAnimationActivity(obj
);
1046 void HTMLCanvasElement::InvalidateCanvas() {
1047 // We don't need to flush anything here; if there's no frame or if
1048 // we plan to reframe we don't need to invalidate it anyway.
1049 nsIFrame
* frame
= GetPrimaryFrame();
1052 frame
->InvalidateFrame();
1055 int32_t HTMLCanvasElement::CountContexts() {
1056 if (mCurrentContext
) return 1;
1061 nsICanvasRenderingContextInternal
* HTMLCanvasElement::GetContextAtIndex(
1063 if (mCurrentContext
&& index
== 0) return mCurrentContext
;
1068 bool HTMLCanvasElement::GetIsOpaque() {
1069 if (mCurrentContext
) {
1070 return mCurrentContext
->GetIsOpaque();
1073 return GetOpaqueAttr();
1076 bool HTMLCanvasElement::GetOpaqueAttr() {
1077 return HasAttr(kNameSpaceID_None
, nsGkAtoms::moz_opaque
);
1080 already_AddRefed
<Layer
> HTMLCanvasElement::GetCanvasLayer(
1081 nsDisplayListBuilder
* aBuilder
, Layer
* aOldLayer
, LayerManager
* aManager
) {
1082 // The address of sOffscreenCanvasLayerUserDataDummy is used as the user
1083 // data key for retained LayerManagers managed by FrameLayerBuilder.
1084 // We don't much care about what value in it, so just assign a dummy
1086 static uint8_t sOffscreenCanvasLayerUserDataDummy
= 0;
1088 if (mCurrentContext
) {
1089 return mCurrentContext
->GetCanvasLayer(aBuilder
, aOldLayer
, aManager
);
1092 if (mOffscreenCanvas
) {
1093 if (!mResetLayer
&& aOldLayer
&&
1094 aOldLayer
->HasUserData(&sOffscreenCanvasLayerUserDataDummy
)) {
1095 RefPtr
<Layer
> ret
= aOldLayer
;
1096 return ret
.forget();
1099 RefPtr
<CanvasLayer
> layer
= aManager
->CreateCanvasLayer();
1101 NS_WARNING("CreateCanvasLayer failed!");
1105 LayerUserData
* userData
= nullptr;
1106 layer
->SetUserData(&sOffscreenCanvasLayerUserDataDummy
, userData
);
1108 CanvasRenderer
* canvasRenderer
= layer
->CreateOrGetCanvasRenderer();
1110 if (!InitializeCanvasRenderer(aBuilder
, canvasRenderer
)) {
1115 return layer
.forget();
1121 bool HTMLCanvasElement::UpdateWebRenderCanvasData(
1122 nsDisplayListBuilder
* aBuilder
, WebRenderCanvasData
* aCanvasData
) {
1123 if (mCurrentContext
) {
1124 return mCurrentContext
->UpdateWebRenderCanvasData(aBuilder
, aCanvasData
);
1126 if (mOffscreenCanvas
) {
1127 CanvasRenderer
* renderer
= aCanvasData
->GetCanvasRenderer();
1129 if (!mResetLayer
&& renderer
) {
1133 renderer
= aCanvasData
->CreateCanvasRenderer();
1134 if (!InitializeCanvasRenderer(aBuilder
, renderer
)) {
1135 // Clear CanvasRenderer of WebRenderCanvasData
1136 aCanvasData
->ClearCanvasRenderer();
1140 MOZ_ASSERT(renderer
);
1141 mResetLayer
= false;
1145 // Clear CanvasRenderer of WebRenderCanvasData
1146 aCanvasData
->ClearCanvasRenderer();
1150 bool HTMLCanvasElement::InitializeCanvasRenderer(nsDisplayListBuilder
* aBuilder
,
1151 CanvasRenderer
* aRenderer
) {
1152 if (mCurrentContext
) {
1153 return mCurrentContext
->InitializeCanvasRenderer(aBuilder
, aRenderer
);
1156 if (mOffscreenCanvas
) {
1157 CanvasInitializeData data
;
1158 data
.mRenderer
= GetAsyncCanvasRenderer();
1159 data
.mSize
= GetWidthHeight();
1160 aRenderer
->Initialize(data
);
1167 bool HTMLCanvasElement::ShouldForceInactiveLayer(LayerManager
* aManager
) {
1168 if (mCurrentContext
) {
1169 return mCurrentContext
->ShouldForceInactiveLayer(aManager
);
1172 if (mOffscreenCanvas
) {
1173 // TODO: We should handle offscreen canvas case.
1180 void HTMLCanvasElement::MarkContextClean() {
1181 if (!mCurrentContext
) return;
1183 mCurrentContext
->MarkContextClean();
1186 void HTMLCanvasElement::MarkContextCleanForFrameCapture() {
1187 if (!mCurrentContext
) return;
1189 mCurrentContext
->MarkContextCleanForFrameCapture();
1192 bool HTMLCanvasElement::IsContextCleanForFrameCapture() {
1193 return mCurrentContext
&& mCurrentContext
->IsContextCleanForFrameCapture();
1196 nsresult
HTMLCanvasElement::RegisterFrameCaptureListener(
1197 FrameCaptureListener
* aListener
, bool aReturnPlaceholderData
) {
1198 WeakPtr
<FrameCaptureListener
> listener
= aListener
;
1200 if (mRequestedFrameListeners
.Contains(listener
)) {
1204 if (!mRequestedFrameRefreshObserver
) {
1205 Document
* doc
= OwnerDoc();
1207 return NS_ERROR_FAILURE
;
1210 while (doc
->GetParentDocument()) {
1211 doc
= doc
->GetParentDocument();
1214 nsPresContext
* context
= doc
->GetPresContext();
1216 return NS_ERROR_FAILURE
;
1219 context
= context
->GetRootPresContext();
1221 return NS_ERROR_FAILURE
;
1224 nsRefreshDriver
* driver
= context
->RefreshDriver();
1226 return NS_ERROR_FAILURE
;
1229 mRequestedFrameRefreshObserver
=
1230 new RequestedFrameRefreshObserver(this, driver
, aReturnPlaceholderData
);
1232 mRequestedFrameRefreshObserver
->SetReturnPlaceholderData(
1233 aReturnPlaceholderData
);
1236 mRequestedFrameListeners
.AppendElement(listener
);
1237 mRequestedFrameRefreshObserver
->Register();
1241 bool HTMLCanvasElement::IsFrameCaptureRequested() const {
1242 for (WeakPtr
<FrameCaptureListener
> listener
: mRequestedFrameListeners
) {
1247 if (listener
->FrameCaptureRequested()) {
1254 void HTMLCanvasElement::ProcessDestroyedFrameListeners() {
1255 // Loop backwards to allow removing elements in the loop.
1256 for (int i
= mRequestedFrameListeners
.Length() - 1; i
>= 0; --i
) {
1257 WeakPtr
<FrameCaptureListener
> listener
= mRequestedFrameListeners
[i
];
1259 // listener was destroyed. Remove it from the list.
1260 mRequestedFrameListeners
.RemoveElementAt(i
);
1265 if (mRequestedFrameListeners
.IsEmpty()) {
1266 mRequestedFrameRefreshObserver
->Unregister();
1270 void HTMLCanvasElement::SetFrameCapture(
1271 already_AddRefed
<SourceSurface
> aSurface
, const TimeStamp
& aTime
) {
1272 RefPtr
<SourceSurface
> surface
= aSurface
;
1273 RefPtr
<SourceSurfaceImage
> image
=
1274 new SourceSurfaceImage(surface
->GetSize(), surface
);
1276 for (WeakPtr
<FrameCaptureListener
> listener
: mRequestedFrameListeners
) {
1281 RefPtr
<Image
> imageRefCopy
= image
.get();
1282 listener
->NewFrame(imageRefCopy
.forget(), aTime
);
1286 already_AddRefed
<SourceSurface
> HTMLCanvasElement::GetSurfaceSnapshot(
1287 gfxAlphaType
* const aOutAlphaType
) {
1288 if (!mCurrentContext
) return nullptr;
1290 return mCurrentContext
->GetSurfaceSnapshot(aOutAlphaType
);
1293 AsyncCanvasRenderer
* HTMLCanvasElement::GetAsyncCanvasRenderer() {
1294 if (!mAsyncCanvasRenderer
) {
1295 mAsyncCanvasRenderer
= new AsyncCanvasRenderer();
1296 mAsyncCanvasRenderer
->mHTMLCanvasElement
= this;
1299 return mAsyncCanvasRenderer
;
1302 layers::LayersBackend
HTMLCanvasElement::GetCompositorBackendType() const {
1303 nsIWidget
* docWidget
= nsContentUtils::WidgetForDocument(OwnerDoc());
1305 layers::LayerManager
* layerManager
= docWidget
->GetLayerManager();
1307 return layerManager
->GetCompositorBackendType();
1311 return LayersBackend::LAYERS_NONE
;
1314 void HTMLCanvasElement::OnVisibilityChange() {
1315 if (OwnerDoc()->Hidden()) {
1319 if (mOffscreenCanvas
) {
1320 class Runnable final
: public CancelableRunnable
{
1322 explicit Runnable(AsyncCanvasRenderer
* aRenderer
)
1323 : mozilla::CancelableRunnable("Runnable"), mRenderer(aRenderer
) {}
1325 NS_IMETHOD
Run() override
{
1326 if (mRenderer
&& mRenderer
->mContext
) {
1327 mRenderer
->mContext
->OnVisibilityChange();
1334 RefPtr
<AsyncCanvasRenderer
> mRenderer
;
1337 RefPtr
<nsIRunnable
> runnable
= new Runnable(mAsyncCanvasRenderer
);
1338 nsCOMPtr
<nsIEventTarget
> activeTarget
=
1339 mAsyncCanvasRenderer
->GetActiveEventTarget();
1341 activeTarget
->Dispatch(runnable
, nsIThread::DISPATCH_NORMAL
);
1346 if (mCurrentContext
) {
1347 mCurrentContext
->OnVisibilityChange();
1351 void HTMLCanvasElement::OnMemoryPressure() {
1352 if (mOffscreenCanvas
) {
1353 class Runnable final
: public CancelableRunnable
{
1355 explicit Runnable(AsyncCanvasRenderer
* aRenderer
)
1356 : mozilla::CancelableRunnable("Runnable"), mRenderer(aRenderer
) {}
1358 NS_IMETHOD
Run() override
{
1359 if (mRenderer
&& mRenderer
->mContext
) {
1360 mRenderer
->mContext
->OnMemoryPressure();
1367 RefPtr
<AsyncCanvasRenderer
> mRenderer
;
1370 RefPtr
<nsIRunnable
> runnable
= new Runnable(mAsyncCanvasRenderer
);
1371 nsCOMPtr
<nsIEventTarget
> activeTarget
=
1372 mAsyncCanvasRenderer
->GetActiveEventTarget();
1374 activeTarget
->Dispatch(runnable
, nsIThread::DISPATCH_NORMAL
);
1379 if (mCurrentContext
) {
1380 mCurrentContext
->OnMemoryPressure();
1385 void HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(
1386 AsyncCanvasRenderer
* aRenderer
) {
1387 HTMLCanvasElement
* element
= aRenderer
->mHTMLCanvasElement
;
1392 if (element
->GetWidthHeight() == aRenderer
->GetSize()) {
1396 gfx::IntSize asyncCanvasSize
= aRenderer
->GetSize();
1399 element
->SetUnsignedIntAttr(nsGkAtoms::width
, asyncCanvasSize
.width
,
1400 DEFAULT_CANVAS_WIDTH
, rv
);
1403 "Failed to set width attribute to a canvas element asynchronously.");
1406 element
->SetUnsignedIntAttr(nsGkAtoms::height
, asyncCanvasSize
.height
,
1407 DEFAULT_CANVAS_HEIGHT
, rv
);
1410 "Failed to set height attribute to a canvas element asynchronously.");
1413 element
->mResetLayer
= true;
1417 void HTMLCanvasElement::InvalidateFromAsyncCanvasRenderer(
1418 AsyncCanvasRenderer
* aRenderer
) {
1419 HTMLCanvasElement
* element
= aRenderer
->mHTMLCanvasElement
;
1424 element
->InvalidateCanvasContent(nullptr);
1427 already_AddRefed
<layers::SharedSurfaceTextureClient
>
1428 HTMLCanvasElement::GetVRFrame() {
1429 if (GetCurrentContextType() != CanvasContextType::WebGL1
&&
1430 GetCurrentContextType() != CanvasContextType::WebGL2
) {
1434 WebGLContext
* webgl
= static_cast<WebGLContext
*>(GetContextAtIndex(0));
1439 return webgl
->GetVRFrame();
1443 } // namespace mozilla