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