image/src/imgLoader.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

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 #ifndef imgLoader_h__
michael@0 8 #define imgLoader_h__
michael@0 9
michael@0 10 #include "mozilla/Attributes.h"
michael@0 11
michael@0 12 #include "imgILoader.h"
michael@0 13 #include "imgICache.h"
michael@0 14 #include "nsWeakReference.h"
michael@0 15 #include "nsIContentSniffer.h"
michael@0 16 #include "nsRefPtrHashtable.h"
michael@0 17 #include "nsExpirationTracker.h"
michael@0 18 #include "nsAutoPtr.h"
michael@0 19 #include "imgRequest.h"
michael@0 20 #include "nsIProgressEventSink.h"
michael@0 21 #include "nsIChannel.h"
michael@0 22 #include "mozIThirdPartyUtil.h"
michael@0 23 #include "nsIThreadRetargetableStreamListener.h"
michael@0 24 #include "imgIRequest.h"
michael@0 25
michael@0 26 class imgLoader;
michael@0 27 class imgRequestProxy;
michael@0 28 class imgINotificationObserver;
michael@0 29 class nsILoadGroup;
michael@0 30 class imgCacheExpirationTracker;
michael@0 31 class imgMemoryReporter;
michael@0 32 class nsIChannelPolicy;
michael@0 33
michael@0 34 namespace mozilla {
michael@0 35 namespace image {
michael@0 36 class ImageURL;
michael@0 37 }
michael@0 38 }
michael@0 39
michael@0 40 class imgCacheEntry
michael@0 41 {
michael@0 42 public:
michael@0 43 imgCacheEntry(imgLoader* loader, imgRequest *request, bool aForcePrincipalCheck);
michael@0 44 ~imgCacheEntry();
michael@0 45
michael@0 46 nsrefcnt AddRef()
michael@0 47 {
michael@0 48 NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt");
michael@0 49 NS_ABORT_IF_FALSE(_mOwningThread.GetThread() == PR_GetCurrentThread(), "imgCacheEntry addref isn't thread-safe!");
michael@0 50 ++mRefCnt;
michael@0 51 NS_LOG_ADDREF(this, mRefCnt, "imgCacheEntry", sizeof(*this));
michael@0 52 return mRefCnt;
michael@0 53 }
michael@0 54
michael@0 55 nsrefcnt Release()
michael@0 56 {
michael@0 57 NS_PRECONDITION(0 != mRefCnt, "dup release");
michael@0 58 NS_ABORT_IF_FALSE(_mOwningThread.GetThread() == PR_GetCurrentThread(), "imgCacheEntry release isn't thread-safe!");
michael@0 59 --mRefCnt;
michael@0 60 NS_LOG_RELEASE(this, mRefCnt, "imgCacheEntry");
michael@0 61 if (mRefCnt == 0) {
michael@0 62 mRefCnt = 1; /* stabilize */
michael@0 63 delete this;
michael@0 64 return 0;
michael@0 65 }
michael@0 66 return mRefCnt;
michael@0 67 }
michael@0 68
michael@0 69 uint32_t GetDataSize() const
michael@0 70 {
michael@0 71 return mDataSize;
michael@0 72 }
michael@0 73 void SetDataSize(uint32_t aDataSize)
michael@0 74 {
michael@0 75 int32_t oldsize = mDataSize;
michael@0 76 mDataSize = aDataSize;
michael@0 77 UpdateCache(mDataSize - oldsize);
michael@0 78 }
michael@0 79
michael@0 80 int32_t GetTouchedTime() const
michael@0 81 {
michael@0 82 return mTouchedTime;
michael@0 83 }
michael@0 84 void SetTouchedTime(int32_t time)
michael@0 85 {
michael@0 86 mTouchedTime = time;
michael@0 87 Touch(/* updateTime = */ false);
michael@0 88 }
michael@0 89
michael@0 90 int32_t GetExpiryTime() const
michael@0 91 {
michael@0 92 return mExpiryTime;
michael@0 93 }
michael@0 94 void SetExpiryTime(int32_t aExpiryTime)
michael@0 95 {
michael@0 96 mExpiryTime = aExpiryTime;
michael@0 97 Touch();
michael@0 98 }
michael@0 99
michael@0 100 bool GetMustValidate() const
michael@0 101 {
michael@0 102 return mMustValidate;
michael@0 103 }
michael@0 104 void SetMustValidate(bool aValidate)
michael@0 105 {
michael@0 106 mMustValidate = aValidate;
michael@0 107 Touch();
michael@0 108 }
michael@0 109
michael@0 110 already_AddRefed<imgRequest> GetRequest() const
michael@0 111 {
michael@0 112 nsRefPtr<imgRequest> req = mRequest;
michael@0 113 return req.forget();
michael@0 114 }
michael@0 115
michael@0 116 bool Evicted() const
michael@0 117 {
michael@0 118 return mEvicted;
michael@0 119 }
michael@0 120
michael@0 121 nsExpirationState *GetExpirationState()
michael@0 122 {
michael@0 123 return &mExpirationState;
michael@0 124 }
michael@0 125
michael@0 126 bool HasNoProxies() const
michael@0 127 {
michael@0 128 return mHasNoProxies;
michael@0 129 }
michael@0 130
michael@0 131 bool ForcePrincipalCheck() const
michael@0 132 {
michael@0 133 return mForcePrincipalCheck;
michael@0 134 }
michael@0 135
michael@0 136 imgLoader* Loader() const
michael@0 137 {
michael@0 138 return mLoader;
michael@0 139 }
michael@0 140
michael@0 141 private: // methods
michael@0 142 friend class imgLoader;
michael@0 143 friend class imgCacheQueue;
michael@0 144 void Touch(bool updateTime = true);
michael@0 145 void UpdateCache(int32_t diff = 0);
michael@0 146 void SetEvicted(bool evict)
michael@0 147 {
michael@0 148 mEvicted = evict;
michael@0 149 }
michael@0 150 void SetHasNoProxies(bool hasNoProxies);
michael@0 151
michael@0 152 // Private, unimplemented copy constructor.
michael@0 153 imgCacheEntry(const imgCacheEntry &);
michael@0 154
michael@0 155 private: // data
michael@0 156 nsAutoRefCnt mRefCnt;
michael@0 157 NS_DECL_OWNINGTHREAD
michael@0 158
michael@0 159 imgLoader* mLoader;
michael@0 160 nsRefPtr<imgRequest> mRequest;
michael@0 161 uint32_t mDataSize;
michael@0 162 int32_t mTouchedTime;
michael@0 163 int32_t mExpiryTime;
michael@0 164 nsExpirationState mExpirationState;
michael@0 165 bool mMustValidate : 1;
michael@0 166 bool mEvicted : 1;
michael@0 167 bool mHasNoProxies : 1;
michael@0 168 bool mForcePrincipalCheck : 1;
michael@0 169 };
michael@0 170
michael@0 171 #include <vector>
michael@0 172
michael@0 173 #define NS_IMGLOADER_CID \
michael@0 174 { /* 9f6a0d2e-1dd1-11b2-a5b8-951f13c846f7 */ \
michael@0 175 0x9f6a0d2e, \
michael@0 176 0x1dd1, \
michael@0 177 0x11b2, \
michael@0 178 {0xa5, 0xb8, 0x95, 0x1f, 0x13, 0xc8, 0x46, 0xf7} \
michael@0 179 }
michael@0 180
michael@0 181 class imgCacheQueue
michael@0 182 {
michael@0 183 public:
michael@0 184 imgCacheQueue();
michael@0 185 void Remove(imgCacheEntry *);
michael@0 186 void Push(imgCacheEntry *);
michael@0 187 void MarkDirty();
michael@0 188 bool IsDirty();
michael@0 189 already_AddRefed<imgCacheEntry> Pop();
michael@0 190 void Refresh();
michael@0 191 uint32_t GetSize() const;
michael@0 192 void UpdateSize(int32_t diff);
michael@0 193 uint32_t GetNumElements() const;
michael@0 194 typedef std::vector<nsRefPtr<imgCacheEntry> > queueContainer;
michael@0 195 typedef queueContainer::iterator iterator;
michael@0 196 typedef queueContainer::const_iterator const_iterator;
michael@0 197
michael@0 198 iterator begin();
michael@0 199 const_iterator begin() const;
michael@0 200 iterator end();
michael@0 201 const_iterator end() const;
michael@0 202
michael@0 203 private:
michael@0 204 queueContainer mQueue;
michael@0 205 bool mDirty;
michael@0 206 uint32_t mSize;
michael@0 207 };
michael@0 208
michael@0 209 class imgLoader : public imgILoader,
michael@0 210 public nsIContentSniffer,
michael@0 211 public imgICache,
michael@0 212 public nsSupportsWeakReference,
michael@0 213 public nsIObserver
michael@0 214 {
michael@0 215 public:
michael@0 216 typedef mozilla::image::ImageURL ImageURL;
michael@0 217 typedef nsRefPtrHashtable<nsCStringHashKey, imgCacheEntry> imgCacheTable;
michael@0 218
michael@0 219 NS_DECL_ISUPPORTS
michael@0 220 NS_DECL_IMGILOADER
michael@0 221 NS_DECL_NSICONTENTSNIFFER
michael@0 222 NS_DECL_IMGICACHE
michael@0 223 NS_DECL_NSIOBSERVER
michael@0 224
michael@0 225 static imgLoader* Singleton();
michael@0 226 static imgLoader* PBSingleton();
michael@0 227
michael@0 228 imgLoader();
michael@0 229 virtual ~imgLoader();
michael@0 230
michael@0 231 nsresult Init();
michael@0 232
michael@0 233 static imgLoader* Create()
michael@0 234 {
michael@0 235 // Unfortunately, we rely on XPCOM module init happening
michael@0 236 // before imgLoader creation. For now, it's easier
michael@0 237 // to just call CallCreateInstance() which will init
michael@0 238 // the image module instead of calling new imgLoader
michael@0 239 // directly.
michael@0 240 imgILoader *loader;
michael@0 241 CallCreateInstance("@mozilla.org/image/loader;1", &loader);
michael@0 242 // There's only one imgLoader implementation so we
michael@0 243 // can safely cast to it.
michael@0 244 return static_cast<imgLoader*>(loader);
michael@0 245 }
michael@0 246
michael@0 247 static already_AddRefed<imgLoader> GetInstance();
michael@0 248
michael@0 249 nsresult LoadImage(nsIURI *aURI,
michael@0 250 nsIURI *aInitialDocumentURI,
michael@0 251 nsIURI *aReferrerURI,
michael@0 252 nsIPrincipal* aLoadingPrincipal,
michael@0 253 nsILoadGroup *aLoadGroup,
michael@0 254 imgINotificationObserver *aObserver,
michael@0 255 nsISupports *aCX,
michael@0 256 nsLoadFlags aLoadFlags,
michael@0 257 nsISupports *aCacheKey,
michael@0 258 nsIChannelPolicy *aPolicy,
michael@0 259 const nsAString& initiatorType,
michael@0 260 imgRequestProxy **_retval);
michael@0 261 nsresult LoadImageWithChannel(nsIChannel *channel,
michael@0 262 imgINotificationObserver *aObserver,
michael@0 263 nsISupports *aCX,
michael@0 264 nsIStreamListener **listener,
michael@0 265 imgRequestProxy **_retval);
michael@0 266
michael@0 267 static nsresult GetMimeTypeFromContent(const char* aContents, uint32_t aLength, nsACString& aContentType);
michael@0 268 // exported for use by mimei.cpp in libxul sdk builds
michael@0 269 static NS_EXPORT_(bool) SupportImageWithMimeType(const char* aMimeType);
michael@0 270
michael@0 271 static void GlobalInit(); // for use by the factory
michael@0 272 static void Shutdown(); // for use by the factory
michael@0 273
michael@0 274 nsresult ClearChromeImageCache();
michael@0 275 nsresult ClearImageCache();
michael@0 276 void MinimizeCaches();
michael@0 277
michael@0 278 nsresult InitCache();
michael@0 279
michael@0 280 nsAutoCString GetCacheKey(nsIURI *firstPartyIsolationURI,
michael@0 281 nsIURI* uri,
michael@0 282 bool *isIsolated);
michael@0 283 nsAutoCString GetCacheKey(nsIURI *firstPartyIsolationURI,
michael@0 284 ImageURL *imgURI,
michael@0 285 bool *isIsolated);
michael@0 286 bool RemoveFromCache(ImageURL *aKey);
michael@0 287 bool RemoveFromCache(nsAutoCString key,
michael@0 288 imgCacheTable &cache,
michael@0 289 imgCacheQueue &queue);
michael@0 290 bool RemoveFromCache(imgCacheEntry *entry);
michael@0 291
michael@0 292 bool PutIntoCache(nsAutoCString key, imgCacheEntry *entry);
michael@0 293
michael@0 294
michael@0 295 // Returns true if we should prefer evicting cache entry |two| over cache
michael@0 296 // entry |one|.
michael@0 297 // This mixes units in the worst way, but provides reasonable results.
michael@0 298 inline static bool CompareCacheEntries(const nsRefPtr<imgCacheEntry> &one,
michael@0 299 const nsRefPtr<imgCacheEntry> &two)
michael@0 300 {
michael@0 301 if (!one)
michael@0 302 return false;
michael@0 303 if (!two)
michael@0 304 return true;
michael@0 305
michael@0 306 const double sizeweight = 1.0 - sCacheTimeWeight;
michael@0 307
michael@0 308 // We want large, old images to be evicted first (depending on their
michael@0 309 // relative weights). Since a larger time is actually newer, we subtract
michael@0 310 // time's weight, so an older image has a larger weight.
michael@0 311 double oneweight = double(one->GetDataSize()) * sizeweight -
michael@0 312 double(one->GetTouchedTime()) * sCacheTimeWeight;
michael@0 313 double twoweight = double(two->GetDataSize()) * sizeweight -
michael@0 314 double(two->GetTouchedTime()) * sCacheTimeWeight;
michael@0 315
michael@0 316 return oneweight < twoweight;
michael@0 317 }
michael@0 318
michael@0 319 void VerifyCacheSizes();
michael@0 320
michael@0 321 // The image loader maintains a hash table of all imgCacheEntries. However,
michael@0 322 // only some of them will be evicted from the cache: those who have no
michael@0 323 // imgRequestProxies watching their imgRequests.
michael@0 324 //
michael@0 325 // Once an imgRequest has no imgRequestProxies, it should notify us by
michael@0 326 // calling HasNoObservers(), and null out its cache entry pointer.
michael@0 327 //
michael@0 328 // Upon having a proxy start observing again, it should notify us by calling
michael@0 329 // HasObservers(). The request's cache entry will be re-set before this
michael@0 330 // happens, by calling imgRequest::SetCacheEntry() when an entry with no
michael@0 331 // observers is re-requested.
michael@0 332 bool SetHasNoProxies(ImageURL *imgURI, imgCacheEntry *entry);
michael@0 333 bool SetHasProxies(nsIURI *firstPartyIsolationURI, ImageURL *imgURI);
michael@0 334
michael@0 335 private: // methods
michael@0 336
michael@0 337 bool ValidateEntry(imgCacheEntry *aEntry, nsIURI *aURI,
michael@0 338 nsIURI *aFirstPartyIsolationURI, nsIURI *aReferrerURI,
michael@0 339 nsILoadGroup *aLoadGroup,
michael@0 340 imgINotificationObserver *aObserver, nsISupports *aCX,
michael@0 341 nsLoadFlags aLoadFlags, bool aCanMakeNewChannel,
michael@0 342 imgRequestProxy **aProxyRequest,
michael@0 343 nsIChannelPolicy *aPolicy,
michael@0 344 nsIPrincipal* aLoadingPrincipal,
michael@0 345 int32_t aCORSMode);
michael@0 346
michael@0 347 bool ValidateRequestWithNewChannel(imgRequest *request, nsIURI *aURI,
michael@0 348 nsIURI *aInitialDocumentURI,
michael@0 349 nsIURI *aReferrerURI,
michael@0 350 nsILoadGroup *aLoadGroup,
michael@0 351 imgINotificationObserver *aObserver,
michael@0 352 nsISupports *aCX, nsLoadFlags aLoadFlags,
michael@0 353 imgRequestProxy **aProxyRequest,
michael@0 354 nsIChannelPolicy *aPolicy,
michael@0 355 nsIPrincipal* aLoadingPrincipal,
michael@0 356 int32_t aCORSMode);
michael@0 357
michael@0 358 nsresult CreateNewProxyForRequest(imgRequest *aRequest, nsILoadGroup *aLoadGroup,
michael@0 359 imgINotificationObserver *aObserver,
michael@0 360 nsLoadFlags aLoadFlags, imgRequestProxy **_retval);
michael@0 361
michael@0 362 void ReadAcceptHeaderPref();
michael@0 363
michael@0 364 nsresult EvictEntries(imgCacheTable &aCacheToClear);
michael@0 365 nsresult EvictEntries(imgCacheQueue &aQueueToClear);
michael@0 366
michael@0 367 imgCacheTable &GetCache(nsIURI *aURI);
michael@0 368 imgCacheQueue &GetCacheQueue(nsIURI *aURI);
michael@0 369 imgCacheTable &GetCache(ImageURL *aURI);
michael@0 370 imgCacheQueue &GetCacheQueue(ImageURL *aURI);
michael@0 371 void CacheEntriesChanged(ImageURL *aURI, int32_t sizediff = 0);
michael@0 372 void CheckCacheLimits(imgCacheTable &cache, imgCacheQueue &queue);
michael@0 373 bool RemoveMatchingUrlsFromCache(nsIURI *aImgURI);
michael@0 374
michael@0 375 private: // data
michael@0 376 friend class imgCacheEntry;
michael@0 377 friend class imgMemoryReporter;
michael@0 378 friend class imgRequest;
michael@0 379
michael@0 380 imgCacheTable mCache;
michael@0 381 imgCacheQueue mCacheQueue;
michael@0 382
michael@0 383 imgCacheTable mChromeCache;
michael@0 384 imgCacheQueue mChromeCacheQueue;
michael@0 385
michael@0 386 static double sCacheTimeWeight;
michael@0 387 static uint32_t sCacheMaxSize;
michael@0 388 static imgMemoryReporter* sMemReporter;
michael@0 389
michael@0 390 static nsCOMPtr<mozIThirdPartyUtil> sThirdPartyUtilSvc;
michael@0 391 nsCString mAcceptHeader;
michael@0 392
michael@0 393 nsAutoPtr<imgCacheExpirationTracker> mCacheTracker;
michael@0 394 bool mRespectPrivacy;
michael@0 395 };
michael@0 396
michael@0 397
michael@0 398
michael@0 399 /**
michael@0 400 * proxy stream listener class used to handle multipart/x-mixed-replace
michael@0 401 */
michael@0 402
michael@0 403 #include "nsCOMPtr.h"
michael@0 404 #include "nsIStreamListener.h"
michael@0 405 #include "nsIThreadRetargetableStreamListener.h"
michael@0 406
michael@0 407 class ProxyListener : public nsIStreamListener
michael@0 408 , public nsIThreadRetargetableStreamListener
michael@0 409 {
michael@0 410 public:
michael@0 411 ProxyListener(nsIStreamListener *dest);
michael@0 412 virtual ~ProxyListener();
michael@0 413
michael@0 414 /* additional members */
michael@0 415 NS_DECL_ISUPPORTS
michael@0 416 NS_DECL_NSISTREAMLISTENER
michael@0 417 NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
michael@0 418 NS_DECL_NSIREQUESTOBSERVER
michael@0 419
michael@0 420 private:
michael@0 421 nsCOMPtr<nsIStreamListener> mDestListener;
michael@0 422 };
michael@0 423
michael@0 424 /**
michael@0 425 * A class that implements nsIProgressEventSink and forwards all calls to it to
michael@0 426 * the original notification callbacks of the channel. Also implements
michael@0 427 * nsIInterfaceRequestor and gives out itself for nsIProgressEventSink calls,
michael@0 428 * and forwards everything else to the channel's notification callbacks.
michael@0 429 */
michael@0 430 class nsProgressNotificationProxy MOZ_FINAL
michael@0 431 : public nsIProgressEventSink
michael@0 432 , public nsIChannelEventSink
michael@0 433 , public nsIInterfaceRequestor
michael@0 434 {
michael@0 435 public:
michael@0 436 nsProgressNotificationProxy(nsIChannel* channel,
michael@0 437 imgIRequest* proxy)
michael@0 438 : mImageRequest(proxy) {
michael@0 439 channel->GetNotificationCallbacks(getter_AddRefs(mOriginalCallbacks));
michael@0 440 }
michael@0 441
michael@0 442 NS_DECL_ISUPPORTS
michael@0 443 NS_DECL_NSIPROGRESSEVENTSINK
michael@0 444 NS_DECL_NSICHANNELEVENTSINK
michael@0 445 NS_DECL_NSIINTERFACEREQUESTOR
michael@0 446 private:
michael@0 447 ~nsProgressNotificationProxy() {}
michael@0 448
michael@0 449 nsCOMPtr<nsIInterfaceRequestor> mOriginalCallbacks;
michael@0 450 nsCOMPtr<nsIRequest> mImageRequest;
michael@0 451 };
michael@0 452
michael@0 453 /**
michael@0 454 * validate checker
michael@0 455 */
michael@0 456
michael@0 457 #include "nsCOMArray.h"
michael@0 458
michael@0 459 class imgCacheValidator : public nsIStreamListener,
michael@0 460 public nsIThreadRetargetableStreamListener,
michael@0 461 public nsIChannelEventSink,
michael@0 462 public nsIInterfaceRequestor,
michael@0 463 public nsIAsyncVerifyRedirectCallback
michael@0 464 {
michael@0 465 public:
michael@0 466 imgCacheValidator(nsProgressNotificationProxy* progress, imgLoader* loader,
michael@0 467 imgRequest *request, void *aContext, bool forcePrincipalCheckForCacheEntry);
michael@0 468 virtual ~imgCacheValidator();
michael@0 469
michael@0 470 void AddProxy(imgRequestProxy *aProxy);
michael@0 471
michael@0 472 NS_DECL_ISUPPORTS
michael@0 473 NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
michael@0 474 NS_DECL_NSISTREAMLISTENER
michael@0 475 NS_DECL_NSIREQUESTOBSERVER
michael@0 476 NS_DECL_NSICHANNELEVENTSINK
michael@0 477 NS_DECL_NSIINTERFACEREQUESTOR
michael@0 478 NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
michael@0 479
michael@0 480 private:
michael@0 481 nsCOMPtr<nsIStreamListener> mDestListener;
michael@0 482 nsRefPtr<nsProgressNotificationProxy> mProgressProxy;
michael@0 483 nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
michael@0 484 nsCOMPtr<nsIChannel> mRedirectChannel;
michael@0 485
michael@0 486 nsRefPtr<imgRequest> mRequest;
michael@0 487 nsCOMArray<imgIRequest> mProxies;
michael@0 488
michael@0 489 nsRefPtr<imgRequest> mNewRequest;
michael@0 490 nsRefPtr<imgCacheEntry> mNewEntry;
michael@0 491
michael@0 492 void *mContext;
michael@0 493
michael@0 494 imgLoader* mImgLoader;
michael@0 495 };
michael@0 496
michael@0 497 #endif // imgLoader_h__

mercurial