summaryrefslogtreecommitdiff
path: root/image/ImageURL.h
blob: fa60ff79eb6ef3660172ec51f52480fb79faf625 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_image_ImageURL_h
#define mozilla_image_ImageURL_h

#include "nsIURI.h"
#include "MainThreadUtils.h"
#include "nsNetUtil.h"
#include "mozilla/HashFunctions.h"
#include "nsHashKeys.h"

namespace mozilla {
namespace image {

class ImageCacheKey;

/** ImageURL
 *
 * nsStandardURL is not threadsafe, so this class is created to hold only the
 * necessary URL data required for image loading and decoding.
 *
 * Note: Although several APIs have the same or similar prototypes as those
 * found in nsIURI/nsStandardURL, the class does not implement nsIURI. This is
 * intentional; functionality is limited, and is only useful for imagelib code.
 * By not implementing nsIURI, external code cannot unintentionally be given an
 * nsIURI pointer with this limited class behind it; instead, conversion to a
 * fully implemented nsIURI is required (e.g. through NS_NewURI).
 */
class ImageURL
{
public:
  explicit ImageURL(nsIURI* aURI, nsresult& aRv)
  {
    MOZ_ASSERT(NS_IsMainThread(), "Cannot use nsIURI off main thread!");

    aRv = aURI->GetSpec(mSpec);
    NS_ENSURE_SUCCESS_VOID(aRv);

    aRv = aURI->GetScheme(mScheme);
    NS_ENSURE_SUCCESS_VOID(aRv);

    aRv = aURI->GetRef(mRef);
    NS_ENSURE_SUCCESS_VOID(aRv);
  }

  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageURL)

  nsresult GetSpec(nsACString& result)
  {
    result = mSpec;
    return NS_OK;
  }

  /// A weak pointer to the URI spec for this ImageURL. For logging only.
  const char* Spec() const { return mSpec.get(); }

  enum TruncatedSpecStatus {
    FitsInto1k,
    TruncatedTo1k
  };
  TruncatedSpecStatus GetSpecTruncatedTo1k(nsACString& result)
  {
    static const size_t sMaxTruncatedLength = 1024;

    if (sMaxTruncatedLength >= mSpec.Length()) {
      result = mSpec;
      return FitsInto1k;
    }

    result = Substring(mSpec, 0, sMaxTruncatedLength);
    return TruncatedTo1k;
  }

  nsresult GetScheme(nsACString& result)
  {
    result = mScheme;
    return NS_OK;
  }

  nsresult SchemeIs(const char* scheme, bool* result)
  {
    NS_PRECONDITION(scheme, "scheme is null");
    NS_PRECONDITION(result, "result is null");

    *result = mScheme.Equals(scheme);
    return NS_OK;
  }

  nsresult GetRef(nsACString& result)
  {
    result = mRef;
    return NS_OK;
  }

  already_AddRefed<nsIURI> ToIURI()
  {
    MOZ_ASSERT(NS_IsMainThread(),
               "Convert to nsIURI on main thread only; it is not threadsafe.");
    nsCOMPtr<nsIURI> newURI;
    NS_NewURI(getter_AddRefs(newURI), mSpec);
    return newURI.forget();
  }

  bool operator==(const ImageURL& aOther) const
  {
    // Note that we don't need to consider mScheme and mRef, because they're
    // already represented in mSpec.
    return mSpec == aOther.mSpec;
  }

  bool HasSameRef(const ImageURL& aOther) const
  {
    return mRef == aOther.mRef;
  }

private:
  friend class ImageCacheKey;

  uint32_t ComputeHash(const Maybe<uint64_t>& aBlobSerial) const
  {
    if (aBlobSerial) {
      // For blob URIs, we hash the serial number of the underlying blob, so that
      // different blob URIs which point to the same blob share a cache entry. We
      // also include the ref portion of the URI to support media fragments which
      // requires us to create different Image objects even if the source data is
      // the same.
      return HashGeneric(*aBlobSerial, HashString(mRef));
    }
    // For non-blob URIs, we hash the URI spec.
    return HashString(mSpec);
  }

  // Since this is a basic storage class, no duplication of spec parsing is
  // included in the functionality. Instead, the class depends upon the
  // parsing implementation in the nsIURI class used in object construction.
  // This means each field is stored separately, but since only a few are
  // required, this small memory tradeoff for threadsafe usage should be ok.
  nsAutoCString mSpec;
  nsAutoCString mScheme;
  nsAutoCString mRef;

  ~ImageURL() { }
};

} // namespace image
} // namespace mozilla

#endif // mozilla_image_ImageURL_h