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