summaryrefslogtreecommitdiff
path: root/image/src/Downscaler.h
blob: 13d54948e8224fca60c85132b076460e646fdcf1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/* -*- 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/. */

/**
 * Downscaler is a high-quality, streaming image downscaler based upon Skia's
 * scaling implementation.
 */

#ifndef MOZILLA_IMAGELIB_DOWNSCALER_H_
#define MOZILLA_IMAGELIB_DOWNSCALER_H_

#include "mozilla/UniquePtr.h"
#include "nsRect.h"

#ifdef MOZ_ENABLE_SKIA

namespace skia {
  class ConvolutionFilter1D;
} // namespace skia

namespace mozilla {
namespace image {

/**
 * Downscaler is a high-quality, streaming image downscaler based upon Skia's
 * scaling implementation.
 *
 * Decoders can construct a Downscaler once they know their target size, then
 * call BeginFrame() for each frame they decode. They should write a decoded row
 * into the buffer returned by RowBuffer(), and then call CommitRow() to signal
 * that they have finished.
 *

 * Because invalidations need to be computed in terms of the scaled version of
 * the image, Downscaler also tracks them. Decoders can call HasInvalidation()
 * and TakeInvalidRect() instead of tracking invalidations themselves.
 */
class Downscaler
{
public:
  /// Constructs a new Downscaler which to scale to size @aTargetSize.
  explicit Downscaler(const nsIntSize& aTargetSize);
  ~Downscaler();

  const nsIntSize& OriginalSize() const { return mOriginalSize; }
  const nsIntSize& TargetSize() const { return mTargetSize; }

  /**
   * Begins a new frame and reinitializes the Downscaler.
   *
   * @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.
   */
  nsresult BeginFrame(const nsIntSize& aOriginalSize,
                      uint8_t* aOutputBuffer,
                      bool aHasAlpha);

  /// 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.
  bool HasInvalidation() const;

  /// Takes the Downscaler's current invalid rect and resets it.
  nsIntRect TakeInvalidRect();

  /**
   * Resets the Downscaler's position in the image, for a new progressive pass
   * over the same frame. Because the same data structures can be reused, this
   * is more efficient than calling BeginFrame.
   */
  void ResetForNextProgressivePass();

private:
  void DownscaleInputLine();
  void ReleaseWindow();

  nsIntSize mOriginalSize;
  nsIntSize mTargetSize;

  uint8_t* mOutputBuffer;

  UniquePtr<uint8_t[]> mRowBuffer;
  UniquePtr<uint8_t*[]> mWindow;

  UniquePtr<skia::ConvolutionFilter1D> mXFilter;
  UniquePtr<skia::ConvolutionFilter1D> mYFilter;

  int32_t mWindowCapacity;

  int32_t mLinesInBuffer;
  int32_t mPrevInvalidatedLine;
  int32_t mCurrentOutLine;
  int32_t mCurrentInLine;

  bool mHasAlpha;
};

} // namespace image
} // namespace mozilla


#else


/**
 * Downscaler requires Skia to work, so we provide a dummy implementation if
 * Skia is disabled that asserts if constructed.
 */

namespace mozilla {
namespace image {

class Downscaler
{
public:
  explicit Downscaler(const nsIntSize&)
  {
    MOZ_RELEASE_ASSERT(false, "Skia is not enabled");
  }

  const nsIntSize& OriginalSize() const { return nsIntSize(); }
  const nsIntSize& TargetSize() const { return nsIntSize(); }

  nsresult BeginFrame(const nsIntSize&, uint8_t*, bool)
  {
    return NS_ERROR_FAILURE;
  }

  uint8_t* RowBuffer() { return nullptr; }
  void CommitRow() { }
  bool HasInvalidation() const { return false; }
  nsIntRect TakeInvalidRect() { return nsIntRect(); }
  void ResetForNextProgressivePass() { }
};


} // namespace image
} // namespace mozilla

#endif

#endif // MOZILLA_IMAGELIB_DOWNSCALER_H_