1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 // A class that handles style system image loads (other image loads are handled
8 // by the nodes in the content tree).
9 
10 #ifndef mozilla_css_ImageLoader_h___
11 #define mozilla_css_ImageLoader_h___
12 
13 #include "mozilla/CORSMode.h"
14 #include "nsClassHashtable.h"
15 #include "nsHashKeys.h"
16 #include "nsRect.h"
17 #include "nsTArray.h"
18 #include "mozilla/Attributes.h"
19 
20 class nsIFrame;
21 class imgIContainer;
22 class imgIRequest;
23 class imgRequestProxy;
24 class nsPresContext;
25 class nsIURI;
26 class nsIPrincipal;
27 class nsIRequest;
28 
29 namespace mozilla {
30 struct MediaFeatureChange;
31 struct StyleComputedUrl;
32 namespace dom {
33 class Document;
34 }
35 
36 namespace css {
37 
38 /**
39  * NOTE: All methods must be called from the main thread unless otherwise
40  * specified.
41  */
42 class ImageLoader final {
43  public:
44   static void Init();
45   static void Shutdown();
46 
47   // We also associate flags alongside frames in the request-to-frames hashmap.
48   // These are used for special handling of events for requests.
49   enum class Flags : uint32_t {
50     // Used for bullets.
51     RequiresReflowOnSizeAvailable = 1u << 0,
52 
53     // Used for shapes.
54     RequiresReflowOnFirstFrameCompleteAndLoadEventBlocking = 1u << 1,
55 
56     // Internal flag, shouldn't be used by callers.
57     IsBlockingLoadEvent = 1u << 2,
58   };
59 
ImageLoader(dom::Document * aDocument)60   explicit ImageLoader(dom::Document* aDocument) : mDocument(aDocument) {
61     MOZ_ASSERT(mDocument);
62   }
63 
64   NS_INLINE_DECL_REFCOUNTING(ImageLoader)
65 
66   void DropDocumentReference();
67 
68   void AssociateRequestToFrame(imgIRequest*, nsIFrame*, Flags = Flags(0));
69   void DisassociateRequestFromFrame(imgIRequest*, nsIFrame*);
70   void DropRequestsForFrame(nsIFrame*);
71 
72   void SetAnimationMode(uint16_t aMode);
73 
74   // The prescontext for this ImageLoader's document. We need it to be passed
75   // in because this can be called during presentation destruction after the
76   // presshell pointer on the document has been cleared.
77   void ClearFrames(nsPresContext* aPresContext);
78 
79   // Triggers an image load.
80   static already_AddRefed<imgRequestProxy> LoadImage(const StyleComputedUrl&,
81                                                      dom::Document&);
82 
83   // Usually, only one style value owns a given proxy. However, we have a hack
84   // to share image proxies in chrome documents under some circumstances. We
85   // need to keep track of this so that we don't stop tracking images too early.
86   //
87   // In practice it shouldn't matter as these chrome images are mostly static,
88   // but it is always good to keep sanity.
89   static void NoteSharedLoad(imgRequestProxy*);
90 
91   // Undoes what `LoadImage` does.
92   static void UnloadImage(imgRequestProxy*);
93 
94   // This is called whenever an image we care about notifies the
95   // GlobalImageObserver.
96   void Notify(imgIRequest*, int32_t aType, const nsIntRect* aData);
97 
98  private:
99   // Called when we stop caring about a given request.
100   void DeregisterImageRequest(imgIRequest*, nsPresContext*);
101   struct ImageReflowCallback;
102 
103   ~ImageLoader() = default;
104 
105   // We need to be able to look up the frames associated with a request (for
106   // delivering notifications) and the requests associated with a frame (when
107   // the frame goes away). Thus we maintain hashtables going both ways.  These
108   // should always be in sync.
109 
110   struct FrameWithFlags {
FrameWithFlagsFrameWithFlags111     explicit FrameWithFlags(nsIFrame* aFrame) : mFrame(aFrame) {
112       MOZ_ASSERT(mFrame);
113     }
114     nsIFrame* const mFrame;
115     Flags mFlags{0};
116   };
117 
118   // A helper class to compare FrameWithFlags by comparing mFrame and
119   // ignoring mFlags.
120   class FrameOnlyComparator {
121    public:
Equals(const FrameWithFlags & aElem1,const FrameWithFlags & aElem2)122     bool Equals(const FrameWithFlags& aElem1,
123                 const FrameWithFlags& aElem2) const {
124       return aElem1.mFrame == aElem2.mFrame;
125     }
126 
LessThan(const FrameWithFlags & aElem1,const FrameWithFlags & aElem2)127     bool LessThan(const FrameWithFlags& aElem1,
128                   const FrameWithFlags& aElem2) const {
129       return aElem1.mFrame < aElem2.mFrame;
130     }
131   };
132 
133   typedef nsTArray<FrameWithFlags> FrameSet;
134   typedef nsTArray<nsCOMPtr<imgIRequest>> RequestSet;
135   typedef nsClassHashtable<nsISupportsHashKey, FrameSet> RequestToFrameMap;
136   typedef nsClassHashtable<nsPtrHashKey<nsIFrame>, RequestSet>
137       FrameToRequestMap;
138 
139   nsPresContext* GetPresContext();
140 
141   void ImageFrameChanged(imgIRequest*, bool aFirstFrame);
142   void UnblockOnloadIfNeeded(nsIFrame*, imgIRequest*);
143   void UnblockOnloadIfNeeded(FrameWithFlags&);
144 
145   void OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage);
146   void OnFrameComplete(imgIRequest* aRequest);
147   void OnImageIsAnimated(imgIRequest* aRequest);
148   void OnFrameUpdate(imgIRequest* aRequest);
149   void OnLoadComplete(imgIRequest* aRequest);
150 
151   // Helpers for DropRequestsForFrame / DisassociateRequestFromFrame above.
152   void RemoveRequestToFrameMapping(imgIRequest* aRequest, nsIFrame* aFrame);
153   void RemoveFrameToRequestMapping(imgIRequest* aRequest, nsIFrame* aFrame);
154 
155   // A map of imgIRequests to the nsIFrames that are using them.
156   RequestToFrameMap mRequestToFrameMap;
157 
158   // A map of nsIFrames to the imgIRequests they use.
159   FrameToRequestMap mFrameToRequestMap;
160 
161   // A weak pointer to our document. Nulled out by DropDocumentReference.
162   dom::Document* mDocument;
163 };
164 
165 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ImageLoader::Flags)
166 
167 }  // namespace css
168 }  // namespace mozilla
169 
170 #endif /* mozilla_css_ImageLoader_h___ */
171