LCOV - code coverage report
Current view: top level - image - imgTools.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 3 139 2.2 %
Date: 2017-07-14 16:53:18 Functions: 4 15 26.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  *
       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 "imgTools.h"
       8             : 
       9             : #include "gfxUtils.h"
      10             : #include "mozilla/gfx/2D.h"
      11             : #include "mozilla/gfx/Logging.h"
      12             : #include "mozilla/RefPtr.h"
      13             : #include "nsCOMPtr.h"
      14             : #include "nsIDocument.h"
      15             : #include "nsIDOMDocument.h"
      16             : #include "nsError.h"
      17             : #include "imgLoader.h"
      18             : #include "imgICache.h"
      19             : #include "imgIContainer.h"
      20             : #include "imgIEncoder.h"
      21             : #include "nsStreamUtils.h"
      22             : #include "nsContentUtils.h"
      23             : #include "ImageFactory.h"
      24             : #include "Image.h"
      25             : #include "ScriptedNotificationObserver.h"
      26             : #include "imgIScriptedNotificationObserver.h"
      27             : #include "gfxPlatform.h"
      28             : 
      29             : using namespace mozilla::gfx;
      30             : 
      31             : namespace mozilla {
      32             : namespace image {
      33             : /* ========== imgITools implementation ========== */
      34             : 
      35             : 
      36             : 
      37          24 : NS_IMPL_ISUPPORTS(imgTools, imgITools)
      38             : 
      39           3 : imgTools::imgTools()
      40             : {
      41             :   /* member initializers and constructor code */
      42           3 : }
      43             : 
      44           0 : imgTools::~imgTools()
      45             : {
      46             :   /* destructor code */
      47           0 : }
      48             : 
      49             : NS_IMETHODIMP
      50           0 : imgTools::DecodeImageData(nsIInputStream* aInStr,
      51             :                           const nsACString& aMimeType,
      52             :                           imgIContainer** aContainer)
      53             : {
      54           0 :   MOZ_ASSERT(*aContainer == nullptr,
      55             :              "Cannot provide an existing image container to DecodeImageData");
      56             : 
      57           0 :   return DecodeImage(aInStr, aMimeType, aContainer);
      58             : }
      59             : 
      60             : NS_IMETHODIMP
      61           0 : imgTools::DecodeImage(nsIInputStream* aInStr,
      62             :                       const nsACString& aMimeType,
      63             :                       imgIContainer** aContainer)
      64             : {
      65           0 :   MOZ_ASSERT(NS_IsMainThread());
      66             : 
      67             :   nsresult rv;
      68             : 
      69           0 :   NS_ENSURE_ARG_POINTER(aInStr);
      70             : 
      71             :   // Create a new image container to hold the decoded data.
      72           0 :   nsAutoCString mimeType(aMimeType);
      73           0 :   RefPtr<image::Image> image = ImageFactory::CreateAnonymousImage(mimeType);
      74           0 :   RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
      75             : 
      76           0 :   if (image->HasError()) {
      77           0 :     return NS_ERROR_FAILURE;
      78             :   }
      79             : 
      80             :   // Prepare the input stream.
      81           0 :   nsCOMPtr<nsIInputStream> inStream = aInStr;
      82           0 :   if (!NS_InputStreamIsBuffered(aInStr)) {
      83           0 :     nsCOMPtr<nsIInputStream> bufStream;
      84           0 :     rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream), aInStr, 1024);
      85           0 :     if (NS_SUCCEEDED(rv)) {
      86           0 :       inStream = bufStream;
      87             :     }
      88             :   }
      89             : 
      90             :   // Figure out how much data we've been passed.
      91             :   uint64_t length;
      92           0 :   rv = inStream->Available(&length);
      93           0 :   NS_ENSURE_SUCCESS(rv, rv);
      94           0 :   NS_ENSURE_TRUE(length <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
      95             : 
      96             :   // Send the source data to the Image.
      97           0 :   rv = image->OnImageDataAvailable(nullptr, nullptr, inStream, 0,
      98           0 :                                    uint32_t(length));
      99           0 :   NS_ENSURE_SUCCESS(rv, rv);
     100             : 
     101             :   // Let the Image know we've sent all the data.
     102           0 :   rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
     103           0 :   tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
     104           0 :   NS_ENSURE_SUCCESS(rv, rv);
     105             : 
     106             :   // All done.
     107           0 :   NS_ADDREF(*aContainer = image.get());
     108           0 :   return NS_OK;
     109             : }
     110             : 
     111             : /**
     112             :  * This takes a DataSourceSurface rather than a SourceSurface because some
     113             :  * of the callers have a DataSourceSurface and we don't want to call
     114             :  * GetDataSurface on such surfaces since that may incure a conversion to
     115             :  * SurfaceType::DATA which we don't need.
     116             :  */
     117             : static nsresult
     118           0 : EncodeImageData(DataSourceSurface* aDataSurface,
     119             :                 const nsACString& aMimeType,
     120             :                 const nsAString& aOutputOptions,
     121             :                 nsIInputStream** aStream)
     122             : {
     123           0 :   MOZ_ASSERT(aDataSurface->GetFormat() ==  SurfaceFormat::B8G8R8A8,
     124             :              "We're assuming B8G8R8A8");
     125             : 
     126             :   // Get an image encoder for the media type
     127             :   nsAutoCString encoderCID(
     128           0 :     NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type=") + aMimeType);
     129             : 
     130           0 :   nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get());
     131           0 :   if (!encoder) {
     132           0 :     return NS_IMAGELIB_ERROR_NO_ENCODER;
     133             :   }
     134             : 
     135             :   DataSourceSurface::MappedSurface map;
     136           0 :   if (!aDataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
     137           0 :     return NS_ERROR_FAILURE;
     138             :   }
     139             : 
     140           0 :   IntSize size = aDataSurface->GetSize();
     141           0 :   uint32_t dataLength = map.mStride * size.height;
     142             : 
     143             :   // Encode the bitmap
     144           0 :   nsresult rv = encoder->InitFromData(map.mData,
     145             :                                       dataLength,
     146           0 :                                       size.width,
     147           0 :                                       size.height,
     148           0 :                                       map.mStride,
     149             :                                       imgIEncoder::INPUT_FORMAT_HOSTARGB,
     150           0 :                                       aOutputOptions);
     151           0 :   aDataSurface->Unmap();
     152           0 :   NS_ENSURE_SUCCESS(rv, rv);
     153             : 
     154           0 :   encoder.forget(aStream);
     155           0 :   return NS_OK;
     156             : }
     157             : 
     158             : NS_IMETHODIMP
     159           0 : imgTools::EncodeImage(imgIContainer* aContainer,
     160             :                       const nsACString& aMimeType,
     161             :                       const nsAString& aOutputOptions,
     162             :                       nsIInputStream** aStream)
     163             : {
     164             :   // Use frame 0 from the image container.
     165             :   RefPtr<SourceSurface> frame =
     166           0 :     aContainer->GetFrame(imgIContainer::FRAME_FIRST,
     167           0 :                          imgIContainer::FLAG_SYNC_DECODE);
     168           0 :   NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
     169             : 
     170           0 :   RefPtr<DataSourceSurface> dataSurface;
     171             : 
     172           0 :   if (frame->GetFormat() == SurfaceFormat::B8G8R8A8) {
     173           0 :     dataSurface = frame->GetDataSurface();
     174             :   } else {
     175             :     // Convert format to SurfaceFormat::B8G8R8A8
     176             :     dataSurface = gfxUtils::
     177           0 :       CopySurfaceToDataSourceSurfaceWithFormat(frame,
     178           0 :                                                SurfaceFormat::B8G8R8A8);
     179             :   }
     180             : 
     181           0 :   NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
     182             : 
     183           0 :   return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
     184             : }
     185             : 
     186             : NS_IMETHODIMP
     187           0 : imgTools::EncodeScaledImage(imgIContainer* aContainer,
     188             :                             const nsACString& aMimeType,
     189             :                             int32_t aScaledWidth,
     190             :                             int32_t aScaledHeight,
     191             :                             const nsAString& aOutputOptions,
     192             :                             nsIInputStream** aStream)
     193             : {
     194           0 :   NS_ENSURE_ARG(aScaledWidth >= 0 && aScaledHeight >= 0);
     195             : 
     196             :   // If no scaled size is specified, we'll just encode the image at its
     197             :   // original size (no scaling).
     198           0 :   if (aScaledWidth == 0 && aScaledHeight == 0) {
     199           0 :     return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
     200             :   }
     201             : 
     202             :   // Retrieve the image's size.
     203           0 :   int32_t imageWidth = 0;
     204           0 :   int32_t imageHeight = 0;
     205           0 :   aContainer->GetWidth(&imageWidth);
     206           0 :   aContainer->GetHeight(&imageHeight);
     207             : 
     208             :   // If the given width or height is zero we'll replace it with the image's
     209             :   // original dimensions.
     210             :   IntSize scaledSize(aScaledWidth == 0 ? imageWidth : aScaledWidth,
     211           0 :                      aScaledHeight == 0 ? imageHeight : aScaledHeight);
     212             : 
     213             :   // Use frame 0 from the image container.
     214             :   RefPtr<SourceSurface> frame =
     215           0 :     aContainer->GetFrameAtSize(scaledSize,
     216             :                                imgIContainer::FRAME_FIRST,
     217             :                                imgIContainer::FLAG_HIGH_QUALITY_SCALING |
     218           0 :                                imgIContainer::FLAG_SYNC_DECODE);
     219           0 :   NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
     220             : 
     221             :   RefPtr<DataSourceSurface> dataSurface =
     222           0 :     Factory::CreateDataSourceSurface(scaledSize, SurfaceFormat::B8G8R8A8);
     223           0 :   if (NS_WARN_IF(!dataSurface)) {
     224           0 :     return NS_ERROR_FAILURE;
     225             :   }
     226             : 
     227             :   DataSourceSurface::MappedSurface map;
     228           0 :   if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
     229           0 :     return NS_ERROR_FAILURE;
     230             :   }
     231             : 
     232             :   RefPtr<DrawTarget> dt =
     233           0 :     Factory::CreateDrawTargetForData(BackendType::CAIRO,
     234             :                                      map.mData,
     235           0 :                                      dataSurface->GetSize(),
     236             :                                      map.mStride,
     237           0 :                                      SurfaceFormat::B8G8R8A8);
     238           0 :   if (!dt) {
     239           0 :     gfxWarning() << "imgTools::EncodeImage failed in CreateDrawTargetForData";
     240           0 :     return NS_ERROR_OUT_OF_MEMORY;
     241             :   }
     242             : 
     243           0 :   IntSize frameSize = frame->GetSize();
     244           0 :   dt->DrawSurface(frame,
     245           0 :                   Rect(0, 0, scaledSize.width, scaledSize.height),
     246           0 :                   Rect(0, 0, frameSize.width, frameSize.height),
     247           0 :                   DrawSurfaceOptions(),
     248           0 :                   DrawOptions(1.0f, CompositionOp::OP_SOURCE));
     249             : 
     250           0 :   dataSurface->Unmap();
     251             : 
     252           0 :   return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
     253             : }
     254             : 
     255             : NS_IMETHODIMP
     256           0 : imgTools::EncodeCroppedImage(imgIContainer* aContainer,
     257             :                              const nsACString& aMimeType,
     258             :                              int32_t aOffsetX,
     259             :                              int32_t aOffsetY,
     260             :                              int32_t aWidth,
     261             :                              int32_t aHeight,
     262             :                              const nsAString& aOutputOptions,
     263             :                              nsIInputStream** aStream)
     264             : {
     265           0 :   NS_ENSURE_ARG(aOffsetX >= 0 && aOffsetY >= 0 && aWidth >= 0 && aHeight >= 0);
     266             : 
     267             :   // Offsets must be zero when no width and height are given or else we're out
     268             :   // of bounds.
     269           0 :   NS_ENSURE_ARG(aWidth + aHeight > 0 || aOffsetX + aOffsetY == 0);
     270             : 
     271             :   // If no size is specified then we'll preserve the image's original dimensions
     272             :   // and don't need to crop.
     273           0 :   if (aWidth == 0 && aHeight == 0) {
     274           0 :     return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
     275             :   }
     276             : 
     277             :   // Use frame 0 from the image container.
     278             :   RefPtr<SourceSurface> frame =
     279           0 :     aContainer->GetFrame(imgIContainer::FRAME_FIRST,
     280           0 :                          imgIContainer::FLAG_SYNC_DECODE);
     281           0 :   NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
     282             : 
     283           0 :   int32_t frameWidth = frame->GetSize().width;
     284           0 :   int32_t frameHeight = frame->GetSize().height;
     285             : 
     286             :   // If the given width or height is zero we'll replace it with the image's
     287             :   // original dimensions.
     288           0 :   if (aWidth == 0) {
     289           0 :     aWidth = frameWidth;
     290           0 :   } else if (aHeight == 0) {
     291           0 :     aHeight = frameHeight;
     292             :   }
     293             : 
     294             :   // Check that the given crop rectangle is within image bounds.
     295           0 :   NS_ENSURE_ARG(frameWidth >= aOffsetX + aWidth &&
     296             :                 frameHeight >= aOffsetY + aHeight);
     297             : 
     298             :   RefPtr<DataSourceSurface> dataSurface =
     299           0 :     Factory::CreateDataSourceSurface(IntSize(aWidth, aHeight),
     300             :                                      SurfaceFormat::B8G8R8A8,
     301           0 :                                      /* aZero = */ true);
     302           0 :   if (NS_WARN_IF(!dataSurface)) {
     303           0 :     return NS_ERROR_FAILURE;
     304             :   }
     305             : 
     306             :   DataSourceSurface::MappedSurface map;
     307           0 :   if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
     308           0 :     return NS_ERROR_FAILURE;
     309             :   }
     310             : 
     311             :   RefPtr<DrawTarget> dt =
     312           0 :     Factory::CreateDrawTargetForData(BackendType::CAIRO,
     313             :                                      map.mData,
     314           0 :                                      dataSurface->GetSize(),
     315             :                                      map.mStride,
     316           0 :                                      SurfaceFormat::B8G8R8A8);
     317           0 :   if (!dt) {
     318           0 :     gfxWarning() <<
     319           0 :       "imgTools::EncodeCroppedImage failed in CreateDrawTargetForData";
     320           0 :     return NS_ERROR_OUT_OF_MEMORY;
     321             :   }
     322           0 :   dt->CopySurface(frame,
     323           0 :                   IntRect(aOffsetX, aOffsetY, aWidth, aHeight),
     324           0 :                   IntPoint(0, 0));
     325             : 
     326           0 :   dataSurface->Unmap();
     327             : 
     328           0 :   return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
     329             : }
     330             : 
     331             : NS_IMETHODIMP
     332           0 : imgTools::CreateScriptedObserver(imgIScriptedNotificationObserver* aInner,
     333             :                                  imgINotificationObserver** aObserver)
     334             : {
     335           0 :   NS_ADDREF(*aObserver = new ScriptedNotificationObserver(aInner));
     336           0 :   return NS_OK;
     337             : }
     338             : 
     339             : NS_IMETHODIMP
     340           0 : imgTools::GetImgLoaderForDocument(nsIDOMDocument* aDoc, imgILoader** aLoader)
     341             : {
     342           0 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
     343           0 :   NS_IF_ADDREF(*aLoader = nsContentUtils::GetImgLoaderForDocument(doc));
     344           0 :   return NS_OK;
     345             : }
     346             : 
     347             : NS_IMETHODIMP
     348           0 : imgTools::GetImgCacheForDocument(nsIDOMDocument* aDoc, imgICache** aCache)
     349             : {
     350           0 :   nsCOMPtr<imgILoader> loader;
     351           0 :   nsresult rv = GetImgLoaderForDocument(aDoc, getter_AddRefs(loader));
     352           0 :   NS_ENSURE_SUCCESS(rv, rv);
     353           0 :   return CallQueryInterface(loader, aCache);
     354             : }
     355             : 
     356             : } // namespace image
     357             : } // namespace mozilla

Generated by: LCOV version 1.13