Bug 1467571 [wpt PR 11385] - Make manifest's parsers quicker, a=testonly
[gecko.git] / image / SurfacePipeFactory.h
blob9fbbff4278fff9b2b13035031671c100ebb72723
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/. */
7 #ifndef mozilla_image_SurfacePipeFactory_h
8 #define mozilla_image_SurfacePipeFactory_h
10 #include "SurfacePipe.h"
11 #include "SurfaceFilters.h"
13 namespace mozilla {
14 namespace image {
16 namespace detail {
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.
25 template <typename... Configs>
26 struct FilterPipeline;
28 template <typename Config, typename... Configs>
29 struct FilterPipeline<Config, Configs...>
31 typedef typename Config::template Filter<typename FilterPipeline<Configs...>::Type> Type;
34 template <typename Config>
35 struct FilterPipeline<Config>
37 typedef typename Config::Filter Type;
40 } // namespace detail
42 /**
43 * Flags for SurfacePipeFactory, used in conjuction with the factory functions
44 * in SurfacePipeFactory to enable or disable various SurfacePipe
45 * functionality.
47 enum class SurfacePipeFlags
49 DEINTERLACE = 1 << 0, // If set, deinterlace the image.
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.
55 FLIP_VERTICALLY = 1 << 2, // If set, flip the image vertically.
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.
63 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SurfacePipeFlags)
65 class SurfacePipeFactory
67 public:
68 /**
69 * Creates and initializes a normal (i.e., non-paletted) SurfacePipe.
71 * @param aDecoder The decoder whose current frame the SurfacePipe will write
72 * to.
73 * @param aInputSize The original size of the image.
74 * @param aOutputSize The size the SurfacePipe should output. Must be the same
75 * as @aInputSize or smaller. If smaller, the image will be
76 * downscaled during decoding.
77 * @param aFrameRect The portion of the image that actually contains data.
78 * @param aFormat The surface format of the image; generally B8G8R8A8 or
79 * B8G8R8X8.
80 * @param aAnimParams Extra parameters used by animated images.
81 * @param aFlags Flags enabling or disabling various functionality for the
82 * SurfacePipe; see the SurfacePipeFlags documentation for more
83 * information.
85 * @return A SurfacePipe if the parameters allowed one to be created
86 * successfully, or Nothing() if the SurfacePipe could not be
87 * initialized.
89 static Maybe<SurfacePipe>
90 CreateSurfacePipe(Decoder* aDecoder,
91 const nsIntSize& aInputSize,
92 const nsIntSize& aOutputSize,
93 const nsIntRect& aFrameRect,
94 gfx::SurfaceFormat aFormat,
95 const Maybe<AnimationParams>& aAnimParams,
96 SurfacePipeFlags aFlags)
98 const bool deinterlace = bool(aFlags & SurfacePipeFlags::DEINTERLACE);
99 const bool flipVertically = bool(aFlags & SurfacePipeFlags::FLIP_VERTICALLY);
100 const bool progressiveDisplay = bool(aFlags & SurfacePipeFlags::PROGRESSIVE_DISPLAY);
101 const bool downscale = aInputSize != aOutputSize;
102 const bool removeFrameRect =
103 !aFrameRect.IsEqualEdges(nsIntRect(0, 0, aInputSize.width, aInputSize.height));
105 // Don't interpolate if we're sure we won't show this surface to the user
106 // until it's completely decoded. The final pass of an ADAM7 image doesn't
107 // need interpolation, so we only need to interpolate if we'll be displaying
108 // the image while it's still being decoded.
109 const bool adam7Interpolate = bool(aFlags & SurfacePipeFlags::ADAM7_INTERPOLATE) &&
110 progressiveDisplay;
112 if (deinterlace && adam7Interpolate) {
113 MOZ_ASSERT_UNREACHABLE("ADAM7 deinterlacing is handled by libpng");
114 return Nothing();
117 // Construct configurations for the SurfaceFilters. Note that the order of
118 // these filters is significant. We want to deinterlace or interpolate raw
119 // input rows, before any other transformations, and we want to remove the
120 // frame rect (which may involve adding blank rows or columns to the image)
121 // before any downscaling, so that the new rows and columns are taken into
122 // account.
123 DeinterlacingConfig<uint32_t> deinterlacingConfig { progressiveDisplay };
124 ADAM7InterpolatingConfig interpolatingConfig;
125 RemoveFrameRectConfig removeFrameRectConfig { aFrameRect };
126 DownscalingConfig downscalingConfig { aInputSize, aFormat };
127 SurfaceConfig surfaceConfig { aDecoder, aOutputSize, aFormat,
128 flipVertically, aAnimParams };
130 Maybe<SurfacePipe> pipe;
132 if (downscale) {
133 if (removeFrameRect) {
134 if (deinterlace) {
135 pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
136 downscalingConfig, surfaceConfig);
137 } else if (adam7Interpolate) {
138 pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
139 downscalingConfig, surfaceConfig);
140 } else { // (deinterlace and adam7Interpolate are false)
141 pipe = MakePipe(removeFrameRectConfig, downscalingConfig, surfaceConfig);
143 } else { // (removeFrameRect is false)
144 if (deinterlace) {
145 pipe = MakePipe(deinterlacingConfig, downscalingConfig, surfaceConfig);
146 } else if (adam7Interpolate) {
147 pipe = MakePipe(interpolatingConfig, downscalingConfig, surfaceConfig);
148 } else { // (deinterlace and adam7Interpolate are false)
149 pipe = MakePipe(downscalingConfig, surfaceConfig);
152 } else { // (downscale is false)
153 if (removeFrameRect) {
154 if (deinterlace) {
155 pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig, surfaceConfig);
156 } else if (adam7Interpolate) {
157 pipe = MakePipe(interpolatingConfig, removeFrameRectConfig, surfaceConfig);
158 } else { // (deinterlace and adam7Interpolate are false)
159 pipe = MakePipe(removeFrameRectConfig, surfaceConfig);
161 } else { // (removeFrameRect is false)
162 if (deinterlace) {
163 pipe = MakePipe(deinterlacingConfig, surfaceConfig);
164 } else if (adam7Interpolate) {
165 pipe = MakePipe(interpolatingConfig, surfaceConfig);
166 } else { // (deinterlace and adam7Interpolate are false)
167 pipe = MakePipe(surfaceConfig);
172 return pipe;
176 * Creates and initializes a paletted SurfacePipe.
178 * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
179 * which means we can remove CreatePalettedSurfacePipe() entirely.
181 * @param aDecoder The decoder whose current frame the SurfacePipe will write
182 * to.
183 * @param aInputSize The original size of the image.
184 * @param aFrameRect The portion of the image that actually contains data.
185 * @param aFormat The surface format of the image; generally B8G8R8A8 or
186 * B8G8R8X8.
187 * @param aPaletteDepth The palette depth of the image.
188 * @param aAnimParams Extra parameters used by animated images.
189 * @param aFlags Flags enabling or disabling various functionality for the
190 * SurfacePipe; see the SurfacePipeFlags documentation for more
191 * information.
193 * @return A SurfacePipe if the parameters allowed one to be created
194 * successfully, or Nothing() if the SurfacePipe could not be
195 * initialized.
197 static Maybe<SurfacePipe>
198 CreatePalettedSurfacePipe(Decoder* aDecoder,
199 const nsIntSize& aInputSize,
200 const nsIntRect& aFrameRect,
201 gfx::SurfaceFormat aFormat,
202 uint8_t aPaletteDepth,
203 const Maybe<AnimationParams>& aAnimParams,
204 SurfacePipeFlags aFlags)
206 const bool deinterlace = bool(aFlags & SurfacePipeFlags::DEINTERLACE);
207 const bool flipVertically = bool(aFlags & SurfacePipeFlags::FLIP_VERTICALLY);
208 const bool progressiveDisplay = bool(aFlags & SurfacePipeFlags::PROGRESSIVE_DISPLAY);
210 // Construct configurations for the SurfaceFilters.
211 DeinterlacingConfig<uint8_t> deinterlacingConfig { progressiveDisplay };
212 PalettedSurfaceConfig palettedSurfaceConfig { aDecoder, aInputSize, aFrameRect,
213 aFormat, aPaletteDepth,
214 flipVertically, aAnimParams };
216 Maybe<SurfacePipe> pipe;
218 if (deinterlace) {
219 pipe = MakePipe(deinterlacingConfig, palettedSurfaceConfig);
220 } else {
221 pipe = MakePipe(palettedSurfaceConfig);
224 return pipe;
227 private:
228 template <typename... Configs>
229 static Maybe<SurfacePipe>
230 MakePipe(const Configs&... aConfigs)
232 auto pipe = MakeUnique<typename detail::FilterPipeline<Configs...>::Type>();
233 nsresult rv = pipe->Configure(aConfigs...);
234 if (NS_FAILED(rv)) {
235 return Nothing();
238 return Some(SurfacePipe { std::move(pipe) } );
241 virtual ~SurfacePipeFactory() = 0;
244 } // namespace image
245 } // namespace mozilla
247 #endif // mozilla_image_SurfacePipeFactory_h