LCOV - code coverage report
Current view: top level - image - ImageFactory.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 71 109 65.1 %
Date: 2017-07-14 16:53:18 Functions: 8 11 72.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 "ImageFactory.h"
       8             : 
       9             : #include <algorithm>
      10             : 
      11             : #include "mozilla/Likely.h"
      12             : 
      13             : #include "nsIHttpChannel.h"
      14             : #include "nsIFileChannel.h"
      15             : #include "nsIFile.h"
      16             : #include "nsMimeTypes.h"
      17             : #include "nsIRequest.h"
      18             : 
      19             : #include "MultipartImage.h"
      20             : #include "RasterImage.h"
      21             : #include "VectorImage.h"
      22             : #include "Image.h"
      23             : #include "nsMediaFragmentURIParser.h"
      24             : #include "nsContentUtils.h"
      25             : #include "nsIScriptSecurityManager.h"
      26             : 
      27             : #include "gfxPrefs.h"
      28             : 
      29             : namespace mozilla {
      30             : namespace image {
      31             : 
      32             : /*static*/ void
      33           3 : ImageFactory::Initialize()
      34           3 : { }
      35             : 
      36             : static uint32_t
      37          41 : ComputeImageFlags(ImageURL* uri, const nsCString& aMimeType, bool isMultiPart)
      38             : {
      39             :   nsresult rv;
      40             : 
      41             :   // We default to the static globals.
      42          41 :   bool isDiscardable = gfxPrefs::ImageMemDiscardable();
      43          41 :   bool doDecodeImmediately = gfxPrefs::ImageDecodeImmediatelyEnabled();
      44             : 
      45             :   // We want UI to be as snappy as possible and not to flicker. Disable
      46             :   // discarding for chrome URLS.
      47          41 :   bool isChrome = false;
      48          41 :   rv = uri->SchemeIs("chrome", &isChrome);
      49          41 :   if (NS_SUCCEEDED(rv) && isChrome) {
      50          40 :     isDiscardable = false;
      51             :   }
      52             : 
      53             :   // We don't want resources like the "loading" icon to be discardable either.
      54          41 :   bool isResource = false;
      55          41 :   rv = uri->SchemeIs("resource", &isResource);
      56          41 :   if (NS_SUCCEEDED(rv) && isResource) {
      57           0 :     isDiscardable = false;
      58             :   }
      59             : 
      60             :   // For multipart/x-mixed-replace, we basically want a direct channel to the
      61             :   // decoder. Disable everything for this case.
      62          41 :   if (isMultiPart) {
      63           0 :     isDiscardable = false;
      64             :   }
      65             : 
      66             :   // We have all the information we need.
      67          41 :   uint32_t imageFlags = Image::INIT_FLAG_NONE;
      68          41 :   if (isDiscardable) {
      69           1 :     imageFlags |= Image::INIT_FLAG_DISCARDABLE;
      70             :   }
      71          41 :   if (doDecodeImmediately) {
      72           0 :     imageFlags |= Image::INIT_FLAG_DECODE_IMMEDIATELY;
      73             :   }
      74          41 :   if (isMultiPart) {
      75           0 :     imageFlags |= Image::INIT_FLAG_TRANSIENT;
      76             :   }
      77             : 
      78          41 :   return imageFlags;
      79             : }
      80             : 
      81             : /* static */ already_AddRefed<Image>
      82          41 : ImageFactory::CreateImage(nsIRequest* aRequest,
      83             :                           ProgressTracker* aProgressTracker,
      84             :                           const nsCString& aMimeType,
      85             :                           ImageURL* aURI,
      86             :                           bool aIsMultiPart,
      87             :                           uint32_t aInnerWindowId)
      88             : {
      89          41 :   MOZ_ASSERT(gfxPrefs::SingletonExists(),
      90             :              "Pref observers should have been initialized already");
      91             : 
      92             :   // Compute the image's initialization flags.
      93          41 :   uint32_t imageFlags = ComputeImageFlags(aURI, aMimeType, aIsMultiPart);
      94             : 
      95             : #ifdef DEBUG
      96             :   // Record the image load for startup performance testing.
      97          41 :   if (NS_IsMainThread()) {
      98          80 :     nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
      99          40 :     NS_WARNING_ASSERTION(obs, "Can't get an observer service handle");
     100          40 :     if (obs) {
     101          80 :       nsAutoCString spec;
     102          40 :       aURI->GetSpec(spec);
     103          40 :       obs->NotifyObservers(nullptr, "image-loading", NS_ConvertUTF8toUTF16(spec).get());
     104             :     }
     105             :   }
     106             : #endif
     107             : 
     108             :   // Select the type of image to create based on MIME type.
     109          41 :   if (aMimeType.EqualsLiteral(IMAGE_SVG_XML)) {
     110             :     return CreateVectorImage(aRequest, aProgressTracker, aMimeType,
     111          21 :                              aURI, imageFlags, aInnerWindowId);
     112             :   } else {
     113             :     return CreateRasterImage(aRequest, aProgressTracker, aMimeType,
     114          20 :                              aURI, imageFlags, aInnerWindowId);
     115             :   }
     116             : }
     117             : 
     118             : // Marks an image as having an error before returning it.
     119             : template <typename T>
     120             : static already_AddRefed<Image>
     121           1 : BadImage(const char* aMessage, RefPtr<T>& aImage)
     122             : {
     123           1 :   aImage->SetHasError();
     124           1 :   return aImage.forget();
     125             : }
     126             : 
     127             : /* static */ already_AddRefed<Image>
     128           0 : ImageFactory::CreateAnonymousImage(const nsCString& aMimeType)
     129             : {
     130             :   nsresult rv;
     131             : 
     132           0 :   RefPtr<RasterImage> newImage = new RasterImage();
     133             : 
     134           0 :   RefPtr<ProgressTracker> newTracker = new ProgressTracker();
     135           0 :   newTracker->SetImage(newImage);
     136           0 :   newImage->SetProgressTracker(newTracker);
     137             : 
     138           0 :   rv = newImage->Init(aMimeType.get(), Image::INIT_FLAG_SYNC_LOAD);
     139           0 :   if (NS_FAILED(rv)) {
     140           0 :     return BadImage("RasterImage::Init failed", newImage);
     141             :   }
     142             : 
     143           0 :   return newImage.forget();
     144             : }
     145             : 
     146             : /* static */ already_AddRefed<MultipartImage>
     147           0 : ImageFactory::CreateMultipartImage(Image* aFirstPart,
     148             :                                    ProgressTracker* aProgressTracker)
     149             : {
     150           0 :   MOZ_ASSERT(aFirstPart);
     151           0 :   MOZ_ASSERT(aProgressTracker);
     152             : 
     153           0 :   RefPtr<MultipartImage> newImage = new MultipartImage(aFirstPart);
     154           0 :   aProgressTracker->SetImage(newImage);
     155           0 :   newImage->SetProgressTracker(aProgressTracker);
     156             : 
     157           0 :   newImage->Init();
     158             : 
     159           0 :   return newImage.forget();
     160             : }
     161             : 
     162             : int32_t
     163          19 : SaturateToInt32(int64_t val)
     164             : {
     165          19 :   if (val > INT_MAX) {
     166           0 :     return INT_MAX;
     167             :   }
     168          19 :   if (val < INT_MIN) {
     169           0 :     return INT_MIN;
     170             :   }
     171             : 
     172          19 :   return static_cast<int32_t>(val);
     173             : }
     174             : 
     175             : uint32_t
     176          19 : GetContentSize(nsIRequest* aRequest)
     177             : {
     178          38 :   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
     179          19 :   if (channel) {
     180             :     int64_t size;
     181          19 :     nsresult rv = channel->GetContentLength(&size);
     182          19 :     if (NS_SUCCEEDED(rv)) {
     183          19 :       return std::max(SaturateToInt32(size), 0);
     184             :     }
     185             :   }
     186             : 
     187             :   // Use the file size as a size hint for file channels.
     188           0 :   nsCOMPtr<nsIFileChannel> fileChannel(do_QueryInterface(aRequest));
     189           0 :   if (fileChannel) {
     190           0 :     nsCOMPtr<nsIFile> file;
     191           0 :     nsresult rv = fileChannel->GetFile(getter_AddRefs(file));
     192           0 :     if (NS_SUCCEEDED(rv)) {
     193             :       int64_t filesize;
     194           0 :       rv = file->GetFileSize(&filesize);
     195           0 :       if (NS_SUCCEEDED(rv)) {
     196           0 :         return std::max(SaturateToInt32(filesize), 0);
     197             :       }
     198             :     }
     199             :   }
     200             : 
     201             :   // Fallback - neither http nor file. We'll use dynamic allocation.
     202           0 :   return 0;
     203             : }
     204             : 
     205             : /* static */ already_AddRefed<Image>
     206          20 : ImageFactory::CreateRasterImage(nsIRequest* aRequest,
     207             :                                 ProgressTracker* aProgressTracker,
     208             :                                 const nsCString& aMimeType,
     209             :                                 ImageURL* aURI,
     210             :                                 uint32_t aImageFlags,
     211             :                                 uint32_t aInnerWindowId)
     212             : {
     213          20 :   MOZ_ASSERT(aProgressTracker);
     214             : 
     215             :   nsresult rv;
     216             : 
     217          40 :   RefPtr<RasterImage> newImage = new RasterImage(aURI);
     218          20 :   aProgressTracker->SetImage(newImage);
     219          20 :   newImage->SetProgressTracker(aProgressTracker);
     220             : 
     221          20 :   rv = newImage->Init(aMimeType.get(), aImageFlags);
     222          20 :   if (NS_FAILED(rv)) {
     223           1 :     return BadImage("RasterImage::Init failed", newImage);
     224             :   }
     225             : 
     226          19 :   newImage->SetInnerWindowID(aInnerWindowId);
     227             : 
     228          19 :   uint32_t len = GetContentSize(aRequest);
     229             : 
     230             :   // Pass anything usable on so that the RasterImage can preallocate
     231             :   // its source buffer.
     232          19 :   if (len > 0) {
     233             :     // Bound by something reasonable
     234          19 :     uint32_t sizeHint = std::min<uint32_t>(len, 20000000);
     235          19 :     rv = newImage->SetSourceSizeHint(sizeHint);
     236          19 :     if (NS_FAILED(rv)) {
     237             :       // Flush memory, try to get some back, and try again.
     238           0 :       rv = nsMemory::HeapMinimize(true);
     239           0 :       nsresult rv2 = newImage->SetSourceSizeHint(sizeHint);
     240             :       // If we've still failed at this point, things are going downhill.
     241           0 :       if (NS_FAILED(rv) || NS_FAILED(rv2)) {
     242           0 :         NS_WARNING("About to hit OOM in imagelib!");
     243             :       }
     244             :     }
     245             :   }
     246             : 
     247          19 :   return newImage.forget();
     248             : }
     249             : 
     250             : /* static */ already_AddRefed<Image>
     251          21 : ImageFactory::CreateVectorImage(nsIRequest* aRequest,
     252             :                                 ProgressTracker* aProgressTracker,
     253             :                                 const nsCString& aMimeType,
     254             :                                 ImageURL* aURI,
     255             :                                 uint32_t aImageFlags,
     256             :                                 uint32_t aInnerWindowId)
     257             : {
     258          21 :   MOZ_ASSERT(aProgressTracker);
     259             : 
     260             :   nsresult rv;
     261             : 
     262          42 :   RefPtr<VectorImage> newImage = new VectorImage(aURI);
     263          21 :   aProgressTracker->SetImage(newImage);
     264          21 :   newImage->SetProgressTracker(aProgressTracker);
     265             : 
     266          21 :   rv = newImage->Init(aMimeType.get(), aImageFlags);
     267          21 :   if (NS_FAILED(rv)) {
     268           0 :     return BadImage("VectorImage::Init failed", newImage);
     269             :   }
     270             : 
     271          21 :   newImage->SetInnerWindowID(aInnerWindowId);
     272             : 
     273          21 :   rv = newImage->OnStartRequest(aRequest, nullptr);
     274          21 :   if (NS_FAILED(rv)) {
     275           0 :     return BadImage("VectorImage::OnStartRequest failed", newImage);
     276             :   }
     277             : 
     278          21 :   return newImage.forget();
     279             : }
     280             : 
     281             : } // namespace image
     282             : } // namespace mozilla

Generated by: LCOV version 1.13