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 /** 8 * Downscaler is a high-quality, streaming image downscaler based upon Skia's 9 * scaling implementation. 10 */ 11 12 #ifndef mozilla_image_Downscaler_h 13 #define mozilla_image_Downscaler_h 14 15 #include "mozilla/Maybe.h" 16 #include "mozilla/UniquePtr.h" 17 #include "gfxPoint.h" 18 #include "nsRect.h" 19 #ifdef MOZ_ENABLE_SKIA 20 #include "mozilla/gfx/ConvolutionFilter.h" 21 #endif 22 23 namespace mozilla { 24 namespace image { 25 26 /** 27 * DownscalerInvalidRect wraps two invalidation rects: one in terms of the 28 * original image size, and one in terms of the target size. 29 */ 30 struct DownscalerInvalidRect { 31 nsIntRect mOriginalSizeRect; 32 nsIntRect mTargetSizeRect; 33 }; 34 35 #ifdef MOZ_ENABLE_SKIA 36 37 /** 38 * Downscaler is a high-quality, streaming image downscaler based upon Skia's 39 * scaling implementation. 40 * 41 * Decoders can construct a Downscaler once they know their target size, then 42 * call BeginFrame() for each frame they decode. They should write a decoded row 43 * into the buffer returned by RowBuffer(), and then call CommitRow() to signal 44 * that they have finished. 45 * 46 47 * Because invalidations need to be computed in terms of the scaled version of 48 * the image, Downscaler also tracks them. Decoders can call HasInvalidation() 49 * and TakeInvalidRect() instead of tracking invalidations themselves. 50 */ 51 class Downscaler { 52 public: 53 /// Constructs a new Downscaler which to scale to size @aTargetSize. 54 explicit Downscaler(const nsIntSize& aTargetSize); 55 ~Downscaler(); 56 OriginalSize()57 const nsIntSize& OriginalSize() const { return mOriginalSize; } TargetSize()58 const nsIntSize& TargetSize() const { return mTargetSize; } FrameSize()59 const nsIntSize FrameSize() const { 60 return nsIntSize(mFrameRect.Width(), mFrameRect.Height()); 61 } Scale()62 const gfxSize& Scale() const { return mScale; } 63 64 /** 65 * Begins a new frame and reinitializes the Downscaler. 66 * 67 * @param aOriginalSize The original size of this frame, before scaling. 68 * @param aFrameRect The region of the original image which has data. 69 * Every pixel outside @aFrameRect is considered blank and 70 * has zero alpha. 71 * @param aOutputBuffer The buffer to which the Downscaler should write its 72 * output; this is the same buffer where the Decoder 73 * would write its output when not downscaling during 74 * decode. 75 * @param aHasAlpha Whether or not this frame has an alpha channel. 76 * Performance is a little better if it doesn't have one. 77 * @param aFlipVertically If true, output rows will be written to the output 78 * buffer in reverse order vertically, which matches 79 * the way they are stored in some image formats. 80 */ 81 nsresult BeginFrame(const nsIntSize& aOriginalSize, 82 const Maybe<nsIntRect>& aFrameRect, 83 uint8_t* aOutputBuffer, bool aHasAlpha, 84 bool aFlipVertically = false); 85 IsFrameComplete()86 bool IsFrameComplete() const { 87 return mCurrentInLine >= mOriginalSize.height; 88 } 89 90 /// Retrieves the buffer into which the Decoder should write each row. RowBuffer()91 uint8_t* RowBuffer() { 92 return mRowBuffer.get() + mFrameRect.X() * sizeof(uint32_t); 93 } 94 95 /// Clears the current row buffer. ClearRow()96 void ClearRow() { ClearRestOfRow(0); } 97 98 /// Clears the current row buffer starting at @aStartingAtCol. 99 void ClearRestOfRow(uint32_t aStartingAtCol); 100 101 /// Signals that the decoder has finished writing a row into the row buffer. 102 void CommitRow(); 103 104 /// Returns true if there is a non-empty invalid rect available. 105 bool HasInvalidation() const; 106 107 /// Takes the Downscaler's current invalid rect and resets it. 108 DownscalerInvalidRect TakeInvalidRect(); 109 110 /** 111 * Resets the Downscaler's position in the image, for a new progressive pass 112 * over the same frame. Because the same data structures can be reused, this 113 * is more efficient than calling BeginFrame. 114 */ 115 void ResetForNextProgressivePass(); 116 117 private: 118 void DownscaleInputLine(); 119 void ReleaseWindow(); 120 void SkipToRow(int32_t aRow); 121 122 nsIntSize mOriginalSize; 123 nsIntSize mTargetSize; 124 nsIntRect mFrameRect; 125 gfxSize mScale; 126 127 uint8_t* mOutputBuffer; 128 129 UniquePtr<uint8_t[]> mRowBuffer; 130 UniquePtr<uint8_t* []> mWindow; 131 132 gfx::ConvolutionFilter mXFilter; 133 gfx::ConvolutionFilter mYFilter; 134 135 int32_t mWindowCapacity; 136 137 int32_t mLinesInBuffer; 138 int32_t mPrevInvalidatedLine; 139 int32_t mCurrentOutLine; 140 int32_t mCurrentInLine; 141 142 bool mHasAlpha : 1; 143 bool mFlipVertically : 1; 144 }; 145 146 #else 147 148 /** 149 * Downscaler requires Skia to work, so we provide a dummy implementation if 150 * Skia is disabled that asserts if constructed. 151 */ 152 153 class Downscaler { 154 public: Downscaler(const nsIntSize &)155 explicit Downscaler(const nsIntSize&) : mScale(1.0, 1.0) { 156 MOZ_RELEASE_ASSERT(false, "Skia is not enabled"); 157 } 158 OriginalSize()159 const nsIntSize& OriginalSize() const { return mSize; } TargetSize()160 const nsIntSize& TargetSize() const { return mSize; } Scale()161 const gfxSize& Scale() const { return mScale; } 162 163 nsresult BeginFrame(const nsIntSize&, const Maybe<nsIntRect>&, uint8_t*, bool, 164 bool = false) { 165 return NS_ERROR_FAILURE; 166 } 167 IsFrameComplete()168 bool IsFrameComplete() const { return false; } RowBuffer()169 uint8_t* RowBuffer() { return nullptr; } ClearRow()170 void ClearRow() {} ClearRestOfRow(uint32_t)171 void ClearRestOfRow(uint32_t) {} CommitRow()172 void CommitRow() {} HasInvalidation()173 bool HasInvalidation() const { return false; } TakeInvalidRect()174 DownscalerInvalidRect TakeInvalidRect() { return DownscalerInvalidRect(); } ResetForNextProgressivePass()175 void ResetForNextProgressivePass() {} FrameSize()176 const nsIntSize FrameSize() const { return nsIntSize(0, 0); } 177 178 private: 179 nsIntSize mSize; 180 gfxSize mScale; 181 }; 182 183 #endif // MOZ_ENABLE_SKIA 184 185 } // namespace image 186 } // namespace mozilla 187 188 #endif // mozilla_image_Downscaler_h 189