tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

FetchDecodedImage.cpp (4421B)


      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 "FetchDecodedImage.h"
      8 
      9 #include "imgINotificationObserver.h"
     10 #include "imgITools.h"
     11 #include "nsIChannel.h"
     12 #include "nsNetUtil.h"
     13 #include "nsServiceManagerUtils.h"
     14 
     15 namespace mozilla::image {
     16 
     17 namespace {
     18 
     19 class FetchDecodedImageHelper;
     20 
     21 MOZ_RUNINIT
     22 HashSet<RefPtr<FetchDecodedImageHelper>,
     23        PointerHasher<FetchDecodedImageHelper*>>
     24    gDecodeRequests;
     25 
     26 class FetchDecodedImageHelper : public imgIContainerCallback,
     27                                public imgINotificationObserver {
     28 public:
     29  NS_DECL_ISUPPORTS
     30 
     31  explicit FetchDecodedImageHelper(
     32      gfx::IntSize aSize, RefPtr<FetchDecodedImagePromise::Private> aPromise)
     33      : mSize(aSize), mPromise(aPromise) {
     34    // Let's make sure we are alive until the request completes
     35    MOZ_ALWAYS_TRUE(gDecodeRequests.putNew(this));
     36  }
     37 
     38  NS_IMETHOD
     39  OnImageReady(imgIContainer* aImage, nsresult aStatus) override {
     40    if (NS_FAILED(aStatus)) {
     41      OnError(aStatus);
     42      return NS_OK;
     43    }
     44 
     45    mImage = aImage;
     46    RequestDecode();
     47    return NS_OK;
     48  }
     49 
     50  void Notify(imgIRequest* aRequest, int32_t aType,
     51              const nsIntRect* aData) override {
     52    if (!mImage) {
     53      return;
     54    }
     55 
     56    if (aType == imgINotificationObserver::LOAD_COMPLETE ||
     57        aType == imgINotificationObserver::FRAME_UPDATE ||
     58        aType == imgINotificationObserver::FRAME_COMPLETE) {
     59      RequestDecode();
     60    }
     61 
     62    if (aType == imgINotificationObserver::DECODE_COMPLETE) {
     63      OnDecodeComplete();
     64    }
     65  }
     66 
     67  void OnError(nsresult aStatus) {
     68    gDecodeRequests.remove(this);
     69    mImage = nullptr;
     70    mPromise->Reject(aStatus, __func__);
     71    mPromise = nullptr;
     72  }
     73 
     74 private:
     75  virtual ~FetchDecodedImageHelper() {}
     76 
     77  void RequestDecode() {
     78    if (mSize.Width() && mSize.Height()) {
     79      if (NS_FAILED(mImage->RequestDecodeForSize(
     80              mSize, imgIContainer::FLAG_ASYNC_NOTIFY,
     81              imgIContainer::FRAME_FIRST))) {
     82        OnError(NS_ERROR_DOM_IMAGE_BROKEN);
     83      }
     84 
     85      return;
     86    }
     87 
     88    switch (mImage->RequestDecodeWithResult(imgIContainer::FLAG_ASYNC_NOTIFY,
     89                                            imgIContainer::FRAME_FIRST)) {
     90      case imgIContainer::DecodeResult::DECODE_REQUEST_FAILED:
     91        OnError(NS_ERROR_DOM_IMAGE_BROKEN);
     92        break;
     93      case imgIContainer::DecodeResult::DECODE_SURFACE_AVAILABLE:
     94        OnDecodeComplete();
     95        break;
     96      case imgIContainer::DecodeResult::DECODE_REQUESTED:
     97        break;
     98    }
     99  }
    100 
    101  void OnDecodeComplete() {
    102    gDecodeRequests.remove(this);
    103    mPromise->Resolve(mImage.forget(), __func__);
    104    mPromise = nullptr;
    105  }
    106 
    107  gfx::IntSize mSize;
    108  RefPtr<FetchDecodedImagePromise::Private> mPromise;
    109  nsCOMPtr<imgIContainer> mImage{};
    110 };
    111 
    112 NS_IMPL_ISUPPORTS(FetchDecodedImageHelper, imgIContainerCallback,
    113                  imgINotificationObserver)
    114 
    115 }  // namespace
    116 
    117 RefPtr<FetchDecodedImagePromise> FetchDecodedImage(
    118    nsIURI* aURI, gfx::IntSize aSize, nsIPrincipal* aLoadingPrincipal,
    119    nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType) {
    120  nsCOMPtr<nsIChannel> channel;
    121  nsresult rv = NS_NewChannel(getter_AddRefs(channel), aURI, aLoadingPrincipal,
    122                              aSecurityFlags, aContentPolicyType);
    123  if (NS_FAILED(rv)) {
    124    return FetchDecodedImagePromise::CreateAndReject(rv, __func__);
    125  }
    126 
    127  return FetchDecodedImage(aURI, channel, aSize);
    128 }
    129 
    130 RefPtr<FetchDecodedImagePromise> FetchDecodedImage(nsIURI* aURI,
    131                                                   nsIChannel* aChannel,
    132                                                   gfx::IntSize aSize) {
    133  nsresult rv;
    134  nsCOMPtr<imgITools> imgTools =
    135      do_GetService("@mozilla.org/image/tools;1", &rv);
    136  if (NS_FAILED(rv)) {
    137    return FetchDecodedImagePromise::CreateAndReject(rv, __func__);
    138  }
    139 
    140  auto promise = MakeRefPtr<FetchDecodedImagePromise::Private>(__func__);
    141 
    142  RefPtr<FetchDecodedImageHelper> helper =
    143      new FetchDecodedImageHelper(aSize, promise);
    144 
    145  rv = imgTools->DecodeImageFromChannelAsync(aURI, aChannel, helper, helper);
    146  if (NS_FAILED(rv)) {
    147    helper->OnError(rv);
    148  }
    149 
    150  return promise;
    151 }
    152 
    153 }  // namespace mozilla::image