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/. */
5 #include "FetchImageHelper.h"
7 #include "mozilla/gfx/2D.h"
8 #include "mozilla/Logging.h"
9 #include "mozilla/NullPrincipal.h"
10 #include "nsIChannel.h"
11 #include "nsNetUtil.h"
13 mozilla::LazyLogModule
gFetchImageLog("FetchImageHelper");
16 #define LOG(msg, ...) \
17 MOZ_LOG(gFetchImageLog, LogLevel::Debug, \
18 ("FetchImageHelper=%p, " msg, this, ##__VA_ARGS__))
20 using namespace mozilla::gfx
;
22 namespace mozilla::dom
{
24 FetchImageHelper::FetchImageHelper(const MediaImage
& aImage
)
25 : mSrc(aImage
.mSrc
) {}
27 FetchImageHelper::~FetchImageHelper() { AbortFetchingImage(); }
29 RefPtr
<ImagePromise
> FetchImageHelper::FetchImage() {
30 MOZ_ASSERT(NS_IsMainThread());
31 if (IsFetchingImage()) {
32 return mPromise
.Ensure(__func__
);
35 LOG("Start fetching image from %s", NS_ConvertUTF16toUTF8(mSrc
).get());
37 if (NS_FAILED(NS_NewURI(getter_AddRefs(uri
), mSrc
))) {
38 LOG("Failed to create URI");
39 return ImagePromise::CreateAndReject(false, __func__
);
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__
);
48 return mPromise
.Ensure(__func__
);
51 void FetchImageHelper::AbortFetchingImage() {
52 MOZ_ASSERT(NS_IsMainThread());
53 LOG("AbortFetchingImage");
54 mPromise
.RejectIfExists(false, __func__
);
55 ClearListenerIfNeeded();
58 void FetchImageHelper::ClearListenerIfNeeded() {
65 bool FetchImageHelper::IsFetchingImage() const {
66 MOZ_ASSERT(NS_IsMainThread());
67 return !mPromise
.IsEmpty() && mListener
;
70 void FetchImageHelper::HandleFetchSuccess(imgIContainer
* aImage
) {
72 MOZ_ASSERT(NS_IsMainThread());
73 MOZ_ASSERT(IsFetchingImage());
74 LOG("Finished fetching image");
75 mPromise
.Resolve(aImage
, __func__
);
76 ClearListenerIfNeeded();
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();
88 * Implementation for FetchImageHelper::ImageFetchListener
90 NS_IMPL_ISUPPORTS(FetchImageHelper::ImageFetchListener
, imgIContainerCallback
)
92 FetchImageHelper::ImageFetchListener::~ImageFetchListener() {
93 MOZ_ASSERT(NS_IsMainThread());
94 MOZ_ASSERT(!mHelper
, "Cancel() should be called before desturction!");
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
;
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
);
113 nsCOMPtr
<imgITools
> imgTools
= do_GetService("@mozilla.org/image/tools;1");
115 return NS_ERROR_FAILURE
;
118 rv
= imgTools
->DecodeImageFromChannelAsync(aURI
, channel
, this, nullptr);
120 return NS_ERROR_FAILURE
;
128 void FetchImageHelper::ImageFetchListener::Clear() {
129 MOZ_ASSERT(NS_IsMainThread());
131 mChannel
->CancelWithReason(
132 NS_BINDING_ABORTED
, "FetchImageHelper::ImageFetchListener::Clear"_ns
);
138 bool FetchImageHelper::ImageFetchListener::IsFetchingImage() const {
139 MOZ_ASSERT(NS_IsMainThread());
140 return mHelper
? mHelper
->IsFetchingImage() : false;
143 NS_IMETHODIMP
FetchImageHelper::ImageFetchListener::OnImageReady(
144 imgIContainer
* aImage
, nsresult aStatus
) {
145 MOZ_ASSERT(NS_IsMainThread());
146 if (!IsFetchingImage()) {
149 // We have received image, so we don't need the channel anymore.
153 if (NS_FAILED(aStatus
) || !aImage
) {
154 mHelper
->HandleFetchFail();
159 mHelper
->HandleFetchSuccess(aImage
);
164 } // namespace mozilla::dom