PageRenderTime 37ms CodeModel.GetById 12ms app.highlight 21ms RepoModel.GetById 1ms app.codeStats 0ms

/image/src/imgLoader.h

http://github.com/zpao/v8monkey
C Header | 462 lines | 316 code | 76 blank | 70 comment | 7 complexity | 98fedd8c42858378a6da41900c5057cc MD5 | raw file
  1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2 *
  3 * ***** BEGIN LICENSE BLOCK *****
  4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  5 *
  6 * The contents of this file are subject to the Mozilla Public License Version
  7 * 1.1 (the "License"); you may not use this file except in compliance with
  8 * the License. You may obtain a copy of the License at
  9 * http://www.mozilla.org/MPL/
 10 *
 11 * Software distributed under the License is distributed on an "AS IS" basis,
 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 13 * for the specific language governing rights and limitations under the
 14 * License.
 15 *
 16 * The Original Code is mozilla.org code.
 17 *
 18 * The Initial Developer of the Original Code is
 19 * Netscape Communications Corporation.
 20 * Portions created by the Initial Developer are Copyright (C) 2001
 21 * the Initial Developer. All Rights Reserved.
 22 *
 23 * Contributor(s):
 24 *   Stuart Parmenter <pavlov@netscape.com>
 25 *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
 26 *
 27 * Alternatively, the contents of this file may be used under the terms of
 28 * either the GNU General Public License Version 2 or later (the "GPL"), or
 29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 30 * in which case the provisions of the GPL or the LGPL are applicable instead
 31 * of those above. If you wish to allow use of your version of this file only
 32 * under the terms of either the GPL or the LGPL, and not to allow others to
 33 * use your version of this file under the terms of the MPL, indicate your
 34 * decision by deleting the provisions above and replace them with the notice
 35 * and other provisions required by the GPL or the LGPL. If you do not delete
 36 * the provisions above, a recipient may use your version of this file under
 37 * the terms of any one of the MPL, the GPL or the LGPL.
 38 *
 39 * ***** END LICENSE BLOCK ***** */
 40
 41#ifndef imgLoader_h__
 42#define imgLoader_h__
 43
 44#include "mozilla/Attributes.h"
 45
 46#include "imgILoader.h"
 47#include "imgICache.h"
 48#include "nsWeakReference.h"
 49#include "nsIContentSniffer.h"
 50#include "nsRefPtrHashtable.h"
 51#include "nsExpirationTracker.h"
 52#include "nsAutoPtr.h"
 53#include "prtypes.h"
 54#include "imgRequest.h"
 55#include "nsIObserverService.h"
 56#include "nsIChannelPolicy.h"
 57#include "nsIProgressEventSink.h"
 58#include "nsIChannel.h"
 59
 60#ifdef LOADER_THREADSAFE
 61#include "prlock.h"
 62#endif
 63
 64class imgRequest;
 65class imgRequestProxy;
 66class imgIRequest;
 67class imgIDecoderObserver;
 68class nsILoadGroup;
 69
 70class imgCacheEntry
 71{
 72public:
 73  imgCacheEntry(imgRequest *request, bool aForcePrincipalCheck);
 74  ~imgCacheEntry();
 75
 76  nsrefcnt AddRef()
 77  {
 78    NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
 79    NS_ABORT_IF_FALSE(_mOwningThread.GetThread() == PR_GetCurrentThread(), "imgCacheEntry addref isn't thread-safe!");
 80    ++mRefCnt;
 81    NS_LOG_ADDREF(this, mRefCnt, "imgCacheEntry", sizeof(*this));
 82    return mRefCnt;
 83  }
 84 
 85  nsrefcnt Release()
 86  {
 87    NS_PRECONDITION(0 != mRefCnt, "dup release");
 88    NS_ABORT_IF_FALSE(_mOwningThread.GetThread() == PR_GetCurrentThread(), "imgCacheEntry release isn't thread-safe!");
 89    --mRefCnt;
 90    NS_LOG_RELEASE(this, mRefCnt, "imgCacheEntry");
 91    if (mRefCnt == 0) {
 92      mRefCnt = 1; /* stabilize */
 93      delete this;
 94      return 0;
 95    }
 96    return mRefCnt;                              
 97  }
 98
 99  PRUint32 GetDataSize() const
100  {
101    return mDataSize;
102  }
103  void SetDataSize(PRUint32 aDataSize)
104  {
105    PRInt32 oldsize = mDataSize;
106    mDataSize = aDataSize;
107    UpdateCache(mDataSize - oldsize);
108  }
109
110  PRInt32 GetTouchedTime() const
111  {
112    return mTouchedTime;
113  }
114  void SetTouchedTime(PRInt32 time)
115  {
116    mTouchedTime = time;
117    Touch(/* updateTime = */ false);
118  }
119
120  PRInt32 GetExpiryTime() const
121  {
122    return mExpiryTime;
123  }
124  void SetExpiryTime(PRInt32 aExpiryTime)
125  {
126    mExpiryTime = aExpiryTime;
127    Touch();
128  }
129
130  bool GetMustValidate() const
131  {
132    return mMustValidate;
133  }
134  void SetMustValidate(bool aValidate)
135  {
136    mMustValidate = aValidate;
137    Touch();
138  }
139
140  already_AddRefed<imgRequest> GetRequest() const
141  {
142    imgRequest *req = mRequest;
143    NS_ADDREF(req);
144    return req;
145  }
146
147  bool Evicted() const
148  {
149    return mEvicted;
150  }
151
152  nsExpirationState *GetExpirationState()
153  {
154    return &mExpirationState;
155  }
156
157  bool HasNoProxies() const
158  {
159    return mHasNoProxies;
160  }
161
162  bool ForcePrincipalCheck() const
163  {
164    return mForcePrincipalCheck;
165  }
166
167private: // methods
168  friend class imgLoader;
169  friend class imgCacheQueue;
170  void Touch(bool updateTime = true);
171  void UpdateCache(PRInt32 diff = 0);
172  void SetEvicted(bool evict)
173  {
174    mEvicted = evict;
175  }
176  void SetHasNoProxies(bool hasNoProxies);
177
178  // Private, unimplemented copy constructor.
179  imgCacheEntry(const imgCacheEntry &);
180
181private: // data
182  nsAutoRefCnt mRefCnt;
183  NS_DECL_OWNINGTHREAD
184
185  nsRefPtr<imgRequest> mRequest;
186  PRUint32 mDataSize;
187  PRInt32 mTouchedTime;
188  PRInt32 mExpiryTime;
189  nsExpirationState mExpirationState;
190  bool mMustValidate : 1;
191  bool mEvicted : 1;
192  bool mHasNoProxies : 1;
193  bool mForcePrincipalCheck : 1;
194};
195
196#include <vector>
197
198#define NS_IMGLOADER_CID \
199{ /* 9f6a0d2e-1dd1-11b2-a5b8-951f13c846f7 */         \
200     0x9f6a0d2e,                                     \
201     0x1dd1,                                         \
202     0x11b2,                                         \
203    {0xa5, 0xb8, 0x95, 0x1f, 0x13, 0xc8, 0x46, 0xf7} \
204}
205
206class imgCacheQueue
207{
208public: 
209  imgCacheQueue();
210  void Remove(imgCacheEntry *);
211  void Push(imgCacheEntry *);
212  void MarkDirty();
213  bool IsDirty();
214  already_AddRefed<imgCacheEntry> Pop();
215  void Refresh();
216  PRUint32 GetSize() const;
217  void UpdateSize(PRInt32 diff);
218  PRUint32 GetNumElements() const;
219  typedef std::vector<nsRefPtr<imgCacheEntry> > queueContainer;  
220  typedef queueContainer::iterator iterator;
221  typedef queueContainer::const_iterator const_iterator;
222
223  iterator begin();
224  const_iterator begin() const;
225  iterator end();
226  const_iterator end() const;
227
228private:
229  queueContainer mQueue;
230  bool mDirty;
231  PRUint32 mSize;
232};
233
234class imgMemoryReporter;
235
236class imgLoader : public imgILoader,
237                  public nsIContentSniffer,
238                  public imgICache,
239                  public nsSupportsWeakReference,
240                  public nsIObserver
241{
242public:
243  NS_DECL_ISUPPORTS
244  NS_DECL_IMGILOADER
245  NS_DECL_NSICONTENTSNIFFER
246  NS_DECL_IMGICACHE
247  NS_DECL_NSIOBSERVER
248
249  imgLoader();
250  virtual ~imgLoader();
251
252  nsresult Init();
253
254  static nsresult GetMimeTypeFromContent(const char* aContents, PRUint32 aLength, nsACString& aContentType);
255
256  static void Shutdown(); // for use by the factory
257
258  static nsresult ClearChromeImageCache();
259  static nsresult ClearImageCache();
260  static void MinimizeCaches();
261
262  static nsresult InitCache();
263
264  static bool RemoveFromCache(nsIURI *aKey);
265  static bool RemoveFromCache(imgCacheEntry *entry);
266
267  static bool PutIntoCache(nsIURI *key, imgCacheEntry *entry);
268
269  // Returns true if we should prefer evicting cache entry |two| over cache
270  // entry |one|.
271  // This mixes units in the worst way, but provides reasonable results.
272  inline static bool CompareCacheEntries(const nsRefPtr<imgCacheEntry> &one,
273                                         const nsRefPtr<imgCacheEntry> &two)
274  {
275    if (!one)
276      return false;
277    if (!two)
278      return true;
279
280    const double sizeweight = 1.0 - sCacheTimeWeight;
281
282    // We want large, old images to be evicted first (depending on their
283    // relative weights). Since a larger time is actually newer, we subtract
284    // time's weight, so an older image has a larger weight.
285    double oneweight = double(one->GetDataSize()) * sizeweight -
286                       double(one->GetTouchedTime()) * sCacheTimeWeight;
287    double twoweight = double(two->GetDataSize()) * sizeweight -
288                       double(two->GetTouchedTime()) * sCacheTimeWeight;
289
290    return oneweight < twoweight;
291  }
292
293  static void VerifyCacheSizes();
294
295  // The image loader maintains a hash table of all imgCacheEntries. However,
296  // only some of them will be evicted from the cache: those who have no
297  // imgRequestProxies watching their imgRequests. 
298  //
299  // Once an imgRequest has no imgRequestProxies, it should notify us by
300  // calling HasNoObservers(), and null out its cache entry pointer.
301  // 
302  // Upon having a proxy start observing again, it should notify us by calling
303  // HasObservers(). The request's cache entry will be re-set before this
304  // happens, by calling imgRequest::SetCacheEntry() when an entry with no
305  // observers is re-requested.
306  static bool SetHasNoProxies(nsIURI *key, imgCacheEntry *entry);
307  static bool SetHasProxies(nsIURI *key);
308
309private: // methods
310
311
312  bool ValidateEntry(imgCacheEntry *aEntry, nsIURI *aKey,
313                       nsIURI *aInitialDocumentURI, nsIURI *aReferrerURI, 
314                       nsILoadGroup *aLoadGroup,
315                       imgIDecoderObserver *aObserver, nsISupports *aCX,
316                       nsLoadFlags aLoadFlags, bool aCanMakeNewChannel,
317                       imgIRequest *aExistingRequest,
318                       imgIRequest **aProxyRequest,
319                       nsIChannelPolicy *aPolicy,
320                       nsIPrincipal* aLoadingPrincipal,
321                       PRInt32 aCORSMode);
322  bool ValidateRequestWithNewChannel(imgRequest *request, nsIURI *aURI,
323                                       nsIURI *aInitialDocumentURI,
324                                       nsIURI *aReferrerURI,
325                                       nsILoadGroup *aLoadGroup,
326                                       imgIDecoderObserver *aObserver,
327                                       nsISupports *aCX, nsLoadFlags aLoadFlags,
328                                       imgIRequest *aExistingRequest,
329                                       imgIRequest **aProxyRequest,
330                                       nsIChannelPolicy *aPolicy,
331                                       nsIPrincipal* aLoadingPrincipal,
332                                       PRInt32 aCORSMode);
333
334  nsresult CreateNewProxyForRequest(imgRequest *aRequest, nsILoadGroup *aLoadGroup,
335                                    imgIDecoderObserver *aObserver,
336                                    nsLoadFlags aLoadFlags, imgIRequest *aRequestProxy,
337                                    imgIRequest **_retval);
338
339  void ReadAcceptHeaderPref();
340
341
342  typedef nsRefPtrHashtable<nsCStringHashKey, imgCacheEntry> imgCacheTable;
343
344  static nsresult EvictEntries(imgCacheTable &aCacheToClear);
345  static nsresult EvictEntries(imgCacheQueue &aQueueToClear);
346
347  static imgCacheTable &GetCache(nsIURI *aURI);
348  static imgCacheQueue &GetCacheQueue(nsIURI *aURI);
349  static void CacheEntriesChanged(nsIURI *aURI, PRInt32 sizediff = 0);
350  static void CheckCacheLimits(imgCacheTable &cache, imgCacheQueue &queue);
351
352private: // data
353  friend class imgCacheEntry;
354  friend class imgMemoryReporter;
355
356  static imgCacheTable sCache;
357  static imgCacheQueue sCacheQueue;
358
359  static imgCacheTable sChromeCache;
360  static imgCacheQueue sChromeCacheQueue;
361  static PRFloat64 sCacheTimeWeight;
362  static PRUint32 sCacheMaxSize;
363
364  nsCString mAcceptHeader;
365};
366
367
368
369/**
370 * proxy stream listener class used to handle multipart/x-mixed-replace
371 */
372
373#include "nsCOMPtr.h"
374#include "nsIStreamListener.h"
375
376class ProxyListener : public nsIStreamListener
377{
378public:
379  ProxyListener(nsIStreamListener *dest);
380  virtual ~ProxyListener();
381
382  /* additional members */
383  NS_DECL_ISUPPORTS
384  NS_DECL_NSISTREAMLISTENER
385  NS_DECL_NSIREQUESTOBSERVER
386
387private:
388  nsCOMPtr<nsIStreamListener> mDestListener;
389};
390
391/**
392 * A class that implements nsIProgressEventSink and forwards all calls to it to
393 * the original notification callbacks of the channel. Also implements
394 * nsIInterfaceRequestor and gives out itself for nsIProgressEventSink calls,
395 * and forwards everything else to the channel's notification callbacks.
396 */
397class nsProgressNotificationProxy MOZ_FINAL
398  : public nsIProgressEventSink
399  , public nsIChannelEventSink
400  , public nsIInterfaceRequestor
401{
402  public:
403    nsProgressNotificationProxy(nsIChannel* channel,
404                                imgIRequest* proxy)
405        : mImageRequest(proxy) {
406      channel->GetNotificationCallbacks(getter_AddRefs(mOriginalCallbacks));
407    }
408
409    NS_DECL_ISUPPORTS
410    NS_DECL_NSIPROGRESSEVENTSINK
411    NS_DECL_NSICHANNELEVENTSINK
412    NS_DECL_NSIINTERFACEREQUESTOR
413  private:
414    ~nsProgressNotificationProxy() {}
415
416    nsCOMPtr<nsIInterfaceRequestor> mOriginalCallbacks;
417    nsCOMPtr<nsIRequest> mImageRequest;
418};
419
420/**
421 * validate checker
422 */
423
424#include "nsCOMArray.h"
425
426class imgCacheValidator : public nsIStreamListener,
427                          public nsIChannelEventSink,
428                          public nsIInterfaceRequestor,
429                          public nsIAsyncVerifyRedirectCallback
430{
431public:
432  imgCacheValidator(nsProgressNotificationProxy* progress, imgRequest *request,
433                    void *aContext, bool forcePrincipalCheckForCacheEntry);
434  virtual ~imgCacheValidator();
435
436  void AddProxy(imgRequestProxy *aProxy);
437
438  NS_DECL_ISUPPORTS
439  NS_DECL_NSISTREAMLISTENER
440  NS_DECL_NSIREQUESTOBSERVER
441  NS_DECL_NSICHANNELEVENTSINK
442  NS_DECL_NSIINTERFACEREQUESTOR
443  NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
444
445private:
446  nsCOMPtr<nsIStreamListener> mDestListener;
447  nsRefPtr<nsProgressNotificationProxy> mProgressProxy;
448  nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
449  nsCOMPtr<nsIChannel> mRedirectChannel;
450
451  nsRefPtr<imgRequest> mRequest;
452  nsCOMArray<imgIRequest> mProxies;
453
454  nsRefPtr<imgRequest> mNewRequest;
455  nsRefPtr<imgCacheEntry> mNewEntry;
456
457  void *mContext;
458
459  static imgLoader sImgLoader;
460};
461
462#endif  // imgLoader_h__