Bug 869723 (Part 1) - Add imgIContainer::GetOrientation. r=joe sr=bz
authorSeth Fowler <seth@mozilla.com>
Sat, 24 Aug 2013 17:31:14 -0700
changeset 152224 75abb578641eba400cf888cbaed6ae4fd7d93ba6
parent 152223 62a1a184b2c3a8833921d27a095f41ab9b07f379
child 152225 c4ed3470f04b59f70a822d62c56257cffa5b1e65
push idunknown
push userunknown
push dateunknown
reviewersjoe, bz
bugs869723
milestone26.0a1
Bug 869723 (Part 1) - Add imgIContainer::GetOrientation. r=joe sr=bz
image/public/imgIContainer.idl
image/src/ClippedImage.cpp
image/src/ClippedImage.h
image/src/Decoder.cpp
image/src/Decoder.h
image/src/ImageMetadata.h
image/src/ImageWrapper.cpp
image/src/Orientation.h
image/src/RasterImage.cpp
image/src/RasterImage.h
image/src/VectorImage.cpp
--- a/image/public/imgIContainer.idl
+++ b/image/public/imgIContainer.idl
@@ -26,43 +26,50 @@ class ImageContainer;
 
 class nsIFrame;
 
 namespace mozilla {
 class TimeStamp;
 class SVGImageContext;
 }
 
+namespace mozilla {
+namespace image {
+class Orientation;
+}
+}
+
 %}
 
 [ptr] native gfxImageSurface(gfxImageSurface);
 [ptr] native gfxASurface(gfxASurface);
 native gfxImageFormat(gfxASurface::gfxImageFormat);
 [ptr] native gfxContext(gfxContext);
 [ref] native gfxMatrix(gfxMatrix);
 [ref] native gfxRect(gfxRect);
 native gfxGraphicsFilter(gfxPattern::GraphicsFilter);
 [ref] native nsIntRect(nsIntRect);
 [ref] native nsIntSize(nsIntSize);
 native nsSize(nsSize);
 [ptr] native nsIFrame(nsIFrame);
 [ptr] native ImageContainer(mozilla::layers::ImageContainer);
 [ptr] native LayerManager(mozilla::layers::LayerManager);
+native Orientation(mozilla::image::Orientation);
 [ref] native TimeStamp(mozilla::TimeStamp);
 [ptr] native SVGImageContext(mozilla::SVGImageContext);
 
 
 /**
  * imgIContainer is the interface that represents an image. It allows
  * access to frames as Thebes surfaces. It also allows drawing of images
  * onto Thebes contexts.
  *
  * Internally, imgIContainer also manages animation of images.
  */
-[scriptable, builtinclass, uuid(f9029a03-758c-4047-a1f3-4b2e51e47363)]
+[scriptable, builtinclass, uuid(73340b79-e3ae-4f02-97d0-822db78017e5)]
 interface imgIContainer : nsISupports
 {
   /**
    * The width of the container rectangle.  In the case of any error,
    * zero is returned, and an exception will be thrown.
    */
   readonly attribute int32_t width;
 
@@ -298,16 +305,22 @@ interface imgIContainer : nsISupports
    * draw(..FRAME_CURRENT..) will draw the same frame. The same holds for
    * FRAME_FIRST as well.
    *
    * @param aWhichFrame Frame specifier of the FRAME_* variety.
    */
   [notxpcom] float getFrameIndex(in uint32_t aWhichFrame);
 
   /*
+   * Returns the inherent orientation of the image, as described in the image's
+   * metadata (e.g. EXIF).
+   */
+  [notxpcom] Orientation getOrientation();
+
+  /*
    * Returns the delay, in ms, between the first and second frame. If this
    * returns 0, there is no delay between first and second frame (i.e., this
    * image could render differently whenever it draws).
    *
    * If this image is not animated, or not known to be animated (see attribute
    * animated), returns -1.
    */
   [notxpcom] int32_t getFirstFrameDelay();
--- a/image/src/ClippedImage.cpp
+++ b/image/src/ClippedImage.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gfxDrawable.h"
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "mozilla/dom/SVGSVGElement.h"
 
 #include "ClippedImage.h"
+#include "Orientation.h"
 
 using mozilla::layers::LayerManager;
 using mozilla::layers::ImageContainer;
 
 namespace mozilla {
 namespace image {
 
 class ClippedImageCachedSurface
@@ -406,10 +407,18 @@ NS_IMETHODIMP
 ClippedImage::RequestDiscard()
 {
   // We're very aggressive about discarding.
   mCachedSurface = nullptr;
 
   return InnerImage()->RequestDiscard();
 }
 
+NS_IMETHODIMP_(Orientation)
+ClippedImage::GetOrientation()
+{
+  // XXX(seth): This should not actually be here; this is just to work around a
+  // what appears to be a bug in MSVC's linker.
+  return InnerImage()->GetOrientation();
+}
+
 } // namespace image
 } // namespace mozilla
--- a/image/src/ClippedImage.h
+++ b/image/src/ClippedImage.h
@@ -45,16 +45,17 @@ public:
                   const gfxMatrix& aUserSpaceToImageSpace,
                   const gfxRect& aFill,
                   const nsIntRect& aSubimage,
                   const nsIntSize& aViewportSize,
                   const SVGImageContext* aSVGContext,
                   uint32_t aWhichFrame,
                   uint32_t aFlags) MOZ_OVERRIDE;
   NS_IMETHOD RequestDiscard() MOZ_OVERRIDE;
+  NS_IMETHOD_(Orientation) GetOrientation() MOZ_OVERRIDE;
 
 protected:
   ClippedImage(Image* aImage, nsIntRect aClip);
 
 private:
   nsresult GetFrameInternal(const nsIntSize& aViewportSize,
                             const SVGImageContext* aSVGContext,
                             uint32_t aWhichFrame,
--- a/image/src/Decoder.cpp
+++ b/image/src/Decoder.cpp
@@ -261,40 +261,47 @@ Decoder::FlushInvalidations()
 
   // Clear the invalidation rectangle
   mInvalidRect.SetEmpty();
 }
 
 void
 Decoder::SetSizeOnImage()
 {
-  mImage.SetSize(mImageMetadata.GetWidth(), mImageMetadata.GetHeight());
+  MOZ_ASSERT(mImageMetadata.HasSize(), "Should have size");
+  MOZ_ASSERT(mImageMetadata.HasOrientation(), "Should have orientation");
+
+  mImage.SetSize(mImageMetadata.GetWidth(),
+                 mImageMetadata.GetHeight(),
+                 mImageMetadata.GetOrientation());
 }
 
 /*
  * Hook stubs. Override these as necessary in decoder implementations.
  */
 
 void Decoder::InitInternal() { }
 void Decoder::WriteInternal(const char* aBuffer, uint32_t aCount) { }
 void Decoder::FinishInternal() { }
 
 /*
  * Progress Notifications
  */
 
 void
-Decoder::PostSize(int32_t aWidth, int32_t aHeight)
+Decoder::PostSize(int32_t aWidth,
+                  int32_t aHeight,
+                  Orientation aOrientation /* = Orientation()*/)
 {
   // Validate
   NS_ABORT_IF_FALSE(aWidth >= 0, "Width can't be negative!");
   NS_ABORT_IF_FALSE(aHeight >= 0, "Height can't be negative!");
 
   // Tell the image
-  mImageMetadata.SetSize(aWidth, aHeight);
+  mImageMetadata.SetSize(aWidth, aHeight, aOrientation);
 
   // Notify the observer
   if (mObserver)
     mObserver->OnStartContainer();
 }
 
 void
 Decoder::PostFrameStart()
--- a/image/src/Decoder.h
+++ b/image/src/Decoder.h
@@ -5,16 +5,17 @@
 
 #ifndef MOZILLA_IMAGELIB_DECODER_H_
 #define MOZILLA_IMAGELIB_DECODER_H_
 
 #include "RasterImage.h"
 #include "imgDecoderObserver.h"
 #include "mozilla/RefPtr.h"
 #include "ImageMetadata.h"
+#include "Orientation.h"
 
 namespace mozilla {
 namespace image {
 
 class Decoder
 {
 public:
 
@@ -184,17 +185,19 @@ protected:
   virtual void FinishInternal();
 
   /*
    * Progress notifications.
    */
 
   // Called by decoders when they determine the size of the image. Informs
   // the image of its size and sends notifications.
-  void PostSize(int32_t aWidth, int32_t aHeight);
+  void PostSize(int32_t aWidth,
+                int32_t aHeight,
+                Orientation aOrientation = Orientation());
 
   // Called by decoders when they begin a frame. Informs the image, sends
   // notifications, and does internal book-keeping.
   void PostFrameStart();
 
   // Called by decoders when they end a frame. Informs the image, sends
   // notifications, and does internal book-keeping.
   // Specify whether this frame is opaque as an optimization.
--- a/image/src/ImageMetadata.h
+++ b/image/src/ImageMetadata.h
@@ -2,16 +2,17 @@
  *
  * 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 <stdint.h>
 #include "mozilla/Util.h"
 #include "nsSize.h"
+#include "Orientation.h"
 
 namespace mozilla {
 namespace image {
 
 class RasterImage;
 
 // The metadata about an image that decoders accumulate as they decode.
 class ImageMetadata
@@ -37,33 +38,37 @@ public:
     mLoopCount = loopcount;
   }
 
   void SetIsNonPremultiplied(bool nonPremult)
   {
     mIsNonPremultiplied = nonPremult;
   }
 
-  void SetSize(int32_t width, int32_t height)
+  void SetSize(int32_t width, int32_t height, Orientation orientation)
   {
     mSize.construct(nsIntSize(width, height));
+    mOrientation.construct(orientation);
   }
 
   bool HasSize() const { return !mSize.empty(); }
+  bool HasOrientation() const { return !mOrientation.empty(); }
 
   int32_t GetWidth() const { return mSize.ref().width; }
   int32_t GetHeight() const { return mSize.ref().height; }
+  Orientation GetOrientation() const { return mOrientation.ref(); }
 
 private:
   // The hotspot found on cursors, or -1 if none was found.
   int32_t mHotspotX;
   int32_t mHotspotY;
 
   // The loop count for animated images, or -1 for infinite loop.
   int32_t mLoopCount;
 
   Maybe<nsIntSize> mSize;
+  Maybe<Orientation>  mOrientation;
 
   bool mIsNonPremultiplied;
 };
 
 } // namespace image
 } // namespace mozilla
--- a/image/src/ImageWrapper.cpp
+++ b/image/src/ImageWrapper.cpp
@@ -1,14 +1,15 @@
 /* -*- 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 "ImageWrapper.h"
+#include "Orientation.h"
 
 #include "mozilla/MemoryReporting.h"
 
 using mozilla::layers::LayerManager;
 using mozilla::layers::ImageContainer;
 
 namespace mozilla {
 namespace image {
@@ -162,16 +163,22 @@ ImageWrapper::GetIntrinsicSize(nsSize* a
 }
 
 NS_IMETHODIMP
 ImageWrapper::GetIntrinsicRatio(nsSize* aSize)
 {
   return mInnerImage->GetIntrinsicRatio(aSize);
 }
 
+NS_IMETHODIMP_(Orientation)
+ImageWrapper::GetOrientation()
+{
+  return mInnerImage->GetOrientation();
+}
+
 NS_IMETHODIMP
 ImageWrapper::GetType(uint16_t* aType)
 {
   return mInnerImage->GetType(aType);
 }
 
 NS_IMETHODIMP_(uint16_t)
 ImageWrapper::GetType()
new file mode 100644
--- /dev/null
+++ b/image/src/Orientation.h
@@ -0,0 +1,62 @@
+/* -*- 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_ORIENTATION_H_
+#define MOZILLA_IMAGELIB_ORIENTATION_H_
+
+#include <stdint.h>
+#include "mozilla/TypedEnum.h"
+
+namespace mozilla {
+namespace image {
+
+MOZ_BEGIN_ENUM_CLASS(Angle, uint8_t)
+  D0,
+  D90,
+  D180,
+  D270
+MOZ_END_ENUM_CLASS(Angle)
+
+MOZ_BEGIN_ENUM_CLASS(Flip, uint8_t)
+  Unflipped,
+  Horizontal
+MOZ_END_ENUM_CLASS(Flip)
+
+/**
+ * A struct that describes an image's orientation as a rotation optionally
+ * followed by a reflection. This may be used to be indicate an image's inherent
+ * orientation or a desired orientation for the image.
+ */
+struct Orientation
+{
+  Orientation(Angle aRotation = Angle::D0, Flip mFlip = Flip::Unflipped)
+    : rotation(aRotation)
+    , flip(mFlip)
+  { }
+
+  bool IsIdentity() const {
+    return (rotation == Angle::D0) && (flip == Flip::Unflipped);
+  }
+
+  bool SwapsWidthAndHeight() const {
+    return (rotation == Angle::D90) || (rotation == Angle::D270);
+  }
+
+  bool operator==(const Orientation& aOther) const {
+    return (rotation == aOther.rotation) && (flip == aOther.flip);
+  }
+
+  bool operator!=(const Orientation& aOther) const {
+    return !(*this == aOther);
+  }
+
+  Angle rotation;
+  Flip  flip;
+};
+
+}
+}
+
+#endif
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -614,16 +614,22 @@ RasterImage::GetIntrinsicRatio(nsSize* a
 {
   if (mError)
     return NS_ERROR_FAILURE;
 
   *aRatio = nsSize(mSize.width, mSize.height);
   return NS_OK;
 }
 
+NS_IMETHODIMP_(Orientation)
+RasterImage::GetOrientation()
+{
+  return mOrientation;
+}
+
 //******************************************************************************
 /* unsigned short GetType(); */
 NS_IMETHODIMP
 RasterImage::GetType(uint16_t *aType)
 {
   NS_ENSURE_ARG_POINTER(aType);
 
   *aType = GetType();
@@ -1197,44 +1203,47 @@ RasterImage::ApplyDecodeFlags(uint32_t a
     ForceDiscard();
   }
 
   mFrameDecodeFlags = aNewFlags & DECODE_FLAGS_MASK;
   return true;
 }
 
 nsresult
-RasterImage::SetSize(int32_t aWidth, int32_t aHeight)
+RasterImage::SetSize(int32_t aWidth, int32_t aHeight, Orientation aOrientation)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mError)
     return NS_ERROR_FAILURE;
 
   // Ensure that we have positive values
   // XXX - Why isn't the size unsigned? Should this be changed?
   if ((aWidth < 0) || (aHeight < 0))
     return NS_ERROR_INVALID_ARG;
 
   // if we already have a size, check the new size against the old one
   if (!mMultipart && mHasSize &&
-      ((aWidth != mSize.width) || (aHeight != mSize.height))) {
+      ((aWidth != mSize.width) ||
+       (aHeight != mSize.height) ||
+       (aOrientation != mOrientation))) {
     NS_WARNING("Image changed size on redecode! This should not happen!");
 
     // Make the decoder aware of the error so that it doesn't try to call
     // FinishInternal during ShutdownDecoder.
     if (mDecoder)
       mDecoder->PostResizeError();
 
     DoError();
     return NS_ERROR_UNEXPECTED;
   }
 
   // Set the size and flag that we have it
   mSize.SizeTo(aWidth, aHeight);
+  mOrientation = aOrientation;
   mHasSize = true;
 
   mFrameBlender.SetSize(mSize);
 
   return NS_OK;
 }
 
 nsresult
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -23,16 +23,17 @@
 #include "imgIContainer.h"
 #include "nsIProperties.h"
 #include "nsITimer.h"
 #include "nsIRequest.h"
 #include "nsTArray.h"
 #include "imgFrame.h"
 #include "nsThreadUtils.h"
 #include "DiscardTracker.h"
+#include "Orientation.h"
 #include "nsISupportsImpl.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/WeakPtr.h"
 #include "mozilla/Mutex.h"
@@ -181,23 +182,21 @@ public:
 
   /* Triggers discarding. */
   void Discard(bool force = false);
   void ForceDiscard() { Discard(/* force = */ true); }
 
   /* Callbacks for decoders */
   nsresult SetFrameAsNonPremult(uint32_t aFrameNum, bool aIsNonPremult);
 
-  /**
-   * Sets the size of the container. This should only be called by the
-   * decoder. This function may be called multiple times, but will throw an
-   * error if subsequent calls do not match the first.
+  /** Sets the size and inherent orientation of the container. This should only
+   * be called by the decoder. This function may be called multiple times, but
+   * will throw an error if subsequent calls do not match the first.
    */
-  nsresult SetSize(int32_t aWidth, int32_t aHeight);
-
+  nsresult SetSize(int32_t aWidth, int32_t aHeight, Orientation aOrientation);
 
   /**
    * Ensures that a given frame number exists with the given parameters, and
    * returns pointers to the data storage for that frame.
    * It is not possible to create sparse frame arrays; you can only append
    * frames to the current frame array.
    */
   nsresult EnsureFrame(uint32_t aFramenum, int32_t aX, int32_t aY,
@@ -578,16 +577,17 @@ private:
   // We would like to just check if we have a zero lock count, but we can't do
   // that for animated images because in EnsureAnimExists we lock the image and
   // never unlock so that animated images always have their lock count >= 1. In
   // that case we use our animation consumers count as a proxy for lock count.
   bool IsUnlocked() { return (mLockCount == 0 || (mAnim && mAnimationConsumers == 0)); }
 
 private: // data
   nsIntSize                  mSize;
+  Orientation                mOrientation;
 
   // Whether our frames were decoded using any special flags.
   // Some flags (e.g. unpremultiplied data) may not be compatible
   // with the browser's needs for displaying the image to the user.
   // As such, we may need to redecode if we're being asked for
   // a frame with different flags.  0 indicates default flags.
   //
   // Valid flag bits are imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -22,16 +22,17 @@
 #include "nsIStreamListener.h"
 #include "nsMimeTypes.h"
 #include "nsPresContext.h"
 #include "nsRect.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStubDocumentObserver.h"
 #include "nsSVGEffects.h" // for nsSVGRenderingObserver
 #include "nsSVGUtils.h"  // for nsSVGUtils::ConvertToSurfaceSize
+#include "Orientation.h"
 #include "SVGDocumentWrapper.h"
 
 namespace mozilla {
 
 using namespace dom;
 using namespace layers;
 
 namespace image {
@@ -535,16 +536,22 @@ VectorImage::GetIntrinsicRatio(nsSize* a
   nsIFrame* rootFrame = mSVGDocumentWrapper->GetRootLayoutFrame();
   if (!rootFrame)
     return NS_ERROR_FAILURE;
 
   *aRatio = rootFrame->GetIntrinsicRatio();
   return NS_OK;
 }
 
+NS_IMETHODIMP_(Orientation)
+VectorImage::GetOrientation()
+{
+  return Orientation();
+}
+
 //******************************************************************************
 /* readonly attribute unsigned short type; */
 NS_IMETHODIMP
 VectorImage::GetType(uint16_t* aType)
 {
   NS_ENSURE_ARG_POINTER(aType);
 
   *aType = GetType();