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 "nsIFrame.h" 17 #include "nsIReflowCallback.h" 18 #include "nsTArray.h" 19 #include "imgIRequest.h" 20 #include "imgINotificationObserver.h" 21 #include "mozilla/Attributes.h" 22 23 class imgIContainer; 24 class nsIFrame; 25 class nsPresContext; 26 class nsIURI; 27 class nsIPrincipal; 28 29 namespace mozilla { 30 struct MediaFeatureChange; 31 namespace dom { 32 class Document; 33 } 34 35 namespace css { 36 37 /** 38 * NOTE: All methods must be called from the main thread unless otherwise 39 * specified. 40 */ 41 class ImageLoader final { 42 public: 43 static void Init(); 44 static void Shutdown(); 45 46 // We also associate flags alongside frames in the request-to-frames hashmap. 47 // These are used for special handling of events for requests. 48 typedef uint32_t FrameFlags; 49 enum { 50 REQUEST_REQUIRES_REFLOW = 1u << 0, 51 REQUEST_HAS_BLOCKED_ONLOAD = 1u << 1, 52 }; 53 ImageLoader(dom::Document * aDocument)54 explicit ImageLoader(dom::Document* aDocument) : mDocument(aDocument) { 55 MOZ_ASSERT(mDocument); 56 } 57 58 NS_INLINE_DECL_REFCOUNTING(ImageLoader) 59 60 void DropDocumentReference(); 61 62 void AssociateRequestToFrame(imgIRequest* aRequest, nsIFrame* aFrame, 63 FrameFlags aFlags); 64 65 void DisassociateRequestFromFrame(imgIRequest* aRequest, nsIFrame* aFrame); 66 67 void DropRequestsForFrame(nsIFrame* aFrame); 68 69 void SetAnimationMode(uint16_t aMode); 70 71 // The prescontext for this ImageLoader's document. We need it to be passed 72 // in because this can be called during presentation destruction after the 73 // presshell pointer on the document has been cleared. 74 void ClearFrames(nsPresContext* aPresContext); 75 76 // Triggers an image load. 77 static already_AddRefed<imgRequestProxy> LoadImage( 78 const StyleComputedImageUrl&, dom::Document&); 79 80 // Usually, only one style value owns a given proxy. However, we have a hack 81 // to share image proxies in chrome documents under some circumstances. We 82 // need to keep track of this so that we don't stop tracking images too early. 83 // 84 // In practice it shouldn't matter as these chrome images are mostly static, 85 // but it is always good to keep sanity. 86 static void NoteSharedLoad(imgRequestProxy*); 87 88 // Undoes what `LoadImage` does. 89 static void UnloadImage(imgRequestProxy*); 90 91 // This is called whenever an image we care about notifies the 92 // GlobalImageObserver. 93 void Notify(imgIRequest*, int32_t aType, const nsIntRect* aData); 94 95 private: 96 // Called when we stop caring about a given request. 97 void DeregisterImageRequest(imgIRequest*, nsPresContext*); 98 99 // This callback is used to unblock document onload after a reflow 100 // triggered from an image load. 101 struct ImageReflowCallback final : public nsIReflowCallback { 102 RefPtr<ImageLoader> mLoader; 103 WeakFrame mFrame; 104 nsCOMPtr<imgIRequest> const mRequest; 105 ImageReflowCallbackfinal106 ImageReflowCallback(ImageLoader* aLoader, nsIFrame* aFrame, 107 imgIRequest* aRequest) 108 : mLoader(aLoader), mFrame(aFrame), mRequest(aRequest) {} 109 110 bool ReflowFinished() override; 111 void ReflowCallbackCanceled() override; 112 }; 113 114 ~ImageLoader() = default; 115 116 // We need to be able to look up the frames associated with a request (for 117 // delivering notifications) and the requests associated with a frame (when 118 // the frame goes away). Thus we maintain hashtables going both ways. These 119 // should always be in sync. 120 121 struct FrameWithFlags { FrameWithFlagsFrameWithFlags122 explicit FrameWithFlags(nsIFrame* aFrame) : mFrame(aFrame), mFlags(0) { 123 MOZ_ASSERT(mFrame); 124 } 125 nsIFrame* const mFrame; 126 FrameFlags mFlags; 127 }; 128 129 // A helper class to compare FrameWithFlags by comparing mFrame and 130 // ignoring mFlags. 131 class FrameOnlyComparator { 132 public: Equals(const FrameWithFlags & aElem1,const FrameWithFlags & aElem2)133 bool Equals(const FrameWithFlags& aElem1, 134 const FrameWithFlags& aElem2) const { 135 return aElem1.mFrame == aElem2.mFrame; 136 } 137 LessThan(const FrameWithFlags & aElem1,const FrameWithFlags & aElem2)138 bool LessThan(const FrameWithFlags& aElem1, 139 const FrameWithFlags& aElem2) const { 140 return aElem1.mFrame < aElem2.mFrame; 141 } 142 }; 143 144 typedef nsTArray<FrameWithFlags> FrameSet; 145 typedef nsTArray<nsCOMPtr<imgIRequest>> RequestSet; 146 typedef nsClassHashtable<nsISupportsHashKey, FrameSet> RequestToFrameMap; 147 typedef nsClassHashtable<nsPtrHashKey<nsIFrame>, RequestSet> 148 FrameToRequestMap; 149 150 nsPresContext* GetPresContext(); 151 152 void RequestPaintIfNeeded(FrameSet* aFrameSet, imgIRequest* aRequest, 153 bool aForcePaint); 154 void UnblockOnloadIfNeeded(nsIFrame* aFrame, imgIRequest* aRequest); 155 void RequestReflowIfNeeded(FrameSet* aFrameSet, imgIRequest* aRequest); 156 void RequestReflowOnFrame(FrameWithFlags* aFwf, imgIRequest* aRequest); 157 158 void OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage); 159 void OnFrameComplete(imgIRequest* aRequest); 160 void OnImageIsAnimated(imgIRequest* aRequest); 161 void OnFrameUpdate(imgIRequest* aRequest); 162 void OnLoadComplete(imgIRequest* aRequest); 163 164 // Helpers for DropRequestsForFrame / DisassociateRequestFromFrame above. 165 void RemoveRequestToFrameMapping(imgIRequest* aRequest, nsIFrame* aFrame); 166 void RemoveFrameToRequestMapping(imgIRequest* aRequest, nsIFrame* aFrame); 167 168 // A map of imgIRequests to the nsIFrames that are using them. 169 RequestToFrameMap mRequestToFrameMap; 170 171 // A map of nsIFrames to the imgIRequests they use. 172 FrameToRequestMap mFrameToRequestMap; 173 174 // A weak pointer to our document. Nulled out by DropDocumentReference. 175 dom::Document* mDocument; 176 }; 177 178 } // namespace css 179 } // namespace mozilla 180 181 #endif /* mozilla_css_ImageLoader_h___ */ 182