Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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 | } |