imgFrame.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929
  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. #include "imgFrame.h"
  6. #include "ImageRegion.h"
  7. #include "ShutdownTracker.h"
  8. #include "prenv.h"
  9. #include "gfx2DGlue.h"
  10. #include "gfxPlatform.h"
  11. #include "gfxPrefs.h"
  12. #include "gfxUtils.h"
  13. #include "gfxAlphaRecovery.h"
  14. #include "GeckoProfiler.h"
  15. #include "MainThreadUtils.h"
  16. #include "mozilla/CheckedInt.h"
  17. #include "mozilla/gfx/Tools.h"
  18. #include "mozilla/Likely.h"
  19. #include "mozilla/MemoryReporting.h"
  20. #include "nsMargin.h"
  21. #include "nsThreadUtils.h"
  22. namespace mozilla {
  23. using namespace gfx;
  24. namespace image {
  25. static void
  26. VolatileBufferRelease(void* vbuf)
  27. {
  28. delete static_cast<VolatileBufferPtr<unsigned char>*>(vbuf);
  29. }
  30. static int32_t
  31. VolatileSurfaceStride(const IntSize& size, SurfaceFormat format)
  32. {
  33. // Stride must be a multiple of four or cairo will complain.
  34. return (size.width * BytesPerPixel(format) + 0x3) & ~0x3;
  35. }
  36. static already_AddRefed<DataSourceSurface>
  37. CreateLockedSurface(VolatileBuffer* vbuf,
  38. const IntSize& size,
  39. SurfaceFormat format)
  40. {
  41. VolatileBufferPtr<unsigned char>* vbufptr =
  42. new VolatileBufferPtr<unsigned char>(vbuf);
  43. MOZ_ASSERT(!vbufptr->WasBufferPurged(), "Expected image data!");
  44. const int32_t stride = VolatileSurfaceStride(size, format);
  45. // The VolatileBufferPtr is held by this DataSourceSurface.
  46. RefPtr<DataSourceSurface> surf =
  47. Factory::CreateWrappingDataSourceSurface(*vbufptr, stride, size, format,
  48. &VolatileBufferRelease,
  49. static_cast<void*>(vbufptr));
  50. if (!surf) {
  51. delete vbufptr;
  52. return nullptr;
  53. }
  54. return surf.forget();
  55. }
  56. static already_AddRefed<VolatileBuffer>
  57. AllocateBufferForImage(const IntSize& size, SurfaceFormat format)
  58. {
  59. int32_t stride = VolatileSurfaceStride(size, format);
  60. RefPtr<VolatileBuffer> buf = new VolatileBuffer();
  61. if (buf->Init(stride * size.height,
  62. size_t(1) << gfxAlphaRecovery::GoodAlignmentLog2())) {
  63. return buf.forget();
  64. }
  65. return nullptr;
  66. }
  67. static bool
  68. ClearSurface(VolatileBuffer* aVBuf, const IntSize& aSize, SurfaceFormat aFormat)
  69. {
  70. VolatileBufferPtr<unsigned char> vbufptr(aVBuf);
  71. if (vbufptr.WasBufferPurged()) {
  72. NS_WARNING("VolatileBuffer was purged");
  73. return false;
  74. }
  75. int32_t stride = VolatileSurfaceStride(aSize, aFormat);
  76. if (aFormat == SurfaceFormat::B8G8R8X8) {
  77. // Skia doesn't support RGBX surfaces, so ensure the alpha value is set
  78. // to opaque white. While it would be nice to only do this for Skia,
  79. // imgFrame can run off main thread and past shutdown where
  80. // we might not have gfxPlatform, so just memset everytime instead.
  81. memset(vbufptr, 0xFF, stride * aSize.height);
  82. } else if (aVBuf->OnHeap()) {
  83. // We only need to memset it if the buffer was allocated on the heap.
  84. // Otherwise, it's allocated via mmap and refers to a zeroed page and will
  85. // be COW once it's written to.
  86. memset(vbufptr, 0, stride * aSize.height);
  87. }
  88. return true;
  89. }
  90. // Returns true if an image of aWidth x aHeight is allowed and legal.
  91. static bool
  92. AllowedImageSize(int32_t aWidth, int32_t aHeight)
  93. {
  94. // reject over-wide or over-tall images
  95. const int32_t k64KLimit = 0x0000FFFF;
  96. if (MOZ_UNLIKELY(aWidth > k64KLimit || aHeight > k64KLimit )) {
  97. NS_WARNING("image too big");
  98. return false;
  99. }
  100. // protect against invalid sizes
  101. if (MOZ_UNLIKELY(aHeight <= 0 || aWidth <= 0)) {
  102. return false;
  103. }
  104. // check to make sure we don't overflow 32-bit size for RGBA
  105. CheckedInt32 requiredBytes = CheckedInt32(aWidth) * CheckedInt32(aHeight) * 4;
  106. if (MOZ_UNLIKELY(!requiredBytes.isValid())) {
  107. NS_WARNING("width or height too large");
  108. return false;
  109. }
  110. return true;
  111. }
  112. static bool AllowedImageAndFrameDimensions(const nsIntSize& aImageSize,
  113. const nsIntRect& aFrameRect)
  114. {
  115. if (!AllowedImageSize(aImageSize.width, aImageSize.height)) {
  116. return false;
  117. }
  118. if (!AllowedImageSize(aFrameRect.width, aFrameRect.height)) {
  119. return false;
  120. }
  121. nsIntRect imageRect(0, 0, aImageSize.width, aImageSize.height);
  122. if (!imageRect.Contains(aFrameRect)) {
  123. NS_WARNING("Animated image frame does not fit inside bounds of image");
  124. }
  125. return true;
  126. }
  127. imgFrame::imgFrame()
  128. : mMonitor("imgFrame")
  129. , mDecoded(0, 0, 0, 0)
  130. , mLockCount(0)
  131. , mHasNoAlpha(false)
  132. , mAborted(false)
  133. , mFinished(false)
  134. , mOptimizable(false)
  135. , mTimeout(FrameTimeout::FromRawMilliseconds(100))
  136. , mDisposalMethod(DisposalMethod::NOT_SPECIFIED)
  137. , mBlendMethod(BlendMethod::OVER)
  138. , mPalettedImageData(nullptr)
  139. , mPaletteDepth(0)
  140. , mNonPremult(false)
  141. , mCompositingFailed(false)
  142. {
  143. }
  144. imgFrame::~imgFrame()
  145. {
  146. #ifdef DEBUG
  147. MonitorAutoLock lock(mMonitor);
  148. MOZ_ASSERT(mAborted || AreAllPixelsWritten());
  149. MOZ_ASSERT(mAborted || mFinished);
  150. #endif
  151. free(mPalettedImageData);
  152. mPalettedImageData = nullptr;
  153. }
  154. nsresult
  155. imgFrame::InitForDecoder(const nsIntSize& aImageSize,
  156. const nsIntRect& aRect,
  157. SurfaceFormat aFormat,
  158. uint8_t aPaletteDepth /* = 0 */,
  159. bool aNonPremult /* = false */,
  160. const Maybe<AnimationParams>& aAnimParams /* = Nothing() */)
  161. {
  162. // Assert for properties that should be verified by decoders,
  163. // warn for properties related to bad content.
  164. if (!AllowedImageAndFrameDimensions(aImageSize, aRect)) {
  165. NS_WARNING("Should have legal image size");
  166. mAborted = true;
  167. return NS_ERROR_FAILURE;
  168. }
  169. mImageSize = aImageSize;
  170. mFrameRect = aRect;
  171. if (aAnimParams) {
  172. mBlendRect = aAnimParams->mBlendRect;
  173. mTimeout = aAnimParams->mTimeout;
  174. mBlendMethod = aAnimParams->mBlendMethod;
  175. mDisposalMethod = aAnimParams->mDisposalMethod;
  176. } else {
  177. mBlendRect = aRect;
  178. }
  179. // We only allow a non-trivial frame rect (i.e., a frame rect that doesn't
  180. // cover the entire image) for paletted animation frames. We never draw those
  181. // frames directly; we just use FrameAnimator to composite them and produce a
  182. // BGRA surface that we actually draw. We enforce this here to make sure that
  183. // imgFrame::Draw(), which is responsible for drawing all other kinds of
  184. // frames, never has to deal with a non-trivial frame rect.
  185. if (aPaletteDepth == 0 &&
  186. !mFrameRect.IsEqualEdges(IntRect(IntPoint(), mImageSize))) {
  187. MOZ_ASSERT_UNREACHABLE("Creating a non-paletted imgFrame with a "
  188. "non-trivial frame rect");
  189. return NS_ERROR_FAILURE;
  190. }
  191. mFormat = aFormat;
  192. mPaletteDepth = aPaletteDepth;
  193. mNonPremult = aNonPremult;
  194. if (aPaletteDepth != 0) {
  195. // We're creating for a paletted image.
  196. if (aPaletteDepth > 8) {
  197. NS_WARNING("Should have legal palette depth");
  198. NS_ERROR("This Depth is not supported");
  199. mAborted = true;
  200. return NS_ERROR_FAILURE;
  201. }
  202. // Use the fallible allocator here. Paletted images always use 1 byte per
  203. // pixel, so calculating the amount of memory we need is straightforward.
  204. size_t dataSize = PaletteDataLength() + mFrameRect.Area();
  205. mPalettedImageData = static_cast<uint8_t*>(calloc(dataSize, sizeof(uint8_t)));
  206. if (!mPalettedImageData) {
  207. NS_WARNING("Call to calloc for paletted image data should succeed");
  208. }
  209. NS_ENSURE_TRUE(mPalettedImageData, NS_ERROR_OUT_OF_MEMORY);
  210. } else {
  211. MOZ_ASSERT(!mImageSurface, "Called imgFrame::InitForDecoder() twice?");
  212. mVBuf = AllocateBufferForImage(mFrameRect.Size(), mFormat);
  213. if (!mVBuf) {
  214. mAborted = true;
  215. return NS_ERROR_OUT_OF_MEMORY;
  216. }
  217. mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
  218. if (!mImageSurface) {
  219. NS_WARNING("Failed to create ImageSurface");
  220. mAborted = true;
  221. return NS_ERROR_OUT_OF_MEMORY;
  222. }
  223. if (!ClearSurface(mVBuf, mFrameRect.Size(), mFormat)) {
  224. NS_WARNING("Could not clear allocated buffer");
  225. mAborted = true;
  226. return NS_ERROR_OUT_OF_MEMORY;
  227. }
  228. }
  229. return NS_OK;
  230. }
  231. nsresult
  232. imgFrame::InitWithDrawable(gfxDrawable* aDrawable,
  233. const nsIntSize& aSize,
  234. const SurfaceFormat aFormat,
  235. SamplingFilter aSamplingFilter,
  236. uint32_t aImageFlags,
  237. gfx::BackendType aBackend)
  238. {
  239. // Assert for properties that should be verified by decoders,
  240. // warn for properties related to bad content.
  241. if (!AllowedImageSize(aSize.width, aSize.height)) {
  242. NS_WARNING("Should have legal image size");
  243. mAborted = true;
  244. return NS_ERROR_FAILURE;
  245. }
  246. mImageSize = aSize;
  247. mFrameRect = IntRect(IntPoint(0, 0), aSize);
  248. mFormat = aFormat;
  249. mPaletteDepth = 0;
  250. RefPtr<DrawTarget> target;
  251. bool canUseDataSurface =
  252. gfxPlatform::GetPlatform()->CanRenderContentToDataSurface();
  253. if (canUseDataSurface) {
  254. // It's safe to use data surfaces for content on this platform, so we can
  255. // get away with using volatile buffers.
  256. MOZ_ASSERT(!mImageSurface, "Called imgFrame::InitWithDrawable() twice?");
  257. mVBuf = AllocateBufferForImage(mFrameRect.Size(), mFormat);
  258. if (!mVBuf) {
  259. mAborted = true;
  260. return NS_ERROR_OUT_OF_MEMORY;
  261. }
  262. int32_t stride = VolatileSurfaceStride(mFrameRect.Size(), mFormat);
  263. VolatileBufferPtr<uint8_t> ptr(mVBuf);
  264. if (!ptr) {
  265. mAborted = true;
  266. return NS_ERROR_OUT_OF_MEMORY;
  267. }
  268. mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
  269. if (!mImageSurface) {
  270. NS_WARNING("Failed to create ImageSurface");
  271. mAborted = true;
  272. return NS_ERROR_OUT_OF_MEMORY;
  273. }
  274. if (!ClearSurface(mVBuf, mFrameRect.Size(), mFormat)) {
  275. NS_WARNING("Could not clear allocated buffer");
  276. mAborted = true;
  277. return NS_ERROR_OUT_OF_MEMORY;
  278. }
  279. target = gfxPlatform::CreateDrawTargetForData(
  280. ptr,
  281. mFrameRect.Size(),
  282. stride,
  283. mFormat);
  284. } else {
  285. // We can't use data surfaces for content, so we'll create an offscreen
  286. // surface instead. This means if someone later calls RawAccessRef(), we
  287. // may have to do an expensive readback, but we warned callers about that in
  288. // the documentation for this method.
  289. MOZ_ASSERT(!mOptSurface, "Called imgFrame::InitWithDrawable() twice?");
  290. if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(aBackend)) {
  291. target = gfxPlatform::GetPlatform()->
  292. CreateDrawTargetForBackend(aBackend, mFrameRect.Size(), mFormat);
  293. } else {
  294. target = gfxPlatform::GetPlatform()->
  295. CreateOffscreenContentDrawTarget(mFrameRect.Size(), mFormat);
  296. }
  297. }
  298. if (!target || !target->IsValid()) {
  299. mAborted = true;
  300. return NS_ERROR_OUT_OF_MEMORY;
  301. }
  302. // Draw using the drawable the caller provided.
  303. RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(target);
  304. MOZ_ASSERT(ctx); // Already checked the draw target above.
  305. gfxUtils::DrawPixelSnapped(ctx, aDrawable, mFrameRect.Size(),
  306. ImageRegion::Create(ThebesRect(mFrameRect)),
  307. mFormat, aSamplingFilter, aImageFlags);
  308. if (canUseDataSurface && !mImageSurface) {
  309. NS_WARNING("Failed to create VolatileDataSourceSurface");
  310. mAborted = true;
  311. return NS_ERROR_OUT_OF_MEMORY;
  312. }
  313. if (!canUseDataSurface) {
  314. // We used an offscreen surface, which is an "optimized" surface from
  315. // imgFrame's perspective.
  316. mOptSurface = target->Snapshot();
  317. }
  318. // If we reach this point, we should regard ourselves as complete.
  319. mDecoded = GetRect();
  320. mFinished = true;
  321. #ifdef DEBUG
  322. MonitorAutoLock lock(mMonitor);
  323. MOZ_ASSERT(AreAllPixelsWritten());
  324. #endif
  325. return NS_OK;
  326. }
  327. bool
  328. imgFrame::CanOptimizeOpaqueImage()
  329. {
  330. MOZ_ASSERT(NS_IsMainThread());
  331. MOZ_ASSERT(!ShutdownTracker::ShutdownHasStarted());
  332. mMonitor.AssertCurrentThreadOwns();
  333. // If we're using a surface format with alpha but the image has no alpha,
  334. // change the format. This doesn't change the underlying data at all, but
  335. // allows DrawTargets to avoid blending when drawing known opaque images.
  336. // This optimization is free and safe, so we always do it when we can except
  337. // if we have a Skia backend. Skia doesn't support RGBX so ensure we don't
  338. // optimize to a RGBX surface.
  339. return mHasNoAlpha && mFormat == SurfaceFormat::B8G8R8A8 && mImageSurface &&
  340. (gfxPlatform::GetPlatform()->GetDefaultContentBackend() != BackendType::SKIA);
  341. }
  342. nsresult
  343. imgFrame::Optimize(DrawTarget* aTarget)
  344. {
  345. MOZ_ASSERT(NS_IsMainThread());
  346. mMonitor.AssertCurrentThreadOwns();
  347. if (mLockCount > 0 || !mOptimizable) {
  348. // Don't optimize right now.
  349. return NS_OK;
  350. }
  351. // Check whether image optimization is disabled -- not thread safe!
  352. static bool gDisableOptimize = false;
  353. static bool hasCheckedOptimize = false;
  354. if (!hasCheckedOptimize) {
  355. if (PR_GetEnv("MOZ_DISABLE_IMAGE_OPTIMIZE")) {
  356. gDisableOptimize = true;
  357. }
  358. hasCheckedOptimize = true;
  359. }
  360. // Don't optimize during shutdown because gfxPlatform may not be available.
  361. if (ShutdownTracker::ShutdownHasStarted()) {
  362. return NS_OK;
  363. }
  364. // This optimization is basically free, so we perform it even if optimization is disabled.
  365. if (CanOptimizeOpaqueImage()) {
  366. mFormat = SurfaceFormat::B8G8R8X8;
  367. mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
  368. }
  369. if (gDisableOptimize) {
  370. return NS_OK;
  371. }
  372. if (mPalettedImageData || mOptSurface) {
  373. return NS_OK;
  374. }
  375. // XXX(seth): It's currently unclear if there's any reason why we can't
  376. // optimize non-premult surfaces. We should look into removing this.
  377. if (mNonPremult) {
  378. return NS_OK;
  379. }
  380. mOptSurface = gfxPlatform::GetPlatform()
  381. ->ScreenReferenceDrawTarget()->OptimizeSourceSurface(mImageSurface);
  382. if (mOptSurface == mImageSurface) {
  383. mOptSurface = nullptr;
  384. }
  385. if (mOptSurface) {
  386. // There's no reason to keep our volatile buffer around at all if we have an
  387. // optimized surface. Release our reference to it. This will leave
  388. // |mVBufPtr| and |mImageSurface| as the only things keeping it alive, so
  389. // it'll get freed below.
  390. mVBuf = nullptr;
  391. }
  392. // Release all strong references to our volatile buffer's memory. This will
  393. // allow the operating system to free the memory if it needs to.
  394. mVBufPtr = nullptr;
  395. mImageSurface = nullptr;
  396. mOptimizable = false;
  397. return NS_OK;
  398. }
  399. DrawableFrameRef
  400. imgFrame::DrawableRef()
  401. {
  402. return DrawableFrameRef(this);
  403. }
  404. RawAccessFrameRef
  405. imgFrame::RawAccessRef()
  406. {
  407. return RawAccessFrameRef(this);
  408. }
  409. void
  410. imgFrame::SetRawAccessOnly()
  411. {
  412. AssertImageDataLocked();
  413. // Lock our data and throw away the key.
  414. LockImageData();
  415. }
  416. imgFrame::SurfaceWithFormat
  417. imgFrame::SurfaceForDrawing(bool aDoPartialDecode,
  418. bool aDoTile,
  419. ImageRegion& aRegion,
  420. SourceSurface* aSurface)
  421. {
  422. MOZ_ASSERT(NS_IsMainThread());
  423. mMonitor.AssertCurrentThreadOwns();
  424. if (!aDoPartialDecode) {
  425. return SurfaceWithFormat(new gfxSurfaceDrawable(aSurface, mImageSize),
  426. mFormat);
  427. }
  428. gfxRect available = gfxRect(mDecoded.x, mDecoded.y, mDecoded.width,
  429. mDecoded.height);
  430. if (aDoTile) {
  431. // Create a temporary surface.
  432. // Give this surface an alpha channel because there are
  433. // transparent pixels in the padding or undecoded area
  434. RefPtr<DrawTarget> target =
  435. gfxPlatform::GetPlatform()->
  436. CreateOffscreenContentDrawTarget(mImageSize, SurfaceFormat::B8G8R8A8);
  437. if (!target) {
  438. return SurfaceWithFormat();
  439. }
  440. SurfacePattern pattern(aSurface,
  441. aRegion.GetExtendMode(),
  442. Matrix::Translation(mDecoded.x, mDecoded.y));
  443. target->FillRect(ToRect(aRegion.Intersect(available).Rect()), pattern);
  444. RefPtr<SourceSurface> newsurf = target->Snapshot();
  445. return SurfaceWithFormat(new gfxSurfaceDrawable(newsurf, mImageSize),
  446. target->GetFormat());
  447. }
  448. // Not tiling, and we have a surface, so we can account for
  449. // a partial decode just by twiddling parameters.
  450. aRegion = aRegion.Intersect(available);
  451. IntSize availableSize(mDecoded.width, mDecoded.height);
  452. return SurfaceWithFormat(new gfxSurfaceDrawable(aSurface, availableSize),
  453. mFormat);
  454. }
  455. bool imgFrame::Draw(gfxContext* aContext, const ImageRegion& aRegion,
  456. SamplingFilter aSamplingFilter, uint32_t aImageFlags)
  457. {
  458. PROFILER_LABEL("imgFrame", "Draw",
  459. js::ProfileEntry::Category::GRAPHICS);
  460. MOZ_ASSERT(NS_IsMainThread());
  461. NS_ASSERTION(!aRegion.Rect().IsEmpty(), "Drawing empty region!");
  462. NS_ASSERTION(!aRegion.IsRestricted() ||
  463. !aRegion.Rect().Intersect(aRegion.Restriction()).IsEmpty(),
  464. "We must be allowed to sample *some* source pixels!");
  465. MOZ_ASSERT(mFrameRect.IsEqualEdges(IntRect(IntPoint(), mImageSize)),
  466. "Directly drawing an image with a non-trivial frame rect!");
  467. if (mPalettedImageData) {
  468. MOZ_ASSERT_UNREACHABLE("Directly drawing a paletted image!");
  469. return false;
  470. }
  471. MonitorAutoLock lock(mMonitor);
  472. // Possibly convert this image into a GPU texture, this may also cause our
  473. // mImageSurface to be released and the OS to release the underlying memory.
  474. Optimize(aContext->GetDrawTarget());
  475. bool doPartialDecode = !AreAllPixelsWritten();
  476. RefPtr<SourceSurface> surf = GetSourceSurfaceInternal();
  477. if (!surf) {
  478. return false;
  479. }
  480. gfxRect imageRect(0, 0, mImageSize.width, mImageSize.height);
  481. bool doTile = !imageRect.Contains(aRegion.Rect()) &&
  482. !(aImageFlags & imgIContainer::FLAG_CLAMP);
  483. ImageRegion region(aRegion);
  484. SurfaceWithFormat surfaceResult =
  485. SurfaceForDrawing(doPartialDecode, doTile, region, surf);
  486. if (surfaceResult.IsValid()) {
  487. gfxUtils::DrawPixelSnapped(aContext, surfaceResult.mDrawable,
  488. imageRect.Size(), region, surfaceResult.mFormat,
  489. aSamplingFilter, aImageFlags);
  490. }
  491. return true;
  492. }
  493. nsresult
  494. imgFrame::ImageUpdated(const nsIntRect& aUpdateRect)
  495. {
  496. MonitorAutoLock lock(mMonitor);
  497. return ImageUpdatedInternal(aUpdateRect);
  498. }
  499. nsresult
  500. imgFrame::ImageUpdatedInternal(const nsIntRect& aUpdateRect)
  501. {
  502. mMonitor.AssertCurrentThreadOwns();
  503. mDecoded.UnionRect(mDecoded, aUpdateRect);
  504. // Clamp to the frame rect to ensure that decoder bugs don't result in a
  505. // decoded rect that extends outside the bounds of the frame rect.
  506. mDecoded.IntersectRect(mDecoded, mFrameRect);
  507. return NS_OK;
  508. }
  509. void
  510. imgFrame::Finish(Opacity aFrameOpacity /* = Opacity::SOME_TRANSPARENCY */)
  511. {
  512. MonitorAutoLock lock(mMonitor);
  513. MOZ_ASSERT(mLockCount > 0, "Image data should be locked");
  514. if (aFrameOpacity == Opacity::FULLY_OPAQUE) {
  515. mHasNoAlpha = true;
  516. }
  517. ImageUpdatedInternal(GetRect());
  518. mFinished = true;
  519. // The image is now complete, wake up anyone who's waiting.
  520. mMonitor.NotifyAll();
  521. }
  522. uint32_t
  523. imgFrame::GetImageBytesPerRow() const
  524. {
  525. mMonitor.AssertCurrentThreadOwns();
  526. if (mVBuf) {
  527. return mFrameRect.width * BytesPerPixel(mFormat);
  528. }
  529. if (mPaletteDepth) {
  530. return mFrameRect.width;
  531. }
  532. return 0;
  533. }
  534. uint32_t
  535. imgFrame::GetImageDataLength() const
  536. {
  537. return GetImageBytesPerRow() * mFrameRect.height;
  538. }
  539. void
  540. imgFrame::GetImageData(uint8_t** aData, uint32_t* aLength) const
  541. {
  542. MonitorAutoLock lock(mMonitor);
  543. GetImageDataInternal(aData, aLength);
  544. }
  545. void
  546. imgFrame::GetImageDataInternal(uint8_t** aData, uint32_t* aLength) const
  547. {
  548. mMonitor.AssertCurrentThreadOwns();
  549. MOZ_ASSERT(mLockCount > 0, "Image data should be locked");
  550. if (mImageSurface) {
  551. *aData = mVBufPtr;
  552. MOZ_ASSERT(*aData,
  553. "mImageSurface is non-null, but mVBufPtr is null in GetImageData");
  554. } else if (mPalettedImageData) {
  555. *aData = mPalettedImageData + PaletteDataLength();
  556. MOZ_ASSERT(*aData,
  557. "mPalettedImageData is non-null, but result is null in GetImageData");
  558. } else {
  559. MOZ_ASSERT(false,
  560. "Have neither mImageSurface nor mPalettedImageData in GetImageData");
  561. *aData = nullptr;
  562. }
  563. *aLength = GetImageDataLength();
  564. }
  565. uint8_t*
  566. imgFrame::GetImageData() const
  567. {
  568. uint8_t* data;
  569. uint32_t length;
  570. GetImageData(&data, &length);
  571. return data;
  572. }
  573. bool
  574. imgFrame::GetIsPaletted() const
  575. {
  576. return mPalettedImageData != nullptr;
  577. }
  578. void
  579. imgFrame::GetPaletteData(uint32_t** aPalette, uint32_t* length) const
  580. {
  581. AssertImageDataLocked();
  582. if (!mPalettedImageData) {
  583. *aPalette = nullptr;
  584. *length = 0;
  585. } else {
  586. *aPalette = (uint32_t*) mPalettedImageData;
  587. *length = PaletteDataLength();
  588. }
  589. }
  590. uint32_t*
  591. imgFrame::GetPaletteData() const
  592. {
  593. uint32_t* data;
  594. uint32_t length;
  595. GetPaletteData(&data, &length);
  596. return data;
  597. }
  598. nsresult
  599. imgFrame::LockImageData()
  600. {
  601. MonitorAutoLock lock(mMonitor);
  602. MOZ_ASSERT(mLockCount >= 0, "Unbalanced locks and unlocks");
  603. if (mLockCount < 0) {
  604. return NS_ERROR_FAILURE;
  605. }
  606. mLockCount++;
  607. // If we are not the first lock, there's nothing to do.
  608. if (mLockCount != 1) {
  609. return NS_OK;
  610. }
  611. // If we're the first lock, but have an image surface, we're OK.
  612. if (mImageSurface) {
  613. mVBufPtr = mVBuf;
  614. return NS_OK;
  615. }
  616. // Paletted images don't have surfaces, so there's nothing to do.
  617. if (mPalettedImageData) {
  618. return NS_OK;
  619. }
  620. MOZ_ASSERT_UNREACHABLE("It's illegal to re-lock an optimized imgFrame");
  621. return NS_ERROR_FAILURE;
  622. }
  623. void
  624. imgFrame::AssertImageDataLocked() const
  625. {
  626. #ifdef DEBUG
  627. MonitorAutoLock lock(mMonitor);
  628. MOZ_ASSERT(mLockCount > 0, "Image data should be locked");
  629. #endif
  630. }
  631. nsresult
  632. imgFrame::UnlockImageData()
  633. {
  634. MonitorAutoLock lock(mMonitor);
  635. MOZ_ASSERT(mLockCount > 0, "Unlocking an unlocked image!");
  636. if (mLockCount <= 0) {
  637. return NS_ERROR_FAILURE;
  638. }
  639. MOZ_ASSERT(mLockCount > 1 || mFinished || mAborted,
  640. "Should have Finish()'d or aborted before unlocking");
  641. mLockCount--;
  642. return NS_OK;
  643. }
  644. void
  645. imgFrame::SetOptimizable()
  646. {
  647. AssertImageDataLocked();
  648. MonitorAutoLock lock(mMonitor);
  649. mOptimizable = true;
  650. }
  651. already_AddRefed<SourceSurface>
  652. imgFrame::GetSourceSurface()
  653. {
  654. MonitorAutoLock lock(mMonitor);
  655. return GetSourceSurfaceInternal();
  656. }
  657. already_AddRefed<SourceSurface>
  658. imgFrame::GetSourceSurfaceInternal()
  659. {
  660. mMonitor.AssertCurrentThreadOwns();
  661. if (mOptSurface) {
  662. if (mOptSurface->IsValid()) {
  663. RefPtr<SourceSurface> surf(mOptSurface);
  664. return surf.forget();
  665. } else {
  666. mOptSurface = nullptr;
  667. }
  668. }
  669. if (mImageSurface) {
  670. RefPtr<SourceSurface> surf(mImageSurface);
  671. return surf.forget();
  672. }
  673. if (!mVBuf) {
  674. return nullptr;
  675. }
  676. VolatileBufferPtr<char> buf(mVBuf);
  677. if (buf.WasBufferPurged()) {
  678. return nullptr;
  679. }
  680. return CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
  681. }
  682. AnimationData
  683. imgFrame::GetAnimationData() const
  684. {
  685. MonitorAutoLock lock(mMonitor);
  686. MOZ_ASSERT(mLockCount > 0, "Image data should be locked");
  687. uint8_t* data;
  688. if (mPalettedImageData) {
  689. data = mPalettedImageData;
  690. } else {
  691. uint32_t length;
  692. GetImageDataInternal(&data, &length);
  693. }
  694. bool hasAlpha = mFormat == SurfaceFormat::B8G8R8A8;
  695. return AnimationData(data, PaletteDataLength(), mTimeout, GetRect(),
  696. mBlendMethod, Some(mBlendRect), mDisposalMethod, hasAlpha);
  697. }
  698. void
  699. imgFrame::Abort()
  700. {
  701. MonitorAutoLock lock(mMonitor);
  702. mAborted = true;
  703. // Wake up anyone who's waiting.
  704. mMonitor.NotifyAll();
  705. }
  706. bool
  707. imgFrame::IsAborted() const
  708. {
  709. MonitorAutoLock lock(mMonitor);
  710. return mAborted;
  711. }
  712. bool
  713. imgFrame::IsFinished() const
  714. {
  715. MonitorAutoLock lock(mMonitor);
  716. return mFinished;
  717. }
  718. void
  719. imgFrame::WaitUntilFinished() const
  720. {
  721. MonitorAutoLock lock(mMonitor);
  722. while (true) {
  723. // Return if we're aborted or complete.
  724. if (mAborted || mFinished) {
  725. return;
  726. }
  727. // Not complete yet, so we'll have to wait.
  728. mMonitor.Wait();
  729. }
  730. }
  731. bool
  732. imgFrame::AreAllPixelsWritten() const
  733. {
  734. mMonitor.AssertCurrentThreadOwns();
  735. return mDecoded.IsEqualInterior(mFrameRect);
  736. }
  737. bool imgFrame::GetCompositingFailed() const
  738. {
  739. MOZ_ASSERT(NS_IsMainThread());
  740. return mCompositingFailed;
  741. }
  742. void
  743. imgFrame::SetCompositingFailed(bool val)
  744. {
  745. MOZ_ASSERT(NS_IsMainThread());
  746. mCompositingFailed = val;
  747. }
  748. void
  749. imgFrame::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
  750. size_t& aHeapSizeOut,
  751. size_t& aNonHeapSizeOut) const
  752. {
  753. MonitorAutoLock lock(mMonitor);
  754. if (mPalettedImageData) {
  755. aHeapSizeOut += aMallocSizeOf(mPalettedImageData);
  756. }
  757. if (mImageSurface) {
  758. aHeapSizeOut += aMallocSizeOf(mImageSurface);
  759. }
  760. if (mOptSurface) {
  761. aHeapSizeOut += aMallocSizeOf(mOptSurface);
  762. }
  763. if (mVBuf) {
  764. aHeapSizeOut += aMallocSizeOf(mVBuf);
  765. aHeapSizeOut += mVBuf->HeapSizeOfExcludingThis(aMallocSizeOf);
  766. aNonHeapSizeOut += mVBuf->NonHeapSizeOfExcludingThis();
  767. }
  768. }
  769. } // namespace image
  770. } // namespace mozilla