SurfacePipeFactory.h 9.9 KB

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