Image.h (14182B)
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_Image_h 7 #define mozilla_image_Image_h 8 9 #include "mozilla/Attributes.h" 10 #include "mozilla/MemoryReporting.h" 11 #include "mozilla/ProfilerMarkers.h" 12 #include "mozilla/SizeOfState.h" 13 #include "mozilla/TimeStamp.h" 14 15 #include "gfx2DGlue.h" 16 #include "imgIContainer.h" 17 #include "ImageContainer.h" 18 #include "ImageRegion.h" 19 #include "LookupResult.h" 20 #include "nsStringFwd.h" 21 #include "ProgressTracker.h" 22 #include "SurfaceCache.h" 23 #include "WebRenderImageProvider.h" 24 25 class imgRequest; 26 class nsIRequest; 27 class nsIInputStream; 28 29 namespace mozilla { 30 namespace image { 31 32 class Image; 33 34 /////////////////////////////////////////////////////////////////////////////// 35 // Memory Reporting 36 /////////////////////////////////////////////////////////////////////////////// 37 38 struct MemoryCounter { 39 MemoryCounter() 40 : mSource(0), 41 mDecodedHeap(0), 42 mDecodedNonHeap(0), 43 mDecodedUnknown(0), 44 mExternalHandles(0), 45 mFrameIndex(0), 46 mExternalId(0), 47 mSurfaceTypes(0) {} 48 49 void SetSource(size_t aCount) { mSource = aCount; } 50 size_t Source() const { return mSource; } 51 void SetDecodedHeap(size_t aCount) { mDecodedHeap = aCount; } 52 size_t DecodedHeap() const { return mDecodedHeap; } 53 void SetDecodedNonHeap(size_t aCount) { mDecodedNonHeap = aCount; } 54 size_t DecodedNonHeap() const { return mDecodedNonHeap; } 55 void SetDecodedUnknown(size_t aCount) { mDecodedUnknown = aCount; } 56 size_t DecodedUnknown() const { return mDecodedUnknown; } 57 void SetExternalHandles(size_t aCount) { mExternalHandles = aCount; } 58 size_t ExternalHandles() const { return mExternalHandles; } 59 void SetFrameIndex(size_t aIndex) { mFrameIndex = aIndex; } 60 size_t FrameIndex() const { return mFrameIndex; } 61 void SetExternalId(uint64_t aId) { mExternalId = aId; } 62 uint64_t ExternalId() const { return mExternalId; } 63 void SetSurfaceTypes(uint32_t aTypes) { mSurfaceTypes = aTypes; } 64 uint32_t SurfaceTypes() const { return mSurfaceTypes; } 65 66 MemoryCounter& operator+=(const MemoryCounter& aOther) { 67 mSource += aOther.mSource; 68 mDecodedHeap += aOther.mDecodedHeap; 69 mDecodedNonHeap += aOther.mDecodedNonHeap; 70 mDecodedUnknown += aOther.mDecodedUnknown; 71 mExternalHandles += aOther.mExternalHandles; 72 mSurfaceTypes |= aOther.mSurfaceTypes; 73 return *this; 74 } 75 76 private: 77 size_t mSource; 78 size_t mDecodedHeap; 79 size_t mDecodedNonHeap; 80 size_t mDecodedUnknown; 81 size_t mExternalHandles; 82 size_t mFrameIndex; 83 uint64_t mExternalId; 84 uint32_t mSurfaceTypes; 85 }; 86 87 enum class SurfaceMemoryCounterType { NORMAL, CONTAINER }; 88 89 struct SurfaceMemoryCounter { 90 SurfaceMemoryCounter( 91 const SurfaceKey& aKey, bool aIsLocked, bool aCannotSubstitute, 92 bool aIsFactor2, bool aFinished, 93 SurfaceMemoryCounterType aType = SurfaceMemoryCounterType::NORMAL) 94 : mKey(aKey), 95 mType(aType), 96 mIsLocked(aIsLocked), 97 mCannotSubstitute(aCannotSubstitute), 98 mIsFactor2(aIsFactor2), 99 mFinished(aFinished) {} 100 101 const SurfaceKey& Key() const { return mKey; } 102 MemoryCounter& Values() { return mValues; } 103 const MemoryCounter& Values() const { return mValues; } 104 SurfaceMemoryCounterType Type() const { return mType; } 105 bool IsLocked() const { return mIsLocked; } 106 bool CannotSubstitute() const { return mCannotSubstitute; } 107 bool IsFactor2() const { return mIsFactor2; } 108 bool IsFinished() const { return mFinished; } 109 110 private: 111 const SurfaceKey mKey; 112 MemoryCounter mValues; 113 const SurfaceMemoryCounterType mType; 114 const bool mIsLocked; 115 const bool mCannotSubstitute; 116 const bool mIsFactor2; 117 const bool mFinished; 118 }; 119 120 struct ImageMemoryCounter { 121 ImageMemoryCounter(imgRequest* aRequest, SizeOfState& aState, bool aIsUsed); 122 ImageMemoryCounter(imgRequest* aRequest, Image* aImage, SizeOfState& aState, 123 bool aIsUsed); 124 125 nsCString& URI() { return mURI; } 126 const nsCString& URI() const { return mURI; } 127 const nsTArray<SurfaceMemoryCounter>& Surfaces() const { return mSurfaces; } 128 const gfx::IntSize IntrinsicSize() const { return mIntrinsicSize; } 129 const MemoryCounter& Values() const { return mValues; } 130 uint32_t Progress() const { return mProgress; } 131 uint16_t Type() const { return mType; } 132 bool IsUsed() const { return mIsUsed; } 133 bool HasError() const { return mHasError; } 134 bool IsValidating() const { return mValidating; } 135 136 bool IsNotable() const { 137 // Errors or requests without images are always notable. 138 if (mHasError || mValidating || mProgress == UINT32_MAX || 139 mProgress & FLAG_HAS_ERROR || mType == imgIContainer::TYPE_REQUEST) { 140 return true; 141 } 142 143 // Sufficiently large images are notable. 144 const size_t NotableThreshold = 16 * 1024; 145 size_t total = mValues.Source() + mValues.DecodedHeap() + 146 mValues.DecodedNonHeap() + mValues.DecodedUnknown(); 147 if (total >= NotableThreshold) { 148 return true; 149 } 150 151 // Incomplete images are always notable as well; the odds of capturing 152 // mid-decode should be fairly low. 153 for (const auto& surface : mSurfaces) { 154 if (!surface.IsFinished()) { 155 return true; 156 } 157 } 158 159 return false; 160 } 161 162 private: 163 nsCString mURI; 164 nsTArray<SurfaceMemoryCounter> mSurfaces; 165 gfx::IntSize mIntrinsicSize; 166 MemoryCounter mValues; 167 uint32_t mProgress; 168 uint16_t mType; 169 const bool mIsUsed; 170 bool mHasError; 171 bool mValidating; 172 }; 173 174 /////////////////////////////////////////////////////////////////////////////// 175 // Image Base Types 176 /////////////////////////////////////////////////////////////////////////////// 177 178 class Image : public imgIContainer { 179 public: 180 /** 181 * Flags for Image initialization. 182 * 183 * Meanings: 184 * 185 * INIT_FLAG_NONE: Lack of flags 186 * 187 * INIT_FLAG_DISCARDABLE: The container should be discardable 188 * 189 * INIT_FLAG_DECODE_IMMEDIATELY: The container should decode as soon as 190 * possible, regardless of what our heuristics say. 191 * 192 * INIT_FLAG_TRANSIENT: The container is likely to exist for only a short time 193 * before being destroyed. (For example, containers for 194 * multipart/x-mixed-replace image parts fall into this category.) If this 195 * flag is set, INIT_FLAG_DISCARDABLE and INIT_FLAG_DECODE_ONLY_ON_DRAW must 196 * not be set. 197 * 198 * INIT_FLAG_SYNC_LOAD: The container is being loaded synchronously, so 199 * it should avoid relying on async workers to get the container ready. 200 */ 201 static const uint32_t INIT_FLAG_NONE = 0x0; 202 static const uint32_t INIT_FLAG_DISCARDABLE = 0x1; 203 static const uint32_t INIT_FLAG_DECODE_IMMEDIATELY = 0x2; 204 static const uint32_t INIT_FLAG_TRANSIENT = 0x4; 205 static const uint32_t INIT_FLAG_SYNC_LOAD = 0x8; 206 207 virtual already_AddRefed<ProgressTracker> GetProgressTracker() = 0; 208 virtual void SetProgressTracker(ProgressTracker* aProgressTracker) {} 209 210 /** 211 * The size, in bytes, occupied by the compressed source data of the image. 212 * If MallocSizeOf does not work on this platform, uses a fallback approach to 213 * ensure that something reasonable is always returned. 214 */ 215 virtual size_t SizeOfSourceWithComputedFallback( 216 SizeOfState& aState) const = 0; 217 218 /** 219 * Collect an accounting of the memory occupied by the image's surfaces (which 220 * together make up its decoded data). Each surface is recorded as a separate 221 * SurfaceMemoryCounter, stored in @aCounters. 222 */ 223 virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters, 224 MallocSizeOf aMallocSizeOf) const = 0; 225 226 virtual void IncrementAnimationConsumers() = 0; 227 virtual void DecrementAnimationConsumers() = 0; 228 #ifdef DEBUG 229 virtual uint32_t GetAnimationConsumers() = 0; 230 #endif 231 232 /** 233 * Called from OnDataAvailable when the stream associated with the image has 234 * received new image data. The arguments are the same as OnDataAvailable's, 235 * but by separating this functionality into a different method we don't 236 * interfere with subclasses which wish to implement nsIStreamListener. 237 * 238 * Images should not do anything that could send out notifications until they 239 * have received their first OnImageDataAvailable notification; in 240 * particular, this means that instantiating decoders should be deferred 241 * until OnImageDataAvailable is called. 242 */ 243 virtual nsresult OnImageDataAvailable(nsIRequest* aRequest, 244 nsIInputStream* aInStr, 245 uint64_t aSourceOffset, 246 uint32_t aCount) = 0; 247 248 /** 249 * Called from OnStopRequest when the image's underlying request completes. 250 * 251 * @param aRequest The completed request. 252 * @param aStatus A success or failure code. 253 * @param aLastPart Whether this is the final part of the underlying request. 254 */ 255 virtual nsresult OnImageDataComplete(nsIRequest* aRequest, nsresult aStatus, 256 bool aLastPart) = 0; 257 258 /** 259 * Called when the SurfaceCache discards a surface belonging to this image. 260 */ 261 virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) = 0; 262 263 virtual void SetInnerWindowID(uint64_t aInnerWindowId) = 0; 264 virtual uint64_t InnerWindowID() const = 0; 265 266 virtual bool HasError() = 0; 267 virtual void SetHasError() = 0; 268 269 virtual nsIURI* GetURI() const = 0; 270 271 NS_IMETHOD GetHotspotX(int32_t* aX) override { 272 *aX = 0; 273 return NS_OK; 274 } 275 NS_IMETHOD GetHotspotY(int32_t* aY) override { 276 *aY = 0; 277 return NS_OK; 278 } 279 }; 280 281 class ImageResource : public Image { 282 public: 283 already_AddRefed<ProgressTracker> GetProgressTracker() override { 284 RefPtr<ProgressTracker> progressTracker = mProgressTracker; 285 MOZ_ASSERT(progressTracker); 286 return progressTracker.forget(); 287 } 288 289 void SetProgressTracker(ProgressTracker* aProgressTracker) final { 290 MOZ_ASSERT(aProgressTracker); 291 MOZ_ASSERT(!mProgressTracker); 292 mProgressTracker = aProgressTracker; 293 } 294 295 virtual void IncrementAnimationConsumers() override; 296 virtual void DecrementAnimationConsumers() override; 297 #ifdef DEBUG 298 virtual uint32_t GetAnimationConsumers() override { 299 return mAnimationConsumers; 300 } 301 #endif 302 303 virtual void OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey) override {} 304 305 virtual void SetInnerWindowID(uint64_t aInnerWindowId) override { 306 mInnerWindowId = aInnerWindowId; 307 } 308 virtual uint64_t InnerWindowID() const override { return mInnerWindowId; } 309 310 virtual bool HasError() override { return mError; } 311 virtual void SetHasError() override { mError = true; } 312 313 /* 314 * Returns a non-AddRefed pointer to the URI associated with this image. 315 * Illegal to use off-main-thread. 316 */ 317 nsIURI* GetURI() const override { return mURI; } 318 319 /* 320 * Should be called by its subclasses after they populate @aCounters so that 321 * we can cross reference against any of our ImageContainers that contain 322 * surfaces not in the cache. 323 */ 324 void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters, 325 MallocSizeOf aMallocSizeOf) const override; 326 327 ImageProviderId GetImageProviderId() const { return mProviderId; } 328 329 protected: 330 explicit ImageResource(nsIURI* aURI); 331 ~ImageResource(); 332 333 bool GetSpecTruncatedTo1k(nsCString& aSpec) const; 334 335 // Shared functionality for implementors of imgIContainer. Every 336 // implementation of attribute animationMode should forward here. 337 nsresult GetAnimationModeInternal(uint16_t* aAnimationMode); 338 nsresult SetAnimationModeInternal(uint16_t aAnimationMode); 339 340 /** 341 * Helper for RequestRefresh. 342 * 343 * If we've had a "recent" refresh (i.e. if this image is being used in 344 * multiple documents & some other document *just* called RequestRefresh() on 345 * this image with a timestamp close to aTime), this method returns true. 346 * 347 * Otherwise, this method updates mLastRefreshTime to aTime & returns false. 348 */ 349 bool HadRecentRefresh(const TimeStamp& aTime); 350 351 /** 352 * Decides whether animation should or should not be happening, 353 * and makes sure the right thing is being done. 354 */ 355 virtual void EvaluateAnimation(); 356 357 /** 358 * Extended by child classes, if they have additional 359 * conditions for being able to animate. 360 */ 361 virtual bool ShouldAnimate() { 362 return mAnimationConsumers > 0 && mAnimationMode != kDontAnimMode; 363 } 364 365 virtual nsresult StartAnimation() = 0; 366 virtual nsresult StopAnimation() = 0; 367 368 void SendOnUnlockedDraw(uint32_t aFlags); 369 370 #ifdef DEBUG 371 // Records the image drawing for startup performance testing. 372 void NotifyDrawingObservers(); 373 #endif 374 375 // Member data shared by all implementations of this abstract class 376 RefPtr<ProgressTracker> mProgressTracker; 377 nsCOMPtr<nsIURI> mURI; 378 TimeStamp mLastRefreshTime; 379 uint64_t mInnerWindowId; 380 uint32_t mAnimationConsumers; 381 uint16_t mAnimationMode; // Enum values in imgIContainer 382 bool mInitialized : 1; // Have we been initialized? 383 bool mAnimating : 1; // Are we currently animating? 384 bool mError : 1; // Error handling 385 386 class MOZ_RAII AutoProfilerImagePaintMarker { 387 public: 388 explicit AutoProfilerImagePaintMarker(ImageResource* self) { 389 if (self->mURI && profiler_thread_is_being_profiled_for_markers()) { 390 mStartTime = TimeStamp::Now(); 391 static const size_t sMaxTruncatedLength = 1024; 392 mSpec = nsContentUtils::TruncatedURLForDisplay(self->mURI, 393 sMaxTruncatedLength); 394 } 395 } 396 397 ~AutoProfilerImagePaintMarker() { 398 if (!mSpec.IsEmpty()) { 399 PROFILER_MARKER_TEXT("Image Paint", GRAPHICS, 400 MarkerTiming::IntervalUntilNowFrom(mStartTime), 401 mSpec); 402 } 403 } 404 405 protected: 406 TimeStamp mStartTime; 407 nsAutoCString mSpec; 408 }; 409 410 private: 411 ImageProviderId mProviderId; 412 }; 413 414 } // namespace image 415 } // namespace mozilla 416 417 #endif // mozilla_image_Image_h