LCOV - code coverage report
Current view: top level - dom/canvas - OffscreenCanvas.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 8 160 5.0 %
Date: 2017-07-14 16:53:18 Functions: 2 28 7.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       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 "OffscreenCanvas.h"
       8             : 
       9             : #include "mozilla/dom/OffscreenCanvasBinding.h"
      10             : #include "mozilla/dom/WorkerPrivate.h"
      11             : #include "mozilla/dom/WorkerScope.h"
      12             : #include "mozilla/layers/AsyncCanvasRenderer.h"
      13             : #include "mozilla/layers/CanvasClient.h"
      14             : #include "mozilla/layers/ImageBridgeChild.h"
      15             : #include "mozilla/Telemetry.h"
      16             : #include "CanvasRenderingContext2D.h"
      17             : #include "CanvasUtils.h"
      18             : #include "GLScreenBuffer.h"
      19             : #include "WebGL1Context.h"
      20             : #include "WebGL2Context.h"
      21             : 
      22             : namespace mozilla {
      23             : namespace dom {
      24             : 
      25           0 : OffscreenCanvasCloneData::OffscreenCanvasCloneData(layers::AsyncCanvasRenderer* aRenderer,
      26             :                                                    uint32_t aWidth, uint32_t aHeight,
      27             :                                                    layers::LayersBackend aCompositorBackend,
      28           0 :                                                    bool aNeutered, bool aIsWriteOnly)
      29             :   : mRenderer(aRenderer)
      30             :   , mWidth(aWidth)
      31             :   , mHeight(aHeight)
      32             :   , mCompositorBackendType(aCompositorBackend)
      33             :   , mNeutered(aNeutered)
      34           0 :   , mIsWriteOnly(aIsWriteOnly)
      35             : {
      36           0 : }
      37             : 
      38           0 : OffscreenCanvasCloneData::~OffscreenCanvasCloneData()
      39             : {
      40           0 : }
      41             : 
      42           0 : OffscreenCanvas::OffscreenCanvas(nsIGlobalObject* aGlobal,
      43             :                                  uint32_t aWidth,
      44             :                                  uint32_t aHeight,
      45             :                                  layers::LayersBackend aCompositorBackend,
      46           0 :                                  layers::AsyncCanvasRenderer* aRenderer)
      47             :   : DOMEventTargetHelper(aGlobal)
      48             :   , mAttrDirty(false)
      49             :   , mNeutered(false)
      50             :   , mIsWriteOnly(false)
      51             :   , mWidth(aWidth)
      52             :   , mHeight(aHeight)
      53             :   , mCompositorBackendType(aCompositorBackend)
      54           0 :   , mCanvasRenderer(aRenderer)
      55           0 : {}
      56             : 
      57           0 : OffscreenCanvas::~OffscreenCanvas()
      58             : {
      59           0 :   ClearResources();
      60           0 : }
      61             : 
      62             : JSObject*
      63           0 : OffscreenCanvas::WrapObject(JSContext* aCx,
      64             :                             JS::Handle<JSObject*> aGivenProto)
      65             : {
      66           0 :   return OffscreenCanvasBinding::Wrap(aCx, this, aGivenProto);
      67             : }
      68             : 
      69             : /* static */ already_AddRefed<OffscreenCanvas>
      70           0 : OffscreenCanvas::Constructor(const GlobalObject& aGlobal,
      71             :                              uint32_t aWidth,
      72             :                              uint32_t aHeight,
      73             :                              ErrorResult& aRv)
      74             : {
      75           0 :   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
      76             :   RefPtr<OffscreenCanvas> offscreenCanvas =
      77             :     new OffscreenCanvas(global, aWidth, aHeight,
      78           0 :                         layers::LayersBackend::LAYERS_NONE, nullptr);
      79           0 :   return offscreenCanvas.forget();
      80             : }
      81             : 
      82             : void
      83           0 : OffscreenCanvas::ClearResources()
      84             : {
      85           0 :   if (mCanvasClient) {
      86           0 :     mCanvasClient->Clear();
      87             : 
      88           0 :     if (mCanvasRenderer) {
      89           0 :       nsCOMPtr<nsISerialEventTarget> activeTarget = mCanvasRenderer->GetActiveEventTarget();
      90           0 :       MOZ_RELEASE_ASSERT(activeTarget, "GFX: failed to get active event target.");
      91             :       bool current;
      92           0 :       activeTarget->IsOnCurrentThread(&current);
      93           0 :       MOZ_RELEASE_ASSERT(current, "GFX: active thread is not current thread.");
      94           0 :       mCanvasRenderer->SetCanvasClient(nullptr);
      95           0 :       mCanvasRenderer->mContext = nullptr;
      96           0 :       mCanvasRenderer->mGLContext = nullptr;
      97           0 :       mCanvasRenderer->ResetActiveEventTarget();
      98             :     }
      99             : 
     100           0 :     mCanvasClient = nullptr;
     101             :   }
     102           0 : }
     103             : 
     104             : already_AddRefed<nsISupports>
     105           0 : OffscreenCanvas::GetContext(JSContext* aCx,
     106             :                             const nsAString& aContextId,
     107             :                             JS::Handle<JS::Value> aContextOptions,
     108             :                             ErrorResult& aRv)
     109             : {
     110           0 :   if (mNeutered) {
     111           0 :     aRv.Throw(NS_ERROR_FAILURE);
     112           0 :     return nullptr;
     113             :   }
     114             : 
     115             :   // We only support WebGL in workers for now
     116             :   CanvasContextType contextType;
     117           0 :   if (!CanvasUtils::GetCanvasContextType(aContextId, &contextType)) {
     118           0 :     aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
     119           0 :     return nullptr;
     120             :   }
     121             : 
     122           0 :   if (!(contextType == CanvasContextType::WebGL1 ||
     123           0 :         contextType == CanvasContextType::WebGL2 ||
     124           0 :         contextType == CanvasContextType::ImageBitmap))
     125             :   {
     126           0 :     aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
     127           0 :     return nullptr;
     128             :   }
     129             : 
     130             :   already_AddRefed<nsISupports> result =
     131             :     CanvasRenderingContextHelper::GetContext(aCx,
     132             :                                              aContextId,
     133             :                                              aContextOptions,
     134           0 :                                              aRv);
     135             : 
     136           0 :   if (!mCurrentContext) {
     137           0 :     return nullptr;
     138             :   }
     139             : 
     140           0 :   if (mCanvasRenderer) {
     141           0 :     if (contextType == CanvasContextType::WebGL1 ||
     142           0 :         contextType == CanvasContextType::WebGL2) {
     143           0 :       WebGLContext* webGL = static_cast<WebGLContext*>(mCurrentContext.get());
     144           0 :       gl::GLContext* gl = webGL->GL();
     145           0 :       mCanvasRenderer->mContext = mCurrentContext;
     146           0 :       mCanvasRenderer->SetActiveEventTarget();
     147           0 :       mCanvasRenderer->mGLContext = gl;
     148           0 :       mCanvasRenderer->SetIsAlphaPremultiplied(webGL->IsPremultAlpha() || !gl->Caps().alpha);
     149             : 
     150           0 :       if (RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton()) {
     151           0 :         TextureFlags flags = TextureFlags::ORIGIN_BOTTOM_LEFT;
     152           0 :         mCanvasClient = imageBridge->CreateCanvasClient(CanvasClient::CanvasClientTypeShSurf, flags);
     153           0 :         mCanvasRenderer->SetCanvasClient(mCanvasClient);
     154             : 
     155           0 :         gl::GLScreenBuffer* screen = gl->Screen();
     156           0 :         gl::SurfaceCaps caps = screen->mCaps;
     157           0 :         auto forwarder = mCanvasClient->GetForwarder();
     158             : 
     159             :         UniquePtr<gl::SurfaceFactory> factory =
     160           0 :           gl::GLScreenBuffer::CreateFactory(gl, caps, forwarder, flags);
     161             : 
     162           0 :         if (factory)
     163           0 :           screen->Morph(Move(factory));
     164             :       }
     165             :     }
     166             :   }
     167             : 
     168           0 :   return result;
     169             : }
     170             : 
     171             : already_AddRefed<nsICanvasRenderingContextInternal>
     172           0 : OffscreenCanvas::CreateContext(CanvasContextType aContextType)
     173             : {
     174             :   RefPtr<nsICanvasRenderingContextInternal> ret =
     175           0 :     CanvasRenderingContextHelper::CreateContext(aContextType);
     176             : 
     177           0 :   ret->SetOffscreenCanvas(this);
     178           0 :   return ret.forget();
     179             : }
     180             : 
     181             : void
     182           0 : OffscreenCanvas::CommitFrameToCompositor()
     183             : {
     184           0 :   if (!mCanvasRenderer) {
     185             :     // This offscreen canvas doesn't associate to any HTML canvas element.
     186             :     // So, just bail out.
     187           0 :     return;
     188             :   }
     189             : 
     190             :   // The attributes has changed, we have to notify main
     191             :   // thread to change canvas size.
     192           0 :   if (mAttrDirty) {
     193           0 :     if (mCanvasRenderer) {
     194           0 :       mCanvasRenderer->SetWidth(mWidth);
     195           0 :       mCanvasRenderer->SetHeight(mHeight);
     196           0 :       mCanvasRenderer->NotifyElementAboutAttributesChanged();
     197             :     }
     198           0 :     mAttrDirty = false;
     199             :   }
     200             : 
     201           0 :   if (mCurrentContext) {
     202           0 :     static_cast<WebGLContext*>(mCurrentContext.get())->PresentScreenBuffer();
     203             :   }
     204             : 
     205           0 :   if (mCanvasRenderer && mCanvasRenderer->mGLContext) {
     206           0 :     mCanvasRenderer->NotifyElementAboutInvalidation();
     207           0 :     ImageBridgeChild::GetSingleton()->
     208           0 :       UpdateAsyncCanvasRenderer(mCanvasRenderer);
     209             :   }
     210             : }
     211             : 
     212             : OffscreenCanvasCloneData*
     213           0 : OffscreenCanvas::ToCloneData()
     214             : {
     215             :   return new OffscreenCanvasCloneData(mCanvasRenderer, mWidth, mHeight,
     216           0 :                                       mCompositorBackendType, mNeutered, mIsWriteOnly);
     217             : }
     218             : 
     219             : already_AddRefed<ImageBitmap>
     220           0 : OffscreenCanvas::TransferToImageBitmap()
     221             : {
     222           0 :   ErrorResult rv;
     223           0 :   nsCOMPtr<nsIGlobalObject> globalObject = GetGlobalObject();
     224           0 :   RefPtr<ImageBitmap> result = ImageBitmap::CreateFromOffscreenCanvas(globalObject, *this, rv);
     225             : 
     226             :   // Clear the content.
     227           0 :   if ((mCurrentContextType == CanvasContextType::WebGL1 ||
     228           0 :        mCurrentContextType == CanvasContextType::WebGL2))
     229             :   {
     230           0 :     WebGLContext* webGL = static_cast<WebGLContext*>(mCurrentContext.get());
     231           0 :     webGL->ClearScreen();
     232             :   }
     233             : 
     234           0 :   return result.forget();
     235             : }
     236             : 
     237             : already_AddRefed<Promise>
     238           0 : OffscreenCanvas::ToBlob(JSContext* aCx,
     239             :                         const nsAString& aType,
     240             :                         JS::Handle<JS::Value> aParams,
     241             :                         ErrorResult& aRv)
     242             : {
     243             :   // do a trust check if this is a write-only canvas
     244           0 :   if (mIsWriteOnly) {
     245           0 :     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     246           0 :     return nullptr;
     247             :   }
     248             : 
     249           0 :   nsCOMPtr<nsIGlobalObject> global = GetGlobalObject();
     250             : 
     251           0 :   RefPtr<Promise> promise = Promise::Create(global, aRv);
     252           0 :   if (aRv.Failed()) {
     253           0 :     return nullptr;
     254             :   }
     255             : 
     256             :   // Encoder callback when encoding is complete.
     257           0 :   class EncodeCallback : public EncodeCompleteCallback
     258             :   {
     259             :   public:
     260           0 :     EncodeCallback(nsIGlobalObject* aGlobal, Promise* aPromise)
     261           0 :       : mGlobal(aGlobal)
     262           0 :       , mPromise(aPromise) {}
     263             : 
     264             :     // This is called on main thread.
     265           0 :     nsresult ReceiveBlob(already_AddRefed<Blob> aBlob)
     266             :     {
     267           0 :       RefPtr<Blob> blob = aBlob;
     268             : 
     269           0 :       ErrorResult rv;
     270           0 :       uint64_t size = blob->GetSize(rv);
     271           0 :       if (rv.Failed()) {
     272           0 :         rv.SuppressException();
     273             :       } else {
     274           0 :         AutoJSAPI jsapi;
     275           0 :         if (jsapi.Init(mGlobal)) {
     276           0 :           JS_updateMallocCounter(jsapi.cx(), size);
     277             :         }
     278             :       }
     279             : 
     280           0 :       if (mPromise) {
     281           0 :         RefPtr<Blob> newBlob = Blob::Create(mGlobal, blob->Impl());
     282           0 :         mPromise->MaybeResolve(newBlob);
     283             :       }
     284             : 
     285           0 :       mGlobal = nullptr;
     286           0 :       mPromise = nullptr;
     287             : 
     288           0 :       return rv.StealNSResult();
     289             :     }
     290             : 
     291             :     nsCOMPtr<nsIGlobalObject> mGlobal;
     292             :     RefPtr<Promise> mPromise;
     293             :   };
     294             : 
     295             :   RefPtr<EncodeCompleteCallback> callback =
     296           0 :     new EncodeCallback(global, promise);
     297             : 
     298           0 :   CanvasRenderingContextHelper::ToBlob(aCx, global,
     299           0 :                                        callback, aType, aParams, aRv);
     300             : 
     301           0 :   return promise.forget();
     302             : }
     303             : 
     304             : already_AddRefed<gfx::SourceSurface>
     305           0 : OffscreenCanvas::GetSurfaceSnapshot(gfxAlphaType* const aOutAlphaType)
     306             : {
     307           0 :   if (!mCurrentContext) {
     308           0 :     return nullptr;
     309             :   }
     310             : 
     311           0 :   return mCurrentContext->GetSurfaceSnapshot(aOutAlphaType);
     312             : }
     313             : 
     314             : nsCOMPtr<nsIGlobalObject>
     315           0 : OffscreenCanvas::GetGlobalObject()
     316             : {
     317           0 :   if (NS_IsMainThread()) {
     318           0 :     return GetParentObject();
     319             :   }
     320             : 
     321             :   dom::workers::WorkerPrivate* workerPrivate =
     322           0 :     dom::workers::GetCurrentThreadWorkerPrivate();
     323           0 :   return workerPrivate->GlobalScope();
     324             : }
     325             : 
     326             : /* static */ already_AddRefed<OffscreenCanvas>
     327           0 : OffscreenCanvas::CreateFromCloneData(nsIGlobalObject* aGlobal, OffscreenCanvasCloneData* aData)
     328             : {
     329           0 :   MOZ_ASSERT(aData);
     330             :   RefPtr<OffscreenCanvas> wc =
     331             :     new OffscreenCanvas(aGlobal, aData->mWidth, aData->mHeight,
     332           0 :                         aData->mCompositorBackendType, aData->mRenderer);
     333           0 :   if (aData->mNeutered) {
     334           0 :     wc->SetNeutered();
     335             :   }
     336           0 :   return wc.forget();
     337             : }
     338             : 
     339             : /* static */ bool
     340          12 : OffscreenCanvas::PrefEnabled(JSContext* aCx, JSObject* aObj)
     341             : {
     342          12 :   if (NS_IsMainThread()) {
     343           0 :     return Preferences::GetBool("gfx.offscreencanvas.enabled");
     344             :   } else {
     345          12 :     WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
     346          12 :     MOZ_ASSERT(workerPrivate);
     347          12 :     return workerPrivate->OffscreenCanvasEnabled();
     348             :   }
     349             : }
     350             : 
     351             : /* static */ bool
     352          11 : OffscreenCanvas::PrefEnabledOnWorkerThread(JSContext* aCx, JSObject* aObj)
     353             : {
     354          11 :   if (NS_IsMainThread()) {
     355           0 :     return true;
     356             :   }
     357             : 
     358          11 :   return PrefEnabled(aCx, aObj);
     359             : }
     360             : 
     361           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(OffscreenCanvas, DOMEventTargetHelper, mCurrentContext)
     362             : 
     363           0 : NS_IMPL_ADDREF_INHERITED(OffscreenCanvas, DOMEventTargetHelper)
     364           0 : NS_IMPL_RELEASE_INHERITED(OffscreenCanvas, DOMEventTargetHelper)
     365             : 
     366           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(OffscreenCanvas)
     367           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     368           0 : NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
     369             : 
     370             : } // namespace dom
     371             : } // namespace mozilla

Generated by: LCOV version 1.13