Bug 1551001 [wpt PR 16740] - Don't mark disconnected tree-scopes for style update...
[gecko.git] / image / SurfacePipeFactory.h
blob52fc650d8251a956603310b3954060f58770b870
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...> {
30 typedef typename Config::template Filter<
31 typename FilterPipeline<Configs...>::Type>
32 Type;
35 template <typename Config>
36 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 {
48 DEINTERLACE = 1 << 0, // If set, deinterlace the image.
50 ADAM7_INTERPOLATE =
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 {
66 public:
67 /**
68 * Creates and initializes a normal (i.e., non-paletted) SurfacePipe.
70 * @param aDecoder The decoder whose current frame the SurfacePipe will write
71 * to.
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
78 * B8G8R8X8.
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
82 * information.
84 * @return A SurfacePipe if the parameters allowed one to be created
85 * successfully, or Nothing() if the SurfacePipe could not be
86 * initialized.
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) &&
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 BlendAnimationConfig blendAnimationConfig{aDecoder};
127 DownscalingConfig downscalingConfig{aInputSize, aFormat};
128 ColorManagementConfig colorManagementConfig{aTransform};
129 SurfaceConfig surfaceConfig{aDecoder, aOutputSize, aFormat, flipVertically,
130 aAnimParams};
132 Maybe<SurfacePipe> pipe;
134 if (colorManagement) {
135 if (downscale) {
136 MOZ_ASSERT(!blendAnimation);
137 if (removeFrameRect) {
138 if (deinterlace) {
139 pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
140 downscalingConfig, colorManagementConfig,
141 surfaceConfig);
142 } else if (adam7Interpolate) {
143 pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
144 downscalingConfig, colorManagementConfig,
145 surfaceConfig);
146 } else { // (deinterlace and adam7Interpolate are false)
147 pipe = MakePipe(removeFrameRectConfig, downscalingConfig,
148 colorManagementConfig, surfaceConfig);
150 } else { // (removeFrameRect is false)
151 if (deinterlace) {
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,
159 surfaceConfig);
162 } else { // (downscale is false)
163 if (blendAnimation) {
164 if (deinterlace) {
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,
172 surfaceConfig);
174 } else if (removeFrameRect) {
175 if (deinterlace) {
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,
183 surfaceConfig);
185 } else { // (blendAnimation and removeFrameRect is false)
186 if (deinterlace) {
187 pipe = MakePipe(deinterlacingConfig, colorManagementConfig,
188 surfaceConfig);
189 } else if (adam7Interpolate) {
190 pipe = MakePipe(interpolatingConfig, colorManagementConfig,
191 surfaceConfig);
192 } else { // (deinterlace and adam7Interpolate are false)
193 pipe = MakePipe(colorManagementConfig, surfaceConfig);
197 } else { // (colorManagement is false)
198 if (downscale) {
199 MOZ_ASSERT(!blendAnimation);
200 if (removeFrameRect) {
201 if (deinterlace) {
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,
209 surfaceConfig);
211 } else { // (removeFrameRect is false)
212 if (deinterlace) {
213 pipe =
214 MakePipe(deinterlacingConfig, downscalingConfig, surfaceConfig);
215 } else if (adam7Interpolate) {
216 pipe =
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) {
224 if (deinterlace) {
225 pipe = MakePipe(deinterlacingConfig, blendAnimationConfig,
226 surfaceConfig);
227 } else if (adam7Interpolate) {
228 pipe = MakePipe(interpolatingConfig, blendAnimationConfig,
229 surfaceConfig);
230 } else { // (deinterlace and adam7Interpolate are false)
231 pipe = MakePipe(blendAnimationConfig, surfaceConfig);
233 } else if (removeFrameRect) {
234 if (deinterlace) {
235 pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
236 surfaceConfig);
237 } else if (adam7Interpolate) {
238 pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
239 surfaceConfig);
240 } else { // (deinterlace and adam7Interpolate are false)
241 pipe = MakePipe(removeFrameRectConfig, surfaceConfig);
243 } else { // (blendAnimation and removeFrameRect is false)
244 if (deinterlace) {
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);
255 return pipe;
258 private:
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...);
263 if (NS_FAILED(rv)) {
264 return Nothing();
267 return Some(SurfacePipe{std::move(pipe)});
270 virtual ~SurfacePipeFactory() = 0;
273 } // namespace image
274 } // namespace mozilla
276 #endif // mozilla_image_SurfacePipeFactory_h