Downscaler.h 5.8 KB

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