tor-browser

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

FetchImageHelper.cpp (4745B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "FetchImageHelper.h"
      6 
      7 #include "mozilla/Logging.h"
      8 #include "mozilla/NullPrincipal.h"
      9 #include "mozilla/gfx/2D.h"
     10 #include "nsIChannel.h"
     11 #include "nsNetUtil.h"
     12 
     13 mozilla::LazyLogModule gFetchImageLog("FetchImageHelper");
     14 
     15 #undef LOG
     16 #define LOG(msg, ...)                      \
     17  MOZ_LOG(gFetchImageLog, LogLevel::Debug, \
     18          ("FetchImageHelper=%p, " msg, this, ##__VA_ARGS__))
     19 
     20 using namespace mozilla::gfx;
     21 
     22 namespace mozilla::dom {
     23 
     24 FetchImageHelper::FetchImageHelper(const MediaImage& aImage)
     25    : mSrc(aImage.mSrc) {}
     26 
     27 FetchImageHelper::~FetchImageHelper() { AbortFetchingImage(); }
     28 
     29 RefPtr<ImagePromise> FetchImageHelper::FetchImage() {
     30  MOZ_ASSERT(NS_IsMainThread());
     31  if (IsFetchingImage()) {
     32    return mPromise.Ensure(__func__);
     33  }
     34 
     35  LOG("Start fetching image from %s", NS_ConvertUTF16toUTF8(mSrc).get());
     36  nsCOMPtr<nsIURI> uri;
     37  if (NS_FAILED(NS_NewURI(getter_AddRefs(uri), mSrc))) {
     38    LOG("Failed to create URI");
     39    return ImagePromise::CreateAndReject(false, __func__);
     40  }
     41 
     42  MOZ_ASSERT(!mListener);
     43  mListener = new ImageFetchListener();
     44  if (NS_FAILED(mListener->FetchDecodedImageFromURI(uri, this))) {
     45    LOG("Failed to decode image from async channel");
     46    return ImagePromise::CreateAndReject(false, __func__);
     47  }
     48  return mPromise.Ensure(__func__);
     49 }
     50 
     51 void FetchImageHelper::AbortFetchingImage() {
     52  MOZ_ASSERT(NS_IsMainThread());
     53  LOG("AbortFetchingImage");
     54  mPromise.RejectIfExists(false, __func__);
     55  ClearListenerIfNeeded();
     56 }
     57 
     58 void FetchImageHelper::ClearListenerIfNeeded() {
     59  if (mListener) {
     60    mListener->Clear();
     61    mListener = nullptr;
     62  }
     63 }
     64 
     65 bool FetchImageHelper::IsFetchingImage() const {
     66  MOZ_ASSERT(NS_IsMainThread());
     67  return !mPromise.IsEmpty() && mListener;
     68 }
     69 
     70 void FetchImageHelper::HandleFetchSuccess(imgIContainer* aImage) {
     71  MOZ_ASSERT(aImage);
     72  MOZ_ASSERT(NS_IsMainThread());
     73  MOZ_ASSERT(IsFetchingImage());
     74  LOG("Finished fetching image");
     75  mPromise.Resolve(aImage, __func__);
     76  ClearListenerIfNeeded();
     77 }
     78 
     79 void FetchImageHelper::HandleFetchFail() {
     80  MOZ_ASSERT(NS_IsMainThread());
     81  MOZ_ASSERT(IsFetchingImage());
     82  LOG("Reject the promise because of fetching failed");
     83  mPromise.RejectIfExists(false, __func__);
     84  ClearListenerIfNeeded();
     85 }
     86 
     87 /**
     88 * Implementation for FetchImageHelper::ImageFetchListener
     89 */
     90 NS_IMPL_ISUPPORTS(FetchImageHelper::ImageFetchListener, imgIContainerCallback)
     91 
     92 FetchImageHelper::ImageFetchListener::~ImageFetchListener() {
     93  MOZ_ASSERT(NS_IsMainThread());
     94  MOZ_ASSERT(!mHelper, "Cancel() should be called before desturction!");
     95 }
     96 
     97 nsresult FetchImageHelper::ImageFetchListener::FetchDecodedImageFromURI(
     98    nsIURI* aURI, FetchImageHelper* aHelper) {
     99  MOZ_ASSERT(!mHelper && !mChannel,
    100             "Should call Clear() berfore running another fetching process!");
    101  RefPtr<nsIPrincipal> nullPrincipal =
    102      NullPrincipal::CreateWithoutOriginAttributes();
    103  nsCOMPtr<nsIChannel> channel;
    104  nsresult rv =
    105      NS_NewChannel(getter_AddRefs(channel), aURI, nullPrincipal,
    106                    nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
    107                    nsIContentPolicy::TYPE_INTERNAL_IMAGE, nullptr, nullptr,
    108                    nullptr, nullptr, nsIRequest::LOAD_ANONYMOUS);
    109  if (NS_FAILED(rv)) {
    110    return rv;
    111  }
    112 
    113  nsCOMPtr<imgITools> imgTools = do_GetService("@mozilla.org/image/tools;1");
    114  if (!imgTools) {
    115    return NS_ERROR_FAILURE;
    116  }
    117 
    118  rv = imgTools->DecodeImageFromChannelAsync(aURI, channel, this, nullptr);
    119  if (NS_FAILED(rv)) {
    120    return NS_ERROR_FAILURE;
    121  }
    122  MOZ_ASSERT(aHelper);
    123  mHelper = aHelper;
    124  mChannel = channel;
    125  return NS_OK;
    126 }
    127 
    128 void FetchImageHelper::ImageFetchListener::Clear() {
    129  MOZ_ASSERT(NS_IsMainThread());
    130  if (mChannel) {
    131    mChannel->CancelWithReason(
    132        NS_BINDING_ABORTED, "FetchImageHelper::ImageFetchListener::Clear"_ns);
    133    mChannel = nullptr;
    134  }
    135  mHelper = nullptr;
    136 }
    137 
    138 bool FetchImageHelper::ImageFetchListener::IsFetchingImage() const {
    139  MOZ_ASSERT(NS_IsMainThread());
    140  return mHelper ? mHelper->IsFetchingImage() : false;
    141 }
    142 
    143 NS_IMETHODIMP FetchImageHelper::ImageFetchListener::OnImageReady(
    144    imgIContainer* aImage, nsresult aStatus) {
    145  MOZ_ASSERT(NS_IsMainThread());
    146  if (!IsFetchingImage()) {
    147    return NS_OK;
    148  }
    149  // We have received image, so we don't need the channel anymore.
    150  mChannel = nullptr;
    151 
    152  MOZ_ASSERT(mHelper);
    153  if (NS_FAILED(aStatus) || !aImage) {
    154    mHelper->HandleFetchFail();
    155    Clear();
    156    return aStatus;
    157  }
    158 
    159  mHelper->HandleFetchSuccess(aImage);
    160 
    161  return NS_OK;
    162 }
    163 
    164 }  // namespace mozilla::dom