/src/mozilla-central/image/Downscaler.h
Line | Count | Source (jump to first uncovered line) |
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 | | { |
32 | | nsIntRect mOriginalSizeRect; |
33 | | nsIntRect mTargetSizeRect; |
34 | | }; |
35 | | |
36 | | #ifdef MOZ_ENABLE_SKIA |
37 | | |
38 | | /** |
39 | | * Downscaler is a high-quality, streaming image downscaler based upon Skia's |
40 | | * scaling implementation. |
41 | | * |
42 | | * Decoders can construct a Downscaler once they know their target size, then |
43 | | * call BeginFrame() for each frame they decode. They should write a decoded row |
44 | | * into the buffer returned by RowBuffer(), and then call CommitRow() to signal |
45 | | * that they have finished. |
46 | | * |
47 | | |
48 | | * Because invalidations need to be computed in terms of the scaled version of |
49 | | * the image, Downscaler also tracks them. Decoders can call HasInvalidation() |
50 | | * and TakeInvalidRect() instead of tracking invalidations themselves. |
51 | | */ |
52 | | class Downscaler |
53 | | { |
54 | | public: |
55 | | /// Constructs a new Downscaler which to scale to size @aTargetSize. |
56 | | explicit Downscaler(const nsIntSize& aTargetSize); |
57 | | ~Downscaler(); |
58 | | |
59 | 0 | const nsIntSize& OriginalSize() const { return mOriginalSize; } |
60 | 0 | const nsIntSize& TargetSize() const { return mTargetSize; } |
61 | 0 | const nsIntSize FrameSize() const { return nsIntSize(mFrameRect.Width(), mFrameRect.Height()); } |
62 | 0 | 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, |
84 | | bool aHasAlpha, |
85 | | bool aFlipVertically = false); |
86 | | |
87 | 0 | bool IsFrameComplete() const { return mCurrentInLine >= mOriginalSize.height; } |
88 | | |
89 | | /// Retrieves the buffer into which the Decoder should write each row. |
90 | | uint8_t* RowBuffer() |
91 | 0 | { |
92 | 0 | return mRowBuffer.get() + mFrameRect.X() * sizeof(uint32_t); |
93 | 0 | } |
94 | | |
95 | | /// Clears the current row buffer. |
96 | 0 | 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 | | { |
155 | | public: |
156 | | explicit Downscaler(const nsIntSize&) : mScale(1.0, 1.0) |
157 | | { |
158 | | MOZ_RELEASE_ASSERT(false, "Skia is not enabled"); |
159 | | } |
160 | | |
161 | | const nsIntSize& OriginalSize() const { return mSize; } |
162 | | const nsIntSize& TargetSize() const { return mSize; } |
163 | | const gfxSize& Scale() const { return mScale; } |
164 | | |
165 | | nsresult BeginFrame(const nsIntSize&, const Maybe<nsIntRect>&, uint8_t*, bool, bool = false) |
166 | | { |
167 | | return NS_ERROR_FAILURE; |
168 | | } |
169 | | |
170 | | bool IsFrameComplete() const { return false; } |
171 | | uint8_t* RowBuffer() { return nullptr; } |
172 | | void ClearRow() { } |
173 | | void ClearRestOfRow(uint32_t) { } |
174 | | void CommitRow() { } |
175 | | bool HasInvalidation() const { return false; } |
176 | | DownscalerInvalidRect TakeInvalidRect() { return DownscalerInvalidRect(); } |
177 | | void ResetForNextProgressivePass() { } |
178 | | const nsIntSize FrameSize() const { return nsIntSize(0, 0); } |
179 | | private: |
180 | | nsIntSize mSize; |
181 | | gfxSize mScale; |
182 | | }; |
183 | | |
184 | | #endif // MOZ_ENABLE_SKIA |
185 | | |
186 | | |
187 | | |
188 | | } // namespace image |
189 | | } // namespace mozilla |
190 | | |
191 | | #endif // mozilla_image_Downscaler_h |