Bug 1062066 (Part 1) - Add support for vertically flipping downscaler output. r=tn
authorSeth Fowler <mark.seth.fowler@gmail.com>
Tue, 08 Sep 2015 22:07:04 -0700
changeset 294081 4e79a95104e873507fd24409c1a4d84e6c2968b9
parent 294080 f088e6dbb1ba6f27e0fb6bd42ba090b464d3a5df
child 294082 f5f8a22450302e242bde358a5d085acfdb5ecaa4
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn
bugs1062066
milestone43.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 1062066 (Part 1) - Add support for vertically flipping downscaler output. r=tn
image/Downscaler.cpp
image/Downscaler.h
--- a/image/Downscaler.cpp
+++ b/image/Downscaler.cpp
@@ -22,16 +22,17 @@ namespace image {
 
 Downscaler::Downscaler(const nsIntSize& aTargetSize)
   : mTargetSize(aTargetSize)
   , mOutputBuffer(nullptr)
   , mXFilter(MakeUnique<skia::ConvolutionFilter1D>())
   , mYFilter(MakeUnique<skia::ConvolutionFilter1D>())
   , mWindowCapacity(0)
   , mHasAlpha(true)
+  , mFlipVertically(false)
 {
   MOZ_ASSERT(gfxPrefs::ImageDownscaleDuringDecodeEnabled(),
              "Downscaling even though downscale-during-decode is disabled?");
   MOZ_ASSERT(mTargetSize.width > 0 && mTargetSize.height > 0,
              "Invalid target size");
 }
 
 Downscaler::~Downscaler()
@@ -52,33 +53,35 @@ Downscaler::ReleaseWindow()
 
   mWindow = nullptr;
   mWindowCapacity = 0;
 }
 
 nsresult
 Downscaler::BeginFrame(const nsIntSize& aOriginalSize,
                        uint8_t* aOutputBuffer,
-                       bool aHasAlpha)
+                       bool aHasAlpha,
+                       bool aFlipVertically /* = false */)
 {
   MOZ_ASSERT(aOutputBuffer);
   MOZ_ASSERT(mTargetSize != aOriginalSize,
              "Created a downscaler, but not downscaling?");
   MOZ_ASSERT(mTargetSize.width <= aOriginalSize.width,
              "Created a downscaler, but width is larger");
   MOZ_ASSERT(mTargetSize.height <= aOriginalSize.height,
              "Created a downscaler, but height is larger");
   MOZ_ASSERT(aOriginalSize.width > 0 && aOriginalSize.height > 0,
              "Invalid original size");
 
   mOriginalSize = aOriginalSize;
   mScale = gfxSize(double(mOriginalSize.width) / mTargetSize.width,
                    double(mOriginalSize.height) / mTargetSize.height);
   mOutputBuffer = aOutputBuffer;
   mHasAlpha = aHasAlpha;
+  mFlipVertically = aFlipVertically;
 
   ResetForNextProgressivePass();
   ReleaseWindow();
 
   auto resizeMethod = skia::ImageOperations::RESIZE_LANCZOS3;
 
   skia::resize::ComputeFilters(resizeMethod,
                                mOriginalSize.width, mTargetSize.width,
@@ -193,19 +196,28 @@ Downscaler::TakeInvalidRect()
 {
   if (MOZ_UNLIKELY(!HasInvalidation())) {
     return DownscalerInvalidRect();
   }
 
   DownscalerInvalidRect invalidRect;
 
   // Compute the target size invalid rect.
-  invalidRect.mTargetSizeRect =
-    nsIntRect(0, mPrevInvalidatedLine,
+  if (mFlipVertically) {
+    // We need to flip it. This will implicitly flip the original size invalid
+    // rect, since we compute it by scaling this rect.
+    invalidRect.mTargetSizeRect =
+      IntRect(0, mTargetSize.height - mCurrentOutLine,
               mTargetSize.width, mCurrentOutLine - mPrevInvalidatedLine);
+  } else {
+    invalidRect.mTargetSizeRect =
+      IntRect(0, mPrevInvalidatedLine,
+              mTargetSize.width, mCurrentOutLine - mPrevInvalidatedLine);
+  }
+
   mPrevInvalidatedLine = mCurrentOutLine;
 
   // Compute the original size invalid rect.
   invalidRect.mOriginalSizeRect = invalidRect.mTargetSizeRect;
   invalidRect.mOriginalSizeRect.ScaleRoundOut(mScale.width, mScale.height);
 
   return invalidRect;
 }
@@ -220,18 +232,23 @@ Downscaler::DownscaleInputLine()
              "Writing past end of output");
 
   int32_t filterOffset = 0;
   int32_t filterLength = 0;
   MOZ_ASSERT(mCurrentOutLine < mYFilter->num_values());
   auto filterValues =
     mYFilter->FilterForValue(mCurrentOutLine, &filterOffset, &filterLength);
 
+  int32_t currentOutLine = mFlipVertically
+                         ? mTargetSize.height - (mCurrentOutLine + 1)
+                         : mCurrentOutLine;
+  MOZ_ASSERT(currentOutLine >= 0);
+
   uint8_t* outputLine =
-    &mOutputBuffer[mCurrentOutLine * mTargetSize.width * sizeof(uint32_t)];
+    &mOutputBuffer[currentOutLine * mTargetSize.width * sizeof(uint32_t)];
   skia::ConvolveVertically(static_cast<const FilterValue*>(filterValues),
                            filterLength, mWindow.get(), mXFilter->num_values(),
                            outputLine, mHasAlpha, supports_sse2());
 
   mCurrentOutLine += 1;
 
   if (mCurrentOutLine == mTargetSize.height) {
     // We're done.
--- a/image/Downscaler.h
+++ b/image/Downscaler.h
@@ -65,20 +65,24 @@ public:
    *
    * @param aOriginalSize The original size of this frame, before scaling.
    * @param aOutputBuffer The buffer to which the Downscaler should write its
    *                      output; this is the same buffer where the Decoder
    *                      would write its output when not downscaling during
    *                      decode.
    * @param aHasAlpha Whether or not this frame has an alpha channel.
    *                  Performance is a little better if it doesn't have one.
+   * @param aFlipVertically If true, output rows will be written to the output
+   *                        buffer in reverse order vertically, which matches
+   *                        the way they are stored in some image formats.
    */
   nsresult BeginFrame(const nsIntSize& aOriginalSize,
                       uint8_t* aOutputBuffer,
-                      bool aHasAlpha);
+                      bool aHasAlpha,
+                      bool aFlipVertically = false);
 
   /// Retrieves the buffer into which the Decoder should write each row.
   uint8_t* RowBuffer() { return mRowBuffer.get(); }
 
   /// Signals that the decoder has finished writing a row into the row buffer.
   void CommitRow();
 
   /// Returns true if there is a non-empty invalid rect available.
@@ -112,17 +116,18 @@ private:
 
   int32_t mWindowCapacity;
 
   int32_t mLinesInBuffer;
   int32_t mPrevInvalidatedLine;
   int32_t mCurrentOutLine;
   int32_t mCurrentInLine;
 
-  bool mHasAlpha;
+  bool mHasAlpha : 1;
+  bool mFlipVertically : 1;
 };
 
 #else
 
 /**
  * Downscaler requires Skia to work, so we provide a dummy implementation if
  * Skia is disabled that asserts if constructed.
  */
@@ -134,17 +139,17 @@ public:
   {
     MOZ_RELEASE_ASSERT(false, "Skia is not enabled");
   }
 
   const nsIntSize& OriginalSize() const { return nsIntSize(); }
   const nsIntSize& TargetSize() const { return nsIntSize(); }
   const gfxSize& Scale() const { return gfxSize(1.0, 1.0); }
 
-  nsresult BeginFrame(const nsIntSize&, uint8_t*, bool)
+  nsresult BeginFrame(const nsIntSize&, uint8_t*, bool, bool = false)
   {
     return NS_ERROR_FAILURE;
   }
 
   uint8_t* RowBuffer() { return nullptr; }
   void CommitRow() { }
   bool HasInvalidation() const { return false; }
   DownscalerInvalidRect TakeInvalidRect() { return DownscalerInvalidRect(); }