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"
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
25 template <typename
... Configs
>
26 struct FilterPipeline
;
28 template <typename Config
, typename
... Configs
>
29 struct FilterPipeline
<Config
, Configs
...> {
30 typedef typename
Config::template Filter
<
31 typename FilterPipeline
<Configs
...>::Type
>
35 template <typename Config
>
36 struct FilterPipeline
<Config
> {
37 typedef typename
Config::Filter Type
;
43 * Flags for SurfacePipeFactory, used in conjuction with the factory functions
44 * in SurfacePipeFactory to enable or disable various SurfacePipe
47 enum class SurfacePipeFlags
{
48 DEINTERLACE
= 1 << 0, // If set, deinterlace the image.
51 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
{
68 * Creates and initializes a normal (i.e., non-paletted) SurfacePipe.
70 * @param aDecoder The decoder whose current frame the SurfacePipe will write
72 * @param aInputSize The original size of the image.
73 * @param aOutputSize The size the SurfacePipe should output. Must be the same
74 * as @aInputSize or smaller. If smaller, the image will be
75 * downscaled during decoding.
76 * @param aFrameRect The portion of the image that actually contains data.
77 * @param aFormat The surface format of the image; generally B8G8R8A8 or
79 * @param aAnimParams Extra parameters used by animated images.
80 * @param aFlags Flags enabling or disabling various functionality for the
81 * SurfacePipe; see the SurfacePipeFlags documentation for more
84 * @return A SurfacePipe if the parameters allowed one to be created
85 * successfully, or Nothing() if the SurfacePipe could not be
88 static Maybe
<SurfacePipe
> CreateSurfacePipe(
89 Decoder
* aDecoder
, const nsIntSize
& aInputSize
,
90 const nsIntSize
& aOutputSize
, const nsIntRect
& aFrameRect
,
91 gfx::SurfaceFormat aFormat
, const Maybe
<AnimationParams
>& aAnimParams
,
92 qcms_transform
* aTransform
, SurfacePipeFlags aFlags
) {
93 const bool deinterlace
= bool(aFlags
& SurfacePipeFlags::DEINTERLACE
);
94 const bool flipVertically
=
95 bool(aFlags
& SurfacePipeFlags::FLIP_VERTICALLY
);
96 const bool progressiveDisplay
=
97 bool(aFlags
& SurfacePipeFlags::PROGRESSIVE_DISPLAY
);
98 const bool downscale
= aInputSize
!= aOutputSize
;
99 const bool removeFrameRect
= !aFrameRect
.IsEqualEdges(
100 nsIntRect(0, 0, aInputSize
.width
, aInputSize
.height
));
101 const bool blendAnimation
= aAnimParams
.isSome();
102 const bool colorManagement
= aTransform
!= nullptr;
104 // Don't interpolate if we're sure we won't show this surface to the user
105 // until it's completely decoded. The final pass of an ADAM7 image doesn't
106 // need interpolation, so we only need to interpolate if we'll be displaying
107 // the image while it's still being decoded.
108 const bool adam7Interpolate
=
109 bool(aFlags
& SurfacePipeFlags::ADAM7_INTERPOLATE
) &&
112 if (deinterlace
&& adam7Interpolate
) {
113 MOZ_ASSERT_UNREACHABLE("ADAM7 deinterlacing is handled by libpng");
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
123 DeinterlacingConfig
<uint32_t> deinterlacingConfig
{progressiveDisplay
};
124 ADAM7InterpolatingConfig interpolatingConfig
;
125 RemoveFrameRectConfig removeFrameRectConfig
{aFrameRect
};
126 BlendAnimationConfig blendAnimationConfig
{aDecoder
};
127 DownscalingConfig downscalingConfig
{aInputSize
, aFormat
};
128 ColorManagementConfig colorManagementConfig
{aTransform
};
129 SurfaceConfig surfaceConfig
{aDecoder
, aOutputSize
, aFormat
, flipVertically
,
132 Maybe
<SurfacePipe
> pipe
;
134 if (colorManagement
) {
136 MOZ_ASSERT(!blendAnimation
);
137 if (removeFrameRect
) {
139 pipe
= MakePipe(deinterlacingConfig
, removeFrameRectConfig
,
140 downscalingConfig
, colorManagementConfig
,
142 } else if (adam7Interpolate
) {
143 pipe
= MakePipe(interpolatingConfig
, removeFrameRectConfig
,
144 downscalingConfig
, colorManagementConfig
,
146 } else { // (deinterlace and adam7Interpolate are false)
147 pipe
= MakePipe(removeFrameRectConfig
, downscalingConfig
,
148 colorManagementConfig
, surfaceConfig
);
150 } else { // (removeFrameRect is false)
152 pipe
= MakePipe(deinterlacingConfig
, downscalingConfig
,
153 colorManagementConfig
, surfaceConfig
);
154 } else if (adam7Interpolate
) {
155 pipe
= MakePipe(interpolatingConfig
, downscalingConfig
,
156 colorManagementConfig
, surfaceConfig
);
157 } else { // (deinterlace and adam7Interpolate are false)
158 pipe
= MakePipe(downscalingConfig
, colorManagementConfig
,
162 } else { // (downscale is false)
163 if (blendAnimation
) {
165 pipe
= MakePipe(deinterlacingConfig
, colorManagementConfig
,
166 blendAnimationConfig
, surfaceConfig
);
167 } else if (adam7Interpolate
) {
168 pipe
= MakePipe(interpolatingConfig
, colorManagementConfig
,
169 blendAnimationConfig
, surfaceConfig
);
170 } else { // (deinterlace and adam7Interpolate are false)
171 pipe
= MakePipe(colorManagementConfig
, blendAnimationConfig
,
174 } else if (removeFrameRect
) {
176 pipe
= MakePipe(deinterlacingConfig
, colorManagementConfig
,
177 removeFrameRectConfig
, surfaceConfig
);
178 } else if (adam7Interpolate
) {
179 pipe
= MakePipe(interpolatingConfig
, colorManagementConfig
,
180 removeFrameRectConfig
, surfaceConfig
);
181 } else { // (deinterlace and adam7Interpolate are false)
182 pipe
= MakePipe(colorManagementConfig
, removeFrameRectConfig
,
185 } else { // (blendAnimation and removeFrameRect is false)
187 pipe
= MakePipe(deinterlacingConfig
, colorManagementConfig
,
189 } else if (adam7Interpolate
) {
190 pipe
= MakePipe(interpolatingConfig
, colorManagementConfig
,
192 } else { // (deinterlace and adam7Interpolate are false)
193 pipe
= MakePipe(colorManagementConfig
, surfaceConfig
);
197 } else { // (colorManagement is false)
199 MOZ_ASSERT(!blendAnimation
);
200 if (removeFrameRect
) {
202 pipe
= MakePipe(deinterlacingConfig
, removeFrameRectConfig
,
203 downscalingConfig
, surfaceConfig
);
204 } else if (adam7Interpolate
) {
205 pipe
= MakePipe(interpolatingConfig
, removeFrameRectConfig
,
206 downscalingConfig
, surfaceConfig
);
207 } else { // (deinterlace and adam7Interpolate are false)
208 pipe
= MakePipe(removeFrameRectConfig
, downscalingConfig
,
211 } else { // (removeFrameRect is false)
214 MakePipe(deinterlacingConfig
, downscalingConfig
, surfaceConfig
);
215 } else if (adam7Interpolate
) {
217 MakePipe(interpolatingConfig
, downscalingConfig
, surfaceConfig
);
218 } else { // (deinterlace and adam7Interpolate are false)
219 pipe
= MakePipe(downscalingConfig
, surfaceConfig
);
222 } else { // (downscale is false)
223 if (blendAnimation
) {
225 pipe
= MakePipe(deinterlacingConfig
, blendAnimationConfig
,
227 } else if (adam7Interpolate
) {
228 pipe
= MakePipe(interpolatingConfig
, blendAnimationConfig
,
230 } else { // (deinterlace and adam7Interpolate are false)
231 pipe
= MakePipe(blendAnimationConfig
, surfaceConfig
);
233 } else if (removeFrameRect
) {
235 pipe
= MakePipe(deinterlacingConfig
, removeFrameRectConfig
,
237 } else if (adam7Interpolate
) {
238 pipe
= MakePipe(interpolatingConfig
, removeFrameRectConfig
,
240 } else { // (deinterlace and adam7Interpolate are false)
241 pipe
= MakePipe(removeFrameRectConfig
, surfaceConfig
);
243 } else { // (blendAnimation and removeFrameRect is false)
245 pipe
= MakePipe(deinterlacingConfig
, surfaceConfig
);
246 } else if (adam7Interpolate
) {
247 pipe
= MakePipe(interpolatingConfig
, surfaceConfig
);
248 } else { // (deinterlace and adam7Interpolate are false)
249 pipe
= MakePipe(surfaceConfig
);
259 template <typename
... Configs
>
260 static Maybe
<SurfacePipe
> MakePipe(const Configs
&... aConfigs
) {
261 auto pipe
= MakeUnique
<typename
detail::FilterPipeline
<Configs
...>::Type
>();
262 nsresult rv
= pipe
->Configure(aConfigs
...);
267 return Some(SurfacePipe
{std::move(pipe
)});
270 virtual ~SurfacePipeFactory() = 0;
274 } // namespace mozilla
276 #endif // mozilla_image_SurfacePipeFactory_h