LCOV - code coverage report
Current view: top level - dom/html - HTMLCanvasElement.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 699 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 128 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
       7             : #include "mozilla/dom/HTMLCanvasElement.h"
       8             : 
       9             : #include "ImageEncoder.h"
      10             : #include "jsapi.h"
      11             : #include "jsfriendapi.h"
      12             : #include "Layers.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/File.h"
      20             : #include "mozilla/dom/HTMLCanvasElementBinding.h"
      21             : #include "mozilla/dom/MediaStreamTrack.h"
      22             : #include "mozilla/dom/MouseEvent.h"
      23             : #include "mozilla/dom/OffscreenCanvas.h"
      24             : #include "mozilla/EventDispatcher.h"
      25             : #include "mozilla/gfx/Rect.h"
      26             : #include "mozilla/layers/AsyncCanvasRenderer.h"
      27             : #include "mozilla/MouseEvents.h"
      28             : #include "mozilla/Preferences.h"
      29             : #include "mozilla/Telemetry.h"
      30             : #include "nsAttrValueInlines.h"
      31             : #include "nsContentUtils.h"
      32             : #include "nsDisplayList.h"
      33             : #include "nsDOMJSUtils.h"
      34             : #include "nsIScriptSecurityManager.h"
      35             : #include "nsITimer.h"
      36             : #include "nsIWritablePropertyBag2.h"
      37             : #include "nsIXPConnect.h"
      38             : #include "nsJSUtils.h"
      39             : #include "nsLayoutUtils.h"
      40             : #include "nsMathUtils.h"
      41             : #include "nsNetUtil.h"
      42             : #include "nsRefreshDriver.h"
      43             : #include "nsStreamUtils.h"
      44             : #include "ActiveLayerTracker.h"
      45             : #include "VRManagerChild.h"
      46             : #include "WebGL1Context.h"
      47             : #include "WebGL2Context.h"
      48             : 
      49             : using namespace mozilla::layers;
      50             : using namespace mozilla::gfx;
      51             : 
      52           0 : NS_IMPL_NS_NEW_HTML_ELEMENT(Canvas)
      53             : 
      54             : namespace mozilla {
      55             : namespace dom {
      56             : 
      57             : class RequestedFrameRefreshObserver : public nsARefreshObserver
      58             : {
      59           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RequestedFrameRefreshObserver, override)
      60             : 
      61             : public:
      62           0 :   RequestedFrameRefreshObserver(HTMLCanvasElement* const aOwningElement,
      63             :                                 nsRefreshDriver* aRefreshDriver)
      64           0 :     : mRegistered(false),
      65             :       mOwningElement(aOwningElement),
      66           0 :       mRefreshDriver(aRefreshDriver)
      67             :   {
      68           0 :     MOZ_ASSERT(mOwningElement);
      69           0 :   }
      70             : 
      71             :   static already_AddRefed<DataSourceSurface>
      72           0 :   CopySurface(const RefPtr<SourceSurface>& aSurface)
      73             :   {
      74           0 :     RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
      75           0 :     if (!data) {
      76           0 :       return nullptr;
      77             :     }
      78             : 
      79           0 :     DataSourceSurface::ScopedMap read(data, DataSourceSurface::READ);
      80           0 :     if (!read.IsMapped()) {
      81           0 :       return nullptr;
      82             :     }
      83             : 
      84             :     RefPtr<DataSourceSurface> copy =
      85           0 :       Factory::CreateDataSourceSurfaceWithStride(data->GetSize(),
      86           0 :                                                  data->GetFormat(),
      87           0 :                                                  read.GetStride());
      88           0 :     if (!copy) {
      89           0 :       return nullptr;
      90             :     }
      91             : 
      92           0 :     DataSourceSurface::ScopedMap write(copy, DataSourceSurface::WRITE);
      93           0 :     if (!write.IsMapped()) {
      94           0 :       return nullptr;
      95             :     }
      96             : 
      97           0 :     MOZ_ASSERT(read.GetStride() == write.GetStride());
      98           0 :     MOZ_ASSERT(data->GetSize() == copy->GetSize());
      99           0 :     MOZ_ASSERT(data->GetFormat() == copy->GetFormat());
     100             : 
     101           0 :     memcpy(write.GetData(), read.GetData(),
     102           0 :            write.GetStride() * copy->GetSize().height);
     103             : 
     104           0 :     return copy.forget();
     105             :   }
     106             : 
     107           0 :   void WillRefresh(TimeStamp aTime) override
     108             :   {
     109           0 :     MOZ_ASSERT(NS_IsMainThread());
     110             : 
     111           0 :     AUTO_PROFILER_LABEL("RequestedFrameRefreshObserver::WillRefresh", OTHER);
     112             : 
     113           0 :     if (!mOwningElement) {
     114           0 :       return;
     115             :     }
     116             : 
     117           0 :     if (mOwningElement->IsWriteOnly()) {
     118           0 :       return;
     119             :     }
     120             : 
     121           0 :     if (mOwningElement->IsContextCleanForFrameCapture()) {
     122           0 :       return;
     123             :     }
     124             : 
     125           0 :     mOwningElement->ProcessDestroyedFrameListeners();
     126             : 
     127           0 :     if (!mOwningElement->IsFrameCaptureRequested()) {
     128           0 :       return;
     129             :     }
     130             : 
     131           0 :     RefPtr<SourceSurface> snapshot;
     132             :     {
     133           0 :       AUTO_PROFILER_LABEL(
     134             :         "RequestedFrameRefreshObserver::WillRefresh:GetSnapshot", OTHER);
     135           0 :       snapshot = mOwningElement->GetSurfaceSnapshot(nullptr);
     136           0 :       if (!snapshot) {
     137           0 :         return;
     138             :       }
     139             :     }
     140             : 
     141           0 :     RefPtr<DataSourceSurface> copy;
     142             :     {
     143           0 :       AUTO_PROFILER_LABEL(
     144             :         "RequestedFrameRefreshObserver::WillRefresh:CopySurface", OTHER);
     145           0 :       copy = CopySurface(snapshot);
     146           0 :       if (!copy) {
     147           0 :         return;
     148             :       }
     149             :     }
     150             : 
     151             :     {
     152           0 :       AUTO_PROFILER_LABEL(
     153             :         "RequestedFrameRefreshObserver::WillRefresh:SetFrame", OTHER);
     154           0 :       mOwningElement->SetFrameCapture(copy.forget(), aTime);
     155           0 :       mOwningElement->MarkContextCleanForFrameCapture();
     156             :     }
     157             :   }
     158             : 
     159           0 :   void DetachFromRefreshDriver()
     160             :   {
     161           0 :     MOZ_ASSERT(mOwningElement);
     162           0 :     MOZ_ASSERT(mRefreshDriver);
     163             : 
     164           0 :     Unregister();
     165           0 :     mRefreshDriver = nullptr;
     166           0 :   }
     167             : 
     168           0 :   void Register()
     169             :   {
     170           0 :     if (mRegistered) {
     171           0 :       return;
     172             :     }
     173             : 
     174           0 :     MOZ_ASSERT(mRefreshDriver);
     175           0 :     if (mRefreshDriver) {
     176           0 :       mRefreshDriver->AddRefreshObserver(this, FlushType::Display);
     177           0 :       mRegistered = true;
     178             :     }
     179             :   }
     180             : 
     181           0 :   void Unregister()
     182             :   {
     183           0 :     if (!mRegistered) {
     184           0 :       return;
     185             :     }
     186             : 
     187           0 :     MOZ_ASSERT(mRefreshDriver);
     188           0 :     if (mRefreshDriver) {
     189           0 :       mRefreshDriver->RemoveRefreshObserver(this, FlushType::Display);
     190           0 :       mRegistered = false;
     191             :     }
     192             :   }
     193             : 
     194             : private:
     195           0 :   virtual ~RequestedFrameRefreshObserver()
     196           0 :   {
     197           0 :     MOZ_ASSERT(!mRefreshDriver);
     198           0 :     MOZ_ASSERT(!mRegistered);
     199           0 :   }
     200             : 
     201             :   bool mRegistered;
     202             :   HTMLCanvasElement* const mOwningElement;
     203             :   RefPtr<nsRefreshDriver> mRefreshDriver;
     204             : };
     205             : 
     206             : // ---------------------------------------------------------------------------
     207             : 
     208           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLCanvasPrintState, mCanvas,
     209             :                                       mContext, mCallback)
     210             : 
     211           0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(HTMLCanvasPrintState, AddRef)
     212           0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(HTMLCanvasPrintState, Release)
     213             : 
     214           0 : HTMLCanvasPrintState::HTMLCanvasPrintState(HTMLCanvasElement* aCanvas,
     215             :                                            nsICanvasRenderingContextInternal* aContext,
     216           0 :                                            nsITimerCallback* aCallback)
     217             :   : mIsDone(false), mPendingNotify(false), mCanvas(aCanvas),
     218           0 :     mContext(aContext), mCallback(aCallback)
     219             : {
     220           0 : }
     221             : 
     222           0 : HTMLCanvasPrintState::~HTMLCanvasPrintState()
     223             : {
     224           0 : }
     225             : 
     226             : /* virtual */ JSObject*
     227           0 : HTMLCanvasPrintState::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     228             : {
     229           0 :   return MozCanvasPrintStateBinding::Wrap(aCx, this, aGivenProto);
     230             : }
     231             : 
     232             : nsISupports*
     233           0 : HTMLCanvasPrintState::Context() const
     234             : {
     235           0 :   return mContext;
     236             : }
     237             : 
     238             : void
     239           0 : HTMLCanvasPrintState::Done()
     240             : {
     241           0 :   if (!mPendingNotify && !mIsDone) {
     242             :     // The canvas needs to be invalidated for printing reftests on linux to
     243             :     // work.
     244           0 :     if (mCanvas) {
     245           0 :       mCanvas->InvalidateCanvas();
     246             :     }
     247             :     RefPtr<nsRunnableMethod<HTMLCanvasPrintState>> doneEvent =
     248           0 :       NewRunnableMethod("dom::HTMLCanvasPrintState::NotifyDone",
     249             :                         this,
     250           0 :                         &HTMLCanvasPrintState::NotifyDone);
     251           0 :     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(doneEvent))) {
     252           0 :       mPendingNotify = true;
     253             :     }
     254             :   }
     255           0 : }
     256             : 
     257             : void
     258           0 : HTMLCanvasPrintState::NotifyDone()
     259             : {
     260           0 :   mIsDone = true;
     261           0 :   mPendingNotify = false;
     262           0 :   if (mCallback) {
     263           0 :     mCallback->Notify(nullptr);
     264             :   }
     265           0 : }
     266             : 
     267             : // ---------------------------------------------------------------------------
     268             : 
     269           0 : HTMLCanvasElementObserver::HTMLCanvasElementObserver(HTMLCanvasElement* aElement)
     270           0 :     : mElement(aElement)
     271             : {
     272           0 :   RegisterVisibilityChangeEvent();
     273           0 :   RegisterMemoryPressureEvent();
     274           0 : }
     275             : 
     276           0 : HTMLCanvasElementObserver::~HTMLCanvasElementObserver()
     277             : {
     278           0 :   Destroy();
     279           0 : }
     280             : 
     281             : void
     282           0 : HTMLCanvasElementObserver::Destroy()
     283             : {
     284           0 :   UnregisterMemoryPressureEvent();
     285           0 :   UnregisterVisibilityChangeEvent();
     286           0 :   mElement = nullptr;
     287           0 : }
     288             : 
     289             : void
     290           0 : HTMLCanvasElementObserver::RegisterVisibilityChangeEvent()
     291             : {
     292           0 :   if (!mElement) {
     293           0 :     return;
     294             :   }
     295             : 
     296           0 :   nsIDocument* document = mElement->OwnerDoc();
     297           0 :   document->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
     298           0 :                                    this, true, false);
     299             : }
     300             : 
     301             : void
     302           0 : HTMLCanvasElementObserver::UnregisterVisibilityChangeEvent()
     303             : {
     304           0 :   if (!mElement) {
     305           0 :     return;
     306             :   }
     307             : 
     308           0 :   nsIDocument* document = mElement->OwnerDoc();
     309           0 :   document->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
     310           0 :                                       this, true);
     311             : }
     312             : 
     313             : void
     314           0 : HTMLCanvasElementObserver::RegisterMemoryPressureEvent()
     315             : {
     316           0 :   if (!mElement) {
     317           0 :     return;
     318             :   }
     319             : 
     320             :   nsCOMPtr<nsIObserverService> observerService =
     321           0 :     mozilla::services::GetObserverService();
     322             : 
     323           0 :   MOZ_ASSERT(observerService);
     324             : 
     325           0 :   if (observerService)
     326           0 :     observerService->AddObserver(this, "memory-pressure", false);
     327             : }
     328             : 
     329             : void
     330           0 : HTMLCanvasElementObserver::UnregisterMemoryPressureEvent()
     331             : {
     332           0 :   if (!mElement) {
     333           0 :     return;
     334             :   }
     335             : 
     336             :   nsCOMPtr<nsIObserverService> observerService =
     337           0 :     mozilla::services::GetObserverService();
     338             : 
     339             :   // Do not assert on observerService here. This might be triggered by
     340             :   // the cycle collector at a late enough time, that XPCOM services are
     341             :   // no longer available. See bug 1029504.
     342           0 :   if (observerService)
     343           0 :     observerService->RemoveObserver(this, "memory-pressure");
     344             : }
     345             : 
     346             : NS_IMETHODIMP
     347           0 : HTMLCanvasElementObserver::Observe(nsISupports*, const char* aTopic, const char16_t*)
     348             : {
     349           0 :   if (!mElement || strcmp(aTopic, "memory-pressure")) {
     350           0 :     return NS_OK;
     351             :   }
     352             : 
     353           0 :   mElement->OnMemoryPressure();
     354             : 
     355           0 :   return NS_OK;
     356             : }
     357             : 
     358             : NS_IMETHODIMP
     359           0 : HTMLCanvasElementObserver::HandleEvent(nsIDOMEvent* aEvent)
     360             : {
     361           0 :   nsAutoString type;
     362           0 :   aEvent->GetType(type);
     363           0 :   if (!mElement || !type.EqualsLiteral("visibilitychange")) {
     364           0 :     return NS_OK;
     365             :   }
     366             : 
     367           0 :   mElement->OnVisibilityChange();
     368             : 
     369           0 :   return NS_OK;
     370             : }
     371             : 
     372           0 : NS_IMPL_ISUPPORTS(HTMLCanvasElementObserver, nsIObserver)
     373             : 
     374             : // ---------------------------------------------------------------------------
     375             : 
     376           0 : HTMLCanvasElement::HTMLCanvasElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     377             :   : nsGenericHTMLElement(aNodeInfo),
     378             :     mResetLayer(true) ,
     379             :     mVRPresentationActive(false),
     380           0 :     mWriteOnly(false)
     381           0 : {}
     382             : 
     383           0 : HTMLCanvasElement::~HTMLCanvasElement()
     384             : {
     385           0 :   if (mContextObserver) {
     386           0 :     mContextObserver->Destroy();
     387           0 :     mContextObserver = nullptr;
     388             :   }
     389             : 
     390           0 :   ResetPrintCallback();
     391           0 :   if (mRequestedFrameRefreshObserver) {
     392           0 :     mRequestedFrameRefreshObserver->DetachFromRefreshDriver();
     393             :   }
     394             : 
     395           0 :   if (mAsyncCanvasRenderer) {
     396           0 :     mAsyncCanvasRenderer->mHTMLCanvasElement = nullptr;
     397             :   }
     398           0 : }
     399             : 
     400           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement, nsGenericHTMLElement,
     401             :                                    mCurrentContext, mPrintCallback,
     402             :                                    mPrintState, mOriginalCanvas,
     403             :                                    mOffscreenCanvas)
     404             : 
     405           0 : NS_IMPL_ADDREF_INHERITED(HTMLCanvasElement, Element)
     406           0 : NS_IMPL_RELEASE_INHERITED(HTMLCanvasElement, Element)
     407             : 
     408           0 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement)
     409           0 :   NS_INTERFACE_TABLE_INHERITED(HTMLCanvasElement, nsIDOMHTMLCanvasElement)
     410           0 : NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
     411             : 
     412           0 : NS_IMPL_ELEMENT_CLONE(HTMLCanvasElement)
     413             : 
     414             : /* virtual */ JSObject*
     415           0 : HTMLCanvasElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
     416             : {
     417           0 :   return HTMLCanvasElementBinding::Wrap(aCx, this, aGivenProto);
     418             : }
     419             : 
     420             : already_AddRefed<nsICanvasRenderingContextInternal>
     421           0 : HTMLCanvasElement::CreateContext(CanvasContextType aContextType)
     422             : {
     423             :   // Note that the compositor backend will be LAYERS_NONE if there is no widget.
     424             :   RefPtr<nsICanvasRenderingContextInternal> ret =
     425           0 :     CreateContextHelper(aContextType, GetCompositorBackendType());
     426             : 
     427             :   // Add Observer for webgl canvas.
     428           0 :   if (aContextType == CanvasContextType::WebGL1 ||
     429             :       aContextType == CanvasContextType::WebGL2) {
     430           0 :     if (!mContextObserver) {
     431           0 :       mContextObserver = new HTMLCanvasElementObserver(this);
     432             :     }
     433             :   }
     434             : 
     435           0 :   ret->SetCanvasElement(this);
     436           0 :   return ret.forget();
     437             : }
     438             : 
     439             : nsIntSize
     440           0 : HTMLCanvasElement::GetWidthHeight()
     441             : {
     442           0 :   nsIntSize size(DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT);
     443             :   const nsAttrValue* value;
     444             : 
     445           0 :   if ((value = GetParsedAttr(nsGkAtoms::width)) &&
     446           0 :       value->Type() == nsAttrValue::eInteger)
     447             :   {
     448           0 :       size.width = value->GetIntegerValue();
     449             :   }
     450             : 
     451           0 :   if ((value = GetParsedAttr(nsGkAtoms::height)) &&
     452           0 :       value->Type() == nsAttrValue::eInteger)
     453             :   {
     454           0 :       size.height = value->GetIntegerValue();
     455             :   }
     456             : 
     457           0 :   MOZ_ASSERT(size.width >= 0 && size.height >= 0,
     458             :              "we should've required <canvas> width/height attrs to be "
     459             :              "unsigned (non-negative) values");
     460             : 
     461           0 :   return size;
     462             : }
     463             : 
     464           0 : NS_IMPL_UINT_ATTR_DEFAULT_VALUE(HTMLCanvasElement, Width, width, DEFAULT_CANVAS_WIDTH)
     465           0 : NS_IMPL_UINT_ATTR_DEFAULT_VALUE(HTMLCanvasElement, Height, height, DEFAULT_CANVAS_HEIGHT)
     466           0 : NS_IMPL_BOOL_ATTR(HTMLCanvasElement, MozOpaque, moz_opaque)
     467             : 
     468             : nsresult
     469           0 : HTMLCanvasElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
     470             :                                 const nsAttrValue* aValue,
     471             :                                 const nsAttrValue* aOldValue, bool aNotify)
     472             : {
     473           0 :   AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
     474             : 
     475           0 :   return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
     476           0 :                                             aOldValue, aNotify);
     477             : }
     478             : 
     479             : nsresult
     480           0 : HTMLCanvasElement::OnAttrSetButNotChanged(int32_t aNamespaceID, nsIAtom* aName,
     481             :                                           const nsAttrValueOrString& aValue,
     482             :                                           bool aNotify)
     483             : {
     484           0 :   AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
     485             : 
     486           0 :   return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
     487           0 :                                                       aValue, aNotify);
     488             : }
     489             : 
     490             : void
     491           0 : HTMLCanvasElement::AfterMaybeChangeAttr(int32_t aNamespaceID, nsIAtom* aName,
     492             :                                         bool aNotify)
     493             : {
     494           0 :   if (mCurrentContext && aNamespaceID == kNameSpaceID_None &&
     495           0 :       (aName == nsGkAtoms::width || aName == nsGkAtoms::height ||
     496           0 :        aName == nsGkAtoms::moz_opaque)) {
     497           0 :     ErrorResult dummy;
     498           0 :     UpdateContext(nullptr, JS::NullHandleValue, dummy);
     499             :   }
     500           0 : }
     501             : 
     502             : void
     503           0 : HTMLCanvasElement::HandlePrintCallback(nsPresContext::nsPresContextType aType)
     504             : {
     505             :   // Only call the print callback here if 1) we're in a print testing mode or
     506             :   // print preview mode, 2) the canvas has a print callback and 3) the callback
     507             :   // hasn't already been called. For real printing the callback is handled in
     508             :   // nsSimplePageSequenceFrame::PrePrintNextPage.
     509           0 :   if ((aType == nsPresContext::eContext_PageLayout ||
     510           0 :        aType == nsPresContext::eContext_PrintPreview) &&
     511           0 :       !mPrintState && GetMozPrintCallback()) {
     512           0 :     DispatchPrintCallback(nullptr);
     513             :   }
     514           0 : }
     515             : 
     516             : nsresult
     517           0 : HTMLCanvasElement::DispatchPrintCallback(nsITimerCallback* aCallback)
     518             : {
     519             :   // For print reftests the context may not be initialized yet, so get a context
     520             :   // so mCurrentContext is set.
     521           0 :   if (!mCurrentContext) {
     522             :     nsresult rv;
     523           0 :     nsCOMPtr<nsISupports> context;
     524           0 :     rv = GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(context));
     525           0 :     NS_ENSURE_SUCCESS(rv, rv);
     526             :   }
     527           0 :   mPrintState = new HTMLCanvasPrintState(this, mCurrentContext, aCallback);
     528             : 
     529             :   RefPtr<nsRunnableMethod<HTMLCanvasElement>> renderEvent =
     530           0 :     NewRunnableMethod("dom::HTMLCanvasElement::CallPrintCallback",
     531             :                       this,
     532           0 :                       &HTMLCanvasElement::CallPrintCallback);
     533           0 :   return OwnerDoc()->Dispatch("HTMLCanvasElement::CallPrintCallback",
     534             :                               TaskCategory::Other,
     535           0 :                               renderEvent.forget());
     536             : }
     537             : 
     538             : void
     539           0 : HTMLCanvasElement::CallPrintCallback()
     540             : {
     541           0 :   ErrorResult rv;
     542           0 :   GetMozPrintCallback()->Call(*mPrintState, rv);
     543           0 : }
     544             : 
     545             : void
     546           0 : HTMLCanvasElement::ResetPrintCallback()
     547             : {
     548           0 :   if (mPrintState) {
     549           0 :     mPrintState = nullptr;
     550             :   }
     551           0 : }
     552             : 
     553             : bool
     554           0 : HTMLCanvasElement::IsPrintCallbackDone()
     555             : {
     556           0 :   if (mPrintState == nullptr) {
     557           0 :     return true;
     558             :   }
     559             : 
     560           0 :   return mPrintState->mIsDone;
     561             : }
     562             : 
     563             : HTMLCanvasElement*
     564           0 : HTMLCanvasElement::GetOriginalCanvas()
     565             : {
     566           0 :   return mOriginalCanvas ? mOriginalCanvas.get() : this;
     567             : }
     568             : 
     569             : nsresult
     570           0 : HTMLCanvasElement::CopyInnerTo(Element* aDest,
     571             :                                bool aPreallocateChildren)
     572             : {
     573           0 :   nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest, aPreallocateChildren);
     574           0 :   NS_ENSURE_SUCCESS(rv, rv);
     575           0 :   if (aDest->OwnerDoc()->IsStaticDocument()) {
     576           0 :     HTMLCanvasElement* dest = static_cast<HTMLCanvasElement*>(aDest);
     577           0 :     dest->mOriginalCanvas = this;
     578             : 
     579           0 :     nsCOMPtr<nsISupports> cxt;
     580           0 :     dest->GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(cxt));
     581             :     RefPtr<CanvasRenderingContext2D> context2d =
     582           0 :       static_cast<CanvasRenderingContext2D*>(cxt.get());
     583           0 :     if (context2d && !mPrintCallback) {
     584           0 :       CanvasImageSource source;
     585           0 :       source.SetAsHTMLCanvasElement() = this;
     586           0 :       ErrorResult err;
     587           0 :       context2d->DrawImage(source,
     588           0 :                            0.0, 0.0, err);
     589           0 :       rv = err.StealNSResult();
     590             :     }
     591             :   }
     592           0 :   return rv;
     593             : }
     594             : 
     595           0 : nsresult HTMLCanvasElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
     596             : {
     597           0 :   if (aVisitor.mEvent->mClass == eMouseEventClass) {
     598           0 :     WidgetMouseEventBase* evt = (WidgetMouseEventBase*)aVisitor.mEvent;
     599           0 :     if (mCurrentContext) {
     600           0 :       nsIFrame *frame = GetPrimaryFrame();
     601           0 :       if (!frame)
     602           0 :         return NS_OK;
     603           0 :       nsPoint ptInRoot = nsLayoutUtils::GetEventCoordinatesRelativeTo(evt, frame);
     604           0 :       nsRect paddingRect = frame->GetContentRectRelativeToSelf();
     605           0 :       Point hitpoint;
     606           0 :       hitpoint.x = (ptInRoot.x - paddingRect.x) / AppUnitsPerCSSPixel();
     607           0 :       hitpoint.y = (ptInRoot.y - paddingRect.y) / AppUnitsPerCSSPixel();
     608             : 
     609           0 :       evt->region = mCurrentContext->GetHitRegion(hitpoint);
     610           0 :       aVisitor.mCanHandle = true;
     611             :     }
     612             :   }
     613           0 :   return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
     614             : }
     615             : 
     616             : nsChangeHint
     617           0 : HTMLCanvasElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
     618             :                                           int32_t aModType) const
     619             : {
     620             :   nsChangeHint retval =
     621           0 :     nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
     622           0 :   if (aAttribute == nsGkAtoms::width ||
     623           0 :       aAttribute == nsGkAtoms::height)
     624             :   {
     625           0 :     retval |= NS_STYLE_HINT_REFLOW;
     626           0 :   } else if (aAttribute == nsGkAtoms::moz_opaque)
     627             :   {
     628           0 :     retval |= NS_STYLE_HINT_VISUAL;
     629             :   }
     630           0 :   return retval;
     631             : }
     632             : 
     633             : bool
     634           0 : HTMLCanvasElement::ParseAttribute(int32_t aNamespaceID,
     635             :                                   nsIAtom* aAttribute,
     636             :                                   const nsAString& aValue,
     637             :                                   nsAttrValue& aResult)
     638             : {
     639           0 :   if (aNamespaceID == kNameSpaceID_None &&
     640           0 :       (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height)) {
     641           0 :     return aResult.ParseNonNegativeIntValue(aValue);
     642             :   }
     643             : 
     644           0 :   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
     645           0 :                                               aResult);
     646             : }
     647             : 
     648             : 
     649             : 
     650             : void
     651           0 : HTMLCanvasElement::ToDataURL(JSContext* aCx, const nsAString& aType,
     652             :                              JS::Handle<JS::Value> aParams,
     653             :                              nsAString& aDataURL,
     654             :                              ErrorResult& aRv)
     655             : {
     656             :   // do a trust check if this is a write-only canvas
     657           0 :   if (mWriteOnly &&
     658           0 :       !nsContentUtils::CallerHasPermission(aCx, NS_LITERAL_STRING("<all_urls>"))) {
     659           0 :     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     660           0 :     return;
     661             :   }
     662             : 
     663           0 :   aRv = ToDataURLImpl(aCx, aType, aParams, aDataURL);
     664             : }
     665             : 
     666             : void
     667           0 : HTMLCanvasElement::SetMozPrintCallback(PrintCallback* aCallback)
     668             : {
     669           0 :   mPrintCallback = aCallback;
     670           0 : }
     671             : 
     672             : PrintCallback*
     673           0 : HTMLCanvasElement::GetMozPrintCallback() const
     674             : {
     675           0 :   if (mOriginalCanvas) {
     676           0 :     return mOriginalCanvas->GetMozPrintCallback();
     677             :   }
     678           0 :   return mPrintCallback;
     679             : }
     680             : 
     681             : class CanvasCaptureTrackSource : public MediaStreamTrackSource
     682             : {
     683             : public:
     684             :   NS_DECL_ISUPPORTS_INHERITED
     685           0 :   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CanvasCaptureTrackSource,
     686             :                                            MediaStreamTrackSource)
     687             : 
     688           0 :   CanvasCaptureTrackSource(nsIPrincipal* aPrincipal,
     689             :                            CanvasCaptureMediaStream* aCaptureStream)
     690           0 :     : MediaStreamTrackSource(aPrincipal, nsString())
     691           0 :     , mCaptureStream(aCaptureStream) {}
     692             : 
     693           0 :   MediaSourceEnum GetMediaSource() const override
     694             :   {
     695           0 :     return MediaSourceEnum::Other;
     696             :   }
     697             : 
     698           0 :   void Stop() override
     699             :   {
     700           0 :     if (!mCaptureStream) {
     701           0 :       NS_ERROR("No stream");
     702           0 :       return;
     703             :     }
     704             : 
     705           0 :     mCaptureStream->StopCapture();
     706             :   }
     707             : 
     708             : private:
     709           0 :   virtual ~CanvasCaptureTrackSource() {}
     710             : 
     711             :   RefPtr<CanvasCaptureMediaStream> mCaptureStream;
     712             : };
     713             : 
     714           0 : NS_IMPL_ADDREF_INHERITED(CanvasCaptureTrackSource,
     715             :                          MediaStreamTrackSource)
     716           0 : NS_IMPL_RELEASE_INHERITED(CanvasCaptureTrackSource,
     717             :                           MediaStreamTrackSource)
     718           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(CanvasCaptureTrackSource)
     719           0 : NS_INTERFACE_MAP_END_INHERITING(MediaStreamTrackSource)
     720           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(CanvasCaptureTrackSource,
     721             :                                    MediaStreamTrackSource,
     722             :                                    mCaptureStream)
     723             : 
     724             : already_AddRefed<CanvasCaptureMediaStream>
     725           0 : HTMLCanvasElement::CaptureStream(const Optional<double>& aFrameRate,
     726             :                                  ErrorResult& aRv)
     727             : {
     728           0 :   if (IsWriteOnly()) {
     729           0 :     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     730           0 :     return nullptr;
     731             :   }
     732             : 
     733           0 :   nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
     734           0 :   if (!window) {
     735           0 :     aRv.Throw(NS_ERROR_FAILURE);
     736           0 :     return nullptr;
     737             :   }
     738             : 
     739           0 :   if (!mCurrentContext) {
     740           0 :     aRv.Throw(NS_ERROR_NOT_INITIALIZED);
     741           0 :     return nullptr;
     742             :   }
     743             : 
     744             :   RefPtr<CanvasCaptureMediaStream> stream =
     745           0 :     CanvasCaptureMediaStream::CreateSourceStream(window, this);
     746           0 :   if (!stream) {
     747           0 :     aRv.Throw(NS_ERROR_FAILURE);
     748           0 :     return nullptr;
     749             :   }
     750             : 
     751           0 :   TrackID videoTrackId = 1;
     752           0 :   nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
     753             :   nsresult rv =
     754           0 :     stream->Init(aFrameRate, videoTrackId, principal);
     755           0 :   if (NS_FAILED(rv)) {
     756           0 :     aRv.Throw(rv);
     757           0 :     return nullptr;
     758             :   }
     759             : 
     760             :   RefPtr<MediaStreamTrack> track =
     761           0 :   stream->CreateDOMTrack(videoTrackId, MediaSegment::VIDEO,
     762           0 :                          new CanvasCaptureTrackSource(principal, stream));
     763           0 :   stream->AddTrackInternal(track);
     764             : 
     765           0 :   rv = RegisterFrameCaptureListener(stream->FrameCaptureListener());
     766           0 :   if (NS_FAILED(rv)) {
     767           0 :     aRv.Throw(rv);
     768           0 :     return nullptr;
     769             :   }
     770             : 
     771           0 :   return stream.forget();
     772             : }
     773             : 
     774             : nsresult
     775           0 : HTMLCanvasElement::ExtractData(nsAString& aType,
     776             :                                const nsAString& aOptions,
     777             :                                nsIInputStream** aStream)
     778             : {
     779           0 :   return ImageEncoder::ExtractData(aType,
     780             :                                    aOptions,
     781             :                                    GetSize(),
     782             :                                    mCurrentContext,
     783             :                                    mAsyncCanvasRenderer,
     784           0 :                                    aStream);
     785             : }
     786             : 
     787             : nsresult
     788           0 : HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
     789             :                                  const nsAString& aMimeType,
     790             :                                  const JS::Value& aEncoderOptions,
     791             :                                  nsAString& aDataURL)
     792             : {
     793           0 :   nsIntSize size = GetWidthHeight();
     794           0 :   if (size.height == 0 || size.width == 0) {
     795           0 :     aDataURL = NS_LITERAL_STRING("data:,");
     796           0 :     return NS_OK;
     797             :   }
     798             : 
     799           0 :   nsAutoString type;
     800           0 :   nsContentUtils::ASCIIToLower(aMimeType, type);
     801             : 
     802           0 :   nsAutoString params;
     803             :   bool usingCustomParseOptions;
     804             :   nsresult rv =
     805           0 :     ParseParams(aCx, type, aEncoderOptions, params, &usingCustomParseOptions);
     806           0 :   if (NS_FAILED(rv)) {
     807           0 :     return rv;
     808             :   }
     809             : 
     810           0 :   nsCOMPtr<nsIInputStream> stream;
     811           0 :   rv = ExtractData(type, params, getter_AddRefs(stream));
     812             : 
     813             :   // If there are unrecognized custom parse options, we should fall back to
     814             :   // the default values for the encoder without any options at all.
     815           0 :   if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
     816           0 :     rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
     817             :   }
     818             : 
     819           0 :   NS_ENSURE_SUCCESS(rv, rv);
     820             : 
     821             :   // build data URL string
     822           0 :   aDataURL = NS_LITERAL_STRING("data:") + type + NS_LITERAL_STRING(";base64,");
     823             : 
     824             :   uint64_t count;
     825           0 :   rv = stream->Available(&count);
     826           0 :   NS_ENSURE_SUCCESS(rv, rv);
     827           0 :   NS_ENSURE_TRUE(count <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
     828             : 
     829           0 :   return Base64EncodeInputStream(stream, aDataURL, (uint32_t)count, aDataURL.Length());
     830             : }
     831             : 
     832             : void
     833           0 : HTMLCanvasElement::ToBlob(JSContext* aCx,
     834             :                           BlobCallback& aCallback,
     835             :                           const nsAString& aType,
     836             :                           JS::Handle<JS::Value> aParams,
     837             :                           ErrorResult& aRv)
     838             : {
     839             :   // do a trust check if this is a write-only canvas
     840           0 :   if (mWriteOnly &&
     841           0 :       !nsContentUtils::CallerHasPermission(aCx, NS_LITERAL_STRING("<all_urls>"))) {
     842           0 :     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     843           0 :     return;
     844             :   }
     845             : 
     846           0 :   nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
     847           0 :   MOZ_ASSERT(global);
     848             : 
     849           0 :   nsIntSize elemSize = GetWidthHeight();
     850           0 :   if (elemSize.width == 0 || elemSize.height == 0) {
     851             :     // According to spec, blob should return null if either its horizontal
     852             :     // dimension or its vertical dimension is zero. See link below.
     853             :     // https://html.spec.whatwg.org/multipage/scripting.html#dom-canvas-toblob
     854           0 :     OwnerDoc()->Dispatch(
     855             :       "FireNullBlobEvent",
     856             :       TaskCategory::Other,
     857           0 :       NewRunnableMethod<Blob*, const char*>(
     858             :         "dom::HTMLCanvasElement::ToBlob",
     859           0 :         &aCallback,
     860             :         static_cast<void (BlobCallback::*)(Blob*, const char*)>(
     861             :           &BlobCallback::Call),
     862             :         nullptr,
     863           0 :         nullptr));
     864           0 :     return;
     865             :   }
     866             : 
     867           0 :   CanvasRenderingContextHelper::ToBlob(aCx, global, aCallback, aType,
     868           0 :                                        aParams, aRv);
     869             : 
     870             : }
     871             : 
     872             : OffscreenCanvas*
     873           0 : HTMLCanvasElement::TransferControlToOffscreen(ErrorResult& aRv)
     874             : {
     875           0 :   if (mCurrentContext) {
     876           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     877           0 :     return nullptr;
     878             :   }
     879             : 
     880           0 :   if (!mOffscreenCanvas) {
     881           0 :     nsIntSize sz = GetWidthHeight();
     882           0 :     RefPtr<AsyncCanvasRenderer> renderer = GetAsyncCanvasRenderer();
     883           0 :     renderer->SetWidth(sz.width);
     884           0 :     renderer->SetHeight(sz.height);
     885             : 
     886             :     nsCOMPtr<nsIGlobalObject> global =
     887           0 :       do_QueryInterface(OwnerDoc()->GetInnerWindow());
     888             :     mOffscreenCanvas = new OffscreenCanvas(global,
     889           0 :                                            sz.width,
     890           0 :                                            sz.height,
     891           0 :                                            GetCompositorBackendType(),
     892           0 :                                            renderer);
     893           0 :     if (mWriteOnly) {
     894           0 :       mOffscreenCanvas->SetWriteOnly();
     895             :     }
     896             : 
     897           0 :     if (!mContextObserver) {
     898           0 :       mContextObserver = new HTMLCanvasElementObserver(this);
     899             :     }
     900             :   } else {
     901           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     902             :   }
     903             : 
     904           0 :   return mOffscreenCanvas;
     905             : }
     906             : 
     907             : already_AddRefed<File>
     908           0 : HTMLCanvasElement::MozGetAsFile(const nsAString& aName,
     909             :                                 const nsAString& aType,
     910             :                                 CallerType aCallerType,
     911             :                                 ErrorResult& aRv)
     912             : {
     913           0 :   OwnerDoc()->WarnOnceAbout(nsIDocument::eMozGetAsFile);
     914             : 
     915             :   // do a trust check if this is a write-only canvas
     916           0 :   if (mWriteOnly && aCallerType != CallerType::System) {
     917           0 :     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     918           0 :     return nullptr;
     919             :   }
     920             : 
     921             : 
     922           0 :   RefPtr<File> file;
     923           0 :   aRv = MozGetAsFileImpl(aName, aType, getter_AddRefs(file));
     924           0 :   if (NS_WARN_IF(aRv.Failed())) {
     925           0 :     return nullptr;
     926             :   }
     927           0 :   return file.forget();
     928             : }
     929             : 
     930             : nsresult
     931           0 : HTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
     932             :                                     const nsAString& aType,
     933             :                                     File** aResult)
     934             : {
     935           0 :   nsCOMPtr<nsIInputStream> stream;
     936           0 :   nsAutoString type(aType);
     937           0 :   nsresult rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
     938           0 :   NS_ENSURE_SUCCESS(rv, rv);
     939             : 
     940             :   uint64_t imgSize;
     941           0 :   rv = stream->Available(&imgSize);
     942           0 :   NS_ENSURE_SUCCESS(rv, rv);
     943           0 :   NS_ENSURE_TRUE(imgSize <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
     944             : 
     945           0 :   void* imgData = nullptr;
     946           0 :   rv = NS_ReadInputStreamToBuffer(stream, &imgData, (uint32_t)imgSize);
     947           0 :   NS_ENSURE_SUCCESS(rv, rv);
     948             : 
     949           0 :   JSContext* cx = nsContentUtils::GetCurrentJSContext();
     950           0 :   if (cx) {
     951           0 :     JS_updateMallocCounter(cx, imgSize);
     952             :   }
     953             : 
     954           0 :   nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(OwnerDoc()->GetScopeObject());
     955             : 
     956             :   // The File takes ownership of the buffer
     957             :   RefPtr<File> file =
     958           0 :     File::CreateMemoryFile(win, imgData, (uint32_t)imgSize, aName, type,
     959           0 :                            PR_Now());
     960             : 
     961           0 :   file.forget(aResult);
     962           0 :   return NS_OK;
     963             : }
     964             : 
     965             : nsresult
     966           0 : HTMLCanvasElement::GetContext(const nsAString& aContextId,
     967             :                               nsISupports** aContext)
     968             : {
     969           0 :   ErrorResult rv;
     970           0 :   *aContext = GetContext(nullptr, aContextId, JS::NullHandleValue, rv).take();
     971           0 :   return rv.StealNSResult();
     972             : }
     973             : 
     974             : already_AddRefed<nsISupports>
     975           0 : HTMLCanvasElement::GetContext(JSContext* aCx,
     976             :                               const nsAString& aContextId,
     977             :                               JS::Handle<JS::Value> aContextOptions,
     978             :                               ErrorResult& aRv)
     979             : {
     980           0 :   if (mOffscreenCanvas) {
     981           0 :     return nullptr;
     982             :   }
     983             : 
     984             :   return CanvasRenderingContextHelper::GetContext(aCx, aContextId,
     985           0 :     aContextOptions.isObject() ? aContextOptions : JS::NullHandleValue,
     986           0 :     aRv);
     987             : }
     988             : 
     989             : already_AddRefed<nsISupports>
     990           0 : HTMLCanvasElement::MozGetIPCContext(const nsAString& aContextId,
     991             :                                     ErrorResult& aRv)
     992             : {
     993             :   // Note that we're a [ChromeOnly] method, so from JS we can only be called by
     994             :   // system code.
     995             : 
     996             :   // We only support 2d shmem contexts for now.
     997           0 :   if (!aContextId.EqualsLiteral("2d")) {
     998           0 :     aRv.Throw(NS_ERROR_INVALID_ARG);
     999           0 :     return nullptr;
    1000             :   }
    1001             : 
    1002           0 :   CanvasContextType contextType = CanvasContextType::Canvas2D;
    1003             : 
    1004           0 :   if (!mCurrentContext) {
    1005             :     // This canvas doesn't have a context yet.
    1006             : 
    1007           0 :     RefPtr<nsICanvasRenderingContextInternal> context;
    1008           0 :     context = CreateContext(contextType);
    1009           0 :     if (!context) {
    1010           0 :       return nullptr;
    1011             :     }
    1012             : 
    1013           0 :     mCurrentContext = context;
    1014           0 :     mCurrentContext->SetIsIPC(true);
    1015           0 :     mCurrentContextType = contextType;
    1016             : 
    1017           0 :     ErrorResult dummy;
    1018           0 :     nsresult rv = UpdateContext(nullptr, JS::NullHandleValue, dummy);
    1019           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1020           0 :       aRv.Throw(rv);
    1021           0 :       return nullptr;
    1022             :     }
    1023             :   } else {
    1024             :     // We already have a context of some type.
    1025           0 :     if (contextType != mCurrentContextType) {
    1026           0 :       aRv.Throw(NS_ERROR_INVALID_ARG);
    1027           0 :       return nullptr;
    1028             :     }
    1029             :   }
    1030             : 
    1031           0 :   nsCOMPtr<nsISupports> context(mCurrentContext);
    1032           0 :   return context.forget();
    1033             : }
    1034             : 
    1035             : 
    1036             : nsIntSize
    1037           0 : HTMLCanvasElement::GetSize()
    1038             : {
    1039           0 :   return GetWidthHeight();
    1040             : }
    1041             : 
    1042             : bool
    1043           0 : HTMLCanvasElement::IsWriteOnly()
    1044             : {
    1045           0 :   return mWriteOnly;
    1046             : }
    1047             : 
    1048             : void
    1049           0 : HTMLCanvasElement::SetWriteOnly()
    1050             : {
    1051           0 :   mWriteOnly = true;
    1052           0 : }
    1053             : 
    1054             : void
    1055           0 : HTMLCanvasElement::InvalidateCanvasContent(const gfx::Rect* damageRect)
    1056             : {
    1057             :   // We don't need to flush anything here; if there's no frame or if
    1058             :   // we plan to reframe we don't need to invalidate it anyway.
    1059           0 :   nsIFrame *frame = GetPrimaryFrame();
    1060           0 :   if (!frame)
    1061           0 :     return;
    1062             : 
    1063           0 :   ActiveLayerTracker::NotifyContentChange(frame);
    1064             : 
    1065           0 :   Layer* layer = nullptr;
    1066           0 :   if (damageRect) {
    1067           0 :     nsIntSize size = GetWidthHeight();
    1068           0 :     if (size.width != 0 && size.height != 0) {
    1069           0 :       gfx::IntRect invalRect = gfx::IntRect::Truncate(*damageRect);
    1070           0 :       layer = frame->InvalidateLayer(nsDisplayItem::TYPE_CANVAS, &invalRect);
    1071             :     }
    1072             :   } else {
    1073           0 :     layer = frame->InvalidateLayer(nsDisplayItem::TYPE_CANVAS);
    1074             :   }
    1075           0 :   if (layer) {
    1076           0 :     static_cast<CanvasLayer*>(layer)->Updated();
    1077             :   }
    1078             : 
    1079             :   /*
    1080             :    * Treat canvas invalidations as animation activity for JS. Frequently
    1081             :    * invalidating a canvas will feed into heuristics and cause JIT code to be
    1082             :    * kept around longer, for smoother animations.
    1083             :    */
    1084             :   nsCOMPtr<nsIGlobalObject> global =
    1085           0 :     do_QueryInterface(OwnerDoc()->GetInnerWindow());
    1086             : 
    1087           0 :   if (global) {
    1088           0 :     if (JSObject *obj = global->GetGlobalJSObject()) {
    1089           0 :       js::NotifyAnimationActivity(obj);
    1090             :     }
    1091             :   }
    1092             : }
    1093             : 
    1094             : void
    1095           0 : HTMLCanvasElement::InvalidateCanvas()
    1096             : {
    1097             :   // We don't need to flush anything here; if there's no frame or if
    1098             :   // we plan to reframe we don't need to invalidate it anyway.
    1099           0 :   nsIFrame *frame = GetPrimaryFrame();
    1100           0 :   if (!frame)
    1101           0 :     return;
    1102             : 
    1103           0 :   frame->InvalidateFrame();
    1104             : }
    1105             : 
    1106             : int32_t
    1107           0 : HTMLCanvasElement::CountContexts()
    1108             : {
    1109           0 :   if (mCurrentContext)
    1110           0 :     return 1;
    1111             : 
    1112           0 :   return 0;
    1113             : }
    1114             : 
    1115             : nsICanvasRenderingContextInternal *
    1116           0 : HTMLCanvasElement::GetContextAtIndex(int32_t index)
    1117             : {
    1118           0 :   if (mCurrentContext && index == 0)
    1119           0 :     return mCurrentContext;
    1120             : 
    1121           0 :   return nullptr;
    1122             : }
    1123             : 
    1124             : bool
    1125           0 : HTMLCanvasElement::GetIsOpaque()
    1126             : {
    1127           0 :   if (mCurrentContext) {
    1128           0 :     return mCurrentContext->GetIsOpaque();
    1129             :   }
    1130             : 
    1131           0 :   return GetOpaqueAttr();
    1132             : }
    1133             : 
    1134             : bool
    1135           0 : HTMLCanvasElement::GetOpaqueAttr()
    1136             : {
    1137           0 :   return HasAttr(kNameSpaceID_None, nsGkAtoms::moz_opaque);
    1138             : }
    1139             : 
    1140             : already_AddRefed<Layer>
    1141           0 : HTMLCanvasElement::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
    1142             :                                   Layer *aOldLayer,
    1143             :                                   LayerManager *aManager)
    1144             : {
    1145             :   // The address of sOffscreenCanvasLayerUserDataDummy is used as the user
    1146             :   // data key for retained LayerManagers managed by FrameLayerBuilder.
    1147             :   // We don't much care about what value in it, so just assign a dummy
    1148             :   // value for it.
    1149             :   static uint8_t sOffscreenCanvasLayerUserDataDummy = 0;
    1150             : 
    1151           0 :   if (mCurrentContext) {
    1152           0 :     return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager, mVRPresentationActive);
    1153             :   }
    1154             : 
    1155           0 :   if (mOffscreenCanvas) {
    1156           0 :     if (!mResetLayer &&
    1157           0 :         aOldLayer && aOldLayer->HasUserData(&sOffscreenCanvasLayerUserDataDummy)) {
    1158           0 :       RefPtr<Layer> ret = aOldLayer;
    1159           0 :       return ret.forget();
    1160             :     }
    1161             : 
    1162           0 :     RefPtr<CanvasLayer> layer = aManager->CreateCanvasLayer();
    1163           0 :     if (!layer) {
    1164           0 :       NS_WARNING("CreateCanvasLayer failed!");
    1165           0 :       return nullptr;
    1166             :     }
    1167             : 
    1168           0 :     LayerUserData* userData = nullptr;
    1169           0 :     layer->SetUserData(&sOffscreenCanvasLayerUserDataDummy, userData);
    1170             : 
    1171           0 :     CanvasLayer::Data data;
    1172           0 :     data.mRenderer = GetAsyncCanvasRenderer();
    1173           0 :     data.mSize = GetWidthHeight();
    1174           0 :     layer->Initialize(data);
    1175             : 
    1176           0 :     layer->Updated();
    1177           0 :     return layer.forget();
    1178             :   }
    1179             : 
    1180           0 :   return nullptr;
    1181             : }
    1182             : 
    1183             : bool
    1184           0 : HTMLCanvasElement::ShouldForceInactiveLayer(LayerManager* aManager)
    1185             : {
    1186           0 :   if (mCurrentContext) {
    1187           0 :     return mCurrentContext->ShouldForceInactiveLayer(aManager);
    1188             :   }
    1189             : 
    1190           0 :   if (mOffscreenCanvas) {
    1191             :     // TODO: We should handle offscreen canvas case.
    1192           0 :     return false;
    1193             :   }
    1194             : 
    1195           0 :   return true;
    1196             : }
    1197             : 
    1198             : void
    1199           0 : HTMLCanvasElement::MarkContextClean()
    1200             : {
    1201           0 :   if (!mCurrentContext)
    1202           0 :     return;
    1203             : 
    1204           0 :   mCurrentContext->MarkContextClean();
    1205             : }
    1206             : 
    1207             : void
    1208           0 : HTMLCanvasElement::MarkContextCleanForFrameCapture()
    1209             : {
    1210           0 :   if (!mCurrentContext)
    1211           0 :     return;
    1212             : 
    1213           0 :   mCurrentContext->MarkContextCleanForFrameCapture();
    1214             : }
    1215             : 
    1216             : bool
    1217           0 : HTMLCanvasElement::IsContextCleanForFrameCapture()
    1218             : {
    1219           0 :   return mCurrentContext && mCurrentContext->IsContextCleanForFrameCapture();
    1220             : }
    1221             : 
    1222             : nsresult
    1223           0 : HTMLCanvasElement::RegisterFrameCaptureListener(FrameCaptureListener* aListener)
    1224             : {
    1225           0 :   WeakPtr<FrameCaptureListener> listener = aListener;
    1226             : 
    1227           0 :   if (mRequestedFrameListeners.Contains(listener)) {
    1228           0 :     return NS_OK;
    1229             :   }
    1230             : 
    1231           0 :   if (!mRequestedFrameRefreshObserver) {
    1232           0 :     nsIDocument* doc = OwnerDoc();
    1233           0 :     if (!doc) {
    1234           0 :       return NS_ERROR_FAILURE;
    1235             :     }
    1236             : 
    1237           0 :     while (doc->GetParentDocument()) {
    1238           0 :       doc = doc->GetParentDocument();
    1239             :     }
    1240             : 
    1241           0 :     nsIPresShell* shell = doc->GetShell();
    1242           0 :     if (!shell) {
    1243           0 :       return NS_ERROR_FAILURE;
    1244             :     }
    1245             : 
    1246           0 :     nsPresContext* context = shell->GetPresContext();
    1247           0 :     if (!context) {
    1248           0 :       return NS_ERROR_FAILURE;
    1249             :     }
    1250             : 
    1251           0 :     context = context->GetRootPresContext();
    1252           0 :     if (!context) {
    1253           0 :       return NS_ERROR_FAILURE;
    1254             :     }
    1255             : 
    1256           0 :     nsRefreshDriver* driver = context->RefreshDriver();
    1257           0 :     if (!driver) {
    1258           0 :       return NS_ERROR_FAILURE;
    1259             :     }
    1260             : 
    1261             :     mRequestedFrameRefreshObserver =
    1262           0 :       new RequestedFrameRefreshObserver(this, driver);
    1263             :   }
    1264             : 
    1265           0 :   mRequestedFrameListeners.AppendElement(listener);
    1266           0 :   mRequestedFrameRefreshObserver->Register();
    1267           0 :   return NS_OK;
    1268             : }
    1269             : 
    1270             : bool
    1271           0 : HTMLCanvasElement::IsFrameCaptureRequested() const
    1272             : {
    1273           0 :   for (WeakPtr<FrameCaptureListener> listener : mRequestedFrameListeners) {
    1274           0 :     if (!listener) {
    1275           0 :       continue;
    1276             :     }
    1277             : 
    1278           0 :     if (listener->FrameCaptureRequested()) {
    1279           0 :       return true;
    1280             :     }
    1281             :   }
    1282           0 :   return false;
    1283             : }
    1284             : 
    1285             : void
    1286           0 : HTMLCanvasElement::ProcessDestroyedFrameListeners()
    1287             : {
    1288             :   // Loop backwards to allow removing elements in the loop.
    1289           0 :   for (int i = mRequestedFrameListeners.Length() - 1; i >= 0; --i) {
    1290           0 :     WeakPtr<FrameCaptureListener> listener = mRequestedFrameListeners[i];
    1291           0 :     if (!listener) {
    1292             :       // listener was destroyed. Remove it from the list.
    1293           0 :       mRequestedFrameListeners.RemoveElementAt(i);
    1294           0 :       continue;
    1295             :     }
    1296             :   }
    1297             : 
    1298           0 :   if (mRequestedFrameListeners.IsEmpty()) {
    1299           0 :     mRequestedFrameRefreshObserver->Unregister();
    1300             :   }
    1301           0 : }
    1302             : 
    1303             : void
    1304           0 : HTMLCanvasElement::SetFrameCapture(already_AddRefed<SourceSurface> aSurface,
    1305             :                                    const TimeStamp& aTime)
    1306             : {
    1307           0 :   RefPtr<SourceSurface> surface = aSurface;
    1308           0 :   RefPtr<SourceSurfaceImage> image = new SourceSurfaceImage(surface->GetSize(), surface);
    1309             : 
    1310           0 :   for (WeakPtr<FrameCaptureListener> listener : mRequestedFrameListeners) {
    1311           0 :     if (!listener) {
    1312           0 :       continue;
    1313             :     }
    1314             : 
    1315           0 :     RefPtr<Image> imageRefCopy = image.get();
    1316           0 :     listener->NewFrame(imageRefCopy.forget(), aTime);
    1317             :   }
    1318           0 : }
    1319             : 
    1320             : already_AddRefed<SourceSurface>
    1321           0 : HTMLCanvasElement::GetSurfaceSnapshot(gfxAlphaType* const aOutAlphaType)
    1322             : {
    1323           0 :   if (!mCurrentContext)
    1324           0 :     return nullptr;
    1325             : 
    1326           0 :   return mCurrentContext->GetSurfaceSnapshot(aOutAlphaType);
    1327             : }
    1328             : 
    1329             : AsyncCanvasRenderer*
    1330           0 : HTMLCanvasElement::GetAsyncCanvasRenderer()
    1331             : {
    1332           0 :   if (!mAsyncCanvasRenderer) {
    1333           0 :     mAsyncCanvasRenderer = new AsyncCanvasRenderer();
    1334           0 :     mAsyncCanvasRenderer->mHTMLCanvasElement = this;
    1335             :   }
    1336             : 
    1337           0 :   return mAsyncCanvasRenderer;
    1338             : }
    1339             : 
    1340             : layers::LayersBackend
    1341           0 : HTMLCanvasElement::GetCompositorBackendType() const
    1342             : {
    1343           0 :   nsIWidget* docWidget = nsContentUtils::WidgetForDocument(OwnerDoc());
    1344           0 :   if (docWidget) {
    1345           0 :     layers::LayerManager* layerManager = docWidget->GetLayerManager();
    1346           0 :     if (layerManager) {
    1347           0 :       return layerManager->GetCompositorBackendType();
    1348             :     }
    1349             :   }
    1350             : 
    1351           0 :   return LayersBackend::LAYERS_NONE;
    1352             : }
    1353             : 
    1354             : void
    1355           0 : HTMLCanvasElement::OnVisibilityChange()
    1356             : {
    1357           0 :   if (OwnerDoc()->Hidden()) {
    1358           0 :     return;
    1359             :   }
    1360             : 
    1361           0 :   if (mOffscreenCanvas) {
    1362           0 :     class Runnable final : public CancelableRunnable
    1363             :     {
    1364             :     public:
    1365           0 :       explicit Runnable(AsyncCanvasRenderer* aRenderer)
    1366           0 :         : mozilla::CancelableRunnable("Runnable")
    1367           0 :         , mRenderer(aRenderer)
    1368           0 :       {}
    1369             : 
    1370           0 :       NS_IMETHOD Run() override
    1371             :       {
    1372           0 :         if (mRenderer && mRenderer->mContext) {
    1373           0 :           mRenderer->mContext->OnVisibilityChange();
    1374             :         }
    1375             : 
    1376           0 :         return NS_OK;
    1377             :       }
    1378             : 
    1379             :     private:
    1380             :       RefPtr<AsyncCanvasRenderer> mRenderer;
    1381             :     };
    1382             : 
    1383           0 :     RefPtr<nsIRunnable> runnable = new Runnable(mAsyncCanvasRenderer);
    1384           0 :     nsCOMPtr<nsIEventTarget> activeTarget = mAsyncCanvasRenderer->GetActiveEventTarget();
    1385           0 :     if (activeTarget) {
    1386           0 :       activeTarget->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
    1387             :     }
    1388           0 :     return;
    1389             :   }
    1390             : 
    1391           0 :   if (mCurrentContext) {
    1392           0 :     mCurrentContext->OnVisibilityChange();
    1393             :   }
    1394             : }
    1395             : 
    1396             : void
    1397           0 : HTMLCanvasElement::OnMemoryPressure()
    1398             : {
    1399           0 :   if (mOffscreenCanvas) {
    1400           0 :     class Runnable final : public CancelableRunnable
    1401             :     {
    1402             :     public:
    1403           0 :       explicit Runnable(AsyncCanvasRenderer* aRenderer)
    1404           0 :         : mozilla::CancelableRunnable("Runnable")
    1405           0 :         , mRenderer(aRenderer)
    1406           0 :       {}
    1407             : 
    1408           0 :       NS_IMETHOD Run() override
    1409             :       {
    1410           0 :         if (mRenderer && mRenderer->mContext) {
    1411           0 :           mRenderer->mContext->OnMemoryPressure();
    1412             :         }
    1413             : 
    1414           0 :         return NS_OK;
    1415             :       }
    1416             : 
    1417             :     private:
    1418             :       RefPtr<AsyncCanvasRenderer> mRenderer;
    1419             :     };
    1420             : 
    1421           0 :     RefPtr<nsIRunnable> runnable = new Runnable(mAsyncCanvasRenderer);
    1422           0 :     nsCOMPtr<nsIEventTarget> activeTarget = mAsyncCanvasRenderer->GetActiveEventTarget();
    1423           0 :     if (activeTarget) {
    1424           0 :       activeTarget->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
    1425             :     }
    1426           0 :     return;
    1427             :   }
    1428             : 
    1429           0 :   if (mCurrentContext) {
    1430           0 :     mCurrentContext->OnMemoryPressure();
    1431             :   }
    1432             : }
    1433             : 
    1434             : /* static */ void
    1435           0 : HTMLCanvasElement::SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer)
    1436             : {
    1437           0 :   HTMLCanvasElement *element = aRenderer->mHTMLCanvasElement;
    1438           0 :   if (!element) {
    1439           0 :     return;
    1440             :   }
    1441             : 
    1442           0 :   if (element->GetWidthHeight() == aRenderer->GetSize()) {
    1443           0 :     return;
    1444             :   }
    1445             : 
    1446           0 :   gfx::IntSize asyncCanvasSize = aRenderer->GetSize();
    1447             : 
    1448           0 :   ErrorResult rv;
    1449           0 :   element->SetUnsignedIntAttr(nsGkAtoms::width, asyncCanvasSize.width,
    1450           0 :                               DEFAULT_CANVAS_WIDTH, rv);
    1451           0 :   if (rv.Failed()) {
    1452           0 :     NS_WARNING("Failed to set width attribute to a canvas element asynchronously.");
    1453             :   }
    1454             : 
    1455           0 :   element->SetUnsignedIntAttr(nsGkAtoms::height, asyncCanvasSize.height,
    1456           0 :                               DEFAULT_CANVAS_HEIGHT, rv);
    1457           0 :   if (rv.Failed()) {
    1458           0 :     NS_WARNING("Failed to set height attribute to a canvas element asynchronously.");
    1459             :   }
    1460             : 
    1461           0 :   element->mResetLayer = true;
    1462             : }
    1463             : 
    1464             : /* static */ void
    1465           0 : HTMLCanvasElement::InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer)
    1466             : {
    1467           0 :   HTMLCanvasElement *element = aRenderer->mHTMLCanvasElement;
    1468           0 :   if (!element) {
    1469           0 :     return;
    1470             :   }
    1471             : 
    1472           0 :   element->InvalidateCanvasContent(nullptr);
    1473             : }
    1474             : 
    1475             : void
    1476           0 : HTMLCanvasElement::StartVRPresentation()
    1477             : {
    1478           0 :   if (GetCurrentContextType() != CanvasContextType::WebGL1 &&
    1479           0 :       GetCurrentContextType() != CanvasContextType::WebGL2) {
    1480           0 :     return;
    1481             :   }
    1482             : 
    1483           0 :   WebGLContext* webgl = static_cast<WebGLContext*>(GetContextAtIndex(0));
    1484           0 :   if (!webgl) {
    1485           0 :     return;
    1486             :   }
    1487             : 
    1488           0 :   if (!webgl->StartVRPresentation()) {
    1489           0 :     return;
    1490             :   }
    1491             : 
    1492           0 :   mVRPresentationActive = true;
    1493             : }
    1494             : 
    1495             : void
    1496           0 : HTMLCanvasElement::StopVRPresentation()
    1497             : {
    1498           0 :   mVRPresentationActive = false;
    1499           0 : }
    1500             : 
    1501             : already_AddRefed<layers::SharedSurfaceTextureClient>
    1502           0 : HTMLCanvasElement::GetVRFrame()
    1503             : {
    1504           0 :   if (GetCurrentContextType() != CanvasContextType::WebGL1 &&
    1505           0 :       GetCurrentContextType() != CanvasContextType::WebGL2) {
    1506           0 :     return nullptr;
    1507             :   }
    1508             : 
    1509           0 :   WebGLContext* webgl = static_cast<WebGLContext*>(GetContextAtIndex(0));
    1510           0 :   if (!webgl) {
    1511           0 :     return nullptr;
    1512             :   }
    1513             : 
    1514           0 :   return webgl->GetVRFrame();
    1515             : }
    1516             : 
    1517             : } // namespace dom
    1518             : } // namespace mozilla

Generated by: LCOV version 1.13