/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_image_SurfacePipeFactory_h #define mozilla_image_SurfacePipeFactory_h #include "SurfacePipe.h" #include "SurfaceFilters.h" namespace mozilla { namespace image { namespace detail { /** * FilterPipeline is a helper template for SurfacePipeFactory that determines * the full type of the sequence of SurfaceFilters that a sequence of * configuration structs corresponds to. To make this work, all configuration * structs must include a typedef 'Filter' that identifies the SurfaceFilter * they configure. */ template struct FilterPipeline; template struct FilterPipeline { typedef typename Config::template Filter::Type> Type; }; template struct FilterPipeline { typedef typename Config::Filter Type; }; } // namespace detail /** * Flags for SurfacePipeFactory, used in conjuction with the factory functions * in SurfacePipeFactory to enable or disable various SurfacePipe * functionality. */ enum class SurfacePipeFlags { DEINTERLACE = 1 << 0, // If set, deinterlace the image. FLIP_VERTICALLY = 1 << 1, // If set, flip the image vertically. PROGRESSIVE_DISPLAY = 1 << 2 // If set, we expect the image to be displayed // progressively. This enables features that // result in a better user experience for // progressive display but which may be more // computationally expensive. }; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SurfacePipeFlags) class SurfacePipeFactory { public: /** * Creates and initializes a normal (i.e., non-paletted) SurfacePipe. * * @param aDecoder The decoder whose current frame the SurfacePipe will write * to. * @param aFrameNum Which frame the SurfacePipe will write to. This will be 0 * for non-animated images. * @param aInputSize The original size of the image. * @param aOutputSize The size the SurfacePipe should output. Must be the same * as @aInputSize or smaller. If smaller, the image will be * downscaled during decoding. * @param aFrameRect The portion of the image that actually contains data. * @param aFormat The surface format of the image; generally B8G8R8A8 or * B8G8R8X8. * @param aFlags Flags enabling or disabling various functionality for the * SurfacePipe; see the SurfacePipeFlags documentation for more * information. * * @return A SurfacePipe if the parameters allowed one to be created * successfully, or Nothing() if the SurfacePipe could not be * initialized. */ static Maybe CreateSurfacePipe(Decoder* aDecoder, uint32_t aFrameNum, const nsIntSize& aInputSize, const nsIntSize& aOutputSize, const nsIntRect& aFrameRect, gfx::SurfaceFormat aFormat, SurfacePipeFlags aFlags) { const bool deinterlace = bool(aFlags & SurfacePipeFlags::DEINTERLACE); const bool flipVertically = bool(aFlags & SurfacePipeFlags::FLIP_VERTICALLY); const bool progressiveDisplay = bool(aFlags & SurfacePipeFlags::PROGRESSIVE_DISPLAY); const bool downscale = aInputSize != aOutputSize; const bool removeFrameRect = !aFrameRect.IsEqualEdges(nsIntRect(0, 0, aInputSize.width, aInputSize.height)); // Construct configurations for the SurfaceFilters. Note that the order of // these filters is significant. We want to deinterlace raw input rows, // before any other transformations, and we want to remove the frame rect // (which may involve adding blank rows or columns to the image) before any // downscaling, so that the new rows and columns are taken into account. DeinterlacingConfig deinterlacingConfig { progressiveDisplay }; RemoveFrameRectConfig removeFrameRectConfig { aFrameRect }; DownscalingConfig downscalingConfig { aInputSize, aFormat }; SurfaceConfig surfaceConfig { aDecoder, aFrameNum, aOutputSize, aFormat, flipVertically }; Maybe pipe; if (downscale) { if (removeFrameRect) { if (deinterlace) { pipe = MakePipe(aFrameRect.Size(), deinterlacingConfig, removeFrameRectConfig, downscalingConfig, surfaceConfig); } else { // (deinterlace is false) pipe = MakePipe(aFrameRect.Size(), removeFrameRectConfig, downscalingConfig, surfaceConfig); } } else { // (removeFrameRect is false) if (deinterlace) { pipe = MakePipe(aInputSize, deinterlacingConfig, downscalingConfig, surfaceConfig); } else { // (deinterlace is false) pipe = MakePipe(aInputSize, downscalingConfig, surfaceConfig); } } } else { // (downscale is false) if (removeFrameRect) { if (deinterlace) { pipe = MakePipe(aFrameRect.Size(), deinterlacingConfig, removeFrameRectConfig, surfaceConfig); } else { // (deinterlace is false) pipe = MakePipe(aFrameRect.Size(), removeFrameRectConfig, surfaceConfig); } } else { // (removeFrameRect is false) if (deinterlace) { pipe = MakePipe(aInputSize, deinterlacingConfig, surfaceConfig); } else { // (deinterlace is false) pipe = MakePipe(aInputSize, surfaceConfig); } } } return pipe; } /** * Creates and initializes a paletted SurfacePipe. * * XXX(seth): We'll remove all support for paletted surfaces in bug 1247520, * which means we can remove CreatePalettedSurfacePipe() entirely. * * @param aDecoder The decoder whose current frame the SurfacePipe will write * to. * @param aFrameNum Which frame the SurfacePipe will write to. This will be 0 * for non-animated images. * @param aInputSize The original size of the image. * @param aFrameRect The portion of the image that actually contains data. * @param aFormat The surface format of the image; generally B8G8R8A8 or * B8G8R8X8. * @param aPaletteDepth The palette depth of the image. * @param aFlags Flags enabling or disabling various functionality for the * SurfacePipe; see the SurfacePipeFlags documentation for more * information. * * @return A SurfacePipe if the parameters allowed one to be created * successfully, or Nothing() if the SurfacePipe could not be * initialized. */ static Maybe CreatePalettedSurfacePipe(Decoder* aDecoder, uint32_t aFrameNum, const nsIntSize& aInputSize, const nsIntRect& aFrameRect, gfx::SurfaceFormat aFormat, uint8_t aPaletteDepth, SurfacePipeFlags aFlags) { const bool deinterlace = bool(aFlags & SurfacePipeFlags::DEINTERLACE); const bool flipVertically = bool(aFlags & SurfacePipeFlags::FLIP_VERTICALLY); const bool progressiveDisplay = bool(aFlags & SurfacePipeFlags::PROGRESSIVE_DISPLAY); // Construct configurations for the SurfaceFilters. DeinterlacingConfig deinterlacingConfig { progressiveDisplay }; PalettedSurfaceConfig palettedSurfaceConfig { aDecoder, aFrameNum, aInputSize, aFrameRect, aFormat, aPaletteDepth, flipVertically }; Maybe pipe; if (deinterlace) { pipe = MakePipe(aFrameRect.Size(), deinterlacingConfig, palettedSurfaceConfig); } else { pipe = MakePipe(aFrameRect.Size(), palettedSurfaceConfig); } return pipe; } private: template static Maybe MakePipe(const nsIntSize& aInputSize, Configs... aConfigs) { auto pipe = MakeUnique::Type>(); nsresult rv = pipe->Configure(aConfigs...); if (NS_FAILED(rv)) { return Nothing(); } return Some(SurfacePipe { Move(pipe) } ); } virtual ~SurfacePipeFactory() = 0; }; } // namespace image } // namespace mozilla #endif // mozilla_image_SurfacePipeFactory_h