Bug 1880550 - Propagate explicit heights to scrolled table cells as min-heights....
[gecko.git] / toolkit / components / alerts / AlertNotification.cpp
blob3cc2ec4380fc779e4b270c2125f0b4bfc95546ab
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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/. */
7 #include "mozilla/AlertNotification.h"
9 #include "imgIContainer.h"
10 #include "imgINotificationObserver.h"
11 #include "imgIRequest.h"
12 #include "imgLoader.h"
13 #include "nsAlertsUtils.h"
14 #include "nsComponentManagerUtils.h"
15 #include "nsContentUtils.h"
16 #include "nsNetUtil.h"
17 #include "nsServiceManagerUtils.h"
19 #include "mozilla/Unused.h"
21 namespace mozilla {
23 NS_IMPL_ISUPPORTS(AlertNotification, nsIAlertNotification)
25 AlertNotification::AlertNotification()
26 : mTextClickable(false), mInPrivateBrowsing(false) {}
28 AlertNotification::~AlertNotification() = default;
30 NS_IMETHODIMP
31 AlertNotification::Init(const nsAString& aName, const nsAString& aImageURL,
32 const nsAString& aTitle, const nsAString& aText,
33 bool aTextClickable, const nsAString& aCookie,
34 const nsAString& aDir, const nsAString& aLang,
35 const nsAString& aData, nsIPrincipal* aPrincipal,
36 bool aInPrivateBrowsing, bool aRequireInteraction,
37 bool aSilent, const nsTArray<uint32_t>& aVibrate) {
38 mName = aName;
39 mImageURL = aImageURL;
40 mTitle = aTitle;
41 mText = aText;
42 mTextClickable = aTextClickable;
43 mCookie = aCookie;
44 mDir = aDir;
45 mLang = aLang;
46 mData = aData;
47 mPrincipal = aPrincipal;
48 mInPrivateBrowsing = aInPrivateBrowsing;
49 mRequireInteraction = aRequireInteraction;
50 mSilent = aSilent;
51 mVibrate = aVibrate.Clone();
52 return NS_OK;
55 NS_IMETHODIMP
56 AlertNotification::SetActions(
57 const nsTArray<RefPtr<nsIAlertAction>>& aActions) {
58 mActions = aActions.Clone();
59 return NS_OK;
62 NS_IMETHODIMP
63 AlertNotification::GetName(nsAString& aName) {
64 aName = mName;
65 return NS_OK;
68 NS_IMETHODIMP
69 AlertNotification::GetImageURL(nsAString& aImageURL) {
70 aImageURL = mImageURL;
71 return NS_OK;
74 NS_IMETHODIMP
75 AlertNotification::GetTitle(nsAString& aTitle) {
76 aTitle = mTitle;
77 return NS_OK;
80 NS_IMETHODIMP
81 AlertNotification::GetText(nsAString& aText) {
82 aText = mText;
83 return NS_OK;
86 NS_IMETHODIMP
87 AlertNotification::GetTextClickable(bool* aTextClickable) {
88 *aTextClickable = mTextClickable;
89 return NS_OK;
92 NS_IMETHODIMP
93 AlertNotification::GetCookie(nsAString& aCookie) {
94 aCookie = mCookie;
95 return NS_OK;
98 NS_IMETHODIMP
99 AlertNotification::GetDir(nsAString& aDir) {
100 aDir = mDir;
101 return NS_OK;
104 NS_IMETHODIMP
105 AlertNotification::GetLang(nsAString& aLang) {
106 aLang = mLang;
107 return NS_OK;
110 NS_IMETHODIMP
111 AlertNotification::GetRequireInteraction(bool* aRequireInteraction) {
112 *aRequireInteraction = mRequireInteraction;
113 return NS_OK;
116 NS_IMETHODIMP
117 AlertNotification::GetData(nsAString& aData) {
118 aData = mData;
119 return NS_OK;
122 NS_IMETHODIMP
123 AlertNotification::GetPrincipal(nsIPrincipal** aPrincipal) {
124 NS_IF_ADDREF(*aPrincipal = mPrincipal);
125 return NS_OK;
128 NS_IMETHODIMP
129 AlertNotification::GetURI(nsIURI** aURI) {
130 if (!nsAlertsUtils::IsActionablePrincipal(mPrincipal)) {
131 *aURI = nullptr;
132 return NS_OK;
134 auto* basePrin = BasePrincipal::Cast(mPrincipal);
135 return basePrin->GetURI(aURI);
138 NS_IMETHODIMP
139 AlertNotification::GetInPrivateBrowsing(bool* aInPrivateBrowsing) {
140 *aInPrivateBrowsing = mInPrivateBrowsing;
141 return NS_OK;
144 NS_IMETHODIMP
145 AlertNotification::GetActionable(bool* aActionable) {
146 *aActionable = nsAlertsUtils::IsActionablePrincipal(mPrincipal);
147 return NS_OK;
150 NS_IMETHODIMP
151 AlertNotification::GetSilent(bool* aSilent) {
152 *aSilent = mSilent;
153 return NS_OK;
156 NS_IMETHODIMP
157 AlertNotification::GetVibrate(nsTArray<uint32_t>& aVibrate) {
158 aVibrate = mVibrate.Clone();
159 return NS_OK;
162 NS_IMETHODIMP
163 AlertNotification::GetActions(nsTArray<RefPtr<nsIAlertAction>>& aActions) {
164 aActions = mActions.Clone();
165 return NS_OK;
168 NS_IMETHODIMP
169 AlertNotification::GetSource(nsAString& aSource) {
170 nsAlertsUtils::GetSourceHostPort(mPrincipal, aSource);
171 return NS_OK;
174 NS_IMETHODIMP
175 AlertNotification::GetOpaqueRelaunchData(nsAString& aOpaqueRelaunchData) {
176 aOpaqueRelaunchData = mOpaqueRelaunchData;
177 return NS_OK;
180 NS_IMETHODIMP
181 AlertNotification::SetOpaqueRelaunchData(const nsAString& aOpaqueRelaunchData) {
182 mOpaqueRelaunchData = aOpaqueRelaunchData;
183 return NS_OK;
186 NS_IMETHODIMP
187 AlertNotification::LoadImage(uint32_t aTimeout,
188 nsIAlertNotificationImageListener* aListener,
189 nsISupports* aUserData, nsICancelable** aRequest) {
190 NS_ENSURE_ARG(aListener);
191 NS_ENSURE_ARG_POINTER(aRequest);
192 *aRequest = nullptr;
194 // Exit early if this alert doesn't have an image.
195 if (mImageURL.IsEmpty()) {
196 return aListener->OnImageMissing(aUserData);
198 nsCOMPtr<nsIURI> imageURI;
199 NS_NewURI(getter_AddRefs(imageURI), mImageURL);
200 if (!imageURI) {
201 return aListener->OnImageMissing(aUserData);
204 RefPtr<AlertImageRequest> request = new AlertImageRequest(
205 imageURI, mPrincipal, mInPrivateBrowsing, aTimeout, aListener, aUserData);
206 request->Start();
207 request.forget(aRequest);
208 return NS_OK;
211 NS_IMPL_CYCLE_COLLECTION(AlertImageRequest, mURI, mPrincipal, mListener,
212 mUserData)
214 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AlertImageRequest)
215 NS_INTERFACE_MAP_ENTRY(imgINotificationObserver)
216 NS_INTERFACE_MAP_ENTRY(nsICancelable)
217 NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
218 NS_INTERFACE_MAP_ENTRY(nsINamed)
219 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, imgINotificationObserver)
220 NS_INTERFACE_MAP_END
222 NS_IMPL_CYCLE_COLLECTING_ADDREF(AlertImageRequest)
223 NS_IMPL_CYCLE_COLLECTING_RELEASE(AlertImageRequest)
225 AlertImageRequest::AlertImageRequest(
226 nsIURI* aURI, nsIPrincipal* aPrincipal, bool aInPrivateBrowsing,
227 uint32_t aTimeout, nsIAlertNotificationImageListener* aListener,
228 nsISupports* aUserData)
229 : mURI(aURI),
230 mPrincipal(aPrincipal),
231 mInPrivateBrowsing(aInPrivateBrowsing),
232 mTimeout(aTimeout),
233 mListener(aListener),
234 mUserData(aUserData) {}
236 AlertImageRequest::~AlertImageRequest() {
237 if (mRequest) {
238 mRequest->CancelAndForgetObserver(NS_BINDING_ABORTED);
242 void AlertImageRequest::Notify(imgIRequest* aRequest, int32_t aType,
243 const nsIntRect* aData) {
244 MOZ_ASSERT(aRequest == mRequest);
246 uint32_t imgStatus = imgIRequest::STATUS_ERROR;
247 nsresult rv = aRequest->GetImageStatus(&imgStatus);
248 if (NS_WARN_IF(NS_FAILED(rv)) || (imgStatus & imgIRequest::STATUS_ERROR)) {
249 NotifyMissing();
250 return;
253 // If the image is already decoded, `FRAME_COMPLETE` will fire before
254 // `LOAD_COMPLETE`, so we can notify the listener immediately. Otherwise,
255 // we'll need to request a decode when `LOAD_COMPLETE` fires, and wait
256 // for the first frame.
258 if (aType == imgINotificationObserver::LOAD_COMPLETE) {
259 if (!(imgStatus & imgIRequest::STATUS_FRAME_COMPLETE)) {
260 nsCOMPtr<imgIContainer> image;
261 rv = aRequest->GetImage(getter_AddRefs(image));
262 if (NS_WARN_IF(NS_FAILED(rv) || !image)) {
263 NotifyMissing();
264 return;
267 // Ask the image to decode at its intrinsic size.
268 int32_t width = 0, height = 0;
269 image->GetWidth(&width);
270 image->GetHeight(&height);
271 image->RequestDecodeForSize(gfx::IntSize(width, height),
272 imgIContainer::FLAG_HIGH_QUALITY_SCALING);
274 return;
277 if (aType == imgINotificationObserver::FRAME_COMPLETE) {
278 return NotifyComplete();
282 NS_IMETHODIMP
283 AlertImageRequest::Notify(nsITimer* aTimer) {
284 MOZ_ASSERT(aTimer == mTimer);
285 return NotifyMissing();
288 NS_IMETHODIMP
289 AlertImageRequest::GetName(nsACString& aName) {
290 aName.AssignLiteral("AlertImageRequest");
291 return NS_OK;
294 NS_IMETHODIMP
295 AlertImageRequest::Cancel(nsresult aReason) {
296 if (mRequest) {
297 mRequest->Cancel(aReason);
299 // We call `NotifyMissing` here because we won't receive a `LOAD_COMPLETE`
300 // notification if we cancel the request before it loads (bug 1233086,
301 // comment 33). Once that's fixed, `nsIAlertNotification::loadImage` could
302 // return the underlying `imgIRequest` instead of the wrapper.
303 return NotifyMissing();
306 nsresult AlertImageRequest::Start() {
307 // Keep the request alive until we notify the image listener.
308 NS_ADDREF_THIS();
310 nsresult rv;
311 if (mTimeout > 0) {
312 rv = NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, mTimeout,
313 nsITimer::TYPE_ONE_SHOT);
314 if (NS_WARN_IF(NS_FAILED(rv))) {
315 return NotifyMissing();
319 // Begin loading the image.
320 imgLoader* il = imgLoader::NormalLoader();
321 if (!il) {
322 return NotifyMissing();
325 // Bug 1237405: `LOAD_ANONYMOUS` disables cookies, but we want to use a
326 // temporary cookie jar instead. We should also use
327 // `imgLoader::PrivateBrowsingLoader()` instead of the normal loader.
328 // Unfortunately, the PB loader checks the load group, and asserts if its
329 // load context's PB flag isn't set. The fix is to pass the load group to
330 // `nsIAlertNotification::loadImage`.
331 int32_t loadFlags = nsIRequest::LOAD_NORMAL;
332 if (mInPrivateBrowsing) {
333 loadFlags = nsIRequest::LOAD_ANONYMOUS;
336 rv = il->LoadImageXPCOM(
337 mURI, nullptr, nullptr, mPrincipal, nullptr, this, nullptr, loadFlags,
338 nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE, getter_AddRefs(mRequest));
339 if (NS_WARN_IF(NS_FAILED(rv))) {
340 return NotifyMissing();
343 return NS_OK;
346 nsresult AlertImageRequest::NotifyMissing() {
347 if (mTimer) {
348 mTimer->Cancel();
349 mTimer = nullptr;
351 if (nsCOMPtr<nsIAlertNotificationImageListener> listener =
352 std::move(mListener)) {
353 nsresult rv = listener->OnImageMissing(mUserData);
354 NS_RELEASE_THIS();
355 return rv;
358 return NS_OK;
361 void AlertImageRequest::NotifyComplete() {
362 if (mTimer) {
363 mTimer->Cancel();
364 mTimer = nullptr;
366 if (nsCOMPtr<nsIAlertNotificationImageListener> listener =
367 std::move(mListener)) {
368 listener->OnImageReady(mUserData, mRequest);
369 NS_RELEASE_THIS();
373 } // namespace mozilla