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

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "CanvasRenderingContextHelper.h"
       7             : #include "ImageBitmapRenderingContext.h"
       8             : #include "ImageEncoder.h"
       9             : #include "mozilla/dom/CanvasRenderingContext2D.h"
      10             : #include "mozilla/Telemetry.h"
      11             : #include "mozilla/UniquePtr.h"
      12             : #include "nsContentUtils.h"
      13             : #include "nsDOMJSUtils.h"
      14             : #include "nsIScriptContext.h"
      15             : #include "nsJSUtils.h"
      16             : #include "WebGL1Context.h"
      17             : #include "WebGL2Context.h"
      18             : 
      19             : namespace mozilla {
      20             : namespace dom {
      21             : 
      22             : void
      23           0 : CanvasRenderingContextHelper::ToBlob(JSContext* aCx,
      24             :                                      nsIGlobalObject* aGlobal,
      25             :                                      BlobCallback& aCallback,
      26             :                                      const nsAString& aType,
      27             :                                      JS::Handle<JS::Value> aParams,
      28             :                                      ErrorResult& aRv)
      29             : {
      30             :   // Encoder callback when encoding is complete.
      31           0 :   class EncodeCallback : public EncodeCompleteCallback
      32             :   {
      33             :   public:
      34           0 :     EncodeCallback(nsIGlobalObject* aGlobal, BlobCallback* aCallback)
      35           0 :       : mGlobal(aGlobal)
      36           0 :       , mBlobCallback(aCallback) {}
      37             : 
      38             :     // This is called on main thread.
      39           0 :     nsresult ReceiveBlob(already_AddRefed<Blob> aBlob)
      40             :     {
      41           0 :       RefPtr<Blob> blob = aBlob;
      42             : 
      43           0 :       ErrorResult rv;
      44           0 :       uint64_t size = blob->GetSize(rv);
      45           0 :       if (rv.Failed()) {
      46           0 :         rv.SuppressException();
      47             :       } else {
      48           0 :         AutoJSAPI jsapi;
      49           0 :         if (jsapi.Init(mGlobal)) {
      50           0 :           JS_updateMallocCounter(jsapi.cx(), size);
      51             :         }
      52             :       }
      53             : 
      54           0 :       RefPtr<Blob> newBlob = Blob::Create(mGlobal, blob->Impl());
      55             : 
      56           0 :       mBlobCallback->Call(newBlob, rv);
      57             : 
      58           0 :       mGlobal = nullptr;
      59           0 :       mBlobCallback = nullptr;
      60             : 
      61           0 :       return rv.StealNSResult();
      62             :     }
      63             : 
      64             :     nsCOMPtr<nsIGlobalObject> mGlobal;
      65             :     RefPtr<BlobCallback> mBlobCallback;
      66             :   };
      67             : 
      68             :   RefPtr<EncodeCompleteCallback> callback =
      69           0 :     new EncodeCallback(aGlobal, &aCallback);
      70             : 
      71           0 :   ToBlob(aCx, aGlobal, callback, aType, aParams, aRv);
      72           0 : }
      73             : 
      74             : void
      75           0 : CanvasRenderingContextHelper::ToBlob(JSContext* aCx,
      76             :                                      nsIGlobalObject* aGlobal,
      77             :                                      EncodeCompleteCallback* aCallback,
      78             :                                      const nsAString& aType,
      79             :                                      JS::Handle<JS::Value> aParams,
      80             :                                      ErrorResult& aRv)
      81             : {
      82           0 :   nsAutoString type;
      83           0 :   nsContentUtils::ASCIIToLower(aType, type);
      84             : 
      85           0 :   nsAutoString params;
      86             :   bool usingCustomParseOptions;
      87           0 :   aRv = ParseParams(aCx, type, aParams, params, &usingCustomParseOptions);
      88           0 :   if (aRv.Failed()) {
      89           0 :     return;
      90             :   }
      91             : 
      92           0 :   if (mCurrentContext) {
      93             :     // We disallow canvases of width or height zero, and set them to 1, so
      94             :     // we will have a discrepancy with the sizes of the canvas and the context.
      95             :     // That discrepancy is OK, the rest are not.
      96           0 :     nsIntSize elementSize = GetWidthHeight();
      97           0 :     if ((elementSize.width != mCurrentContext->GetWidth() &&
      98           0 :          (elementSize.width != 0 || mCurrentContext->GetWidth() != 1)) ||
      99           0 :         (elementSize.height != mCurrentContext->GetHeight() &&
     100           0 :          (elementSize.height != 0 || mCurrentContext->GetHeight() != 1))) {
     101           0 :       aRv.Throw(NS_ERROR_FAILURE);
     102           0 :       return;
     103             :     }
     104             :   }
     105             : 
     106           0 :   UniquePtr<uint8_t[]> imageBuffer;
     107           0 :   int32_t format = 0;
     108           0 :   if (mCurrentContext) {
     109           0 :     imageBuffer = mCurrentContext->GetImageBuffer(&format);
     110             :   }
     111             : 
     112           0 :   RefPtr<EncodeCompleteCallback> callback = aCallback;
     113             : 
     114           0 :   aRv = ImageEncoder::ExtractDataAsync(type,
     115             :                                        params,
     116             :                                        usingCustomParseOptions,
     117           0 :                                        Move(imageBuffer),
     118             :                                        format,
     119           0 :                                        GetWidthHeight(),
     120           0 :                                        callback);
     121             : }
     122             : 
     123             : already_AddRefed<nsICanvasRenderingContextInternal>
     124           0 : CanvasRenderingContextHelper::CreateContext(CanvasContextType aContextType)
     125             : {
     126           0 :   return CreateContextHelper(aContextType, layers::LayersBackend::LAYERS_NONE);
     127             : }
     128             : 
     129             : already_AddRefed<nsICanvasRenderingContextInternal>
     130           0 : CanvasRenderingContextHelper::CreateContextHelper(CanvasContextType aContextType,
     131             :                                                   layers::LayersBackend aCompositorBackend)
     132             : {
     133           0 :   MOZ_ASSERT(aContextType != CanvasContextType::NoContext);
     134           0 :   RefPtr<nsICanvasRenderingContextInternal> ret;
     135             : 
     136           0 :   switch (aContextType) {
     137             :   case CanvasContextType::NoContext:
     138           0 :     break;
     139             : 
     140             :   case CanvasContextType::Canvas2D:
     141           0 :     Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1);
     142           0 :     ret = new CanvasRenderingContext2D(aCompositorBackend);
     143           0 :     break;
     144             : 
     145             :   case CanvasContextType::WebGL1:
     146           0 :     Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
     147             : 
     148           0 :     ret = WebGL1Context::Create();
     149           0 :     if (!ret)
     150           0 :       return nullptr;
     151             : 
     152           0 :     break;
     153             : 
     154             :   case CanvasContextType::WebGL2:
     155           0 :     Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
     156             : 
     157           0 :     ret = WebGL2Context::Create();
     158           0 :     if (!ret)
     159           0 :       return nullptr;
     160             : 
     161           0 :     break;
     162             : 
     163             :   case CanvasContextType::ImageBitmap:
     164           0 :     ret = new ImageBitmapRenderingContext();
     165             : 
     166           0 :     break;
     167             :   }
     168           0 :   MOZ_ASSERT(ret);
     169             : 
     170           0 :   return ret.forget();
     171             : }
     172             : 
     173             : already_AddRefed<nsISupports>
     174           0 : CanvasRenderingContextHelper::GetContext(JSContext* aCx,
     175             :                                          const nsAString& aContextId,
     176             :                                          JS::Handle<JS::Value> aContextOptions,
     177             :                                          ErrorResult& aRv)
     178             : {
     179             :   CanvasContextType contextType;
     180           0 :   if (!CanvasUtils::GetCanvasContextType(aContextId, &contextType))
     181           0 :     return nullptr;
     182             : 
     183           0 :   if (!mCurrentContext) {
     184             :     // This canvas doesn't have a context yet.
     185           0 :     RefPtr<nsICanvasRenderingContextInternal> context;
     186           0 :     context = CreateContext(contextType);
     187           0 :     if (!context) {
     188           0 :       return nullptr;
     189             :     }
     190             : 
     191             :     // Ensure that the context participates in CC.  Note that returning a
     192             :     // CC participant from QI doesn't addref.
     193           0 :     nsXPCOMCycleCollectionParticipant* cp = nullptr;
     194           0 :     CallQueryInterface(context, &cp);
     195           0 :     if (!cp) {
     196           0 :       aRv.Throw(NS_ERROR_FAILURE);
     197           0 :       return nullptr;
     198             :     }
     199             : 
     200           0 :     mCurrentContext = context.forget();
     201           0 :     mCurrentContextType = contextType;
     202             : 
     203           0 :     nsresult rv = UpdateContext(aCx, aContextOptions, aRv);
     204           0 :     if (NS_FAILED(rv)) {
     205             :       // See bug 645792 and bug 1215072.
     206             :       // We want to throw only if dictionary initialization fails,
     207             :       // so only in case aRv has been set to some error value.
     208           0 :       if (contextType == CanvasContextType::WebGL1)
     209           0 :         Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_SUCCESS, 0);
     210           0 :       else if (contextType == CanvasContextType::WebGL2)
     211           0 :         Telemetry::Accumulate(Telemetry::CANVAS_WEBGL2_SUCCESS, 0);
     212           0 :       return nullptr;
     213             :     }
     214           0 :     if (contextType == CanvasContextType::WebGL1)
     215           0 :       Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_SUCCESS, 1);
     216           0 :     else if (contextType == CanvasContextType::WebGL2)
     217           0 :       Telemetry::Accumulate(Telemetry::CANVAS_WEBGL2_SUCCESS, 1);
     218             :   } else {
     219             :     // We already have a context of some type.
     220           0 :     if (contextType != mCurrentContextType)
     221           0 :       return nullptr;
     222             :   }
     223             : 
     224           0 :   nsCOMPtr<nsICanvasRenderingContextInternal> context = mCurrentContext;
     225           0 :   return context.forget();
     226             : }
     227             : 
     228             : nsresult
     229           0 : CanvasRenderingContextHelper::UpdateContext(JSContext* aCx,
     230             :                                             JS::Handle<JS::Value> aNewContextOptions,
     231             :                                             ErrorResult& aRvForDictionaryInit)
     232             : {
     233           0 :   if (!mCurrentContext)
     234           0 :     return NS_OK;
     235             : 
     236           0 :   nsIntSize sz = GetWidthHeight();
     237             : 
     238           0 :   nsCOMPtr<nsICanvasRenderingContextInternal> currentContext = mCurrentContext;
     239             : 
     240           0 :   currentContext->SetIsOpaque(GetOpaqueAttr());
     241             : 
     242           0 :   nsresult rv = currentContext->SetContextOptions(aCx, aNewContextOptions,
     243           0 :                                          aRvForDictionaryInit);
     244           0 :   if (NS_FAILED(rv)) {
     245           0 :     mCurrentContext = nullptr;
     246           0 :     return rv;
     247             :   }
     248             : 
     249           0 :   rv = currentContext->SetDimensions(sz.width, sz.height);
     250           0 :   if (NS_FAILED(rv)) {
     251           0 :     mCurrentContext = nullptr;
     252             :   }
     253             : 
     254           0 :   return rv;
     255             : }
     256             : 
     257             : nsresult
     258           0 : CanvasRenderingContextHelper::ParseParams(JSContext* aCx,
     259             :                                           const nsAString& aType,
     260             :                                           const JS::Value& aEncoderOptions,
     261             :                                           nsAString& outParams,
     262             :                                           bool* const outUsingCustomParseOptions)
     263             : {
     264             :   // Quality parameter is only valid for the image/jpeg MIME type
     265           0 :   if (aType.EqualsLiteral("image/jpeg")) {
     266           0 :     if (aEncoderOptions.isNumber()) {
     267           0 :       double quality = aEncoderOptions.toNumber();
     268             :       // Quality must be between 0.0 and 1.0, inclusive
     269           0 :       if (quality >= 0.0 && quality <= 1.0) {
     270           0 :         outParams.AppendLiteral("quality=");
     271           0 :         outParams.AppendInt(NS_lround(quality * 100.0));
     272             :       }
     273             :     }
     274             :   }
     275             : 
     276             :   // If we haven't parsed the aParams check for proprietary options.
     277             :   // The proprietary option -moz-parse-options will take a image lib encoder
     278             :   // parse options string as is and pass it to the encoder.
     279           0 :   *outUsingCustomParseOptions = false;
     280           0 :   if (outParams.Length() == 0 && aEncoderOptions.isString()) {
     281           0 :     NS_NAMED_LITERAL_STRING(mozParseOptions, "-moz-parse-options:");
     282           0 :     nsAutoJSString paramString;
     283           0 :     if (!paramString.init(aCx, aEncoderOptions.toString())) {
     284           0 :       return NS_ERROR_FAILURE;
     285             :     }
     286           0 :     if (StringBeginsWith(paramString, mozParseOptions)) {
     287             :       nsDependentSubstring parseOptions = Substring(paramString,
     288             :                                                     mozParseOptions.Length(),
     289           0 :                                                     paramString.Length() -
     290           0 :                                                     mozParseOptions.Length());
     291           0 :       outParams.Append(parseOptions);
     292           0 :       *outUsingCustomParseOptions = true;
     293             :     }
     294             :   }
     295             : 
     296           0 :   return NS_OK;
     297             : }
     298             : 
     299             : } // namespace dom
     300             : } // namespace mozilla

Generated by: LCOV version 1.13