imgFrame.h (14457B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * 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 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_image_imgFrame_h 8 #define mozilla_image_imgFrame_h 9 10 #include <functional> 11 #include <utility> 12 13 #include "AnimationParams.h" 14 #include "MainThreadUtils.h" 15 #include "gfxDrawable.h" 16 #include "mozilla/layers/SourceSurfaceSharedData.h" 17 #include "mozilla/Maybe.h" 18 #include "mozilla/MemoryReporting.h" 19 #include "mozilla/Monitor.h" 20 #include "nsRect.h" 21 22 namespace mozilla { 23 namespace image { 24 25 class ImageRegion; 26 class DrawableFrameRef; 27 class RawAccessFrameRef; 28 29 enum class Opacity : uint8_t { FULLY_OPAQUE, SOME_TRANSPARENCY }; 30 31 class imgFrame { 32 typedef gfx::SourceSurfaceSharedData SourceSurfaceSharedData; 33 typedef gfx::DrawTarget DrawTarget; 34 typedef gfx::SamplingFilter SamplingFilter; 35 typedef gfx::IntPoint IntPoint; 36 typedef gfx::IntRect IntRect; 37 typedef gfx::IntSize IntSize; 38 typedef gfx::SourceSurface SourceSurface; 39 typedef gfx::SurfaceFormat SurfaceFormat; 40 41 public: 42 MOZ_DECLARE_REFCOUNTED_TYPENAME(imgFrame) 43 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgFrame) 44 45 imgFrame(); 46 47 /** 48 * Initialize this imgFrame with an empty surface and prepare it for being 49 * written to by a decoder. 50 * 51 * This is appropriate for use with decoded images, but it should not be used 52 * when drawing content into an imgFrame, as it may use a different graphics 53 * backend than normal content drawing. 54 */ 55 nsresult InitForDecoder(const nsIntSize& aImageSize, SurfaceFormat aFormat, 56 bool aNonPremult, 57 const Maybe<AnimationParams>& aAnimParams, 58 bool aShouldRecycle, 59 uint32_t* aImageDataLength = nullptr); 60 61 /** 62 * Reinitialize this imgFrame with the new parameters, but otherwise retain 63 * the underlying buffer. 64 * 65 * This is appropriate for use with animated images, where the decoder was 66 * given an IDecoderFrameRecycler object which may yield a recycled imgFrame 67 * that was discarded to save memory. 68 */ 69 nsresult InitForDecoderRecycle(const AnimationParams& aAnimParams, 70 uint32_t* aImageDataLength = nullptr); 71 72 /** 73 * Initialize this imgFrame with a new surface and draw the provided 74 * gfxDrawable into it. 75 * 76 * This is appropriate to use when drawing content into an imgFrame, as it 77 * uses the same graphics backend as normal content drawing. The downside is 78 * that the underlying surface may not be stored in a volatile buffer on all 79 * platforms, and raw access to the surface (using RawAccessRef()) may be much 80 * more expensive than in the InitForDecoder() case. 81 * 82 * aBackend specifies the DrawTarget backend type this imgFrame is supposed 83 * to be drawn to. 84 */ 85 nsresult InitWithDrawable(gfxDrawable* aDrawable, const nsIntSize& aSize, 86 const SurfaceFormat aFormat, 87 SamplingFilter aSamplingFilter, 88 uint32_t aImageFlags, gfx::BackendType aBackend); 89 90 DrawableFrameRef DrawableRef(); 91 92 /** 93 * Create a RawAccessFrameRef for the frame. 94 */ 95 RawAccessFrameRef RawAccessRef( 96 gfx::DataSourceSurface::MapType aMapType = gfx::DataSourceSurface::READ); 97 98 bool Draw(gfxContext* aContext, const ImageRegion& aRegion, 99 SamplingFilter aSamplingFilter, uint32_t aImageFlags, 100 float aOpacity); 101 102 nsresult ImageUpdated(const nsIntRect& aUpdateRect); 103 104 /** 105 * Mark this imgFrame as completely decoded, and set final options. 106 * 107 * You must always call either Finish() or Abort() before releasing the last 108 * RawAccessFrameRef pointing to an imgFrame. 109 * 110 * @param aFrameOpacity Whether this imgFrame is opaque. 111 * @param aFinalize Finalize the underlying surface (e.g. so that it 112 * may be marked as read only if possible). 113 */ 114 void Finish(Opacity aFrameOpacity = Opacity::SOME_TRANSPARENCY, 115 bool aFinalize = true, 116 bool aOrientationSwapsWidthAndHeight = false); 117 118 /** 119 * Mark this imgFrame as aborted. This informs the imgFrame that if it isn't 120 * completely decoded now, it never will be. 121 * 122 * You must always call either Finish() or Abort() before releasing the last 123 * RawAccessFrameRef pointing to an imgFrame. 124 */ 125 void Abort(); 126 127 /** 128 * Returns true if this imgFrame has been aborted. 129 */ 130 bool IsAborted() const; 131 132 /** 133 * Returns true if this imgFrame is completely decoded. 134 */ 135 bool IsFinished() const; 136 137 /** 138 * Blocks until this imgFrame is either completely decoded, or is marked as 139 * aborted. 140 * 141 * Note that calling this on the main thread _blocks the main thread_. Be very 142 * careful in your use of this method to avoid excessive main thread jank or 143 * deadlock. 144 */ 145 void WaitUntilFinished() const; 146 147 /** 148 * Returns the number of bytes per pixel this imgFrame requires. 149 */ 150 uint32_t GetBytesPerPixel() const { return 4; } 151 152 const IntSize& GetSize() const { return mImageSize; } 153 IntRect GetRect() const { return IntRect(IntPoint(0, 0), mImageSize); } 154 const IntRect& GetBlendRect() const { return mBlendRect; } 155 IntRect GetBoundedBlendRect() const { 156 return mBlendRect.Intersect(GetRect()); 157 } 158 nsIntRect GetDecodedRect() const { 159 MonitorAutoLock lock(mMonitor); 160 return mDecoded; 161 } 162 FrameTimeout GetTimeout() const { return mTimeout; } 163 BlendMethod GetBlendMethod() const { return mBlendMethod; } 164 DisposalMethod GetDisposalMethod() const { return mDisposalMethod; } 165 bool FormatHasAlpha() const { return mFormat == SurfaceFormat::OS_RGBA; } 166 167 const IntRect& GetDirtyRect() const { return mDirtyRect; } 168 void SetDirtyRect(const IntRect& aDirtyRect) { mDirtyRect = aDirtyRect; } 169 170 void FinalizeSurface(); 171 already_AddRefed<SourceSurface> GetSourceSurface(); 172 173 struct AddSizeOfCbData : public SourceSurface::SizeOfInfo { 174 AddSizeOfCbData() : mIndex(0), mFinished(false) {} 175 176 size_t mIndex; 177 bool mFinished; 178 }; 179 180 typedef std::function<void(AddSizeOfCbData& aMetadata)> AddSizeOfCb; 181 182 void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, 183 const AddSizeOfCb& aCallback) const; 184 185 private: // methods 186 ~imgFrame(); 187 188 bool AreAllPixelsWritten() const MOZ_REQUIRES(mMonitor); 189 nsresult ImageUpdatedInternal(const nsIntRect& aUpdateRect); 190 uint32_t GetImageBytesPerRow() const; 191 uint32_t GetImageDataLength() const; 192 void FinalizeSurfaceInternal(); 193 already_AddRefed<SourceSurface> GetSourceSurfaceInternal(); 194 195 struct SurfaceWithFormat { 196 RefPtr<gfxDrawable> mDrawable; 197 SurfaceFormat mFormat; 198 SurfaceWithFormat() : mFormat(SurfaceFormat::UNKNOWN) {} 199 SurfaceWithFormat(gfxDrawable* aDrawable, SurfaceFormat aFormat) 200 : mDrawable(aDrawable), mFormat(aFormat) {} 201 SurfaceWithFormat(SurfaceWithFormat&& aOther) 202 : mDrawable(std::move(aOther.mDrawable)), mFormat(aOther.mFormat) {} 203 SurfaceWithFormat& operator=(SurfaceWithFormat&& aOther) { 204 mDrawable = std::move(aOther.mDrawable); 205 mFormat = aOther.mFormat; 206 return *this; 207 } 208 SurfaceWithFormat& operator=(const SurfaceWithFormat& aOther) = delete; 209 SurfaceWithFormat(const SurfaceWithFormat& aOther) = delete; 210 bool IsValid() { return !!mDrawable; } 211 }; 212 213 SurfaceWithFormat SurfaceForDrawing(bool aDoPartialDecode, bool aDoTile, 214 ImageRegion& aRegion, 215 SourceSurface* aSurface); 216 217 private: // data 218 friend class DrawableFrameRef; 219 friend class RawAccessFrameRef; 220 friend class UnlockImageDataRunnable; 221 222 ////////////////////////////////////////////////////////////////////////////// 223 // Thread-safe mutable data, protected by mMonitor. 224 ////////////////////////////////////////////////////////////////////////////// 225 226 mutable Monitor mMonitor; 227 228 /** 229 * Used for rasterized images, this contains the raw pixel data. 230 */ 231 RefPtr<SourceSurfaceSharedData> mRawSurface MOZ_GUARDED_BY(mMonitor); 232 RefPtr<SourceSurfaceSharedData> mBlankRawSurface MOZ_GUARDED_BY(mMonitor); 233 234 /** 235 * Used for vector images that were not rasterized directly. This might be a 236 * blob recording or native surface. 237 */ 238 RefPtr<SourceSurface> mOptSurface MOZ_GUARDED_BY(mMonitor); 239 240 nsIntRect mDecoded MOZ_GUARDED_BY(mMonitor); 241 242 bool mAborted MOZ_GUARDED_BY(mMonitor); 243 bool mFinished MOZ_GUARDED_BY(mMonitor); 244 bool mShouldRecycle MOZ_GUARDED_BY(mMonitor); 245 246 ////////////////////////////////////////////////////////////////////////////// 247 // Effectively const data, only mutated in the Init methods. 248 ////////////////////////////////////////////////////////////////////////////// 249 250 //! The size of the buffer we are decoding to. 251 IntSize mImageSize; 252 253 //! The contents for the frame, as represented in the encoded image. This may 254 //! differ from mImageSize because it may be a partial frame. For the first 255 //! frame, this means we need to shift the data in place, and for animated 256 //! frames, it likely need to combine with a previous frame to get the full 257 //! contents. 258 IntRect mBlendRect; 259 260 //! This is the region that has changed between this frame and the previous 261 //! frame of an animation. For the first frame, this will be the same as 262 //! mFrameRect. 263 IntRect mDirtyRect; 264 265 //! The timeout for this frame. 266 FrameTimeout mTimeout; 267 268 DisposalMethod mDisposalMethod; 269 BlendMethod mBlendMethod; 270 SurfaceFormat mFormat; 271 272 bool mNonPremult; 273 }; 274 275 /** 276 * A reference to an imgFrame that holds the imgFrame's surface in memory, 277 * allowing drawing. If you have a DrawableFrameRef |ref| and |if (ref)| returns 278 * true, then calls to Draw() and GetSourceSurface() are guaranteed to succeed. 279 */ 280 class DrawableFrameRef final { 281 typedef gfx::DataSourceSurface DataSourceSurface; 282 283 public: 284 DrawableFrameRef() = default; 285 286 explicit DrawableFrameRef(imgFrame* aFrame) : mFrame(aFrame) { 287 MOZ_ASSERT(aFrame); 288 MonitorAutoLock lock(aFrame->mMonitor); 289 290 if (aFrame->mRawSurface) { 291 mRef.emplace(aFrame->mRawSurface, DataSourceSurface::READ); 292 if (!mRef->IsMapped()) { 293 mFrame = nullptr; 294 mRef.reset(); 295 } 296 } else if (!aFrame->mOptSurface || !aFrame->mOptSurface->IsValid()) { 297 // The optimized surface has become invalid, so we need to redecode. 298 // For example, on Windows, there may have been a device reset, and 299 // all D2D surfaces now need to be recreated. 300 mFrame = nullptr; 301 } 302 } 303 304 DrawableFrameRef(DrawableFrameRef&& aOther) 305 : mFrame(std::move(aOther.mFrame)), mRef(std::move(aOther.mRef)) {} 306 307 DrawableFrameRef& operator=(DrawableFrameRef&& aOther) { 308 MOZ_ASSERT(this != &aOther, "Self-moves are prohibited"); 309 mFrame = std::move(aOther.mFrame); 310 mRef = std::move(aOther.mRef); 311 return *this; 312 } 313 314 explicit operator bool() const { return bool(mFrame); } 315 316 imgFrame* operator->() { 317 MOZ_ASSERT(mFrame); 318 return mFrame; 319 } 320 321 const imgFrame* operator->() const { 322 MOZ_ASSERT(mFrame); 323 return mFrame; 324 } 325 326 imgFrame* get() { return mFrame; } 327 const imgFrame* get() const { return mFrame; } 328 329 void reset() { 330 mFrame = nullptr; 331 mRef.reset(); 332 } 333 334 private: 335 DrawableFrameRef(const DrawableFrameRef& aOther) = delete; 336 DrawableFrameRef& operator=(const DrawableFrameRef& aOther) = delete; 337 338 RefPtr<imgFrame> mFrame; 339 Maybe<DataSourceSurface::ScopedMap> mRef; 340 }; 341 342 /** 343 * A reference to an imgFrame that holds the imgFrame's surface in memory in a 344 * format appropriate for access as raw data. If you have a RawAccessFrameRef 345 * |ref| and |if (ref)| is true, then calls to GetImageData() is guaranteed to 346 * succeed. This guarantee is stronger than DrawableFrameRef, so everything that 347 * a valid DrawableFrameRef guarantees is also guaranteed by a valid 348 * RawAccessFrameRef. 349 * 350 * This may be considerably more expensive than is necessary just for drawing, 351 * so only use this when you need to read or write the raw underlying image data 352 * that the imgFrame holds. 353 * 354 * Once all an imgFrame's RawAccessFrameRefs go out of scope, new 355 * RawAccessFrameRefs cannot be created. 356 */ 357 class RawAccessFrameRef final { 358 public: 359 RawAccessFrameRef() = default; 360 361 explicit RawAccessFrameRef(imgFrame* aFrame, 362 gfx::DataSourceSurface::MapType aMapType) 363 : mFrame(aFrame) { 364 MOZ_ASSERT(mFrame, "Need a frame"); 365 366 // Note that we do not use ScopedMap here because it holds a strong 367 // reference to the underlying surface. This affects the reuse logic for 368 // recycling in imgFrame::InitForDecoderRecycle. 369 { 370 MonitorAutoLock lock(mFrame->mMonitor); 371 gfx::DataSourceSurface::MappedSurface map; 372 if (mFrame->mRawSurface && mFrame->mRawSurface->Map(aMapType, &map)) { 373 MOZ_ASSERT(map.mData); 374 mData = map.mData; 375 } 376 } 377 378 if (!mData) { 379 mFrame = nullptr; 380 } 381 } 382 383 RawAccessFrameRef(RawAccessFrameRef&& aOther) 384 : mFrame(std::move(aOther.mFrame)), mData(aOther.mData) { 385 aOther.mData = nullptr; 386 } 387 388 ~RawAccessFrameRef() { reset(); } 389 390 RawAccessFrameRef& operator=(RawAccessFrameRef&& aOther) { 391 MOZ_ASSERT(this != &aOther, "Self-moves are prohibited"); 392 393 if (mFrame) { 394 MonitorAutoLock lock(mFrame->mMonitor); 395 mFrame->mRawSurface->Unmap(); 396 } 397 mFrame = std::move(aOther.mFrame); 398 mData = aOther.mData; 399 aOther.mData = nullptr; 400 401 return *this; 402 } 403 404 explicit operator bool() const { return bool(mFrame); } 405 406 imgFrame* operator->() { 407 MOZ_ASSERT(mFrame); 408 return mFrame.get(); 409 } 410 411 const imgFrame* operator->() const { 412 MOZ_ASSERT(mFrame); 413 return mFrame; 414 } 415 416 imgFrame* get() { return mFrame; } 417 const imgFrame* get() const { return mFrame; } 418 419 void reset() { 420 if (mFrame) { 421 MonitorAutoLock lock(mFrame->mMonitor); 422 mFrame->mRawSurface->Unmap(); 423 } 424 mFrame = nullptr; 425 mData = nullptr; 426 } 427 428 uint8_t* Data() const { return mData; } 429 430 private: 431 RawAccessFrameRef(const RawAccessFrameRef& aOther) = delete; 432 RawAccessFrameRef& operator=(const RawAccessFrameRef& aOther) = delete; 433 434 RefPtr<imgFrame> mFrame; 435 uint8_t* mData = nullptr; 436 }; 437 438 } // namespace image 439 } // namespace mozilla 440 441 #endif // mozilla_image_imgFrame_h