1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef mozilla_image_ImageURL_h
7 #define mozilla_image_ImageURL_h
8 
9 #include "nsIURI.h"
10 #include "MainThreadUtils.h"
11 #include "nsNetUtil.h"
12 #include "mozilla/HashFunctions.h"
13 #include "nsHashKeys.h"
14 #include "nsProxyRelease.h"
15 
16 namespace mozilla {
17 namespace image {
18 
19 class ImageCacheKey;
20 
21 /** ImageURL
22  *
23  * nsStandardURL is not threadsafe, so this class is created to hold only the
24  * necessary URL data required for image loading and decoding.
25  *
26  * Note: Although several APIs have the same or similar prototypes as those
27  * found in nsIURI/nsStandardURL, the class does not implement nsIURI. This is
28  * intentional; functionality is limited, and is only useful for imagelib code.
29  * By not implementing nsIURI, external code cannot unintentionally be given an
30  * nsIURI pointer with this limited class behind it; instead, conversion to a
31  * fully implemented nsIURI is required (e.g. through NS_NewURI).
32  */
33 class ImageURL {
34  public:
ImageURL(nsIURI * aURI,nsresult & aRv)35   explicit ImageURL(nsIURI* aURI, nsresult& aRv)
36       : mURI(new nsMainThreadPtrHolder<nsIURI>("ImageURL::mURI", aURI)) {
37     MOZ_ASSERT(NS_IsMainThread(), "Cannot use nsIURI off main thread!");
38 
39     aRv = aURI->GetSpec(mSpec);
40     NS_ENSURE_SUCCESS_VOID(aRv);
41 
42     aRv = aURI->GetScheme(mScheme);
43     NS_ENSURE_SUCCESS_VOID(aRv);
44 
45     aRv = aURI->GetRef(mRef);
46     NS_ENSURE_SUCCESS_VOID(aRv);
47   }
48 
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageURL)49   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageURL)
50 
51   nsresult GetSpec(nsACString& result) {
52     result = mSpec;
53     return NS_OK;
54   }
55 
56   /// A weak pointer to the URI spec for this ImageURL. For logging only.
Spec()57   const char* Spec() const { return mSpec.get(); }
58 
59   enum TruncatedSpecStatus { FitsInto1k, TruncatedTo1k };
GetSpecTruncatedTo1k(nsACString & result)60   TruncatedSpecStatus GetSpecTruncatedTo1k(nsACString& result) {
61     static const size_t sMaxTruncatedLength = 1024;
62 
63     if (sMaxTruncatedLength >= mSpec.Length()) {
64       result = mSpec;
65       return FitsInto1k;
66     }
67 
68     result = Substring(mSpec, 0, sMaxTruncatedLength);
69     return TruncatedTo1k;
70   }
71 
GetScheme(nsACString & result)72   nsresult GetScheme(nsACString& result) {
73     result = mScheme;
74     return NS_OK;
75   }
76 
SchemeIs(const char * scheme,bool * result)77   nsresult SchemeIs(const char* scheme, bool* result) {
78     NS_PRECONDITION(scheme, "scheme is null");
79     NS_PRECONDITION(result, "result is null");
80 
81     *result = mScheme.Equals(scheme);
82     return NS_OK;
83   }
84 
GetRef(nsACString & result)85   nsresult GetRef(nsACString& result) {
86     result = mRef;
87     return NS_OK;
88   }
89 
ToIURI()90   already_AddRefed<nsIURI> ToIURI() {
91     nsCOMPtr<nsIURI> newURI = mURI.get();
92     return newURI.forget();
93   }
94 
95   bool operator==(const ImageURL& aOther) const {
96     // Note that we don't need to consider mScheme and mRef, because they're
97     // already represented in mSpec.
98     return mSpec == aOther.mSpec;
99   }
100 
HasSameRef(const ImageURL & aOther)101   bool HasSameRef(const ImageURL& aOther) const { return mRef == aOther.mRef; }
102 
103  private:
104   friend class ImageCacheKey;
105 
ComputeHash(const Maybe<uint64_t> & aBlobSerial)106   PLDHashNumber ComputeHash(const Maybe<uint64_t>& aBlobSerial) const {
107     if (aBlobSerial) {
108       // For blob URIs, we hash the serial number of the underlying blob, so
109       // that different blob URIs which point to the same blob share a cache
110       // entry. We also include the ref portion of the URI to support media
111       // fragments which requires us to create different Image objects even if
112       // the source data is the same.
113       return HashGeneric(*aBlobSerial, HashString(mRef));
114     }
115     // For non-blob URIs, we hash the URI spec.
116     return HashString(mSpec);
117   }
118 
119   nsMainThreadPtrHandle<nsIURI> mURI;
120 
121   // Since this is a basic storage class, no duplication of spec parsing is
122   // included in the functionality. Instead, the class depends upon the
123   // parsing implementation in the nsIURI class used in object construction.
124   // This means each field is stored separately, but since only a few are
125   // required, this small memory tradeoff for threadsafe usage should be ok.
126   nsAutoCString mSpec;
127   nsAutoCString mScheme;
128   nsAutoCString mRef;
129 
~ImageURL()130   ~ImageURL() {}
131 };
132 
133 }  // namespace image
134 }  // namespace mozilla
135 
136 #endif  // mozilla_image_ImageURL_h
137