image/src/imgRequestProxy.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 *
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "imgRequestProxy.h"
michael@0 8 #include "imgIOnloadBlocker.h"
michael@0 9
michael@0 10 #include "Image.h"
michael@0 11 #include "ImageOps.h"
michael@0 12 #include "nsError.h"
michael@0 13 #include "ImageLogging.h"
michael@0 14 #include "nsCRTGlue.h"
michael@0 15 #include "imgINotificationObserver.h"
michael@0 16 #include "nsNetUtil.h"
michael@0 17
michael@0 18 using namespace mozilla::image;
michael@0 19
michael@0 20 // The split of imgRequestProxy and imgRequestProxyStatic means that
michael@0 21 // certain overridden functions need to be usable in the destructor.
michael@0 22 // Since virtual functions can't be used in that way, this class
michael@0 23 // provides a behavioural trait for each class to use instead.
michael@0 24 class ProxyBehaviour
michael@0 25 {
michael@0 26 public:
michael@0 27 virtual ~ProxyBehaviour() {}
michael@0 28
michael@0 29 virtual already_AddRefed<mozilla::image::Image> GetImage() const = 0;
michael@0 30 virtual bool HasImage() const = 0;
michael@0 31 virtual already_AddRefed<imgStatusTracker> GetStatusTracker() const = 0;
michael@0 32 virtual imgRequest* GetOwner() const = 0;
michael@0 33 virtual void SetOwner(imgRequest* aOwner) = 0;
michael@0 34 };
michael@0 35
michael@0 36 class RequestBehaviour : public ProxyBehaviour
michael@0 37 {
michael@0 38 public:
michael@0 39 RequestBehaviour() : mOwner(nullptr), mOwnerHasImage(false) {}
michael@0 40
michael@0 41 virtual already_AddRefed<mozilla::image::Image> GetImage() const MOZ_OVERRIDE;
michael@0 42 virtual bool HasImage() const MOZ_OVERRIDE;
michael@0 43 virtual already_AddRefed<imgStatusTracker> GetStatusTracker() const MOZ_OVERRIDE;
michael@0 44
michael@0 45 virtual imgRequest* GetOwner() const MOZ_OVERRIDE {
michael@0 46 return mOwner;
michael@0 47 }
michael@0 48
michael@0 49 virtual void SetOwner(imgRequest* aOwner) MOZ_OVERRIDE {
michael@0 50 mOwner = aOwner;
michael@0 51
michael@0 52 if (mOwner) {
michael@0 53 nsRefPtr<imgStatusTracker> ownerStatusTracker = GetStatusTracker();
michael@0 54 mOwnerHasImage = ownerStatusTracker && ownerStatusTracker->HasImage();
michael@0 55 } else {
michael@0 56 mOwnerHasImage = false;
michael@0 57 }
michael@0 58 }
michael@0 59
michael@0 60 private:
michael@0 61 // We maintain the following invariant:
michael@0 62 // The proxy is registered at most with a single imgRequest as an observer,
michael@0 63 // and whenever it is, mOwner points to that object. This helps ensure that
michael@0 64 // imgRequestProxy::~imgRequestProxy unregisters the proxy as an observer
michael@0 65 // from whatever request it was registered with (if any). This, in turn,
michael@0 66 // means that imgRequest::mObservers will not have any stale pointers in it.
michael@0 67 nsRefPtr<imgRequest> mOwner;
michael@0 68
michael@0 69 bool mOwnerHasImage;
michael@0 70 };
michael@0 71
michael@0 72 already_AddRefed<mozilla::image::Image>
michael@0 73 RequestBehaviour::GetImage() const
michael@0 74 {
michael@0 75 if (!mOwnerHasImage)
michael@0 76 return nullptr;
michael@0 77 nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
michael@0 78 return statusTracker->GetImage();
michael@0 79 }
michael@0 80
michael@0 81 already_AddRefed<imgStatusTracker>
michael@0 82 RequestBehaviour::GetStatusTracker() const
michael@0 83 {
michael@0 84 // NOTE: It's possible that our mOwner has an Image that it didn't notify
michael@0 85 // us about, if we were Canceled before its Image was constructed.
michael@0 86 // (Canceling removes us as an observer, so mOwner has no way to notify us).
michael@0 87 // That's why this method uses mOwner->GetStatusTracker() instead of just
michael@0 88 // mOwner->mStatusTracker -- we might have a null mImage and yet have an
michael@0 89 // mOwner with a non-null mImage (and a null mStatusTracker pointer).
michael@0 90 return mOwner->GetStatusTracker();
michael@0 91 }
michael@0 92
michael@0 93 NS_IMPL_ADDREF(imgRequestProxy)
michael@0 94 NS_IMPL_RELEASE(imgRequestProxy)
michael@0 95
michael@0 96 NS_INTERFACE_MAP_BEGIN(imgRequestProxy)
michael@0 97 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, imgIRequest)
michael@0 98 NS_INTERFACE_MAP_ENTRY(imgIRequest)
michael@0 99 NS_INTERFACE_MAP_ENTRY(nsIRequest)
michael@0 100 NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
michael@0 101 NS_INTERFACE_MAP_ENTRY(nsISecurityInfoProvider)
michael@0 102 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsITimedChannel, TimedChannel() != nullptr)
michael@0 103 NS_INTERFACE_MAP_END
michael@0 104
michael@0 105 imgRequestProxy::imgRequestProxy() :
michael@0 106 mBehaviour(new RequestBehaviour),
michael@0 107 mURI(nullptr),
michael@0 108 mListener(nullptr),
michael@0 109 mLoadFlags(nsIRequest::LOAD_NORMAL),
michael@0 110 mLockCount(0),
michael@0 111 mAnimationConsumers(0),
michael@0 112 mCanceled(false),
michael@0 113 mIsInLoadGroup(false),
michael@0 114 mListenerIsStrongRef(false),
michael@0 115 mDecodeRequested(false),
michael@0 116 mDeferNotifications(false),
michael@0 117 mSentStartContainer(false)
michael@0 118 {
michael@0 119 /* member initializers and constructor code */
michael@0 120
michael@0 121 }
michael@0 122
michael@0 123 imgRequestProxy::~imgRequestProxy()
michael@0 124 {
michael@0 125 /* destructor code */
michael@0 126 NS_PRECONDITION(!mListener, "Someone forgot to properly cancel this request!");
michael@0 127
michael@0 128 // Unlock the image the proper number of times if we're holding locks on it.
michael@0 129 // Note that UnlockImage() decrements mLockCount each time it's called.
michael@0 130 while (mLockCount)
michael@0 131 UnlockImage();
michael@0 132
michael@0 133 ClearAnimationConsumers();
michael@0 134
michael@0 135 // Explicitly set mListener to null to ensure that the RemoveProxy
michael@0 136 // call below can't send |this| to an arbitrary listener while |this|
michael@0 137 // is being destroyed. This is all belt-and-suspenders in view of the
michael@0 138 // above assert.
michael@0 139 NullOutListener();
michael@0 140
michael@0 141 if (GetOwner()) {
michael@0 142 /* Call RemoveProxy with a successful status. This will keep the
michael@0 143 channel, if still downloading data, from being canceled if 'this' is
michael@0 144 the last observer. This allows the image to continue to download and
michael@0 145 be cached even if no one is using it currently.
michael@0 146 */
michael@0 147 mCanceled = true;
michael@0 148 GetOwner()->RemoveProxy(this, NS_OK);
michael@0 149 }
michael@0 150 }
michael@0 151
michael@0 152 nsresult imgRequestProxy::Init(imgRequest* aOwner,
michael@0 153 nsILoadGroup* aLoadGroup,
michael@0 154 ImageURL* aURI,
michael@0 155 imgINotificationObserver* aObserver)
michael@0 156 {
michael@0 157 NS_PRECONDITION(!GetOwner() && !mListener, "imgRequestProxy is already initialized");
michael@0 158
michael@0 159 LOG_SCOPE_WITH_PARAM(GetImgLog(), "imgRequestProxy::Init", "request", aOwner);
michael@0 160
michael@0 161 NS_ABORT_IF_FALSE(mAnimationConsumers == 0, "Cannot have animation before Init");
michael@0 162
michael@0 163 mBehaviour->SetOwner(aOwner);
michael@0 164 mListener = aObserver;
michael@0 165 // Make sure to addref mListener before the AddProxy call below, since
michael@0 166 // that call might well want to release it if the imgRequest has
michael@0 167 // already seen OnStopRequest.
michael@0 168 if (mListener) {
michael@0 169 mListenerIsStrongRef = true;
michael@0 170 NS_ADDREF(mListener);
michael@0 171 }
michael@0 172 mLoadGroup = aLoadGroup;
michael@0 173 mURI = aURI;
michael@0 174
michael@0 175 // Note: AddProxy won't send all the On* notifications immediately
michael@0 176 if (GetOwner())
michael@0 177 GetOwner()->AddProxy(this);
michael@0 178
michael@0 179 return NS_OK;
michael@0 180 }
michael@0 181
michael@0 182 nsresult imgRequestProxy::ChangeOwner(imgRequest *aNewOwner)
michael@0 183 {
michael@0 184 NS_PRECONDITION(GetOwner(), "Cannot ChangeOwner on a proxy without an owner!");
michael@0 185
michael@0 186 if (mCanceled) {
michael@0 187 // Ensure that this proxy has received all notifications to date before
michael@0 188 // we clean it up when removing it from the old owner below.
michael@0 189 SyncNotifyListener();
michael@0 190 }
michael@0 191
michael@0 192 // If we're holding locks, unlock the old image.
michael@0 193 // Note that UnlockImage decrements mLockCount each time it's called.
michael@0 194 uint32_t oldLockCount = mLockCount;
michael@0 195 while (mLockCount)
michael@0 196 UnlockImage();
michael@0 197
michael@0 198 // If we're holding animation requests, undo them.
michael@0 199 uint32_t oldAnimationConsumers = mAnimationConsumers;
michael@0 200 ClearAnimationConsumers();
michael@0 201
michael@0 202 // Were we decoded before?
michael@0 203 bool wasDecoded = false;
michael@0 204 nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
michael@0 205 if (statusTracker->HasImage() &&
michael@0 206 statusTracker->GetImageStatus() & imgIRequest::STATUS_FRAME_COMPLETE) {
michael@0 207 wasDecoded = true;
michael@0 208 }
michael@0 209
michael@0 210 GetOwner()->RemoveProxy(this, NS_IMAGELIB_CHANGING_OWNER);
michael@0 211
michael@0 212 mBehaviour->SetOwner(aNewOwner);
michael@0 213
michael@0 214 // If we were locked, apply the locks here
michael@0 215 for (uint32_t i = 0; i < oldLockCount; i++)
michael@0 216 LockImage();
michael@0 217
michael@0 218 // If we had animation requests, restore them here. Note that we
michael@0 219 // do this *after* RemoveProxy, which clears out animation consumers
michael@0 220 // (see bug 601723).
michael@0 221 for (uint32_t i = 0; i < oldAnimationConsumers; i++)
michael@0 222 IncrementAnimationConsumers();
michael@0 223
michael@0 224 GetOwner()->AddProxy(this);
michael@0 225
michael@0 226 // If we were decoded, or if we'd previously requested a decode, request a
michael@0 227 // decode on the new image
michael@0 228 if (wasDecoded || mDecodeRequested)
michael@0 229 GetOwner()->StartDecoding();
michael@0 230
michael@0 231 return NS_OK;
michael@0 232 }
michael@0 233
michael@0 234 void imgRequestProxy::AddToLoadGroup()
michael@0 235 {
michael@0 236 NS_ASSERTION(!mIsInLoadGroup, "Whaa, we're already in the loadgroup!");
michael@0 237
michael@0 238 if (!mIsInLoadGroup && mLoadGroup) {
michael@0 239 mLoadGroup->AddRequest(this, nullptr);
michael@0 240 mIsInLoadGroup = true;
michael@0 241 }
michael@0 242 }
michael@0 243
michael@0 244 void imgRequestProxy::RemoveFromLoadGroup(bool releaseLoadGroup)
michael@0 245 {
michael@0 246 if (!mIsInLoadGroup)
michael@0 247 return;
michael@0 248
michael@0 249 /* calling RemoveFromLoadGroup may cause the document to finish
michael@0 250 loading, which could result in our death. We need to make sure
michael@0 251 that we stay alive long enough to fight another battle... at
michael@0 252 least until we exit this function.
michael@0 253 */
michael@0 254 nsCOMPtr<imgIRequest> kungFuDeathGrip(this);
michael@0 255
michael@0 256 mLoadGroup->RemoveRequest(this, nullptr, NS_OK);
michael@0 257 mIsInLoadGroup = false;
michael@0 258
michael@0 259 if (releaseLoadGroup) {
michael@0 260 // We're done with the loadgroup, release it.
michael@0 261 mLoadGroup = nullptr;
michael@0 262 }
michael@0 263 }
michael@0 264
michael@0 265
michael@0 266 /** nsIRequest / imgIRequest methods **/
michael@0 267
michael@0 268 /* readonly attribute wstring name; */
michael@0 269 NS_IMETHODIMP imgRequestProxy::GetName(nsACString &aName)
michael@0 270 {
michael@0 271 aName.Truncate();
michael@0 272
michael@0 273 if (mURI)
michael@0 274 mURI->GetSpec(aName);
michael@0 275
michael@0 276 return NS_OK;
michael@0 277 }
michael@0 278
michael@0 279 /* boolean isPending (); */
michael@0 280 NS_IMETHODIMP imgRequestProxy::IsPending(bool *_retval)
michael@0 281 {
michael@0 282 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 283 }
michael@0 284
michael@0 285 /* readonly attribute nsresult status; */
michael@0 286 NS_IMETHODIMP imgRequestProxy::GetStatus(nsresult *aStatus)
michael@0 287 {
michael@0 288 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 289 }
michael@0 290
michael@0 291 /* void cancel (in nsresult status); */
michael@0 292 NS_IMETHODIMP imgRequestProxy::Cancel(nsresult status)
michael@0 293 {
michael@0 294 if (mCanceled)
michael@0 295 return NS_ERROR_FAILURE;
michael@0 296
michael@0 297 LOG_SCOPE(GetImgLog(), "imgRequestProxy::Cancel");
michael@0 298
michael@0 299 mCanceled = true;
michael@0 300
michael@0 301 nsCOMPtr<nsIRunnable> ev = new imgCancelRunnable(this, status);
michael@0 302 return NS_DispatchToCurrentThread(ev);
michael@0 303 }
michael@0 304
michael@0 305 void
michael@0 306 imgRequestProxy::DoCancel(nsresult status)
michael@0 307 {
michael@0 308 if (GetOwner()) {
michael@0 309 GetOwner()->RemoveProxy(this, status);
michael@0 310 }
michael@0 311
michael@0 312 NullOutListener();
michael@0 313 }
michael@0 314
michael@0 315 /* void cancelAndForgetObserver (in nsresult aStatus); */
michael@0 316 NS_IMETHODIMP imgRequestProxy::CancelAndForgetObserver(nsresult aStatus)
michael@0 317 {
michael@0 318 // If mCanceled is true but mListener is non-null, that means
michael@0 319 // someone called Cancel() on us but the imgCancelRunnable is still
michael@0 320 // pending. We still need to null out mListener before returning
michael@0 321 // from this function in this case. That means we want to do the
michael@0 322 // RemoveProxy call right now, because we need to deliver the
michael@0 323 // onStopRequest.
michael@0 324 if (mCanceled && !mListener)
michael@0 325 return NS_ERROR_FAILURE;
michael@0 326
michael@0 327 LOG_SCOPE(GetImgLog(), "imgRequestProxy::CancelAndForgetObserver");
michael@0 328
michael@0 329 mCanceled = true;
michael@0 330
michael@0 331 // Now cheat and make sure our removal from loadgroup happens async
michael@0 332 bool oldIsInLoadGroup = mIsInLoadGroup;
michael@0 333 mIsInLoadGroup = false;
michael@0 334
michael@0 335 if (GetOwner()) {
michael@0 336 GetOwner()->RemoveProxy(this, aStatus);
michael@0 337 }
michael@0 338
michael@0 339 mIsInLoadGroup = oldIsInLoadGroup;
michael@0 340
michael@0 341 if (mIsInLoadGroup) {
michael@0 342 nsCOMPtr<nsIRunnable> ev =
michael@0 343 NS_NewRunnableMethod(this, &imgRequestProxy::DoRemoveFromLoadGroup);
michael@0 344 NS_DispatchToCurrentThread(ev);
michael@0 345 }
michael@0 346
michael@0 347 NullOutListener();
michael@0 348
michael@0 349 return NS_OK;
michael@0 350 }
michael@0 351
michael@0 352 /* void startDecode (); */
michael@0 353 NS_IMETHODIMP
michael@0 354 imgRequestProxy::StartDecoding()
michael@0 355 {
michael@0 356 if (!GetOwner())
michael@0 357 return NS_ERROR_FAILURE;
michael@0 358
michael@0 359 // Flag this, so we know to transfer the request if our owner changes
michael@0 360 mDecodeRequested = true;
michael@0 361
michael@0 362 // Forward the request
michael@0 363 return GetOwner()->StartDecoding();
michael@0 364 }
michael@0 365
michael@0 366 /* void requestDecode (); */
michael@0 367 NS_IMETHODIMP
michael@0 368 imgRequestProxy::RequestDecode()
michael@0 369 {
michael@0 370 if (!GetOwner())
michael@0 371 return NS_ERROR_FAILURE;
michael@0 372
michael@0 373 // Flag this, so we know to transfer the request if our owner changes
michael@0 374 mDecodeRequested = true;
michael@0 375
michael@0 376 // Forward the request
michael@0 377 return GetOwner()->RequestDecode();
michael@0 378 }
michael@0 379
michael@0 380
michael@0 381 /* void lockImage (); */
michael@0 382 NS_IMETHODIMP
michael@0 383 imgRequestProxy::LockImage()
michael@0 384 {
michael@0 385 mLockCount++;
michael@0 386 nsRefPtr<Image> image = GetImage();
michael@0 387 if (image)
michael@0 388 return image->LockImage();
michael@0 389 return NS_OK;
michael@0 390 }
michael@0 391
michael@0 392 /* void unlockImage (); */
michael@0 393 NS_IMETHODIMP
michael@0 394 imgRequestProxy::UnlockImage()
michael@0 395 {
michael@0 396 NS_ABORT_IF_FALSE(mLockCount > 0, "calling unlock but no locks!");
michael@0 397
michael@0 398 mLockCount--;
michael@0 399 nsRefPtr<Image> image = GetImage();
michael@0 400 if (image)
michael@0 401 return image->UnlockImage();
michael@0 402 return NS_OK;
michael@0 403 }
michael@0 404
michael@0 405 /* void requestDiscard (); */
michael@0 406 NS_IMETHODIMP
michael@0 407 imgRequestProxy::RequestDiscard()
michael@0 408 {
michael@0 409 nsRefPtr<Image> image = GetImage();
michael@0 410 if (image)
michael@0 411 return image->RequestDiscard();
michael@0 412 return NS_OK;
michael@0 413 }
michael@0 414
michael@0 415 NS_IMETHODIMP
michael@0 416 imgRequestProxy::IncrementAnimationConsumers()
michael@0 417 {
michael@0 418 mAnimationConsumers++;
michael@0 419 nsRefPtr<Image> image = GetImage();
michael@0 420 if (image)
michael@0 421 image->IncrementAnimationConsumers();
michael@0 422 return NS_OK;
michael@0 423 }
michael@0 424
michael@0 425 NS_IMETHODIMP
michael@0 426 imgRequestProxy::DecrementAnimationConsumers()
michael@0 427 {
michael@0 428 // We may get here if some responsible code called Increment,
michael@0 429 // then called us, but we have meanwhile called ClearAnimationConsumers
michael@0 430 // because we needed to get rid of them earlier (see
michael@0 431 // imgRequest::RemoveProxy), and hence have nothing left to
michael@0 432 // decrement. (In such a case we got rid of the animation consumers
michael@0 433 // early, but not the observer.)
michael@0 434 if (mAnimationConsumers > 0) {
michael@0 435 mAnimationConsumers--;
michael@0 436 nsRefPtr<Image> image = GetImage();
michael@0 437 if (image)
michael@0 438 image->DecrementAnimationConsumers();
michael@0 439 }
michael@0 440 return NS_OK;
michael@0 441 }
michael@0 442
michael@0 443 void
michael@0 444 imgRequestProxy::ClearAnimationConsumers()
michael@0 445 {
michael@0 446 while (mAnimationConsumers > 0)
michael@0 447 DecrementAnimationConsumers();
michael@0 448 }
michael@0 449
michael@0 450 /* void suspend (); */
michael@0 451 NS_IMETHODIMP imgRequestProxy::Suspend()
michael@0 452 {
michael@0 453 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 454 }
michael@0 455
michael@0 456 /* void resume (); */
michael@0 457 NS_IMETHODIMP imgRequestProxy::Resume()
michael@0 458 {
michael@0 459 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 460 }
michael@0 461
michael@0 462 /* attribute nsILoadGroup loadGroup */
michael@0 463 NS_IMETHODIMP imgRequestProxy::GetLoadGroup(nsILoadGroup **loadGroup)
michael@0 464 {
michael@0 465 NS_IF_ADDREF(*loadGroup = mLoadGroup.get());
michael@0 466 return NS_OK;
michael@0 467 }
michael@0 468 NS_IMETHODIMP imgRequestProxy::SetLoadGroup(nsILoadGroup *loadGroup)
michael@0 469 {
michael@0 470 mLoadGroup = loadGroup;
michael@0 471 return NS_OK;
michael@0 472 }
michael@0 473
michael@0 474 /* attribute nsLoadFlags loadFlags */
michael@0 475 NS_IMETHODIMP imgRequestProxy::GetLoadFlags(nsLoadFlags *flags)
michael@0 476 {
michael@0 477 *flags = mLoadFlags;
michael@0 478 return NS_OK;
michael@0 479 }
michael@0 480 NS_IMETHODIMP imgRequestProxy::SetLoadFlags(nsLoadFlags flags)
michael@0 481 {
michael@0 482 mLoadFlags = flags;
michael@0 483 return NS_OK;
michael@0 484 }
michael@0 485
michael@0 486 /** imgIRequest methods **/
michael@0 487
michael@0 488 /* attribute imgIContainer image; */
michael@0 489 NS_IMETHODIMP imgRequestProxy::GetImage(imgIContainer **aImage)
michael@0 490 {
michael@0 491 NS_ENSURE_TRUE(aImage, NS_ERROR_NULL_POINTER);
michael@0 492 // It's possible that our owner has an image but hasn't notified us of it -
michael@0 493 // that'll happen if we get Canceled before the owner instantiates its image
michael@0 494 // (because Canceling unregisters us as a listener on mOwner). If we're
michael@0 495 // in that situation, just grab the image off of mOwner.
michael@0 496 nsRefPtr<Image> image = GetImage();
michael@0 497 nsCOMPtr<imgIContainer> imageToReturn;
michael@0 498 if (image)
michael@0 499 imageToReturn = do_QueryInterface(image);
michael@0 500 if (!imageToReturn && GetOwner())
michael@0 501 imageToReturn = GetOwner()->mImage;
michael@0 502
michael@0 503 if (!imageToReturn)
michael@0 504 return NS_ERROR_FAILURE;
michael@0 505
michael@0 506 imageToReturn.swap(*aImage);
michael@0 507
michael@0 508 return NS_OK;
michael@0 509 }
michael@0 510
michael@0 511 /* readonly attribute unsigned long imageStatus; */
michael@0 512 NS_IMETHODIMP imgRequestProxy::GetImageStatus(uint32_t *aStatus)
michael@0 513 {
michael@0 514 nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
michael@0 515 *aStatus = statusTracker->GetImageStatus();
michael@0 516
michael@0 517 return NS_OK;
michael@0 518 }
michael@0 519
michael@0 520 /* readonly attribute nsIURI URI; */
michael@0 521 NS_IMETHODIMP imgRequestProxy::GetURI(nsIURI **aURI)
michael@0 522 {
michael@0 523 MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread to convert URI");
michael@0 524 nsCOMPtr<nsIURI> uri = mURI->ToIURI();
michael@0 525 uri.forget(aURI);
michael@0 526 return NS_OK;
michael@0 527 }
michael@0 528
michael@0 529 nsresult imgRequestProxy::GetURI(ImageURL **aURI)
michael@0 530 {
michael@0 531 if (!mURI)
michael@0 532 return NS_ERROR_FAILURE;
michael@0 533
michael@0 534 NS_ADDREF(*aURI = mURI);
michael@0 535
michael@0 536 return NS_OK;
michael@0 537 }
michael@0 538
michael@0 539 /* readonly attribute imgINotificationObserver notificationObserver; */
michael@0 540 NS_IMETHODIMP imgRequestProxy::GetNotificationObserver(imgINotificationObserver **aObserver)
michael@0 541 {
michael@0 542 *aObserver = mListener;
michael@0 543 NS_IF_ADDREF(*aObserver);
michael@0 544 return NS_OK;
michael@0 545 }
michael@0 546
michael@0 547 /* readonly attribute string mimeType; */
michael@0 548 NS_IMETHODIMP imgRequestProxy::GetMimeType(char **aMimeType)
michael@0 549 {
michael@0 550 if (!GetOwner())
michael@0 551 return NS_ERROR_FAILURE;
michael@0 552
michael@0 553 const char *type = GetOwner()->GetMimeType();
michael@0 554 if (!type)
michael@0 555 return NS_ERROR_FAILURE;
michael@0 556
michael@0 557 *aMimeType = NS_strdup(type);
michael@0 558
michael@0 559 return NS_OK;
michael@0 560 }
michael@0 561
michael@0 562 static imgRequestProxy* NewProxy(imgRequestProxy* /*aThis*/)
michael@0 563 {
michael@0 564 return new imgRequestProxy();
michael@0 565 }
michael@0 566
michael@0 567 imgRequestProxy* NewStaticProxy(imgRequestProxy* aThis)
michael@0 568 {
michael@0 569 nsCOMPtr<nsIPrincipal> currentPrincipal;
michael@0 570 aThis->GetImagePrincipal(getter_AddRefs(currentPrincipal));
michael@0 571 nsRefPtr<Image> image = aThis->GetImage();
michael@0 572 return new imgRequestProxyStatic(image, currentPrincipal);
michael@0 573 }
michael@0 574
michael@0 575 NS_IMETHODIMP imgRequestProxy::Clone(imgINotificationObserver* aObserver,
michael@0 576 imgIRequest** aClone)
michael@0 577 {
michael@0 578 nsresult result;
michael@0 579 imgRequestProxy* proxy;
michael@0 580 result = Clone(aObserver, &proxy);
michael@0 581 *aClone = proxy;
michael@0 582 return result;
michael@0 583 }
michael@0 584
michael@0 585 nsresult imgRequestProxy::Clone(imgINotificationObserver* aObserver,
michael@0 586 imgRequestProxy** aClone)
michael@0 587 {
michael@0 588 return PerformClone(aObserver, NewProxy, aClone);
michael@0 589 }
michael@0 590
michael@0 591 nsresult imgRequestProxy::PerformClone(imgINotificationObserver* aObserver,
michael@0 592 imgRequestProxy* (aAllocFn)(imgRequestProxy*),
michael@0 593 imgRequestProxy** aClone)
michael@0 594 {
michael@0 595 NS_PRECONDITION(aClone, "Null out param");
michael@0 596
michael@0 597 LOG_SCOPE(GetImgLog(), "imgRequestProxy::Clone");
michael@0 598
michael@0 599 *aClone = nullptr;
michael@0 600 nsRefPtr<imgRequestProxy> clone = aAllocFn(this);
michael@0 601
michael@0 602 // It is important to call |SetLoadFlags()| before calling |Init()| because
michael@0 603 // |Init()| adds the request to the loadgroup.
michael@0 604 // When a request is added to a loadgroup, its load flags are merged
michael@0 605 // with the load flags of the loadgroup.
michael@0 606 // XXXldb That's not true anymore. Stuff from imgLoader adds the
michael@0 607 // request to the loadgroup.
michael@0 608 clone->SetLoadFlags(mLoadFlags);
michael@0 609 nsresult rv = clone->Init(mBehaviour->GetOwner(), mLoadGroup, mURI, aObserver);
michael@0 610 if (NS_FAILED(rv))
michael@0 611 return rv;
michael@0 612
michael@0 613 // Assign to *aClone before calling Notify so that if the caller expects to
michael@0 614 // only be notified for requests it's already holding pointers to it won't be
michael@0 615 // surprised.
michael@0 616 NS_ADDREF(*aClone = clone);
michael@0 617
michael@0 618 // This is wrong!!! We need to notify asynchronously, but there's code that
michael@0 619 // assumes that we don't. This will be fixed in bug 580466.
michael@0 620 clone->SyncNotifyListener();
michael@0 621
michael@0 622 return NS_OK;
michael@0 623 }
michael@0 624
michael@0 625 /* readonly attribute nsIPrincipal imagePrincipal; */
michael@0 626 NS_IMETHODIMP imgRequestProxy::GetImagePrincipal(nsIPrincipal **aPrincipal)
michael@0 627 {
michael@0 628 if (!GetOwner())
michael@0 629 return NS_ERROR_FAILURE;
michael@0 630
michael@0 631 NS_ADDREF(*aPrincipal = GetOwner()->GetPrincipal());
michael@0 632 return NS_OK;
michael@0 633 }
michael@0 634
michael@0 635 /* readonly attribute bool multipart; */
michael@0 636 NS_IMETHODIMP imgRequestProxy::GetMultipart(bool *aMultipart)
michael@0 637 {
michael@0 638 if (!GetOwner())
michael@0 639 return NS_ERROR_FAILURE;
michael@0 640
michael@0 641 *aMultipart = GetOwner()->GetMultipart();
michael@0 642
michael@0 643 return NS_OK;
michael@0 644 }
michael@0 645
michael@0 646 /* readonly attribute int32_t CORSMode; */
michael@0 647 NS_IMETHODIMP imgRequestProxy::GetCORSMode(int32_t* aCorsMode)
michael@0 648 {
michael@0 649 if (!GetOwner())
michael@0 650 return NS_ERROR_FAILURE;
michael@0 651
michael@0 652 *aCorsMode = GetOwner()->GetCORSMode();
michael@0 653
michael@0 654 return NS_OK;
michael@0 655 }
michael@0 656
michael@0 657 /** nsISupportsPriority methods **/
michael@0 658
michael@0 659 NS_IMETHODIMP imgRequestProxy::GetPriority(int32_t *priority)
michael@0 660 {
michael@0 661 NS_ENSURE_STATE(GetOwner());
michael@0 662 *priority = GetOwner()->Priority();
michael@0 663 return NS_OK;
michael@0 664 }
michael@0 665
michael@0 666 NS_IMETHODIMP imgRequestProxy::SetPriority(int32_t priority)
michael@0 667 {
michael@0 668 NS_ENSURE_STATE(GetOwner() && !mCanceled);
michael@0 669 GetOwner()->AdjustPriority(this, priority - GetOwner()->Priority());
michael@0 670 return NS_OK;
michael@0 671 }
michael@0 672
michael@0 673 NS_IMETHODIMP imgRequestProxy::AdjustPriority(int32_t priority)
michael@0 674 {
michael@0 675 // We don't require |!mCanceled| here. This may be called even if we're
michael@0 676 // cancelled, because it's invoked as part of the process of removing an image
michael@0 677 // from the load group.
michael@0 678 NS_ENSURE_STATE(GetOwner());
michael@0 679 GetOwner()->AdjustPriority(this, priority);
michael@0 680 return NS_OK;
michael@0 681 }
michael@0 682
michael@0 683 /** nsISecurityInfoProvider methods **/
michael@0 684
michael@0 685 NS_IMETHODIMP imgRequestProxy::GetSecurityInfo(nsISupports** _retval)
michael@0 686 {
michael@0 687 if (GetOwner())
michael@0 688 return GetOwner()->GetSecurityInfo(_retval);
michael@0 689
michael@0 690 *_retval = nullptr;
michael@0 691 return NS_OK;
michael@0 692 }
michael@0 693
michael@0 694 NS_IMETHODIMP imgRequestProxy::GetHasTransferredData(bool* hasData)
michael@0 695 {
michael@0 696 if (GetOwner()) {
michael@0 697 *hasData = GetOwner()->HasTransferredData();
michael@0 698 } else {
michael@0 699 // The safe thing to do is to claim we have data
michael@0 700 *hasData = true;
michael@0 701 }
michael@0 702 return NS_OK;
michael@0 703 }
michael@0 704
michael@0 705 /** imgDecoderObserver methods **/
michael@0 706
michael@0 707 void imgRequestProxy::OnStartDecode()
michael@0 708 {
michael@0 709 // This notification is deliberately not propagated since there are no
michael@0 710 // listeners who care about it.
michael@0 711 if (GetOwner()) {
michael@0 712 // In the case of streaming jpegs, it is possible to get multiple
michael@0 713 // OnStartDecodes which indicates the beginning of a new decode. The cache
michael@0 714 // entry's size therefore needs to be reset to 0 here. If we do not do
michael@0 715 // this, the code in imgStatusTrackerObserver::OnStopFrame will continue to
michael@0 716 // increase the data size cumulatively.
michael@0 717 GetOwner()->ResetCacheEntry();
michael@0 718 }
michael@0 719 }
michael@0 720
michael@0 721 void imgRequestProxy::OnStartContainer()
michael@0 722 {
michael@0 723 LOG_FUNC(GetImgLog(), "imgRequestProxy::OnStartContainer");
michael@0 724
michael@0 725 if (mListener && !mCanceled && !mSentStartContainer) {
michael@0 726 // Hold a ref to the listener while we call it, just in case.
michael@0 727 nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
michael@0 728 mListener->Notify(this, imgINotificationObserver::SIZE_AVAILABLE, nullptr);
michael@0 729 mSentStartContainer = true;
michael@0 730 }
michael@0 731 }
michael@0 732
michael@0 733 void imgRequestProxy::OnFrameUpdate(const nsIntRect * rect)
michael@0 734 {
michael@0 735 LOG_FUNC(GetImgLog(), "imgRequestProxy::OnDataAvailable");
michael@0 736
michael@0 737 if (mListener && !mCanceled) {
michael@0 738 // Hold a ref to the listener while we call it, just in case.
michael@0 739 nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
michael@0 740 mListener->Notify(this, imgINotificationObserver::FRAME_UPDATE, rect);
michael@0 741 }
michael@0 742 }
michael@0 743
michael@0 744 void imgRequestProxy::OnStopFrame()
michael@0 745 {
michael@0 746 LOG_FUNC(GetImgLog(), "imgRequestProxy::OnStopFrame");
michael@0 747
michael@0 748 if (mListener && !mCanceled) {
michael@0 749 // Hold a ref to the listener while we call it, just in case.
michael@0 750 nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
michael@0 751 mListener->Notify(this, imgINotificationObserver::FRAME_COMPLETE, nullptr);
michael@0 752 }
michael@0 753 }
michael@0 754
michael@0 755 void imgRequestProxy::OnStopDecode()
michael@0 756 {
michael@0 757 LOG_FUNC(GetImgLog(), "imgRequestProxy::OnStopDecode");
michael@0 758
michael@0 759 if (mListener && !mCanceled) {
michael@0 760 // Hold a ref to the listener while we call it, just in case.
michael@0 761 nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
michael@0 762 mListener->Notify(this, imgINotificationObserver::DECODE_COMPLETE, nullptr);
michael@0 763 }
michael@0 764
michael@0 765 if (GetOwner()) {
michael@0 766 // We finished the decode, and thus have the decoded frames. Update the cache
michael@0 767 // entry size to take this into account.
michael@0 768 GetOwner()->UpdateCacheEntrySize();
michael@0 769
michael@0 770 // Multipart needs reset for next OnStartContainer.
michael@0 771 if (GetOwner()->GetMultipart())
michael@0 772 mSentStartContainer = false;
michael@0 773 }
michael@0 774 }
michael@0 775
michael@0 776 void imgRequestProxy::OnDiscard()
michael@0 777 {
michael@0 778 LOG_FUNC(GetImgLog(), "imgRequestProxy::OnDiscard");
michael@0 779
michael@0 780 if (mListener && !mCanceled) {
michael@0 781 // Hold a ref to the listener while we call it, just in case.
michael@0 782 nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
michael@0 783 mListener->Notify(this, imgINotificationObserver::DISCARD, nullptr);
michael@0 784 }
michael@0 785 if (GetOwner()) {
michael@0 786 // Update the cache entry size, since we just got rid of frame data.
michael@0 787 GetOwner()->UpdateCacheEntrySize();
michael@0 788 }
michael@0 789 }
michael@0 790
michael@0 791 void imgRequestProxy::OnUnlockedDraw()
michael@0 792 {
michael@0 793 LOG_FUNC(GetImgLog(), "imgRequestProxy::OnUnlockedDraw");
michael@0 794
michael@0 795 if (mListener && !mCanceled) {
michael@0 796 // Hold a ref to the listener while we call it, just in case.
michael@0 797 nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
michael@0 798 mListener->Notify(this, imgINotificationObserver::UNLOCKED_DRAW, nullptr);
michael@0 799 }
michael@0 800 }
michael@0 801
michael@0 802 void imgRequestProxy::OnImageIsAnimated()
michael@0 803 {
michael@0 804 LOG_FUNC(GetImgLog(), "imgRequestProxy::OnImageIsAnimated");
michael@0 805 if (mListener && !mCanceled) {
michael@0 806 // Hold a ref to the listener while we call it, just in case.
michael@0 807 nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
michael@0 808 mListener->Notify(this, imgINotificationObserver::IS_ANIMATED, nullptr);
michael@0 809 }
michael@0 810 }
michael@0 811
michael@0 812 void imgRequestProxy::OnStartRequest()
michael@0 813 {
michael@0 814 #ifdef PR_LOGGING
michael@0 815 nsAutoCString name;
michael@0 816 GetName(name);
michael@0 817 LOG_FUNC_WITH_PARAM(GetImgLog(), "imgRequestProxy::OnStartRequest", "name", name.get());
michael@0 818 #endif
michael@0 819 }
michael@0 820
michael@0 821 void imgRequestProxy::OnStopRequest(bool lastPart)
michael@0 822 {
michael@0 823 #ifdef PR_LOGGING
michael@0 824 nsAutoCString name;
michael@0 825 GetName(name);
michael@0 826 LOG_FUNC_WITH_PARAM(GetImgLog(), "imgRequestProxy::OnStopRequest", "name", name.get());
michael@0 827 #endif
michael@0 828 // There's all sorts of stuff here that could kill us (the OnStopRequest call
michael@0 829 // on the listener, the removal from the loadgroup, the release of the
michael@0 830 // listener, etc). Don't let them do it.
michael@0 831 nsCOMPtr<imgIRequest> kungFuDeathGrip(this);
michael@0 832
michael@0 833 if (mListener && !mCanceled) {
michael@0 834 // Hold a ref to the listener while we call it, just in case.
michael@0 835 nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
michael@0 836 mListener->Notify(this, imgINotificationObserver::LOAD_COMPLETE, nullptr);
michael@0 837 }
michael@0 838
michael@0 839 // If we're expecting more data from a multipart channel, re-add ourself
michael@0 840 // to the loadgroup so that the document doesn't lose track of the load.
michael@0 841 // If the request is already a background request and there's more data
michael@0 842 // coming, we can just leave the request in the loadgroup as-is.
michael@0 843 if (lastPart || (mLoadFlags & nsIRequest::LOAD_BACKGROUND) == 0) {
michael@0 844 RemoveFromLoadGroup(lastPart);
michael@0 845 // More data is coming, so change the request to be a background request
michael@0 846 // and put it back in the loadgroup.
michael@0 847 if (!lastPart) {
michael@0 848 mLoadFlags |= nsIRequest::LOAD_BACKGROUND;
michael@0 849 AddToLoadGroup();
michael@0 850 }
michael@0 851 }
michael@0 852
michael@0 853 if (mListenerIsStrongRef && lastPart) {
michael@0 854 NS_PRECONDITION(mListener, "How did that happen?");
michael@0 855 // Drop our strong ref to the listener now that we're done with
michael@0 856 // everything. Note that this can cancel us and other fun things
michael@0 857 // like that. Don't add anything in this method after this point.
michael@0 858 imgINotificationObserver* obs = mListener;
michael@0 859 mListenerIsStrongRef = false;
michael@0 860 NS_RELEASE(obs);
michael@0 861 }
michael@0 862 }
michael@0 863
michael@0 864 void imgRequestProxy::BlockOnload()
michael@0 865 {
michael@0 866 #ifdef PR_LOGGING
michael@0 867 nsAutoCString name;
michael@0 868 GetName(name);
michael@0 869 LOG_FUNC_WITH_PARAM(GetImgLog(), "imgRequestProxy::BlockOnload", "name", name.get());
michael@0 870 #endif
michael@0 871
michael@0 872 nsCOMPtr<imgIOnloadBlocker> blocker = do_QueryInterface(mListener);
michael@0 873 if (blocker) {
michael@0 874 blocker->BlockOnload(this);
michael@0 875 }
michael@0 876 }
michael@0 877
michael@0 878 void imgRequestProxy::UnblockOnload()
michael@0 879 {
michael@0 880 #ifdef PR_LOGGING
michael@0 881 nsAutoCString name;
michael@0 882 GetName(name);
michael@0 883 LOG_FUNC_WITH_PARAM(GetImgLog(), "imgRequestProxy::UnblockOnload", "name", name.get());
michael@0 884 #endif
michael@0 885
michael@0 886 nsCOMPtr<imgIOnloadBlocker> blocker = do_QueryInterface(mListener);
michael@0 887 if (blocker) {
michael@0 888 blocker->UnblockOnload(this);
michael@0 889 }
michael@0 890 }
michael@0 891
michael@0 892 void imgRequestProxy::NullOutListener()
michael@0 893 {
michael@0 894 // If we have animation consumers, then they don't matter anymore
michael@0 895 if (mListener)
michael@0 896 ClearAnimationConsumers();
michael@0 897
michael@0 898 if (mListenerIsStrongRef) {
michael@0 899 // Releasing could do weird reentery stuff, so just play it super-safe
michael@0 900 nsCOMPtr<imgINotificationObserver> obs;
michael@0 901 obs.swap(mListener);
michael@0 902 mListenerIsStrongRef = false;
michael@0 903 } else {
michael@0 904 mListener = nullptr;
michael@0 905 }
michael@0 906 }
michael@0 907
michael@0 908 NS_IMETHODIMP
michael@0 909 imgRequestProxy::GetStaticRequest(imgIRequest** aReturn)
michael@0 910 {
michael@0 911 imgRequestProxy *proxy;
michael@0 912 nsresult result = GetStaticRequest(&proxy);
michael@0 913 *aReturn = proxy;
michael@0 914 return result;
michael@0 915 }
michael@0 916
michael@0 917 nsresult
michael@0 918 imgRequestProxy::GetStaticRequest(imgRequestProxy** aReturn)
michael@0 919 {
michael@0 920 *aReturn = nullptr;
michael@0 921 nsRefPtr<Image> image = GetImage();
michael@0 922
michael@0 923 bool animated;
michael@0 924 if (!image || (NS_SUCCEEDED(image->GetAnimated(&animated)) && !animated)) {
michael@0 925 // Early exit - we're not animated, so we don't have to do anything.
michael@0 926 NS_ADDREF(*aReturn = this);
michael@0 927 return NS_OK;
michael@0 928 }
michael@0 929
michael@0 930 // Check for errors in the image. Callers code rely on GetStaticRequest
michael@0 931 // failing in this case, though with FrozenImage there's no technical reason
michael@0 932 // for it anymore.
michael@0 933 if (image->HasError()) {
michael@0 934 return NS_ERROR_FAILURE;
michael@0 935 }
michael@0 936
michael@0 937 // We are animated. We need to create a frozen version of this image.
michael@0 938 nsRefPtr<Image> frozenImage = ImageOps::Freeze(image);
michael@0 939
michael@0 940 // Create a static imgRequestProxy with our new extracted frame.
michael@0 941 nsCOMPtr<nsIPrincipal> currentPrincipal;
michael@0 942 GetImagePrincipal(getter_AddRefs(currentPrincipal));
michael@0 943 nsRefPtr<imgRequestProxy> req = new imgRequestProxyStatic(frozenImage,
michael@0 944 currentPrincipal);
michael@0 945 req->Init(nullptr, nullptr, mURI, nullptr);
michael@0 946
michael@0 947 NS_ADDREF(*aReturn = req);
michael@0 948
michael@0 949 return NS_OK;
michael@0 950 }
michael@0 951
michael@0 952 void imgRequestProxy::NotifyListener()
michael@0 953 {
michael@0 954 // It would be nice to notify the observer directly in the status tracker
michael@0 955 // instead of through the proxy, but there are several places we do extra
michael@0 956 // processing when we receive notifications (like OnStopRequest()), and we
michael@0 957 // need to check mCanceled everywhere too.
michael@0 958
michael@0 959 nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
michael@0 960 if (GetOwner()) {
michael@0 961 // Send the notifications to our listener asynchronously.
michael@0 962 statusTracker->Notify(this);
michael@0 963 } else {
michael@0 964 // We don't have an imgRequest, so we can only notify the clone of our
michael@0 965 // current state, but we still have to do that asynchronously.
michael@0 966 NS_ABORT_IF_FALSE(HasImage(),
michael@0 967 "if we have no imgRequest, we should have an Image");
michael@0 968 statusTracker->NotifyCurrentState(this);
michael@0 969 }
michael@0 970 }
michael@0 971
michael@0 972 void imgRequestProxy::SyncNotifyListener()
michael@0 973 {
michael@0 974 // It would be nice to notify the observer directly in the status tracker
michael@0 975 // instead of through the proxy, but there are several places we do extra
michael@0 976 // processing when we receive notifications (like OnStopRequest()), and we
michael@0 977 // need to check mCanceled everywhere too.
michael@0 978
michael@0 979 nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
michael@0 980 statusTracker->SyncNotify(this);
michael@0 981 }
michael@0 982
michael@0 983 void
michael@0 984 imgRequestProxy::SetHasImage()
michael@0 985 {
michael@0 986 nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
michael@0 987 MOZ_ASSERT(statusTracker);
michael@0 988 nsRefPtr<Image> image = statusTracker->GetImage();
michael@0 989 MOZ_ASSERT(image);
michael@0 990
michael@0 991 // Force any private status related to the owner to reflect
michael@0 992 // the presence of an image;
michael@0 993 mBehaviour->SetOwner(mBehaviour->GetOwner());
michael@0 994
michael@0 995 // Apply any locks we have
michael@0 996 for (uint32_t i = 0; i < mLockCount; ++i)
michael@0 997 image->LockImage();
michael@0 998
michael@0 999 // Apply any animation consumers we have
michael@0 1000 for (uint32_t i = 0; i < mAnimationConsumers; i++)
michael@0 1001 image->IncrementAnimationConsumers();
michael@0 1002 }
michael@0 1003
michael@0 1004 already_AddRefed<imgStatusTracker>
michael@0 1005 imgRequestProxy::GetStatusTracker() const
michael@0 1006 {
michael@0 1007 return mBehaviour->GetStatusTracker();
michael@0 1008 }
michael@0 1009
michael@0 1010 already_AddRefed<mozilla::image::Image>
michael@0 1011 imgRequestProxy::GetImage() const
michael@0 1012 {
michael@0 1013 return mBehaviour->GetImage();
michael@0 1014 }
michael@0 1015
michael@0 1016 bool
michael@0 1017 RequestBehaviour::HasImage() const
michael@0 1018 {
michael@0 1019 if (!mOwnerHasImage)
michael@0 1020 return false;
michael@0 1021 nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
michael@0 1022 return statusTracker ? statusTracker->HasImage() : false;
michael@0 1023 }
michael@0 1024
michael@0 1025 bool
michael@0 1026 imgRequestProxy::HasImage() const
michael@0 1027 {
michael@0 1028 return mBehaviour->HasImage();
michael@0 1029 }
michael@0 1030
michael@0 1031 imgRequest*
michael@0 1032 imgRequestProxy::GetOwner() const
michael@0 1033 {
michael@0 1034 return mBehaviour->GetOwner();
michael@0 1035 }
michael@0 1036
michael@0 1037 ////////////////// imgRequestProxyStatic methods
michael@0 1038
michael@0 1039 class StaticBehaviour : public ProxyBehaviour
michael@0 1040 {
michael@0 1041 public:
michael@0 1042 StaticBehaviour(mozilla::image::Image* aImage) : mImage(aImage) {}
michael@0 1043
michael@0 1044 virtual already_AddRefed<mozilla::image::Image>
michael@0 1045 GetImage() const MOZ_OVERRIDE {
michael@0 1046 nsRefPtr<mozilla::image::Image> image = mImage;
michael@0 1047 return image.forget();
michael@0 1048 }
michael@0 1049
michael@0 1050 virtual bool HasImage() const MOZ_OVERRIDE {
michael@0 1051 return mImage;
michael@0 1052 }
michael@0 1053
michael@0 1054 virtual already_AddRefed<imgStatusTracker> GetStatusTracker() const MOZ_OVERRIDE {
michael@0 1055 return mImage->GetStatusTracker();
michael@0 1056 }
michael@0 1057
michael@0 1058 virtual imgRequest* GetOwner() const MOZ_OVERRIDE {
michael@0 1059 return nullptr;
michael@0 1060 }
michael@0 1061
michael@0 1062 virtual void SetOwner(imgRequest* aOwner) MOZ_OVERRIDE {
michael@0 1063 MOZ_ASSERT(!aOwner, "We shouldn't be giving static requests a non-null owner.");
michael@0 1064 }
michael@0 1065
michael@0 1066 private:
michael@0 1067 // Our image. We have to hold a strong reference here, because that's normally
michael@0 1068 // the job of the underlying request.
michael@0 1069 nsRefPtr<mozilla::image::Image> mImage;
michael@0 1070 };
michael@0 1071
michael@0 1072 imgRequestProxyStatic::imgRequestProxyStatic(mozilla::image::Image* aImage,
michael@0 1073 nsIPrincipal* aPrincipal)
michael@0 1074 : mPrincipal(aPrincipal)
michael@0 1075 {
michael@0 1076 mBehaviour = new StaticBehaviour(aImage);
michael@0 1077 }
michael@0 1078
michael@0 1079 NS_IMETHODIMP imgRequestProxyStatic::GetImagePrincipal(nsIPrincipal **aPrincipal)
michael@0 1080 {
michael@0 1081 if (!mPrincipal)
michael@0 1082 return NS_ERROR_FAILURE;
michael@0 1083
michael@0 1084 NS_ADDREF(*aPrincipal = mPrincipal);
michael@0 1085
michael@0 1086 return NS_OK;
michael@0 1087 }
michael@0 1088
michael@0 1089 nsresult
michael@0 1090 imgRequestProxyStatic::Clone(imgINotificationObserver* aObserver,
michael@0 1091 imgRequestProxy** aClone)
michael@0 1092 {
michael@0 1093 return PerformClone(aObserver, NewStaticProxy, aClone);
michael@0 1094 }

mercurial