Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 : #ifndef mozilla_image_SurfacePipeFactory_h
8 : #define mozilla_image_SurfacePipeFactory_h
9 :
10 : #include "SurfacePipe.h"
11 : #include "SurfaceFilters.h"
12 :
13 : namespace mozilla {
14 : namespace image {
15 :
16 : namespace detail {
17 :
18 : /**
19 : * FilterPipeline is a helper template for SurfacePipeFactory that determines
20 : * the full type of the sequence of SurfaceFilters that a sequence of
21 : * configuration structs corresponds to. To make this work, all configuration
22 : * structs must include a typedef 'Filter' that identifies the SurfaceFilter
23 : * they configure.
24 : */
25 : template <typename... Configs>
26 : struct FilterPipeline;
27 :
28 : template <typename Config, typename... Configs>
29 : struct FilterPipeline<Config, Configs...>
30 : {
31 : typedef typename Config::template Filter<typename FilterPipeline<Configs...>::Type> Type;
32 : };
33 :
34 : template <typename Config>
35 : struct FilterPipeline<Config>
36 : {
37 : typedef typename Config::Filter Type;
38 : };
39 :
40 : } // namespace detail
41 :
42 : /**
43 : * Flags for SurfacePipeFactory, used in conjuction with the factory functions
44 : * in SurfacePipeFactory to enable or disable various SurfacePipe
45 : * functionality.
46 : */
47 : enum class SurfacePipeFlags
48 : {
49 : DEINTERLACE = 1 << 0, // If set, deinterlace the image.
50 :
51 : ADAM7_INTERPOLATE = 1 << 1, // If set, the caller is deinterlacing the
52 : // image using ADAM7, and we may want to
53 : // interpolate it for better intermediate results.
54 :
55 : FLIP_VERTICALLY = 1 << 2, // If set, flip the image vertically.
56 :
57 : PROGRESSIVE_DISPLAY = 1 << 3 // If set, we expect the image to be displayed
58 : // progressively. This enables features that
59 : // result in a better user experience for
60 : // progressive display but which may be more
61 : // computationally expensive.
62 : };
63 220 : MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SurfacePipeFlags)
64 :
65 : class SurfacePipeFactory
66 : {
67 : public:
68 : /**
69 : * Creates and initializes a normal (i.e., non-paletted) SurfacePipe.
70 : *
71 : * @param aDecoder The decoder whose current frame the SurfacePipe will write
72 : * to.
73 : * @param aFrameNum Which frame the SurfacePipe will write to. This will be 0
74 : * for non-animated images.
75 : * @param aInputSize The original size of the image.
76 : * @param aOutputSize The size the SurfacePipe should output. Must be the same
77 : * as @aInputSize or smaller. If smaller, the image will be
78 : * downscaled during decoding.
79 : * @param aFrameRect The portion of the image that actually contains data.
80 : * @param aFormat The surface format of the image; generally B8G8R8A8 or
81 : * B8G8R8X8.
82 : * @param aFlags Flags enabling or disabling various functionality for the
83 : * SurfacePipe; see the SurfacePipeFlags documentation for more
84 : * information.
85 : *
86 : * @return A SurfacePipe if the parameters allowed one to be created
87 : * successfully, or Nothing() if the SurfacePipe could not be
88 : * initialized.
89 : */
90 : static Maybe<SurfacePipe>
91 48 : CreateSurfacePipe(Decoder* aDecoder,
92 : uint32_t aFrameNum,
93 : const nsIntSize& aInputSize,
94 : const nsIntSize& aOutputSize,
95 : const nsIntRect& aFrameRect,
96 : gfx::SurfaceFormat aFormat,
97 : SurfacePipeFlags aFlags)
98 : {
99 48 : const bool deinterlace = bool(aFlags & SurfacePipeFlags::DEINTERLACE);
100 48 : const bool flipVertically = bool(aFlags & SurfacePipeFlags::FLIP_VERTICALLY);
101 48 : const bool progressiveDisplay = bool(aFlags & SurfacePipeFlags::PROGRESSIVE_DISPLAY);
102 48 : const bool downscale = aInputSize != aOutputSize;
103 : const bool removeFrameRect =
104 48 : !aFrameRect.IsEqualEdges(nsIntRect(0, 0, aInputSize.width, aInputSize.height));
105 :
106 : // Don't interpolate if we're sure we won't show this surface to the user
107 : // until it's completely decoded. The final pass of an ADAM7 image doesn't
108 : // need interpolation, so we only need to interpolate if we'll be displaying
109 : // the image while it's still being decoded.
110 144 : const bool adam7Interpolate = bool(aFlags & SurfacePipeFlags::ADAM7_INTERPOLATE) &&
111 48 : progressiveDisplay;
112 :
113 48 : if (deinterlace && adam7Interpolate) {
114 0 : MOZ_ASSERT_UNREACHABLE("ADAM7 deinterlacing is handled by libpng");
115 : return Nothing();
116 : }
117 :
118 : // Construct configurations for the SurfaceFilters. Note that the order of
119 : // these filters is significant. We want to deinterlace or interpolate raw
120 : // input rows, before any other transformations, and we want to remove the
121 : // frame rect (which may involve adding blank rows or columns to the image)
122 : // before any downscaling, so that the new rows and columns are taken into
123 : // account.
124 48 : DeinterlacingConfig<uint32_t> deinterlacingConfig { progressiveDisplay };
125 : ADAM7InterpolatingConfig interpolatingConfig;
126 48 : RemoveFrameRectConfig removeFrameRectConfig { aFrameRect };
127 48 : DownscalingConfig downscalingConfig { aInputSize, aFormat };
128 : SurfaceConfig surfaceConfig { aDecoder, aFrameNum, aOutputSize,
129 48 : aFormat, flipVertically };
130 :
131 96 : Maybe<SurfacePipe> pipe;
132 :
133 48 : if (downscale) {
134 0 : if (removeFrameRect) {
135 0 : if (deinterlace) {
136 0 : pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
137 0 : downscalingConfig, surfaceConfig);
138 0 : } else if (adam7Interpolate) {
139 0 : pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
140 0 : downscalingConfig, surfaceConfig);
141 : } else { // (deinterlace and adam7Interpolate are false)
142 0 : pipe = MakePipe(removeFrameRectConfig, downscalingConfig, surfaceConfig);
143 : }
144 : } else { // (removeFrameRect is false)
145 0 : if (deinterlace) {
146 0 : pipe = MakePipe(deinterlacingConfig, downscalingConfig, surfaceConfig);
147 0 : } else if (adam7Interpolate) {
148 0 : pipe = MakePipe(interpolatingConfig, downscalingConfig, surfaceConfig);
149 : } else { // (deinterlace and adam7Interpolate are false)
150 0 : pipe = MakePipe(downscalingConfig, surfaceConfig);
151 : }
152 : }
153 : } else { // (downscale is false)
154 48 : if (removeFrameRect) {
155 0 : if (deinterlace) {
156 0 : pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig, surfaceConfig);
157 0 : } else if (adam7Interpolate) {
158 0 : pipe = MakePipe(interpolatingConfig, removeFrameRectConfig, surfaceConfig);
159 : } else { // (deinterlace and adam7Interpolate are false)
160 0 : pipe = MakePipe(removeFrameRectConfig, surfaceConfig);
161 : }
162 : } else { // (removeFrameRect is false)
163 48 : if (deinterlace) {
164 0 : pipe = MakePipe(deinterlacingConfig, surfaceConfig);
165 48 : } else if (adam7Interpolate) {
166 0 : pipe = MakePipe(interpolatingConfig, surfaceConfig);
167 : } else { // (deinterlace and adam7Interpolate are false)
168 48 : pipe = MakePipe(surfaceConfig);
169 : }
170 : }
171 : }
172 :
173 48 : return pipe;
174 : }
175 :
176 : /**
177 : * Creates and initializes a paletted SurfacePipe.
178 : *
179 : * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
180 : * which means we can remove CreatePalettedSurfacePipe() entirely.
181 : *
182 : * @param aDecoder The decoder whose current frame the SurfacePipe will write
183 : * to.
184 : * @param aFrameNum Which frame the SurfacePipe will write to. This will be 0
185 : * for non-animated images.
186 : * @param aInputSize The original size of the image.
187 : * @param aFrameRect The portion of the image that actually contains data.
188 : * @param aFormat The surface format of the image; generally B8G8R8A8 or
189 : * B8G8R8X8.
190 : * @param aPaletteDepth The palette depth of the image.
191 : * @param aFlags Flags enabling or disabling various functionality for the
192 : * SurfacePipe; see the SurfacePipeFlags documentation for more
193 : * information.
194 : *
195 : * @return A SurfacePipe if the parameters allowed one to be created
196 : * successfully, or Nothing() if the SurfacePipe could not be
197 : * initialized.
198 : */
199 : static Maybe<SurfacePipe>
200 0 : CreatePalettedSurfacePipe(Decoder* aDecoder,
201 : uint32_t aFrameNum,
202 : const nsIntSize& aInputSize,
203 : const nsIntRect& aFrameRect,
204 : gfx::SurfaceFormat aFormat,
205 : uint8_t aPaletteDepth,
206 : SurfacePipeFlags aFlags)
207 : {
208 0 : const bool deinterlace = bool(aFlags & SurfacePipeFlags::DEINTERLACE);
209 0 : const bool flipVertically = bool(aFlags & SurfacePipeFlags::FLIP_VERTICALLY);
210 0 : const bool progressiveDisplay = bool(aFlags & SurfacePipeFlags::PROGRESSIVE_DISPLAY);
211 :
212 : // Construct configurations for the SurfaceFilters.
213 0 : DeinterlacingConfig<uint8_t> deinterlacingConfig { progressiveDisplay };
214 : PalettedSurfaceConfig palettedSurfaceConfig { aDecoder, aFrameNum, aInputSize,
215 : aFrameRect, aFormat, aPaletteDepth,
216 0 : flipVertically };
217 :
218 0 : Maybe<SurfacePipe> pipe;
219 :
220 0 : if (deinterlace) {
221 0 : pipe = MakePipe(deinterlacingConfig, palettedSurfaceConfig);
222 : } else {
223 0 : pipe = MakePipe(palettedSurfaceConfig);
224 : }
225 :
226 0 : return pipe;
227 : }
228 :
229 : private:
230 : template <typename... Configs>
231 : static Maybe<SurfacePipe>
232 48 : MakePipe(Configs... aConfigs)
233 : {
234 96 : auto pipe = MakeUnique<typename detail::FilterPipeline<Configs...>::Type>();
235 48 : nsresult rv = pipe->Configure(aConfigs...);
236 48 : if (NS_FAILED(rv)) {
237 0 : return Nothing();
238 : }
239 :
240 48 : return Some(SurfacePipe { Move(pipe) } );
241 : }
242 :
243 : virtual ~SurfacePipeFactory() = 0;
244 : };
245 :
246 : } // namespace image
247 : } // namespace mozilla
248 :
249 : #endif // mozilla_image_SurfacePipeFactory_h
|