зеркало из https://github.com/mozilla/gecko-dev.git
165 строки
4.6 KiB
C++
165 строки
4.6 KiB
C++
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "FetchImageHelper.h"
|
|
|
|
#include "mozilla/gfx/2D.h"
|
|
#include "mozilla/Logging.h"
|
|
#include "mozilla/NullPrincipal.h"
|
|
#include "nsIChannel.h"
|
|
#include "nsNetUtil.h"
|
|
|
|
mozilla::LazyLogModule gFetchImageLog("FetchImageHelper");
|
|
|
|
#undef LOG
|
|
#define LOG(msg, ...) \
|
|
MOZ_LOG(gFetchImageLog, LogLevel::Debug, \
|
|
("FetchImageHelper=%p, " msg, this, ##__VA_ARGS__))
|
|
|
|
using namespace mozilla::gfx;
|
|
|
|
namespace mozilla::dom {
|
|
|
|
FetchImageHelper::FetchImageHelper(const MediaImage& aImage)
|
|
: mSrc(aImage.mSrc) {}
|
|
|
|
FetchImageHelper::~FetchImageHelper() { AbortFetchingImage(); }
|
|
|
|
RefPtr<ImagePromise> FetchImageHelper::FetchImage() {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
if (IsFetchingImage()) {
|
|
return mPromise.Ensure(__func__);
|
|
}
|
|
|
|
LOG("Start fetching image from %s", NS_ConvertUTF16toUTF8(mSrc).get());
|
|
nsCOMPtr<nsIURI> uri;
|
|
if (NS_FAILED(NS_NewURI(getter_AddRefs(uri), mSrc))) {
|
|
LOG("Failed to create URI");
|
|
return ImagePromise::CreateAndReject(false, __func__);
|
|
}
|
|
|
|
MOZ_ASSERT(!mListener);
|
|
mListener = new ImageFetchListener();
|
|
if (NS_FAILED(mListener->FetchDecodedImageFromURI(uri, this))) {
|
|
LOG("Failed to decode image from async channel");
|
|
return ImagePromise::CreateAndReject(false, __func__);
|
|
}
|
|
return mPromise.Ensure(__func__);
|
|
}
|
|
|
|
void FetchImageHelper::AbortFetchingImage() {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
LOG("AbortFetchingImage");
|
|
mPromise.RejectIfExists(false, __func__);
|
|
ClearListenerIfNeeded();
|
|
}
|
|
|
|
void FetchImageHelper::ClearListenerIfNeeded() {
|
|
if (mListener) {
|
|
mListener->Clear();
|
|
mListener = nullptr;
|
|
}
|
|
}
|
|
|
|
bool FetchImageHelper::IsFetchingImage() const {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
return !mPromise.IsEmpty() && mListener;
|
|
}
|
|
|
|
void FetchImageHelper::HandleFetchSuccess(imgIContainer* aImage) {
|
|
MOZ_ASSERT(aImage);
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(IsFetchingImage());
|
|
LOG("Finished fetching image");
|
|
mPromise.Resolve(aImage, __func__);
|
|
ClearListenerIfNeeded();
|
|
}
|
|
|
|
void FetchImageHelper::HandleFetchFail() {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(IsFetchingImage());
|
|
LOG("Reject the promise because of fetching failed");
|
|
mPromise.RejectIfExists(false, __func__);
|
|
ClearListenerIfNeeded();
|
|
}
|
|
|
|
/**
|
|
* Implementation for FetchImageHelper::ImageFetchListener
|
|
*/
|
|
NS_IMPL_ISUPPORTS(FetchImageHelper::ImageFetchListener, imgIContainerCallback)
|
|
|
|
FetchImageHelper::ImageFetchListener::~ImageFetchListener() {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(!mHelper, "Cancel() should be called before desturction!");
|
|
}
|
|
|
|
nsresult FetchImageHelper::ImageFetchListener::FetchDecodedImageFromURI(
|
|
nsIURI* aURI, FetchImageHelper* aHelper) {
|
|
MOZ_ASSERT(!mHelper && !mChannel,
|
|
"Should call Clear() berfore running another fetching process!");
|
|
RefPtr<nsIPrincipal> nullPrincipal =
|
|
NullPrincipal::CreateWithoutOriginAttributes();
|
|
nsCOMPtr<nsIChannel> channel;
|
|
nsresult rv =
|
|
NS_NewChannel(getter_AddRefs(channel), aURI, nullPrincipal,
|
|
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
|
|
nsIContentPolicy::TYPE_INTERNAL_IMAGE, nullptr, nullptr,
|
|
nullptr, nullptr, nsIRequest::LOAD_ANONYMOUS);
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
|
|
nsCOMPtr<imgITools> imgTools = do_GetService("@mozilla.org/image/tools;1");
|
|
if (!imgTools) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
rv = imgTools->DecodeImageFromChannelAsync(aURI, channel, this, nullptr);
|
|
if (NS_FAILED(rv)) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
MOZ_ASSERT(aHelper);
|
|
mHelper = aHelper;
|
|
mChannel = channel;
|
|
return NS_OK;
|
|
}
|
|
|
|
void FetchImageHelper::ImageFetchListener::Clear() {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
if (mChannel) {
|
|
mChannel->CancelWithReason(
|
|
NS_BINDING_ABORTED, "FetchImageHelper::ImageFetchListener::Clear"_ns);
|
|
mChannel = nullptr;
|
|
}
|
|
mHelper = nullptr;
|
|
}
|
|
|
|
bool FetchImageHelper::ImageFetchListener::IsFetchingImage() const {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
return mHelper ? mHelper->IsFetchingImage() : false;
|
|
}
|
|
|
|
NS_IMETHODIMP FetchImageHelper::ImageFetchListener::OnImageReady(
|
|
imgIContainer* aImage, nsresult aStatus) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
if (!IsFetchingImage()) {
|
|
return NS_OK;
|
|
}
|
|
// We have received image, so we don't need the channel anymore.
|
|
mChannel = nullptr;
|
|
|
|
MOZ_ASSERT(mHelper);
|
|
if (NS_FAILED(aStatus) || !aImage) {
|
|
mHelper->HandleFetchFail();
|
|
Clear();
|
|
return aStatus;
|
|
}
|
|
|
|
mHelper->HandleFetchSuccess(aImage);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
} // namespace mozilla::dom
|