tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SurfacePipeFactory.h (36050B)


      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/. */
      6 
      7 #ifndef mozilla_image_SurfacePipeFactory_h
      8 #define mozilla_image_SurfacePipeFactory_h
      9 
     10 #include "SurfacePipe.h"
     11 #include "SurfaceFilters.h"
     12 
     13 namespace mozilla {
     14 namespace image {
     15 
     16 namespace detail {
     17 
     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.
     24 */
     25 template <typename... Configs>
     26 struct FilterPipeline;
     27 
     28 template <typename Config, typename... Configs>
     29 struct FilterPipeline<Config, Configs...> {
     30  typedef typename Config::template Filter<
     31      typename FilterPipeline<Configs...>::Type>
     32      Type;
     33 };
     34 
     35 template <typename Config>
     36 struct FilterPipeline<Config> {
     37  typedef typename Config::Filter Type;
     38 };
     39 
     40 }  // namespace detail
     41 
     42 /**
     43 * Flags for SurfacePipeFactory, used in conjunction with the factory functions
     44 * in SurfacePipeFactory to enable or disable various SurfacePipe
     45 * functionality.
     46 */
     47 enum class SurfacePipeFlags {
     48  DEINTERLACE = 1 << 0,  // If set, deinterlace the image.
     49 
     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.
     54 
     55  FLIP_VERTICALLY = 1 << 2,  // If set, flip the image vertically.
     56 
     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.
     62 
     63  PREMULTIPLY_ALPHA = 1 << 4,  // If set, we want to premultiply the alpha
     64                               // channel and the individual color channels.
     65 };
     66 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SurfacePipeFlags)
     67 
     68 class SurfacePipeFactory {
     69 public:
     70  /**
     71   * Creates and initializes a normal (i.e., non-paletted) SurfacePipe.
     72   *
     73   * @param aDecoder The decoder whose current frame the SurfacePipe will write
     74   *                 to.
     75   * @param aInputSize The original size of the image.
     76   * @param aOutputSize The size the SurfacePipe should output. Must be the same
     77   *                    as @aInputSize or smaller. If smaller, the image will be
     78   *                    downscaled during decoding.
     79   * @param aFrameRect The portion of the image that actually contains data.
     80   * @param aInFormat The input surface format of the image.
     81   * @param aOutFormat The output surface format of the image; generally
     82   *                   B8G8R8A8 or B8G8R8X8.
     83   * @param aAnimParams Extra parameters used by animated images.
     84   * @param aFlags Flags enabling or disabling various functionality for the
     85   *               SurfacePipe; see the SurfacePipeFlags documentation for more
     86   *               information.
     87   *
     88   * @return A SurfacePipe if the parameters allowed one to be created
     89   *         successfully, or Nothing() if the SurfacePipe could not be
     90   *         initialized.
     91   */
     92  static Maybe<SurfacePipe> CreateSurfacePipe(
     93      Decoder* aDecoder, const OrientedIntSize& aInputSize,
     94      const OrientedIntSize& aOutputSize, const OrientedIntRect& aFrameRect,
     95      gfx::SurfaceFormat aInFormat, gfx::SurfaceFormat aOutFormat,
     96      const Maybe<AnimationParams>& aAnimParams, qcms_transform* aTransform,
     97      SurfacePipeFlags aFlags) {
     98    const bool deinterlace = bool(aFlags & SurfacePipeFlags::DEINTERLACE);
     99    const bool flipVertically =
    100        bool(aFlags & SurfacePipeFlags::FLIP_VERTICALLY);
    101    const bool progressiveDisplay =
    102        bool(aFlags & SurfacePipeFlags::PROGRESSIVE_DISPLAY);
    103    const bool downscale = aInputSize != aOutputSize;
    104    const bool removeFrameRect = !aFrameRect.IsEqualEdges(
    105        OrientedIntRect(OrientedIntPoint(0, 0), aInputSize));
    106    const bool blendAnimation = aAnimParams.isSome();
    107    const bool colorManagement = aTransform != nullptr;
    108    const bool premultiplyAlpha =
    109        bool(aFlags & SurfacePipeFlags::PREMULTIPLY_ALPHA);
    110 
    111    MOZ_ASSERT(aDecoder->GetOrientation().IsIdentity());
    112 
    113    bool unpackOrMaskSwizzle;
    114    bool swapOrAlphaSwizzle;
    115    if (!GetSwizzleConfigInfo(aInFormat, aOutFormat, premultiplyAlpha,
    116                              unpackOrMaskSwizzle, swapOrAlphaSwizzle)) {
    117      return Nothing();
    118    }
    119 
    120    // Don't interpolate if we're sure we won't show this surface to the user
    121    // until it's completely decoded. The final pass of an ADAM7 image doesn't
    122    // need interpolation, so we only need to interpolate if we'll be displaying
    123    // the image while it's still being decoded.
    124    const bool adam7Interpolate =
    125        bool(aFlags & SurfacePipeFlags::ADAM7_INTERPOLATE) &&
    126        progressiveDisplay;
    127 
    128    if (deinterlace && adam7Interpolate) {
    129      MOZ_ASSERT_UNREACHABLE("ADAM7 deinterlacing is handled by libpng");
    130      return Nothing();
    131    }
    132 
    133    // Construct configurations for the SurfaceFilters. Note that the order of
    134    // these filters is significant. We want to deinterlace or interpolate raw
    135    // input rows, before any other transformations, and we want to remove the
    136    // frame rect (which may involve adding blank rows or columns to the image)
    137    // before any downscaling, so that the new rows and columns are taken into
    138    // account.
    139    DeinterlacingConfig<uint32_t> deinterlacingConfig{progressiveDisplay};
    140    ADAM7InterpolatingConfig interpolatingConfig;
    141    RemoveFrameRectConfig removeFrameRectConfig{aFrameRect.ToUnknownRect()};
    142    BlendAnimationConfig blendAnimationConfig{aDecoder};
    143    DownscalingConfig downscalingConfig{aInputSize.ToUnknownSize(), aOutFormat};
    144    ColorManagementConfig colorManagementConfig{aTransform};
    145    SwizzleConfig swizzleConfig{aInFormat, aOutFormat, premultiplyAlpha};
    146    SurfaceConfig surfaceConfig{aDecoder, aOutputSize.ToUnknownSize(),
    147                                aOutFormat, flipVertically, aAnimParams};
    148 
    149    Maybe<SurfacePipe> pipe;
    150 
    151    if (unpackOrMaskSwizzle) {
    152      if (colorManagement) {
    153        if (downscale) {
    154          MOZ_ASSERT(!blendAnimation);
    155          if (removeFrameRect) {
    156            if (deinterlace) {
    157              pipe = MakePipe(swizzleConfig, deinterlacingConfig,
    158                              removeFrameRectConfig, downscalingConfig,
    159                              colorManagementConfig, surfaceConfig);
    160            } else if (adam7Interpolate) {
    161              pipe = MakePipe(swizzleConfig, interpolatingConfig,
    162                              removeFrameRectConfig, downscalingConfig,
    163                              colorManagementConfig, surfaceConfig);
    164            } else {  // (deinterlace and adam7Interpolate are false)
    165              pipe = MakePipe(swizzleConfig, removeFrameRectConfig,
    166                              downscalingConfig, colorManagementConfig,
    167                              surfaceConfig);
    168            }
    169          } else {  // (removeFrameRect is false)
    170            if (deinterlace) {
    171              pipe = MakePipe(swizzleConfig, deinterlacingConfig,
    172                              downscalingConfig, colorManagementConfig,
    173                              surfaceConfig);
    174            } else if (adam7Interpolate) {
    175              pipe = MakePipe(swizzleConfig, interpolatingConfig,
    176                              downscalingConfig, colorManagementConfig,
    177                              surfaceConfig);
    178            } else {  // (deinterlace and adam7Interpolate are false)
    179              pipe = MakePipe(swizzleConfig, downscalingConfig,
    180                              colorManagementConfig, surfaceConfig);
    181            }
    182          }
    183        } else {  // (downscale is false)
    184          if (blendAnimation) {
    185            if (deinterlace) {
    186              pipe = MakePipe(swizzleConfig, deinterlacingConfig,
    187                              colorManagementConfig, blendAnimationConfig,
    188                              surfaceConfig);
    189            } else if (adam7Interpolate) {
    190              pipe = MakePipe(swizzleConfig, interpolatingConfig,
    191                              colorManagementConfig, blendAnimationConfig,
    192                              surfaceConfig);
    193            } else {  // (deinterlace and adam7Interpolate are false)
    194              pipe = MakePipe(swizzleConfig, colorManagementConfig,
    195                              blendAnimationConfig, surfaceConfig);
    196            }
    197          } else if (removeFrameRect) {
    198            if (deinterlace) {
    199              pipe = MakePipe(swizzleConfig, deinterlacingConfig,
    200                              colorManagementConfig, removeFrameRectConfig,
    201                              surfaceConfig);
    202            } else if (adam7Interpolate) {
    203              pipe = MakePipe(swizzleConfig, interpolatingConfig,
    204                              colorManagementConfig, removeFrameRectConfig,
    205                              surfaceConfig);
    206            } else {  // (deinterlace and adam7Interpolate are false)
    207              pipe = MakePipe(swizzleConfig, colorManagementConfig,
    208                              removeFrameRectConfig, surfaceConfig);
    209            }
    210          } else {  // (blendAnimation and removeFrameRect is false)
    211            if (deinterlace) {
    212              pipe = MakePipe(swizzleConfig, deinterlacingConfig,
    213                              colorManagementConfig, surfaceConfig);
    214            } else if (adam7Interpolate) {
    215              pipe = MakePipe(swizzleConfig, interpolatingConfig,
    216                              colorManagementConfig, surfaceConfig);
    217            } else {  // (deinterlace and adam7Interpolate are false)
    218              pipe =
    219                  MakePipe(swizzleConfig, colorManagementConfig, surfaceConfig);
    220            }
    221          }
    222        }
    223      } else {  // (colorManagement is false)
    224        if (downscale) {
    225          MOZ_ASSERT(!blendAnimation);
    226          if (removeFrameRect) {
    227            if (deinterlace) {
    228              pipe = MakePipe(swizzleConfig, deinterlacingConfig,
    229                              removeFrameRectConfig, downscalingConfig,
    230                              surfaceConfig);
    231            } else if (adam7Interpolate) {
    232              pipe = MakePipe(swizzleConfig, interpolatingConfig,
    233                              removeFrameRectConfig, downscalingConfig,
    234                              surfaceConfig);
    235            } else {  // (deinterlace and adam7Interpolate are false)
    236              pipe = MakePipe(swizzleConfig, removeFrameRectConfig,
    237                              downscalingConfig, surfaceConfig);
    238            }
    239          } else {  // (removeFrameRect is false)
    240            if (deinterlace) {
    241              pipe = MakePipe(swizzleConfig, deinterlacingConfig,
    242                              downscalingConfig, surfaceConfig);
    243            } else if (adam7Interpolate) {
    244              pipe = MakePipe(swizzleConfig, interpolatingConfig,
    245                              downscalingConfig, surfaceConfig);
    246            } else {  // (deinterlace and adam7Interpolate are false)
    247              pipe = MakePipe(swizzleConfig, downscalingConfig, surfaceConfig);
    248            }
    249          }
    250        } else {  // (downscale is false)
    251          if (blendAnimation) {
    252            if (deinterlace) {
    253              pipe = MakePipe(swizzleConfig, deinterlacingConfig,
    254                              blendAnimationConfig, surfaceConfig);
    255            } else if (adam7Interpolate) {
    256              pipe = MakePipe(swizzleConfig, interpolatingConfig,
    257                              blendAnimationConfig, surfaceConfig);
    258            } else {  // (deinterlace and adam7Interpolate are false)
    259              pipe =
    260                  MakePipe(swizzleConfig, blendAnimationConfig, surfaceConfig);
    261            }
    262          } else if (removeFrameRect) {
    263            if (deinterlace) {
    264              pipe = MakePipe(swizzleConfig, deinterlacingConfig,
    265                              removeFrameRectConfig, surfaceConfig);
    266            } else if (adam7Interpolate) {
    267              pipe = MakePipe(swizzleConfig, interpolatingConfig,
    268                              removeFrameRectConfig, surfaceConfig);
    269            } else {  // (deinterlace and adam7Interpolate are false)
    270              pipe =
    271                  MakePipe(swizzleConfig, removeFrameRectConfig, surfaceConfig);
    272            }
    273          } else {  // (blendAnimation and removeFrameRect is false)
    274            if (deinterlace) {
    275              pipe =
    276                  MakePipe(swizzleConfig, deinterlacingConfig, surfaceConfig);
    277            } else if (adam7Interpolate) {
    278              pipe =
    279                  MakePipe(swizzleConfig, interpolatingConfig, surfaceConfig);
    280            } else {  // (deinterlace and adam7Interpolate are false)
    281              pipe = MakePipe(swizzleConfig, surfaceConfig);
    282            }
    283          }
    284        }
    285      }
    286    } else if (swapOrAlphaSwizzle) {
    287      if (colorManagement) {
    288        if (downscale) {
    289          MOZ_ASSERT(!blendAnimation);
    290          if (removeFrameRect) {
    291            if (deinterlace) {
    292              pipe = MakePipe(colorManagementConfig, swizzleConfig,
    293                              deinterlacingConfig, removeFrameRectConfig,
    294                              downscalingConfig, surfaceConfig);
    295            } else if (adam7Interpolate) {
    296              pipe = MakePipe(colorManagementConfig, swizzleConfig,
    297                              interpolatingConfig, removeFrameRectConfig,
    298                              downscalingConfig, surfaceConfig);
    299            } else {  // (deinterlace and adam7Interpolate are false)
    300              pipe = MakePipe(colorManagementConfig, swizzleConfig,
    301                              removeFrameRectConfig, downscalingConfig,
    302                              surfaceConfig);
    303            }
    304          } else {  // (removeFrameRect is false)
    305            if (deinterlace) {
    306              pipe = MakePipe(colorManagementConfig, swizzleConfig,
    307                              deinterlacingConfig, downscalingConfig,
    308                              surfaceConfig);
    309            } else if (adam7Interpolate) {
    310              pipe = MakePipe(colorManagementConfig, swizzleConfig,
    311                              interpolatingConfig, downscalingConfig,
    312                              surfaceConfig);
    313            } else {  // (deinterlace and adam7Interpolate are false)
    314              pipe = MakePipe(colorManagementConfig, swizzleConfig,
    315                              downscalingConfig, surfaceConfig);
    316            }
    317          }
    318        } else {  // (downscale is false)
    319          if (blendAnimation) {
    320            if (deinterlace) {
    321              pipe = MakePipe(colorManagementConfig, swizzleConfig,
    322                              deinterlacingConfig, blendAnimationConfig,
    323                              surfaceConfig);
    324            } else if (adam7Interpolate) {
    325              pipe = MakePipe(colorManagementConfig, swizzleConfig,
    326                              interpolatingConfig, blendAnimationConfig,
    327                              surfaceConfig);
    328            } else {  // (deinterlace and adam7Interpolate are false)
    329              pipe = MakePipe(colorManagementConfig, swizzleConfig,
    330                              blendAnimationConfig, surfaceConfig);
    331            }
    332          } else if (removeFrameRect) {
    333            if (deinterlace) {
    334              pipe = MakePipe(colorManagementConfig, swizzleConfig,
    335                              deinterlacingConfig, removeFrameRectConfig,
    336                              surfaceConfig);
    337            } else if (adam7Interpolate) {
    338              pipe = MakePipe(colorManagementConfig, swizzleConfig,
    339                              interpolatingConfig, removeFrameRectConfig,
    340                              surfaceConfig);
    341            } else {  // (deinterlace and adam7Interpolate are false)
    342              pipe = MakePipe(colorManagementConfig, swizzleConfig,
    343                              removeFrameRectConfig, surfaceConfig);
    344            }
    345          } else {  // (blendAnimation and removeFrameRect is false)
    346            if (deinterlace) {
    347              pipe = MakePipe(colorManagementConfig, swizzleConfig,
    348                              deinterlacingConfig, surfaceConfig);
    349            } else if (adam7Interpolate) {
    350              pipe = MakePipe(colorManagementConfig, swizzleConfig,
    351                              interpolatingConfig, surfaceConfig);
    352            } else {  // (deinterlace and adam7Interpolate are false)
    353              pipe =
    354                  MakePipe(colorManagementConfig, swizzleConfig, surfaceConfig);
    355            }
    356          }
    357        }
    358      } else {  // (colorManagement is false)
    359        if (downscale) {
    360          MOZ_ASSERT(!blendAnimation);
    361          if (removeFrameRect) {
    362            if (deinterlace) {
    363              pipe = MakePipe(swizzleConfig, deinterlacingConfig,
    364                              removeFrameRectConfig, downscalingConfig,
    365                              surfaceConfig);
    366            } else if (adam7Interpolate) {
    367              pipe = MakePipe(swizzleConfig, interpolatingConfig,
    368                              removeFrameRectConfig, downscalingConfig,
    369                              surfaceConfig);
    370            } else {  // (deinterlace and adam7Interpolate are false)
    371              pipe = MakePipe(swizzleConfig, removeFrameRectConfig,
    372                              downscalingConfig, surfaceConfig);
    373            }
    374          } else {  // (removeFrameRect is false)
    375            if (deinterlace) {
    376              pipe = MakePipe(swizzleConfig, deinterlacingConfig,
    377                              downscalingConfig, surfaceConfig);
    378            } else if (adam7Interpolate) {
    379              pipe = MakePipe(swizzleConfig, interpolatingConfig,
    380                              downscalingConfig, surfaceConfig);
    381            } else {  // (deinterlace and adam7Interpolate are false)
    382              pipe = MakePipe(swizzleConfig, downscalingConfig, surfaceConfig);
    383            }
    384          }
    385        } else {  // (downscale is false)
    386          if (blendAnimation) {
    387            if (deinterlace) {
    388              pipe = MakePipe(swizzleConfig, deinterlacingConfig,
    389                              blendAnimationConfig, surfaceConfig);
    390            } else if (adam7Interpolate) {
    391              pipe = MakePipe(swizzleConfig, interpolatingConfig,
    392                              blendAnimationConfig, surfaceConfig);
    393            } else {  // (deinterlace and adam7Interpolate are false)
    394              pipe =
    395                  MakePipe(swizzleConfig, blendAnimationConfig, surfaceConfig);
    396            }
    397          } else if (removeFrameRect) {
    398            if (deinterlace) {
    399              pipe = MakePipe(swizzleConfig, deinterlacingConfig,
    400                              removeFrameRectConfig, surfaceConfig);
    401            } else if (adam7Interpolate) {
    402              pipe = MakePipe(swizzleConfig, interpolatingConfig,
    403                              removeFrameRectConfig, surfaceConfig);
    404            } else {  // (deinterlace and adam7Interpolate are false)
    405              pipe =
    406                  MakePipe(swizzleConfig, removeFrameRectConfig, surfaceConfig);
    407            }
    408          } else {  // (blendAnimation and removeFrameRect is false)
    409            if (deinterlace) {
    410              pipe =
    411                  MakePipe(swizzleConfig, deinterlacingConfig, surfaceConfig);
    412            } else if (adam7Interpolate) {
    413              pipe =
    414                  MakePipe(swizzleConfig, interpolatingConfig, surfaceConfig);
    415            } else {  // (deinterlace and adam7Interpolate are false)
    416              pipe = MakePipe(swizzleConfig, surfaceConfig);
    417            }
    418          }
    419        }
    420      }
    421    } else {  // (unpackOrMaskSwizzle and swapOrAlphaSwizzle are false)
    422      if (colorManagement) {
    423        if (downscale) {
    424          MOZ_ASSERT(!blendAnimation);
    425          if (removeFrameRect) {
    426            if (deinterlace) {
    427              pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
    428                              downscalingConfig, colorManagementConfig,
    429                              surfaceConfig);
    430            } else if (adam7Interpolate) {
    431              pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
    432                              downscalingConfig, colorManagementConfig,
    433                              surfaceConfig);
    434            } else {  // (deinterlace and adam7Interpolate are false)
    435              pipe = MakePipe(removeFrameRectConfig, downscalingConfig,
    436                              colorManagementConfig, surfaceConfig);
    437            }
    438          } else {  // (removeFrameRect is false)
    439            if (deinterlace) {
    440              pipe = MakePipe(deinterlacingConfig, downscalingConfig,
    441                              colorManagementConfig, surfaceConfig);
    442            } else if (adam7Interpolate) {
    443              pipe = MakePipe(interpolatingConfig, downscalingConfig,
    444                              colorManagementConfig, surfaceConfig);
    445            } else {  // (deinterlace and adam7Interpolate are false)
    446              pipe = MakePipe(downscalingConfig, colorManagementConfig,
    447                              surfaceConfig);
    448            }
    449          }
    450        } else {  // (downscale is false)
    451          if (blendAnimation) {
    452            if (deinterlace) {
    453              pipe = MakePipe(deinterlacingConfig, colorManagementConfig,
    454                              blendAnimationConfig, surfaceConfig);
    455            } else if (adam7Interpolate) {
    456              pipe = MakePipe(interpolatingConfig, colorManagementConfig,
    457                              blendAnimationConfig, surfaceConfig);
    458            } else {  // (deinterlace and adam7Interpolate are false)
    459              pipe = MakePipe(colorManagementConfig, blendAnimationConfig,
    460                              surfaceConfig);
    461            }
    462          } else if (removeFrameRect) {
    463            if (deinterlace) {
    464              pipe = MakePipe(deinterlacingConfig, colorManagementConfig,
    465                              removeFrameRectConfig, surfaceConfig);
    466            } else if (adam7Interpolate) {
    467              pipe = MakePipe(interpolatingConfig, colorManagementConfig,
    468                              removeFrameRectConfig, surfaceConfig);
    469            } else {  // (deinterlace and adam7Interpolate are false)
    470              pipe = MakePipe(colorManagementConfig, removeFrameRectConfig,
    471                              surfaceConfig);
    472            }
    473          } else {  // (blendAnimation and removeFrameRect is false)
    474            if (deinterlace) {
    475              pipe = MakePipe(deinterlacingConfig, colorManagementConfig,
    476                              surfaceConfig);
    477            } else if (adam7Interpolate) {
    478              pipe = MakePipe(interpolatingConfig, colorManagementConfig,
    479                              surfaceConfig);
    480            } else {  // (deinterlace and adam7Interpolate are false)
    481              pipe = MakePipe(colorManagementConfig, surfaceConfig);
    482            }
    483          }
    484        }
    485      } else {  // (colorManagement is false)
    486        if (downscale) {
    487          MOZ_ASSERT(!blendAnimation);
    488          if (removeFrameRect) {
    489            if (deinterlace) {
    490              pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
    491                              downscalingConfig, surfaceConfig);
    492            } else if (adam7Interpolate) {
    493              pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
    494                              downscalingConfig, surfaceConfig);
    495            } else {  // (deinterlace and adam7Interpolate are false)
    496              pipe = MakePipe(removeFrameRectConfig, downscalingConfig,
    497                              surfaceConfig);
    498            }
    499          } else {  // (removeFrameRect is false)
    500            if (deinterlace) {
    501              pipe = MakePipe(deinterlacingConfig, downscalingConfig,
    502                              surfaceConfig);
    503            } else if (adam7Interpolate) {
    504              pipe = MakePipe(interpolatingConfig, downscalingConfig,
    505                              surfaceConfig);
    506            } else {  // (deinterlace and adam7Interpolate are false)
    507              pipe = MakePipe(downscalingConfig, surfaceConfig);
    508            }
    509          }
    510        } else {  // (downscale is false)
    511          if (blendAnimation) {
    512            if (deinterlace) {
    513              pipe = MakePipe(deinterlacingConfig, blendAnimationConfig,
    514                              surfaceConfig);
    515            } else if (adam7Interpolate) {
    516              pipe = MakePipe(interpolatingConfig, blendAnimationConfig,
    517                              surfaceConfig);
    518            } else {  // (deinterlace and adam7Interpolate are false)
    519              pipe = MakePipe(blendAnimationConfig, surfaceConfig);
    520            }
    521          } else if (removeFrameRect) {
    522            if (deinterlace) {
    523              pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
    524                              surfaceConfig);
    525            } else if (adam7Interpolate) {
    526              pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
    527                              surfaceConfig);
    528            } else {  // (deinterlace and adam7Interpolate are false)
    529              pipe = MakePipe(removeFrameRectConfig, surfaceConfig);
    530            }
    531          } else {  // (blendAnimation and removeFrameRect is false)
    532            if (deinterlace) {
    533              pipe = MakePipe(deinterlacingConfig, surfaceConfig);
    534            } else if (adam7Interpolate) {
    535              pipe = MakePipe(interpolatingConfig, surfaceConfig);
    536            } else {  // (deinterlace and adam7Interpolate are false)
    537              pipe = MakePipe(surfaceConfig);
    538            }
    539          }
    540        }
    541      }
    542    }
    543 
    544    return pipe;
    545  }
    546 
    547  /**
    548   * Creates and initializes a reorienting SurfacePipe.
    549   *
    550   * @param aDecoder The decoder whose current frame the SurfacePipe will write
    551   *                 to.
    552   * @param aInputSize The original size of the image.
    553   * @param aOutputSize The size the SurfacePipe should output. Must be the same
    554   *                    as @aInputSize or smaller. If smaller, the image will be
    555   *                    downscaled during decoding.
    556   * @param aInFormat The input surface format of the image.
    557   * @param aOutFormat The output surface format of the image; generally
    558   *                   B8G8R8A8 or B8G8R8X8.
    559   * @param aOrientation The orientation of the image.
    560   *
    561   * @param aFlags Note that only PREMULTIPLY_ALPHA is supported by this
    562   * function.
    563   *
    564   * @return A SurfacePipe if the parameters allowed one to be created
    565   *         successfully, or Nothing() if the SurfacePipe could not be
    566   *         initialized.
    567   */
    568  static Maybe<SurfacePipe> CreateReorientSurfacePipe(
    569      Decoder* aDecoder, const OrientedIntSize& aInputSize,
    570      const OrientedIntSize& aOutputSize, gfx::SurfaceFormat aInFormat,
    571      gfx::SurfaceFormat aOutFormat, qcms_transform* aTransform,
    572      const Orientation& aOrientation, SurfacePipeFlags aFlags) {
    573    MOZ_ASSERT(aFlags == SurfacePipeFlags() ||
    574               aFlags == SurfacePipeFlags::PREMULTIPLY_ALPHA);
    575 
    576    const bool downscale = aInputSize != aOutputSize;
    577    const bool colorManagement = aTransform != nullptr;
    578    const bool premultiplyAlpha =
    579        bool(aFlags & SurfacePipeFlags::PREMULTIPLY_ALPHA);
    580 
    581    bool unpackOrMaskSwizzle;
    582    bool swapOrAlphaSwizzle;
    583    if (!GetSwizzleConfigInfo(aInFormat, aOutFormat, premultiplyAlpha,
    584                              unpackOrMaskSwizzle, swapOrAlphaSwizzle)) {
    585      return Nothing();
    586    }
    587 
    588    // Construct configurations for the SurfaceFilters. Note that the order of
    589    // these filters is significant. We want to deinterlace or interpolate raw
    590    // input rows, before any other transformations, and we want to remove the
    591    // frame rect (which may involve adding blank rows or columns to the image)
    592    // before any downscaling, so that the new rows and columns are taken into
    593    // account.
    594    DownscalingConfig downscalingConfig{
    595        aOrientation.ToUnoriented(aInputSize).ToUnknownSize(), aOutFormat};
    596    ColorManagementConfig colorManagementConfig{aTransform};
    597    SurfaceConfig surfaceConfig{aDecoder, aOutputSize.ToUnknownSize(),
    598                                aOutFormat,
    599                                /* mFlipVertically */ false,
    600                                /* mAnimParams */ Nothing()};
    601    SwizzleConfig swizzleConfig{aInFormat, aOutFormat, premultiplyAlpha};
    602    ReorientSurfaceConfig reorientSurfaceConfig{aDecoder, aOutputSize,
    603                                                aOutFormat, aOrientation};
    604 
    605    Maybe<SurfacePipe> pipe;
    606 
    607    if (aOrientation.IsIdentity()) {
    608      if (unpackOrMaskSwizzle) {
    609        if (colorManagement) {
    610          if (downscale) {
    611            pipe = MakePipe(swizzleConfig, downscalingConfig,
    612                            colorManagementConfig, surfaceConfig);
    613          } else {  // (downscale is false)
    614            pipe =
    615                MakePipe(swizzleConfig, colorManagementConfig, surfaceConfig);
    616          }
    617        } else {  // (colorManagement is false)
    618          if (downscale) {
    619            pipe = MakePipe(swizzleConfig, downscalingConfig, surfaceConfig);
    620          } else {  // (downscale is false)
    621            pipe = MakePipe(swizzleConfig, surfaceConfig);
    622          }
    623        }
    624      } else if (swapOrAlphaSwizzle) {
    625        if (colorManagement) {
    626          if (downscale) {
    627            pipe = MakePipe(colorManagementConfig, swizzleConfig,
    628                            downscalingConfig, surfaceConfig);
    629          } else {  // (downscale is false)
    630            pipe =
    631                MakePipe(colorManagementConfig, swizzleConfig, surfaceConfig);
    632          }
    633        } else {  // (colorManagement is false)
    634          if (downscale) {
    635            pipe = MakePipe(swizzleConfig, downscalingConfig, surfaceConfig);
    636          } else {  // (downscale is false)
    637            pipe = MakePipe(swizzleConfig, surfaceConfig);
    638          }
    639        }
    640      } else {  // (unpackOrMaskSwizzle and swapOrAlphaSwizzle are false)
    641        if (colorManagement) {
    642          if (downscale) {
    643            pipe = MakePipe(downscalingConfig, colorManagementConfig,
    644                            surfaceConfig);
    645          } else {  // (downscale is false)
    646            pipe = MakePipe(colorManagementConfig, surfaceConfig);
    647          }
    648        } else {  // (colorManagement is false)
    649          if (downscale) {
    650            pipe = MakePipe(downscalingConfig, surfaceConfig);
    651          } else {  // (downscale is false)
    652            pipe = MakePipe(surfaceConfig);
    653          }
    654        }
    655      }
    656    } else {  // (orientation is not identity)
    657      if (unpackOrMaskSwizzle) {
    658        if (colorManagement) {
    659          if (downscale) {
    660            pipe = MakePipe(swizzleConfig, downscalingConfig,
    661                            colorManagementConfig, reorientSurfaceConfig);
    662          } else {  // (downscale is false)
    663            pipe = MakePipe(swizzleConfig, colorManagementConfig,
    664                            reorientSurfaceConfig);
    665          }
    666        } else {  // (colorManagement is false)
    667          if (downscale) {
    668            pipe = MakePipe(swizzleConfig, downscalingConfig,
    669                            reorientSurfaceConfig);
    670          } else {  // (downscale is false)
    671            pipe = MakePipe(swizzleConfig, reorientSurfaceConfig);
    672          }
    673        }
    674      } else if (swapOrAlphaSwizzle) {
    675        if (colorManagement) {
    676          if (downscale) {
    677            pipe = MakePipe(colorManagementConfig, swizzleConfig,
    678                            downscalingConfig, reorientSurfaceConfig);
    679          } else {  // (downscale is false)
    680            pipe = MakePipe(colorManagementConfig, swizzleConfig,
    681                            reorientSurfaceConfig);
    682          }
    683        } else {  // (colorManagement is false)
    684          if (downscale) {
    685            pipe = MakePipe(swizzleConfig, downscalingConfig,
    686                            reorientSurfaceConfig);
    687          } else {  // (downscale is false)
    688            pipe = MakePipe(swizzleConfig, reorientSurfaceConfig);
    689          }
    690        }
    691      } else {  // (unpackOrMaskSwizzle and swapOrAlphaSwizzle are false)
    692        if (colorManagement) {
    693          if (downscale) {
    694            pipe = MakePipe(downscalingConfig, colorManagementConfig,
    695                            reorientSurfaceConfig);
    696          } else {  // (downscale is false)
    697            pipe = MakePipe(colorManagementConfig, reorientSurfaceConfig);
    698          }
    699        } else {  // (colorManagement is false)
    700          if (downscale) {
    701            pipe = MakePipe(downscalingConfig, reorientSurfaceConfig);
    702          } else {  // (downscale is false)
    703            pipe = MakePipe(reorientSurfaceConfig);
    704          }
    705        }
    706      }
    707    }
    708 
    709    return pipe;
    710  }
    711 
    712 private:
    713  static bool GetSwizzleConfigInfo(const gfx::SurfaceFormat aInFormat,
    714                                   const gfx::SurfaceFormat aOutFormat,
    715                                   const bool aPremultiplyAlpha,
    716                                   bool& aOutUnpackOrMaskSwizzle,
    717                                   bool& aOutSwapOrAlphaSwizzle) {
    718    MOZ_ASSERT(aInFormat == gfx::SurfaceFormat::R8G8B8 ||
    719               aInFormat == gfx::SurfaceFormat::R8G8B8A8 ||
    720               aInFormat == gfx::SurfaceFormat::R8G8B8X8 ||
    721               aInFormat == gfx::SurfaceFormat::OS_RGBA ||
    722               aInFormat == gfx::SurfaceFormat::OS_RGBX);
    723 
    724    MOZ_ASSERT(aOutFormat == gfx::SurfaceFormat::OS_RGBA ||
    725               aOutFormat == gfx::SurfaceFormat::OS_RGBX);
    726 
    727    const bool inFormatRgb = aInFormat == gfx::SurfaceFormat::R8G8B8;
    728 
    729    const bool inFormatOpaque = aInFormat == gfx::SurfaceFormat::OS_RGBX ||
    730                                aInFormat == gfx::SurfaceFormat::R8G8B8X8 ||
    731                                inFormatRgb;
    732    const bool outFormatOpaque = aOutFormat == gfx::SurfaceFormat::OS_RGBX;
    733 
    734    const bool inFormatOrder = aInFormat == gfx::SurfaceFormat::R8G8B8A8 ||
    735                               aInFormat == gfx::SurfaceFormat::R8G8B8X8;
    736    const bool outFormatOrder = aOutFormat == gfx::SurfaceFormat::R8G8B8A8 ||
    737                                aOutFormat == gfx::SurfaceFormat::R8G8B8X8;
    738 
    739    // Early swizzles are for unpacking RGB or forcing RGBA/BGRA_U32 to
    740    // RGBX/BGRX_U32. We should never want to premultiply in either case,
    741    // because the image's alpha channel will always be opaque. This must be
    742    // done before downscaling and color management.
    743    aOutUnpackOrMaskSwizzle =
    744        inFormatRgb ||
    745        (!inFormatOpaque && outFormatOpaque && inFormatOrder == outFormatOrder);
    746 
    747    // Late swizzles are for premultiplying RGBA/BGRA_U32 and/or possible
    748    // converting between RGBA and BGRA_U32. It must happen after color
    749    // management, and before downscaling.
    750    aOutSwapOrAlphaSwizzle =
    751        (!inFormatRgb && inFormatOrder != outFormatOrder) || aPremultiplyAlpha;
    752 
    753    if (aOutUnpackOrMaskSwizzle && aOutSwapOrAlphaSwizzle) {
    754      MOZ_ASSERT_UNREACHABLE("Early and late swizzles not supported");
    755      return false;
    756    }
    757 
    758    if (!aOutUnpackOrMaskSwizzle && !aOutSwapOrAlphaSwizzle &&
    759        aInFormat != aOutFormat) {
    760      MOZ_ASSERT_UNREACHABLE("Need to swizzle, but not configured to");
    761      return false;
    762    }
    763    return true;
    764  }
    765 
    766  template <typename... Configs>
    767  static Maybe<SurfacePipe> MakePipe(const Configs&... aConfigs) {
    768    auto pipe = MakeUnique<typename detail::FilterPipeline<Configs...>::Type>();
    769    nsresult rv = pipe->Configure(aConfigs...);
    770    if (NS_FAILED(rv)) {
    771      return Nothing();
    772    }
    773 
    774    return Some(SurfacePipe{std::move(pipe)});
    775  }
    776 
    777  virtual ~SurfacePipeFactory() = 0;
    778 };
    779 
    780 }  // namespace image
    781 }  // namespace mozilla
    782 
    783 #endif  // mozilla_image_SurfacePipeFactory_h