Bug 1031576 (Part 1) - Add an Image subclass for dynamically-created images. r=tn
authorSeth Fowler <seth@mozilla.com>
Mon, 21 Jul 2014 17:59:22 -0700
changeset 195381 ab8ac3c0de7feb48f1f65b919c9c59c86cf9bf6f
parent 195380 fee5c4bdd7131e7515f9f3bc4af667cdae2f5f8e
child 195382 fe38d8c189e541af26b62e6dcabc0299420f2673
push id46576
push usermfowler@mozilla.com
push dateTue, 22 Jul 2014 00:59:51 +0000
treeherdermozilla-inbound@fd4c9f4cd1f0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn
bugs1031576
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1031576 (Part 1) - Add an Image subclass for dynamically-created images. r=tn
image/src/DynamicImage.cpp
image/src/DynamicImage.h
image/src/ImageOps.cpp
image/src/ImageOps.h
image/src/moz.build
new file mode 100644
--- /dev/null
+++ b/image/src/DynamicImage.cpp
@@ -0,0 +1,355 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DynamicImage.h"
+#include "gfxPlatform.h"
+#include "gfxUtils.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/RefPtr.h"
+#include "Orientation.h"
+
+#include "mozilla/MemoryReporting.h"
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+using mozilla::layers::LayerManager;
+using mozilla::layers::ImageContainer;
+
+namespace mozilla {
+namespace image {
+
+// Inherited methods from Image.
+
+nsresult
+DynamicImage::Init(const char* aMimeType, uint32_t aFlags)
+{
+  return NS_OK;
+}
+
+already_AddRefed<imgStatusTracker>
+DynamicImage::GetStatusTracker()
+{
+  return nullptr;
+}
+
+nsIntRect
+DynamicImage::FrameRect(uint32_t aWhichFrame)
+{
+  gfxIntSize size(mDrawable->Size());
+  return nsIntRect(0, 0, size.width, size.height);
+}
+
+uint32_t
+DynamicImage::SizeOfData()
+{
+  // We don't know the answer to this (and the same goes for the other
+  // memory-related methods) since gfxDrawable doesn't expose a way to check.
+  return 0;
+}
+
+size_t
+DynamicImage::HeapSizeOfSourceWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  return 0;
+}
+
+size_t
+DynamicImage::HeapSizeOfDecodedWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  return 0;
+}
+
+size_t
+DynamicImage::NonHeapSizeOfDecoded() const
+{
+  return 0;
+}
+
+size_t
+DynamicImage::OutOfProcessSizeOfDecoded() const
+{
+  return 0;
+}
+
+size_t
+DynamicImage::HeapSizeOfVectorImageDocument(nsACString* aDocURL) const
+{
+  return 0;
+}
+
+void
+DynamicImage::IncrementAnimationConsumers()
+{ }
+
+void
+DynamicImage::DecrementAnimationConsumers()
+{ }
+
+#ifdef DEBUG
+uint32_t
+DynamicImage::GetAnimationConsumers()
+{
+  return 0;
+}
+#endif
+
+nsresult
+DynamicImage::OnImageDataAvailable(nsIRequest* aRequest,
+                                   nsISupports* aContext,
+                                   nsIInputStream* aInStr,
+                                   uint64_t aSourceOffset,
+                                   uint32_t aCount)
+{
+  return NS_OK;
+}
+
+nsresult
+DynamicImage::OnImageDataComplete(nsIRequest* aRequest,
+                                  nsISupports* aContext,
+                                  nsresult aStatus,
+                                  bool aLastPart)
+{
+  return NS_OK;
+}
+
+nsresult
+DynamicImage::OnNewSourceData()
+{
+  return NS_OK;
+}
+
+void
+DynamicImage::SetInnerWindowID(uint64_t aInnerWindowId)
+{ }
+
+uint64_t
+DynamicImage::InnerWindowID() const
+{
+  return 0;
+}
+
+bool
+DynamicImage::HasError()
+{
+  return !mDrawable;
+}
+
+void
+DynamicImage::SetHasError()
+{ }
+
+ImageURL*
+DynamicImage::GetURI()
+{
+  return nullptr;
+}
+
+// Methods inherited from XPCOM interfaces.
+
+NS_IMPL_ISUPPORTS(DynamicImage, imgIContainer)
+
+NS_IMETHODIMP
+DynamicImage::GetWidth(int32_t* aWidth)
+{
+  *aWidth = mDrawable->Size().width;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DynamicImage::GetHeight(int32_t* aHeight)
+{
+  *aHeight = mDrawable->Size().height;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DynamicImage::GetIntrinsicSize(nsSize* aSize)
+{
+  gfxIntSize intSize(mDrawable->Size());
+  *aSize = nsSize(intSize.width, intSize.height);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DynamicImage::GetIntrinsicRatio(nsSize* aSize)
+{
+  gfxIntSize intSize(mDrawable->Size());
+  *aSize = nsSize(intSize.width, intSize.height);
+  return NS_OK;
+}
+
+NS_IMETHODIMP_(Orientation)
+DynamicImage::GetOrientation()
+{
+  return Orientation();
+}
+
+NS_IMETHODIMP
+DynamicImage::GetType(uint16_t* aType)
+{
+  *aType = imgIContainer::TYPE_RASTER;
+  return NS_OK;
+}
+
+NS_IMETHODIMP_(uint16_t)
+DynamicImage::GetType()
+{
+  return imgIContainer::TYPE_RASTER;
+}
+
+NS_IMETHODIMP
+DynamicImage::GetAnimated(bool* aAnimated)
+{
+  *aAnimated = false;
+  return NS_OK;
+}
+
+NS_IMETHODIMP_(TemporaryRef<SourceSurface>)
+DynamicImage::GetFrame(uint32_t aWhichFrame,
+                       uint32_t aFlags)
+{
+  gfxIntSize size(mDrawable->Size());
+
+  RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->
+    CreateOffscreenContentDrawTarget(IntSize(size.width, size.height),
+                                     SurfaceFormat::B8G8R8A8);
+  nsRefPtr<gfxContext> context = new gfxContext(dt);
+
+  nsresult rv = Draw(context, GraphicsFilter::FILTER_NEAREST, gfxMatrix(),
+                     gfxRect(0, 0, size.width, size.height),
+                     nsIntRect(0, 0, size.width, size.height),
+                     size, nullptr, aWhichFrame, aFlags);
+
+  NS_ENSURE_SUCCESS(rv, nullptr);
+  return dt->Snapshot();
+}
+
+NS_IMETHODIMP_(bool)
+DynamicImage::FrameIsOpaque(uint32_t aWhichFrame)
+{
+  // XXX(seth): For performance reasons it'd be better to return true here, but
+  // I'm not sure how we can guarantee it for an arbitrary gfxDrawable.
+  return false;
+}
+
+NS_IMETHODIMP
+DynamicImage::GetImageContainer(LayerManager* aManager, ImageContainer** _retval)
+{
+  *_retval = nullptr;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DynamicImage::Draw(gfxContext* aContext,
+                   GraphicsFilter aFilter,
+                   const gfxMatrix& aUserSpaceToImageSpace,
+                   const gfxRect& aFill,
+                   const nsIntRect& aSubimage,
+                   const nsIntSize& aViewportSize,
+                   const SVGImageContext* aSVGContext,
+                   uint32_t aWhichFrame,
+                   uint32_t aFlags)
+{
+  gfxIntSize drawableSize(mDrawable->Size());
+  gfxRect imageRect(0, 0, drawableSize.width, drawableSize.height);
+  gfxRect sourceRect = aUserSpaceToImageSpace.TransformBounds(aFill);
+
+  gfxUtils::DrawPixelSnapped(aContext, mDrawable, aUserSpaceToImageSpace,
+                             aSubimage, sourceRect, imageRect, aFill,
+                             SurfaceFormat::B8G8R8A8, aFilter, aFlags);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DynamicImage::RequestDecode()
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DynamicImage::StartDecoding()
+{
+  return NS_OK;
+}
+
+bool
+DynamicImage::IsDecoded()
+{
+  return true;
+}
+
+NS_IMETHODIMP
+DynamicImage::LockImage()
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DynamicImage::UnlockImage()
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DynamicImage::RequestDiscard()
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP_(void)
+DynamicImage::RequestRefresh(const mozilla::TimeStamp& aTime)
+{ }
+
+NS_IMETHODIMP
+DynamicImage::GetAnimationMode(uint16_t* aAnimationMode)
+{
+  *aAnimationMode = kNormalAnimMode;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DynamicImage::SetAnimationMode(uint16_t aAnimationMode)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DynamicImage::ResetAnimation()
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP_(float)
+DynamicImage::GetFrameIndex(uint32_t aWhichFrame)
+{
+  return 0;
+}
+
+NS_IMETHODIMP_(int32_t)
+DynamicImage::GetFirstFrameDelay()
+{
+  return 0;
+}
+
+NS_IMETHODIMP_(void)
+DynamicImage::SetAnimationStartTime(const mozilla::TimeStamp& aTime)
+{ }
+
+NS_IMETHODIMP_(nsIntRect)
+DynamicImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect)
+{
+  return aRect;
+}
+
+already_AddRefed<imgIContainer>
+DynamicImage::Unwrap()
+{
+  nsCOMPtr<imgIContainer> self(this);
+  return self.forget();
+}
+
+} // namespace image
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/image/src/DynamicImage.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_IMAGELIB_DYNAMICIMAGE_H_
+#define MOZILLA_IMAGELIB_DYNAMICIMAGE_H_
+
+#include "mozilla/MemoryReporting.h"
+#include "gfxDrawable.h"
+#include "Image.h"
+
+namespace mozilla {
+namespace image {
+
+/**
+ 
+ * An Image that is dynamically created. The content of the image is provided by
+ * a gfxDrawable. It's anticipated that most uses of DynamicImage will be
+ * ephemeral.
+ */
+class DynamicImage : public Image
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_IMGICONTAINER
+
+  DynamicImage(gfxDrawable* aDrawable)
+    : mDrawable(aDrawable)
+  {
+    MOZ_ASSERT(aDrawable, "Must have a gfxDrawable to wrap");
+  }
+
+  // Inherited methods from Image.
+  virtual nsresult Init(const char* aMimeType, uint32_t aFlags) MOZ_OVERRIDE;
+
+  virtual already_AddRefed<imgStatusTracker> GetStatusTracker() MOZ_OVERRIDE;
+  virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
+
+  virtual uint32_t SizeOfData() MOZ_OVERRIDE;
+  virtual size_t HeapSizeOfSourceWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
+  virtual size_t HeapSizeOfDecodedWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
+  virtual size_t NonHeapSizeOfDecoded() const MOZ_OVERRIDE;
+  virtual size_t OutOfProcessSizeOfDecoded() const MOZ_OVERRIDE;
+  virtual size_t HeapSizeOfVectorImageDocument(nsACString* aDocURL = nullptr) const MOZ_OVERRIDE;
+
+  virtual void IncrementAnimationConsumers() MOZ_OVERRIDE;
+  virtual void DecrementAnimationConsumers() MOZ_OVERRIDE;
+#ifdef DEBUG
+  virtual uint32_t GetAnimationConsumers() MOZ_OVERRIDE;
+#endif
+
+  virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
+                                        nsISupports* aContext,
+                                        nsIInputStream* aInStr,
+                                        uint64_t aSourceOffset,
+                                        uint32_t aCount) MOZ_OVERRIDE;
+  virtual nsresult OnImageDataComplete(nsIRequest* aRequest,
+                                       nsISupports* aContext,
+                                       nsresult aStatus,
+                                       bool aLastPart) MOZ_OVERRIDE;
+  virtual nsresult OnNewSourceData() MOZ_OVERRIDE;
+
+  virtual void SetInnerWindowID(uint64_t aInnerWindowId) MOZ_OVERRIDE;
+  virtual uint64_t InnerWindowID() const MOZ_OVERRIDE;
+
+  virtual bool HasError() MOZ_OVERRIDE;
+  virtual void SetHasError() MOZ_OVERRIDE;
+
+  virtual ImageURL* GetURI() MOZ_OVERRIDE;
+
+private:
+  virtual ~DynamicImage() { }
+
+  nsRefPtr<gfxDrawable> mDrawable;
+};
+
+} // namespace image
+} // namespace mozilla
+
+#endif // MOZILLA_IMAGELIB_DYNAMICIMAGE_H_
--- a/image/src/ImageOps.cpp
+++ b/image/src/ImageOps.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "imgIContainer.h"
 #include "ClippedImage.h"
+#include "DynamicImage.h"
 #include "FrozenImage.h"
 #include "OrientedImage.h"
 #include "Image.h"
 
 #include "ImageOps.h"
 
 namespace mozilla {
 namespace image {
@@ -55,10 +56,17 @@ ImageOps::Orient(Image* aImage, Orientat
 /* static */ already_AddRefed<imgIContainer>
 ImageOps::Orient(imgIContainer* aImage, Orientation aOrientation)
 {
   nsCOMPtr<imgIContainer> orientedImage =
     new OrientedImage(static_cast<Image*>(aImage), aOrientation);
   return orientedImage.forget();
 }
 
+/* static */ already_AddRefed<imgIContainer>
+ImageOps::CreateFromDrawable(gfxDrawable* aDrawable)
+{
+  nsCOMPtr<imgIContainer> drawableImage = new DynamicImage(aDrawable);
+  return drawableImage.forget();
+}
+
 } // namespace image
 } // namespace mozilla
--- a/image/src/ImageOps.h
+++ b/image/src/ImageOps.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_IMAGELIB_IMAGEOPS_H_
 #define MOZILLA_IMAGELIB_IMAGEOPS_H_
 
 #include "nsCOMPtr.h"
 
+class gfxDrawable;
 class imgIContainer;
 struct nsIntRect;
 
 namespace mozilla {
 namespace image {
 
 class Image;
 struct Orientation;
@@ -44,16 +45,23 @@ public:
    * the specified orientation.
    *
    * @param aImage         The existing image.
    * @param aOrientation   The desired orientation.
    */
   static already_AddRefed<Image> Orient(Image* aImage, Orientation aOrientation);
   static already_AddRefed<imgIContainer> Orient(imgIContainer* aImage, Orientation aOrientation);
 
+  /**
+   * Creates an image from a gfxDrawable.
+   *
+   * @param aDrawable      The gfxDrawable.
+   */
+  static already_AddRefed<imgIContainer> CreateFromDrawable(gfxDrawable* aDrawable);
+
 private:
   // This is a static utility class, so disallow instantiation.
   virtual ~ImageOps() = 0;
 };
 
 } // namespace image
 } // namespace mozilla
 
--- a/image/src/moz.build
+++ b/image/src/moz.build
@@ -12,16 +12,17 @@ EXPORTS += [
     'Orientation.h',
     'SurfaceCache.h'
 ]
 
 UNIFIED_SOURCES += [
     'ClippedImage.cpp',
     'Decoder.cpp',
     'DiscardTracker.cpp',
+    'DynamicImage.cpp',
     'FrameAnimator.cpp',
     'FrameBlender.cpp',
     'FrameSequence.cpp',
     'FrozenImage.cpp',
     'Image.cpp',
     'ImageFactory.cpp',
     'ImageMetadata.cpp',
     'ImageOps.cpp',