12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* 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/. */
- #include "mozilla/dom/HTMLCanvasElement.h"
- #include "ImageEncoder.h"
- #include "jsapi.h"
- #include "jsfriendapi.h"
- #include "Layers.h"
- #include "MediaSegment.h"
- #include "mozilla/Assertions.h"
- #include "mozilla/Base64.h"
- #include "mozilla/CheckedInt.h"
- #include "mozilla/dom/CanvasCaptureMediaStream.h"
- #include "mozilla/dom/CanvasRenderingContext2D.h"
- #include "mozilla/dom/File.h"
- #include "mozilla/dom/HTMLCanvasElementBinding.h"
- #include "mozilla/dom/MediaStreamTrack.h"
- #include "mozilla/dom/MouseEvent.h"
- #include "mozilla/dom/OffscreenCanvas.h"
- #include "mozilla/EventDispatcher.h"
- #include "mozilla/gfx/Rect.h"
- #include "mozilla/layers/AsyncCanvasRenderer.h"
- #include "mozilla/MouseEvents.h"
- #include "mozilla/Preferences.h"
- #include "mozilla/Telemetry.h"
- #include "nsAttrValueInlines.h"
- #include "nsContentUtils.h"
- #include "nsDisplayList.h"
- #include "nsDOMJSUtils.h"
- #include "nsIScriptSecurityManager.h"
- #include "nsITimer.h"
- #include "nsIWritablePropertyBag2.h"
- #include "nsIXPConnect.h"
- #include "nsJSUtils.h"
- #include "nsLayoutUtils.h"
- #include "nsMathUtils.h"
- #include "nsNetUtil.h"
- #include "nsRefreshDriver.h"
- #include "nsStreamUtils.h"
- #include "ActiveLayerTracker.h"
- #include "WebGL1Context.h"
- #include "WebGL2Context.h"
- using namespace mozilla::layers;
- using namespace mozilla::gfx;
- NS_IMPL_NS_NEW_HTML_ELEMENT(Canvas)
- namespace mozilla {
- namespace dom {
- class RequestedFrameRefreshObserver : public nsARefreshObserver
- {
- NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RequestedFrameRefreshObserver, override)
- public:
- RequestedFrameRefreshObserver(HTMLCanvasElement* const aOwningElement,
- nsRefreshDriver* aRefreshDriver)
- : mRegistered(false),
- mOwningElement(aOwningElement),
- mRefreshDriver(aRefreshDriver)
- {
- MOZ_ASSERT(mOwningElement);
- }
- static already_AddRefed<DataSourceSurface>
- CopySurface(const RefPtr<SourceSurface>& aSurface)
- {
- RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
- if (!data) {
- return nullptr;
- }
- DataSourceSurface::ScopedMap read(data, DataSourceSurface::READ);
- if (!read.IsMapped()) {
- return nullptr;
- }
- RefPtr<DataSourceSurface> copy =
- Factory::CreateDataSourceSurfaceWithStride(data->GetSize(),
- data->GetFormat(),
- read.GetStride());
- if (!copy) {
- return nullptr;
- }
- DataSourceSurface::ScopedMap write(copy, DataSourceSurface::WRITE);
- if (!write.IsMapped()) {
- return nullptr;
- }
- MOZ_ASSERT(read.GetStride() == write.GetStride());
- MOZ_ASSERT(data->GetSize() == copy->GetSize());
- MOZ_ASSERT(data->GetFormat() == copy->GetFormat());
- memcpy(write.GetData(), read.GetData(),
- write.GetStride() * copy->GetSize().height);
- return copy.forget();
- }
- void WillRefresh(TimeStamp aTime) override
- {
- MOZ_ASSERT(NS_IsMainThread());
- if (!mOwningElement) {
- return;
- }
- if (mOwningElement->IsWriteOnly()) {
- return;
- }
- if (mOwningElement->IsContextCleanForFrameCapture()) {
- return;
- }
- mOwningElement->ProcessDestroyedFrameListeners();
- if (!mOwningElement->IsFrameCaptureRequested()) {
- return;
- }
- RefPtr<SourceSurface> snapshot = mOwningElement->GetSurfaceSnapshot(nullptr);
- if (!snapshot) {
- return;
- }
- RefPtr<DataSourceSurface> copy = CopySurface(snapshot);
- if (!copy) {
- return;
- }
- mOwningElement->SetFrameCapture(copy.forget());
- mOwningElement->MarkContextCleanForFrameCapture();
- }
- void DetachFromRefreshDriver()
- {
- MOZ_ASSERT(mOwningElement);
- MOZ_ASSERT(mRefreshDriver);
- Unregister();
- mRefreshDriver = nullptr;
- }
- void Register()
- {
- if (mRegistered) {
- return;
- }
- MOZ_ASSERT(mRefreshDriver);
- if (mRefreshDriver) {
- mRefreshDriver->AddRefreshObserver(this, Flush_Display);
- mRegistered = true;
- }
- }
- void Unregister()
- {
- if (!mRegistered) {
- return;
- }
- MOZ_ASSERT(mRefreshDriver);
- if (mRefreshDriver) {
- mRefreshDriver->RemoveRefreshObserver(this, Flush_Display);
- mRegistered = false;
- }
- }
- private:
- virtual ~RequestedFrameRefreshObserver()
- {
- MOZ_ASSERT(!mRefreshDriver);
- MOZ_ASSERT(!mRegistered);
- }
- bool mRegistered;
- HTMLCanvasElement* const mOwningElement;
- RefPtr<nsRefreshDriver> mRefreshDriver;
- };
- // ---------------------------------------------------------------------------
- NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLCanvasPrintState, mCanvas,
- mContext, mCallback)
- NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(HTMLCanvasPrintState, AddRef)
- NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(HTMLCanvasPrintState, Release)
- HTMLCanvasPrintState::HTMLCanvasPrintState(HTMLCanvasElement* aCanvas,
- nsICanvasRenderingContextInternal* aContext,
- nsITimerCallback* aCallback)
- : mIsDone(false), mPendingNotify(false), mCanvas(aCanvas),
- mContext(aContext), mCallback(aCallback)
- {
- }
- HTMLCanvasPrintState::~HTMLCanvasPrintState()
- {
- }
- /* virtual */ JSObject*
- HTMLCanvasPrintState::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
- {
- return MozCanvasPrintStateBinding::Wrap(aCx, this, aGivenProto);
- }
- nsISupports*
- HTMLCanvasPrintState::Context() const
- {
- return mContext;
- }
- void
- HTMLCanvasPrintState::Done()
- {
- if (!mPendingNotify && !mIsDone) {
- // The canvas needs to be invalidated for printing reftests on linux to
- // work.
- if (mCanvas) {
- mCanvas->InvalidateCanvas();
- }
- RefPtr<nsRunnableMethod<HTMLCanvasPrintState> > doneEvent =
- NewRunnableMethod(this, &HTMLCanvasPrintState::NotifyDone);
- if (NS_SUCCEEDED(NS_DispatchToCurrentThread(doneEvent))) {
- mPendingNotify = true;
- }
- }
- }
- void
- HTMLCanvasPrintState::NotifyDone()
- {
- mIsDone = true;
- mPendingNotify = false;
- if (mCallback) {
- mCallback->Notify(nullptr);
- }
- }
- // ---------------------------------------------------------------------------
- HTMLCanvasElementObserver::HTMLCanvasElementObserver(HTMLCanvasElement* aElement)
- : mElement(aElement)
- {
- RegisterVisibilityChangeEvent();
- RegisterMemoryPressureEvent();
- }
- HTMLCanvasElementObserver::~HTMLCanvasElementObserver()
- {
- Destroy();
- }
- void
- HTMLCanvasElementObserver::Destroy()
- {
- UnregisterMemoryPressureEvent();
- UnregisterVisibilityChangeEvent();
- mElement = nullptr;
- }
- void
- HTMLCanvasElementObserver::RegisterVisibilityChangeEvent()
- {
- if (!mElement) {
- return;
- }
- nsIDocument* document = mElement->OwnerDoc();
- document->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
- this, true, false);
- }
- void
- HTMLCanvasElementObserver::UnregisterVisibilityChangeEvent()
- {
- if (!mElement) {
- return;
- }
- nsIDocument* document = mElement->OwnerDoc();
- document->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
- this, true);
- }
- void
- HTMLCanvasElementObserver::RegisterMemoryPressureEvent()
- {
- if (!mElement) {
- return;
- }
- nsCOMPtr<nsIObserverService> observerService =
- mozilla::services::GetObserverService();
- MOZ_ASSERT(observerService);
- if (observerService)
- observerService->AddObserver(this, "memory-pressure", false);
- }
- void
- HTMLCanvasElementObserver::UnregisterMemoryPressureEvent()
- {
- if (!mElement) {
- return;
- }
- nsCOMPtr<nsIObserverService> observerService =
- mozilla::services::GetObserverService();
- // Do not assert on observerService here. This might be triggered by
- // the cycle collector at a late enough time, that XPCOM services are
- // no longer available. See bug 1029504.
- if (observerService)
- observerService->RemoveObserver(this, "memory-pressure");
- }
- NS_IMETHODIMP
- HTMLCanvasElementObserver::Observe(nsISupports*, const char* aTopic, const char16_t*)
- {
- if (!mElement || strcmp(aTopic, "memory-pressure")) {
- return NS_OK;
- }
- mElement->OnMemoryPressure();
- return NS_OK;
- }
- NS_IMETHODIMP
- HTMLCanvasElementObserver::HandleEvent(nsIDOMEvent* aEvent)
- {
- nsAutoString type;
- aEvent->GetType(type);
- if (!mElement || !type.EqualsLiteral("visibilitychange")) {
- return NS_OK;
- }
- mElement->OnVisibilityChange();
- return NS_OK;
- }
- NS_IMPL_ISUPPORTS(HTMLCanvasElementObserver, nsIObserver)
- // ---------------------------------------------------------------------------
- HTMLCanvasElement::HTMLCanvasElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
- : nsGenericHTMLElement(aNodeInfo),
- mResetLayer(true) ,
- mWriteOnly(false)
- {}
- HTMLCanvasElement::~HTMLCanvasElement()
- {
- if (mContextObserver) {
- mContextObserver->Destroy();
- mContextObserver = nullptr;
- }
- ResetPrintCallback();
- if (mRequestedFrameRefreshObserver) {
- mRequestedFrameRefreshObserver->DetachFromRefreshDriver();
- }
- if (mAsyncCanvasRenderer) {
- mAsyncCanvasRenderer->mHTMLCanvasElement = nullptr;
- }
- }
- NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement, nsGenericHTMLElement,
- mCurrentContext, mPrintCallback,
- mPrintState, mOriginalCanvas,
- mOffscreenCanvas)
- NS_IMPL_ADDREF_INHERITED(HTMLCanvasElement, Element)
- NS_IMPL_RELEASE_INHERITED(HTMLCanvasElement, Element)
- NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement)
- NS_INTERFACE_TABLE_INHERITED(HTMLCanvasElement, nsIDOMHTMLCanvasElement)
- NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
- NS_IMPL_ELEMENT_CLONE(HTMLCanvasElement)
- /* virtual */ JSObject*
- HTMLCanvasElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
- {
- return HTMLCanvasElementBinding::Wrap(aCx, this, aGivenProto);
- }
- already_AddRefed<nsICanvasRenderingContextInternal>
- HTMLCanvasElement::CreateContext(CanvasContextType aContextType)
- {
- // Note that the compositor backend will be LAYERS_NONE if there is no widget.
- RefPtr<nsICanvasRenderingContextInternal> ret =
- CreateContextHelper(aContextType, GetCompositorBackendType());
- // Add Observer for webgl canvas.
- if (aContextType == CanvasContextType::WebGL1 ||
- aContextType == CanvasContextType::WebGL2) {
- if (!mContextObserver) {
- mContextObserver = new HTMLCanvasElementObserver(this);
- }
- }
- ret->SetCanvasElement(this);
- return ret.forget();
- }
- nsIntSize
- HTMLCanvasElement::GetWidthHeight()
- {
- nsIntSize size(DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT);
- const nsAttrValue* value;
- if ((value = GetParsedAttr(nsGkAtoms::width)) &&
- value->Type() == nsAttrValue::eInteger)
- {
- size.width = value->GetIntegerValue();
- }
- if ((value = GetParsedAttr(nsGkAtoms::height)) &&
- value->Type() == nsAttrValue::eInteger)
- {
- size.height = value->GetIntegerValue();
- }
- MOZ_ASSERT(size.width >= 0 && size.height >= 0,
- "we should've required <canvas> width/height attrs to be "
- "unsigned (non-negative) values");
- return size;
- }
- NS_IMPL_UINT_ATTR_DEFAULT_VALUE(HTMLCanvasElement, Width, width, DEFAULT_CANVAS_WIDTH)
- NS_IMPL_UINT_ATTR_DEFAULT_VALUE(HTMLCanvasElement, Height, height, DEFAULT_CANVAS_HEIGHT)
- NS_IMPL_BOOL_ATTR(HTMLCanvasElement, MozOpaque, moz_opaque)
- nsresult
- HTMLCanvasElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValue* aValue,
- const nsAttrValue* aOldValue, bool aNotify)
- {
- AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
- return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
- aOldValue, aNotify);
- }
- nsresult
- HTMLCanvasElement::OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
- const nsAttrValueOrString& aValue,
- bool aNotify)
- {
- AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
- return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
- aValue, aNotify);
- }
- void
- HTMLCanvasElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
- bool aNotify)
- {
- if (mCurrentContext && aNamespaceID == kNameSpaceID_None &&
- (aName == nsGkAtoms::width || aName == nsGkAtoms::height ||
- aName == nsGkAtoms::moz_opaque)) {
- ErrorResult dummy;
- UpdateContext(nullptr, JS::NullHandleValue, dummy);
- }
- }
- void
- HTMLCanvasElement::HandlePrintCallback(nsPresContext::nsPresContextType aType)
- {
- // Only call the print callback here if 1) we're in a print testing mode or
- // print preview mode, 2) the canvas has a print callback and 3) the callback
- // hasn't already been called. For real printing the callback is handled in
- // nsSimplePageSequenceFrame::PrePrintNextPage.
- if ((aType == nsPresContext::eContext_PageLayout ||
- aType == nsPresContext::eContext_PrintPreview) &&
- !mPrintState && GetMozPrintCallback()) {
- DispatchPrintCallback(nullptr);
- }
- }
- nsresult
- HTMLCanvasElement::DispatchPrintCallback(nsITimerCallback* aCallback)
- {
- // For print reftests the context may not be initialized yet, so get a context
- // so mCurrentContext is set.
- if (!mCurrentContext) {
- nsresult rv;
- nsCOMPtr<nsISupports> context;
- rv = GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(context));
- NS_ENSURE_SUCCESS(rv, rv);
- }
- mPrintState = new HTMLCanvasPrintState(this, mCurrentContext, aCallback);
- RefPtr<nsRunnableMethod<HTMLCanvasElement> > renderEvent =
- NewRunnableMethod(this, &HTMLCanvasElement::CallPrintCallback);
- return NS_DispatchToCurrentThread(renderEvent);
- }
- void
- HTMLCanvasElement::CallPrintCallback()
- {
- ErrorResult rv;
- GetMozPrintCallback()->Call(*mPrintState, rv);
- }
- void
- HTMLCanvasElement::ResetPrintCallback()
- {
- if (mPrintState) {
- mPrintState = nullptr;
- }
- }
- bool
- HTMLCanvasElement::IsPrintCallbackDone()
- {
- if (mPrintState == nullptr) {
- return true;
- }
- return mPrintState->mIsDone;
- }
- HTMLCanvasElement*
- HTMLCanvasElement::GetOriginalCanvas()
- {
- return mOriginalCanvas ? mOriginalCanvas.get() : this;
- }
- nsresult
- HTMLCanvasElement::CopyInnerTo(Element* aDest)
- {
- nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
- NS_ENSURE_SUCCESS(rv, rv);
- if (aDest->OwnerDoc()->IsStaticDocument()) {
- HTMLCanvasElement* dest = static_cast<HTMLCanvasElement*>(aDest);
- dest->mOriginalCanvas = this;
- // We make sure that the canvas is not zero sized since that would cause
- // the DrawImage call below to return an error, which would cause printing
- // to fail.
- nsIntSize size = GetWidthHeight();
- if (size.height > 0 && size.width > 0) {
- nsCOMPtr<nsISupports> cxt;
- dest->GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(cxt));
- RefPtr<CanvasRenderingContext2D> context2d =
- static_cast<CanvasRenderingContext2D*>(cxt.get());
- if (context2d && !mPrintCallback) {
- CanvasImageSource source;
- source.SetAsHTMLCanvasElement() = this;
- ErrorResult err;
- context2d->DrawImage(source,
- 0.0, 0.0, err);
- rv = err.StealNSResult();
- }
- }
- }
- return rv;
- }
- nsresult HTMLCanvasElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
- {
- if (aVisitor.mEvent->mClass == eMouseEventClass) {
- WidgetMouseEventBase* evt = (WidgetMouseEventBase*)aVisitor.mEvent;
- if (mCurrentContext) {
- nsIFrame *frame = GetPrimaryFrame();
- if (!frame)
- return NS_OK;
- nsPoint ptInRoot = nsLayoutUtils::GetEventCoordinatesRelativeTo(evt, frame);
- nsRect paddingRect = frame->GetContentRectRelativeToSelf();
- Point hitpoint;
- hitpoint.x = (ptInRoot.x - paddingRect.x) / AppUnitsPerCSSPixel();
- hitpoint.y = (ptInRoot.y - paddingRect.y) / AppUnitsPerCSSPixel();
- evt->region = mCurrentContext->GetHitRegion(hitpoint);
- aVisitor.mCanHandle = true;
- }
- }
- return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
- }
- nsChangeHint
- HTMLCanvasElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
- int32_t aModType) const
- {
- nsChangeHint retval =
- nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
- if (aAttribute == nsGkAtoms::width ||
- aAttribute == nsGkAtoms::height)
- {
- retval |= NS_STYLE_HINT_REFLOW;
- } else if (aAttribute == nsGkAtoms::moz_opaque)
- {
- retval |= NS_STYLE_HINT_VISUAL;
- }
- return retval;
- }
- bool
- HTMLCanvasElement::ParseAttribute(int32_t aNamespaceID,
- nsIAtom* aAttribute,
- const nsAString& aValue,
- nsAttrValue& aResult)
- {
- if (aNamespaceID == kNameSpaceID_None &&
- (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height)) {
- return aResult.ParseNonNegativeIntValue(aValue);
- }
- return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
- aResult);
- }
- // HTMLCanvasElement::toDataURL
- NS_IMETHODIMP
- HTMLCanvasElement::ToDataURL(const nsAString& aType, JS::Handle<JS::Value> aParams,
- JSContext* aCx, nsAString& aDataURL)
- {
- // do a trust check if this is a write-only canvas
- if (mWriteOnly && !nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- return ToDataURLImpl(aCx, aType, aParams, aDataURL);
- }
- void
- HTMLCanvasElement::SetMozPrintCallback(PrintCallback* aCallback)
- {
- mPrintCallback = aCallback;
- }
- PrintCallback*
- HTMLCanvasElement::GetMozPrintCallback() const
- {
- if (mOriginalCanvas) {
- return mOriginalCanvas->GetMozPrintCallback();
- }
- return mPrintCallback;
- }
- class CanvasCaptureTrackSource : public MediaStreamTrackSource
- {
- public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CanvasCaptureTrackSource,
- MediaStreamTrackSource)
- CanvasCaptureTrackSource(nsIPrincipal* aPrincipal,
- CanvasCaptureMediaStream* aCaptureStream)
- : MediaStreamTrackSource(aPrincipal, nsString())
- , mCaptureStream(aCaptureStream) {}
- MediaSourceEnum GetMediaSource() const override
- {
- return MediaSourceEnum::Other;
- }
- void Stop() override
- {
- if (!mCaptureStream) {
- NS_ERROR("No stream");
- return;
- }
- mCaptureStream->StopCapture();
- }
- private:
- virtual ~CanvasCaptureTrackSource() {}
- RefPtr<CanvasCaptureMediaStream> mCaptureStream;
- };
- NS_IMPL_ADDREF_INHERITED(CanvasCaptureTrackSource,
- MediaStreamTrackSource)
- NS_IMPL_RELEASE_INHERITED(CanvasCaptureTrackSource,
- MediaStreamTrackSource)
- NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(CanvasCaptureTrackSource)
- NS_INTERFACE_MAP_END_INHERITING(MediaStreamTrackSource)
- NS_IMPL_CYCLE_COLLECTION_INHERITED(CanvasCaptureTrackSource,
- MediaStreamTrackSource,
- mCaptureStream)
- already_AddRefed<CanvasCaptureMediaStream>
- HTMLCanvasElement::CaptureStream(const Optional<double>& aFrameRate,
- ErrorResult& aRv)
- {
- if (IsWriteOnly()) {
- aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
- return nullptr;
- }
- nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
- if (!window) {
- aRv.Throw(NS_ERROR_FAILURE);
- return nullptr;
- }
- if (!mCurrentContext) {
- aRv.Throw(NS_ERROR_NOT_INITIALIZED);
- return nullptr;
- }
- RefPtr<CanvasCaptureMediaStream> stream =
- CanvasCaptureMediaStream::CreateSourceStream(window, this);
- if (!stream) {
- aRv.Throw(NS_ERROR_FAILURE);
- return nullptr;
- }
- TrackID videoTrackId = 1;
- nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
- nsresult rv =
- stream->Init(aFrameRate, videoTrackId, principal);
- if (NS_FAILED(rv)) {
- aRv.Throw(rv);
- return nullptr;
- }
- RefPtr<MediaStreamTrack> track =
- stream->CreateDOMTrack(videoTrackId, MediaSegment::VIDEO,
- new CanvasCaptureTrackSource(principal, stream));
- stream->AddTrackInternal(track);
- rv = RegisterFrameCaptureListener(stream->FrameCaptureListener());
- if (NS_FAILED(rv)) {
- aRv.Throw(rv);
- return nullptr;
- }
- return stream.forget();
- }
- nsresult
- HTMLCanvasElement::ExtractData(nsAString& aType,
- const nsAString& aOptions,
- nsIInputStream** aStream)
- {
- return ImageEncoder::ExtractData(aType,
- aOptions,
- GetSize(),
- mCurrentContext,
- mAsyncCanvasRenderer,
- aStream);
- }
- nsresult
- HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
- const nsAString& aMimeType,
- const JS::Value& aEncoderOptions,
- nsAString& aDataURL)
- {
- nsIntSize size = GetWidthHeight();
- if (size.height == 0 || size.width == 0) {
- aDataURL = NS_LITERAL_STRING("data:,");
- return NS_OK;
- }
- nsAutoString type;
- nsContentUtils::ASCIIToLower(aMimeType, type);
- nsAutoString params;
- bool usingCustomParseOptions;
- nsresult rv =
- ParseParams(aCx, type, aEncoderOptions, params, &usingCustomParseOptions);
- if (NS_FAILED(rv)) {
- return rv;
- }
- nsCOMPtr<nsIInputStream> stream;
- rv = ExtractData(type, params, getter_AddRefs(stream));
- // If there are unrecognized custom parse options, we should fall back to
- // the default values for the encoder without any options at all.
- if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
- rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
- }
- NS_ENSURE_SUCCESS(rv, rv);
- // build data URL string
- aDataURL = NS_LITERAL_STRING("data:") + type + NS_LITERAL_STRING(";base64,");
- uint64_t count;
- rv = stream->Available(&count);
- NS_ENSURE_SUCCESS(rv, rv);
- NS_ENSURE_TRUE(count <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
- return Base64EncodeInputStream(stream, aDataURL, (uint32_t)count, aDataURL.Length());
- }
- void
- HTMLCanvasElement::ToBlob(JSContext* aCx,
- BlobCallback& aCallback,
- const nsAString& aType,
- JS::Handle<JS::Value> aParams,
- ErrorResult& aRv)
- {
- // do a trust check if this is a write-only canvas
- if (mWriteOnly && !nsContentUtils::IsCallerChrome()) {
- aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
- return;
- }
- nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
- MOZ_ASSERT(global);
- CanvasRenderingContextHelper::ToBlob(aCx, global, aCallback, aType,
- aParams, aRv);
- }
- OffscreenCanvas*
- HTMLCanvasElement::TransferControlToOffscreen(ErrorResult& aRv)
- {
- if (mCurrentContext) {
- aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
- return nullptr;
- }
- if (!mOffscreenCanvas) {
- nsIntSize sz = GetWidthHeight();
- RefPtr<AsyncCanvasRenderer> renderer = GetAsyncCanvasRenderer();
- renderer->SetWidth(sz.width);
- renderer->SetHeight(sz.height);
- nsCOMPtr<nsIGlobalObject> global =
- do_QueryInterface(OwnerDoc()->GetInnerWindow());
- mOffscreenCanvas = new OffscreenCanvas(global,
- sz.width,
- sz.height,
- GetCompositorBackendType(),
- renderer);
- if (mWriteOnly) {
- mOffscreenCanvas->SetWriteOnly();
- }
- if (!mContextObserver) {
- mContextObserver = new HTMLCanvasElementObserver(this);
- }
- } else {
- aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
- }
- return mOffscreenCanvas;
- }
- already_AddRefed<File>
- HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
- const nsAString& aType,
- ErrorResult& aRv)
- {
- nsCOMPtr<nsISupports> file;
- aRv = MozGetAsFile(aName, aType, getter_AddRefs(file));
- if (NS_WARN_IF(aRv.Failed())) {
- return nullptr;
- }
- nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(file);
- RefPtr<Blob> domBlob = static_cast<Blob*>(blob.get());
- MOZ_ASSERT(domBlob->IsFile());
- return domBlob->ToFile();
- }
- NS_IMETHODIMP
- HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
- const nsAString& aType,
- nsISupports** aResult)
- {
- OwnerDoc()->WarnOnceAbout(nsIDocument::eMozGetAsFile);
- // do a trust check if this is a write-only canvas
- if ((mWriteOnly) &&
- !nsContentUtils::IsCallerChrome()) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- return MozGetAsBlobImpl(aName, aType, aResult);
- }
- nsresult
- HTMLCanvasElement::MozGetAsBlobImpl(const nsAString& aName,
- const nsAString& aType,
- nsISupports** aResult)
- {
- nsCOMPtr<nsIInputStream> stream;
- nsAutoString type(aType);
- nsresult rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
- NS_ENSURE_SUCCESS(rv, rv);
- uint64_t imgSize;
- rv = stream->Available(&imgSize);
- NS_ENSURE_SUCCESS(rv, rv);
- NS_ENSURE_TRUE(imgSize <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
- void* imgData = nullptr;
- rv = NS_ReadInputStreamToBuffer(stream, &imgData, (uint32_t)imgSize);
- NS_ENSURE_SUCCESS(rv, rv);
- JSContext* cx = nsContentUtils::GetCurrentJSContext();
- if (cx) {
- JS_updateMallocCounter(cx, imgSize);
- }
- nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(OwnerDoc()->GetScopeObject());
- // The File takes ownership of the buffer
- nsCOMPtr<nsIDOMBlob> file =
- File::CreateMemoryFile(win, imgData, (uint32_t)imgSize, aName, type,
- PR_Now());
- file.forget(aResult);
- return NS_OK;
- }
- nsresult
- HTMLCanvasElement::GetContext(const nsAString& aContextId,
- nsISupports** aContext)
- {
- ErrorResult rv;
- *aContext = GetContext(nullptr, aContextId, JS::NullHandleValue, rv).take();
- return rv.StealNSResult();
- }
- already_AddRefed<nsISupports>
- HTMLCanvasElement::GetContext(JSContext* aCx,
- const nsAString& aContextId,
- JS::Handle<JS::Value> aContextOptions,
- ErrorResult& aRv)
- {
- if (mOffscreenCanvas) {
- return nullptr;
- }
- return CanvasRenderingContextHelper::GetContext(aCx, aContextId,
- aContextOptions.isObject() ? aContextOptions : JS::NullHandleValue,
- aRv);
- }
- NS_IMETHODIMP
- HTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId,
- nsISupports **aContext)
- {
- if(!nsContentUtils::IsCallerChrome()) {
- // XXX ERRMSG we need to report an error to developers here! (bug 329026)
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- // We only support 2d shmem contexts for now.
- if (!aContextId.EqualsLiteral("2d"))
- return NS_ERROR_INVALID_ARG;
- CanvasContextType contextType = CanvasContextType::Canvas2D;
- if (!mCurrentContext) {
- // This canvas doesn't have a context yet.
- RefPtr<nsICanvasRenderingContextInternal> context;
- context = CreateContext(contextType);
- if (!context) {
- *aContext = nullptr;
- return NS_OK;
- }
- mCurrentContext = context;
- mCurrentContext->SetIsIPC(true);
- mCurrentContextType = contextType;
- ErrorResult dummy;
- nsresult rv = UpdateContext(nullptr, JS::NullHandleValue, dummy);
- NS_ENSURE_SUCCESS(rv, rv);
- } else {
- // We already have a context of some type.
- if (contextType != mCurrentContextType)
- return NS_ERROR_INVALID_ARG;
- }
- NS_ADDREF (*aContext = mCurrentContext);
- return NS_OK;
- }
- nsIntSize
- HTMLCanvasElement::GetSize()
- {
- return GetWidthHeight();
- }
- bool
- HTMLCanvasElement::IsWriteOnly() const
- {
- return mWriteOnly;
- }
- void
- HTMLCanvasElement::SetWriteOnly()
- {
- mWriteOnly = true;
- }
- void
- HTMLCanvasElement::InvalidateCanvasContent(const gfx::Rect* damageRect)
- {
- // We don't need to flush anything here; if there's no frame or if
- // we plan to reframe we don't need to invalidate it anyway.
- nsIFrame *frame = GetPrimaryFrame();
- if (!frame)
- return;
- ActiveLayerTracker::NotifyContentChange(frame);
- Layer* layer = nullptr;
- if (damageRect) {
- nsIntSize size = GetWidthHeight();
- if (size.width != 0 && size.height != 0) {
- gfx::IntRect invalRect = gfx::IntRect::Truncate(*damageRect);
- layer = frame->InvalidateLayer(nsDisplayItem::TYPE_CANVAS, &invalRect);
- }
- } else {
- layer = frame->InvalidateLayer(nsDisplayItem::TYPE_CANVAS);
- }
- if (layer) {
- static_cast<CanvasLayer*>(layer)->Updated();
- }
- /*
- * Treat canvas invalidations as animation activity for JS. Frequently
- * invalidating a canvas will feed into heuristics and cause JIT code to be
- * kept around longer, for smoother animations.
- */
- nsCOMPtr<nsIGlobalObject> global =
- do_QueryInterface(OwnerDoc()->GetInnerWindow());
- if (global) {
- if (JSObject *obj = global->GetGlobalJSObject()) {
- js::NotifyAnimationActivity(obj);
- }
- }
- }
- void
- HTMLCanvasElement::InvalidateCanvas()
- {
- // We don't need to flush anything here; if there's no frame or if
- // we plan to reframe we don't need to invalidate it anyway.
- nsIFrame *frame = GetPrimaryFrame();
- if (!frame)
- return;
- frame->InvalidateFrame();
- }
- int32_t
- HTMLCanvasElement::CountContexts()
- {
- if (mCurrentContext)
- return 1;
- return 0;
- }
- nsICanvasRenderingContextInternal *
- HTMLCanvasElement::GetContextAtIndex(int32_t index)
- {
- if (mCurrentContext && index == 0)
- return mCurrentContext;
- return nullptr;
- }
- bool
- HTMLCanvasElement::GetIsOpaque()
- {
- if (mCurrentContext) {
- return mCurrentContext->GetIsOpaque();
- }
- return GetOpaqueAttr();
- }
- bool
- HTMLCanvasElement::GetOpaqueAttr()
- {
- return HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque);
- }
- already_AddRefed<Layer>
- HTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
- Layer *aOldLayer,
- LayerManager *aManager)
- {
- // The address of sOffscreenCanvasLayerUserDataDummy is used as the user
- // data key for retained LayerManagers managed by FrameLayerBuilder.
- // We don't much care about what value in it, so just assign a dummy
- // value for it.
- static uint8_t sOffscreenCanvasLayerUserDataDummy = 0;
- if (mCurrentContext) {
- return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager);
- }
- if (mOffscreenCanvas) {
- if (!mResetLayer &&
- aOldLayer && aOldLayer->HasUserData(&sOffscreenCanvasLayerUserDataDummy)) {
- RefPtr<Layer> ret = aOldLayer;
- return ret.forget();
- }
- RefPtr<CanvasLayer> layer = aManager->CreateCanvasLayer();
- if (!layer) {
- NS_WARNING("CreateCanvasLayer failed!");
- return nullptr;
- }
- LayerUserData* userData = nullptr;
- layer->SetUserData(&sOffscreenCanvasLayerUserDataDummy, userData);
- CanvasLayer::Data data;
- data.mRenderer = GetAsyncCanvasRenderer();
- data.mSize = GetWidthHeight();
- layer->Initialize(data);
- layer->Updated();
- return layer.forget();
- }
- return nullptr;
- }
- bool
- HTMLCanvasElement::ShouldForceInactiveLayer(LayerManager* aManager)
- {
- if (mCurrentContext) {
- return mCurrentContext->ShouldForceInactiveLayer(aManager);
- }
- if (mOffscreenCanvas) {
- // TODO: We should handle offscreen canvas case.
- return false;
- }
- return true;
- }
- void
- HTMLCanvasElement::MarkContextClean()
- {
- if (!mCurrentContext)
- return;
- mCurrentContext->MarkContextClean();
- }
- void
- HTMLCanvasElement::MarkContextCleanForFrameCapture()
- {
- if (!mCurrentContext)
- return;
- mCurrentContext->MarkContextCleanForFrameCapture();
- }
- bool
- HTMLCanvasElement::IsContextCleanForFrameCapture()
- {
- return mCurrentContext && mCurrentContext->IsContextCleanForFrameCapture();
- }
- nsresult
- HTMLCanvasElement::RegisterFrameCaptureListener(FrameCaptureListener* aListener)
- {
- WeakPtr<FrameCaptureListener> listener = aListener;
- if (mRequestedFrameListeners.Contains(listener)) {
- return NS_OK;
- }
- if (!mRequestedFrameRefreshObserver) {
- nsIDocument* doc = OwnerDoc();
- if (!doc) {
- return NS_ERROR_FAILURE;
- }
- while (doc->GetParentDocument()) {
- doc = doc->GetParentDocument();
- }
- nsIPresShell* shell = doc->GetShell();
- if (!shell) {
- return NS_ERROR_FAILURE;
- }
- nsPresContext* context = shell->GetPresContext();
- if (!context) {
- return NS_ERROR_FAILURE;
- }
- context = context->GetRootPresContext();
- if (!context) {
- return NS_ERROR_FAILURE;
- }
- nsRefreshDriver* driver = context->RefreshDriver();
- if (!driver) {
- return NS_ERROR_FAILURE;
- }
- mRequestedFrameRefreshObserver =
- new RequestedFrameRefreshObserver(this, driver);
- }
- mRequestedFrameListeners.AppendElement(listener);
- mRequestedFrameRefreshObserver->Register();
- return NS_OK;
- }
- bool
- HTMLCanvasElement::IsFrameCaptureRequested() const
- {
- for (WeakPtr<FrameCaptureListener> listener : mRequestedFrameListeners) {
- if (!listener) {
- continue;
- }
- if (listener->FrameCaptureRequested()) {
- return true;
- }
- }
- return false;
- }
- void
- HTMLCanvasElement::ProcessDestroyedFrameListeners()
- {
- // Loop backwards to allow removing elements in the loop.
- for (int i = mRequestedFrameListeners.Length() - 1; i >= 0; --i) {
- WeakPtr<FrameCaptureListener> listener = mRequestedFrameListeners[i];
- if (!listener) {
- // listener was destroyed. Remove it from the list.
- mRequestedFrameListeners.RemoveElementAt(i);
- continue;
- }
- }
- if (mRequestedFrameListeners.IsEmpty()) {
- mRequestedFrameRefreshObserver->Unregister();
- }
- }
- void
- HTMLCanvasElement::SetFrameCapture(already_AddRefed<SourceSurface> aSurface)
- {
- RefPtr<SourceSurface> surface = aSurface;
- RefPtr<SourceSurfaceImage> image = new SourceSurfaceImage(surface->GetSize(), surface);
- for (WeakPtr<FrameCaptureListener> listener : mRequestedFrameListeners) {
- if (!listener) {
- continue;
- }
- RefPtr<Image> imageRefCopy = image.get();
- listener->NewFrame(imageRefCopy.forget());
- }
- }
- already_AddRefed<SourceSurface>
- HTMLCanvasElement::GetSurfaceSnapshot(bool* aPremultAlpha)
- {
- if (!mCurrentContext)
- return nullptr;
- return mCurrentContext->GetSurfaceSnapshot(aPremultAlpha);
- }
- AsyncCanvasRenderer*
- HTMLCanvasElement::GetAsyncCanvasRenderer()
- {
- if (!mAsyncCanvasRenderer) {
- mAsyncCanvasRenderer = new AsyncCanvasRenderer();
- mAsyncCanvasRenderer->mHTMLCanvasElement = this;
- }
- return mAsyncCanvasRenderer;
- }
- layers::LayersBackend
- HTMLCanvasElement::GetCompositorBackendType() const
- {
- nsIWidget* docWidget = nsContentUtils::WidgetForDocument(OwnerDoc());
- if (docWidget) {
- layers::LayerManager* layerManager = docWidget->GetLayerManager();
- if (layerManager) {
- return layerManager->GetCompositorBackendType();
- }
- }
- return LayersBackend::LAYERS_NONE;
- }
- void
- HTMLCanvasElement::OnVisibilityChange()
- {
- if (OwnerDoc()->Hidden()) {
- return;
- }
- if (mOffscreenCanvas) {
- class Runnable final : public CancelableRunnable
- {
- public:
- explicit Runnable(AsyncCanvasRenderer* aRenderer)
- : mRenderer(aRenderer)
- {}
- NS_IMETHOD Run() override
- {
- if (mRenderer && mRenderer->mContext) {
- mRenderer->mContext->OnVisibilityChange();
- }
- return NS_OK;
- }
- void Revoke()
- {
- mRenderer = nullptr;
- }
- private:
- RefPtr<AsyncCanvasRenderer> mRenderer;
- };
- RefPtr<nsIRunnable> runnable = new Runnable(mAsyncCanvasRenderer);
- nsCOMPtr<nsIThread> activeThread = mAsyncCanvasRenderer->GetActiveThread();
- if (activeThread) {
- activeThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
- }
- return;
- }
- if (mCurrentContext) {
- mCurrentContext->OnVisibilityChange();
- }
- }
- void
- HTMLCanvasElement::OnMemoryPressure()
- {
- if (mOffscreenCanvas) {
- class Runnable final : public CancelableRunnable
- {
- public:
- explicit Runnable(AsyncCanvasRenderer* aRenderer)
- : mRenderer(aRenderer)
- {}
- NS_IMETHOD Run() override
- {
- if (mRenderer && mRenderer->mContext) {
- mRenderer->mContext->OnMemoryPressure();
- }
- return NS_OK;
- }
- void Revoke()
- {
- mRenderer = nullptr;
- }
- private:
- RefPtr<AsyncCanvasRenderer> mRenderer;
- };
- RefPtr<nsIRunnable> runnable = new Runnable(mAsyncCanvasRenderer);
- nsCOMPtr<nsIThread> activeThread = mAsyncCanvasRenderer->GetActiveThread();
- if (activeThread) {
- activeThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
- }
- return;
- }
- if (mCurrentContext) {
- mCurrentContext->OnMemoryPressure();
- }
- }
- /* static */ void
- HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer)
- {
- HTMLCanvasElement *element = aRenderer->mHTMLCanvasElement;
- if (!element) {
- return;
- }
- if (element->GetWidthHeight() == aRenderer->GetSize()) {
- return;
- }
- gfx::IntSize asyncCanvasSize = aRenderer->GetSize();
- ErrorResult rv;
- element->SetUnsignedIntAttr(nsGkAtoms::width, asyncCanvasSize.width,
- DEFAULT_CANVAS_WIDTH, rv);
- if (rv.Failed()) {
- NS_WARNING("Failed to set width attribute to a canvas element asynchronously.");
- }
- element->SetUnsignedIntAttr(nsGkAtoms::height, asyncCanvasSize.height,
- DEFAULT_CANVAS_HEIGHT, rv);
- if (rv.Failed()) {
- NS_WARNING("Failed to set height attribute to a canvas element asynchronously.");
- }
- element->mResetLayer = true;
- }
- /* static */ void
- HTMLCanvasElement::InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer)
- {
- HTMLCanvasElement *element = aRenderer->mHTMLCanvasElement;
- if (!element) {
- return;
- }
- element->InvalidateCanvasContent(nullptr);
- }
- } // namespace dom
- } // namespace mozilla
|