зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1551088 - Part 6. Make image decoders use accelerated methods for swizzling and premultiplication. r=tnikkel
The PNG decoder lacks fast implementations for swizzling/unpacking inside the library, and both PNG and WebP may need to perform premultiplication due to the alpha channel. This patch adds a new filter allowing us to take advantage of our accelerated implementations to perform these transformations on their behalf. Differential Revision: https://phabricator.services.mozilla.com/D46449 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
7b2fde0d05
Коммит
e9dc497c47
|
@ -20,6 +20,7 @@
|
|||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/Swizzle.h"
|
||||
#include "skia/src/core/SkBlitRow.h"
|
||||
|
||||
#include "DownscalingFilter.h"
|
||||
|
@ -29,6 +30,83 @@
|
|||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// SwizzleFilter
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Next>
|
||||
class SwizzleFilter;
|
||||
|
||||
/**
|
||||
* A configuration struct for SwizzleFilter.
|
||||
*/
|
||||
struct SwizzleConfig {
|
||||
template <typename Next>
|
||||
using Filter = SwizzleFilter<Next>;
|
||||
gfx::SurfaceFormat mInFormat;
|
||||
gfx::SurfaceFormat mOutFormat;
|
||||
bool mPremultiplyAlpha;
|
||||
};
|
||||
|
||||
/**
|
||||
* SwizzleFilter performs premultiplication, swizzling and unpacking on
|
||||
* rows written to it. It can use accelerated methods to perform these
|
||||
* operations if supported on the platform.
|
||||
*
|
||||
* The 'Next' template parameter specifies the next filter in the chain.
|
||||
*/
|
||||
template <typename Next>
|
||||
class SwizzleFilter final : public SurfaceFilter {
|
||||
public:
|
||||
SwizzleFilter() : mSwizzleFn(nullptr) {}
|
||||
|
||||
template <typename... Rest>
|
||||
nsresult Configure(const SwizzleConfig& aConfig, const Rest&... aRest) {
|
||||
nsresult rv = mNext.Configure(aRest...);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (aConfig.mPremultiplyAlpha) {
|
||||
mSwizzleFn = gfx::PremultiplyRow(aConfig.mInFormat, aConfig.mOutFormat);
|
||||
} else {
|
||||
mSwizzleFn = gfx::SwizzleRow(aConfig.mInFormat, aConfig.mOutFormat);
|
||||
}
|
||||
|
||||
if (!mSwizzleFn) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ConfigureFilter(mNext.InputSize(), sizeof(uint32_t));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Maybe<SurfaceInvalidRect> TakeInvalidRect() override {
|
||||
return mNext.TakeInvalidRect();
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t* DoResetToFirstRow() override { return mNext.ResetToFirstRow(); }
|
||||
|
||||
uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override {
|
||||
uint8_t* rowPtr = mNext.CurrentRowPointer();
|
||||
if (!rowPtr) {
|
||||
return nullptr; // We already got all the input rows we expect.
|
||||
}
|
||||
|
||||
mSwizzleFn(aInputRow, rowPtr, mNext.InputSize().width);
|
||||
return mNext.AdvanceRow();
|
||||
}
|
||||
|
||||
uint8_t* DoAdvanceRow() override {
|
||||
return DoAdvanceRowFromBuffer(mNext.CurrentRowPointer());
|
||||
}
|
||||
|
||||
Next mNext; /// The next SurfaceFilter in the chain.
|
||||
|
||||
gfx::SwizzleRowFn mSwizzleFn;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// ColorManagementFilter
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -59,6 +59,9 @@ enum class SurfacePipeFlags {
|
|||
// result in a better user experience for
|
||||
// progressive display but which may be more
|
||||
// computationally expensive.
|
||||
|
||||
PREMULTIPLY_ALPHA = 1 << 4, // If set, we want to premultiply the alpha
|
||||
// channel and the individual color channels.
|
||||
};
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SurfacePipeFlags)
|
||||
|
||||
|
@ -88,8 +91,9 @@ class SurfacePipeFactory {
|
|||
static Maybe<SurfacePipe> CreateSurfacePipe(
|
||||
Decoder* aDecoder, const nsIntSize& aInputSize,
|
||||
const nsIntSize& aOutputSize, const nsIntRect& aFrameRect,
|
||||
gfx::SurfaceFormat aFormat, const Maybe<AnimationParams>& aAnimParams,
|
||||
qcms_transform* aTransform, SurfacePipeFlags aFlags) {
|
||||
gfx::SurfaceFormat aInFormat, gfx::SurfaceFormat aOutFormat,
|
||||
const Maybe<AnimationParams>& aAnimParams, qcms_transform* aTransform,
|
||||
SurfacePipeFlags aFlags) {
|
||||
const bool deinterlace = bool(aFlags & SurfacePipeFlags::DEINTERLACE);
|
||||
const bool flipVertically =
|
||||
bool(aFlags & SurfacePipeFlags::FLIP_VERTICALLY);
|
||||
|
@ -100,6 +104,49 @@ class SurfacePipeFactory {
|
|||
nsIntRect(0, 0, aInputSize.width, aInputSize.height));
|
||||
const bool blendAnimation = aAnimParams.isSome();
|
||||
const bool colorManagement = aTransform != nullptr;
|
||||
const bool premultiplyAlpha =
|
||||
bool(aFlags & SurfacePipeFlags::PREMULTIPLY_ALPHA);
|
||||
|
||||
// Early swizzles are for unpacking RGB or forcing RGBA/BGRA to RGBX/BGRX.
|
||||
// We should never want to premultiply in either case, because the image's
|
||||
// alpha channel will always be opaque. This must be done before downscaling
|
||||
// and color management.
|
||||
bool unpackOrMaskSwizzle = aInFormat == gfx::SurfaceFormat::R8G8B8 ||
|
||||
((aInFormat == gfx::SurfaceFormat::R8G8B8A8 &&
|
||||
aOutFormat == gfx::SurfaceFormat::R8G8B8X8) ||
|
||||
(aInFormat == gfx::SurfaceFormat::B8G8R8A8 &&
|
||||
aOutFormat == gfx::SurfaceFormat::B8G8R8X8));
|
||||
|
||||
// Late swizzles are for premultiplying RGBA/BGRA and/or possible converting
|
||||
// between RGBA and BGRA. It must happen after color management, and before
|
||||
// downscaling.
|
||||
bool swapOrAlphaSwizzle = ((aInFormat == gfx::SurfaceFormat::R8G8B8A8 &&
|
||||
aOutFormat == gfx::SurfaceFormat::B8G8R8A8) ||
|
||||
(aInFormat == gfx::SurfaceFormat::B8G8R8A8 &&
|
||||
aOutFormat == gfx::SurfaceFormat::R8G8B8A8)) ||
|
||||
premultiplyAlpha;
|
||||
|
||||
MOZ_ASSERT(aInFormat == gfx::SurfaceFormat::R8G8B8 ||
|
||||
aInFormat == gfx::SurfaceFormat::R8G8B8A8 ||
|
||||
aInFormat == gfx::SurfaceFormat::R8G8B8X8 ||
|
||||
aInFormat == gfx::SurfaceFormat::B8G8R8A8 ||
|
||||
aInFormat == gfx::SurfaceFormat::B8G8R8X8);
|
||||
|
||||
MOZ_ASSERT(aOutFormat == gfx::SurfaceFormat::R8G8B8A8 ||
|
||||
aOutFormat == gfx::SurfaceFormat::R8G8B8X8 ||
|
||||
aOutFormat == gfx::SurfaceFormat::B8G8R8A8 ||
|
||||
aOutFormat == gfx::SurfaceFormat::B8G8R8X8);
|
||||
|
||||
if (unpackOrMaskSwizzle && swapOrAlphaSwizzle) {
|
||||
MOZ_ASSERT_UNREACHABLE("Early and late swizzles not supported");
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
if (!unpackOrMaskSwizzle && !swapOrAlphaSwizzle &&
|
||||
aInFormat != aOutFormat) {
|
||||
MOZ_ASSERT_UNREACHABLE("Need to swizzle, but not configured to");
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
// Don't interpolate if we're sure we won't show this surface to the user
|
||||
// until it's completely decoded. The final pass of an ADAM7 image doesn't
|
||||
|
@ -124,129 +171,402 @@ class SurfacePipeFactory {
|
|||
ADAM7InterpolatingConfig interpolatingConfig;
|
||||
RemoveFrameRectConfig removeFrameRectConfig{aFrameRect};
|
||||
BlendAnimationConfig blendAnimationConfig{aDecoder};
|
||||
DownscalingConfig downscalingConfig{aInputSize, aFormat};
|
||||
DownscalingConfig downscalingConfig{aInputSize, aOutFormat};
|
||||
ColorManagementConfig colorManagementConfig{aTransform};
|
||||
SurfaceConfig surfaceConfig{aDecoder, aOutputSize, aFormat, flipVertically,
|
||||
aAnimParams};
|
||||
SwizzleConfig swizzleConfig{aInFormat, aOutFormat, premultiplyAlpha};
|
||||
SurfaceConfig surfaceConfig{aDecoder, aOutputSize, aOutFormat,
|
||||
flipVertically, aAnimParams};
|
||||
|
||||
Maybe<SurfacePipe> pipe;
|
||||
|
||||
if (colorManagement) {
|
||||
if (downscale) {
|
||||
MOZ_ASSERT(!blendAnimation);
|
||||
if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
|
||||
downscalingConfig, colorManagementConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
|
||||
downscalingConfig, colorManagementConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(removeFrameRectConfig, downscalingConfig,
|
||||
colorManagementConfig, surfaceConfig);
|
||||
if (unpackOrMaskSwizzle) {
|
||||
if (colorManagement) {
|
||||
if (downscale) {
|
||||
MOZ_ASSERT(!blendAnimation);
|
||||
if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(swizzleConfig, deinterlacingConfig,
|
||||
removeFrameRectConfig, downscalingConfig,
|
||||
colorManagementConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(swizzleConfig, interpolatingConfig,
|
||||
removeFrameRectConfig, downscalingConfig,
|
||||
colorManagementConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(swizzleConfig, removeFrameRectConfig,
|
||||
downscalingConfig, colorManagementConfig,
|
||||
surfaceConfig);
|
||||
}
|
||||
} else { // (removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(swizzleConfig, deinterlacingConfig,
|
||||
downscalingConfig, colorManagementConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(swizzleConfig, interpolatingConfig,
|
||||
downscalingConfig, colorManagementConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(swizzleConfig, downscalingConfig,
|
||||
colorManagementConfig, surfaceConfig);
|
||||
}
|
||||
}
|
||||
} else { // (removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, downscalingConfig,
|
||||
colorManagementConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, downscalingConfig,
|
||||
colorManagementConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(downscalingConfig, colorManagementConfig,
|
||||
surfaceConfig);
|
||||
} else { // (downscale is false)
|
||||
if (blendAnimation) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(swizzleConfig, deinterlacingConfig,
|
||||
colorManagementConfig, blendAnimationConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(swizzleConfig, interpolatingConfig,
|
||||
colorManagementConfig, blendAnimationConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(swizzleConfig, colorManagementConfig,
|
||||
blendAnimationConfig, surfaceConfig);
|
||||
}
|
||||
} else if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(swizzleConfig, deinterlacingConfig,
|
||||
colorManagementConfig, removeFrameRectConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(swizzleConfig, interpolatingConfig,
|
||||
colorManagementConfig, removeFrameRectConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(swizzleConfig, colorManagementConfig,
|
||||
removeFrameRectConfig, surfaceConfig);
|
||||
}
|
||||
} else { // (blendAnimation and removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(swizzleConfig, deinterlacingConfig,
|
||||
colorManagementConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(swizzleConfig, interpolatingConfig,
|
||||
colorManagementConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe =
|
||||
MakePipe(swizzleConfig, colorManagementConfig, surfaceConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // (downscale is false)
|
||||
if (blendAnimation) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, colorManagementConfig,
|
||||
blendAnimationConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, colorManagementConfig,
|
||||
blendAnimationConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(colorManagementConfig, blendAnimationConfig,
|
||||
surfaceConfig);
|
||||
} else { // (colorManagement is false)
|
||||
if (downscale) {
|
||||
MOZ_ASSERT(!blendAnimation);
|
||||
if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(swizzleConfig, deinterlacingConfig,
|
||||
removeFrameRectConfig, downscalingConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(swizzleConfig, interpolatingConfig,
|
||||
removeFrameRectConfig, downscalingConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(swizzleConfig, removeFrameRectConfig,
|
||||
downscalingConfig, surfaceConfig);
|
||||
}
|
||||
} else { // (removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(swizzleConfig, deinterlacingConfig,
|
||||
downscalingConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(swizzleConfig, interpolatingConfig,
|
||||
downscalingConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(swizzleConfig, downscalingConfig, surfaceConfig);
|
||||
}
|
||||
}
|
||||
} else if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, colorManagementConfig,
|
||||
removeFrameRectConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, colorManagementConfig,
|
||||
removeFrameRectConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(colorManagementConfig, removeFrameRectConfig,
|
||||
surfaceConfig);
|
||||
}
|
||||
} else { // (blendAnimation and removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, colorManagementConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, colorManagementConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(colorManagementConfig, surfaceConfig);
|
||||
} else { // (downscale is false)
|
||||
if (blendAnimation) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(swizzleConfig, deinterlacingConfig,
|
||||
blendAnimationConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(swizzleConfig, interpolatingConfig,
|
||||
blendAnimationConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe =
|
||||
MakePipe(swizzleConfig, blendAnimationConfig, surfaceConfig);
|
||||
}
|
||||
} else if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(swizzleConfig, deinterlacingConfig,
|
||||
removeFrameRectConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(swizzleConfig, interpolatingConfig,
|
||||
removeFrameRectConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe =
|
||||
MakePipe(swizzleConfig, removeFrameRectConfig, surfaceConfig);
|
||||
}
|
||||
} else { // (blendAnimation and removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe =
|
||||
MakePipe(swizzleConfig, deinterlacingConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe =
|
||||
MakePipe(swizzleConfig, interpolatingConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(swizzleConfig, surfaceConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // (colorManagement is false)
|
||||
if (downscale) {
|
||||
MOZ_ASSERT(!blendAnimation);
|
||||
if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
|
||||
downscalingConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
|
||||
downscalingConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(removeFrameRectConfig, downscalingConfig,
|
||||
surfaceConfig);
|
||||
} else if (swapOrAlphaSwizzle) {
|
||||
if (colorManagement) {
|
||||
if (downscale) {
|
||||
MOZ_ASSERT(!blendAnimation);
|
||||
if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
deinterlacingConfig, removeFrameRectConfig,
|
||||
downscalingConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
interpolatingConfig, removeFrameRectConfig,
|
||||
downscalingConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
removeFrameRectConfig, downscalingConfig,
|
||||
surfaceConfig);
|
||||
}
|
||||
} else { // (removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
deinterlacingConfig, downscalingConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
interpolatingConfig, downscalingConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
downscalingConfig, surfaceConfig);
|
||||
}
|
||||
}
|
||||
} else { // (removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe =
|
||||
MakePipe(deinterlacingConfig, downscalingConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe =
|
||||
MakePipe(interpolatingConfig, downscalingConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(downscalingConfig, surfaceConfig);
|
||||
} else { // (downscale is false)
|
||||
if (blendAnimation) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
deinterlacingConfig, blendAnimationConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
interpolatingConfig, blendAnimationConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
blendAnimationConfig, surfaceConfig);
|
||||
}
|
||||
} else if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
deinterlacingConfig, removeFrameRectConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
interpolatingConfig, removeFrameRectConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
removeFrameRectConfig, surfaceConfig);
|
||||
}
|
||||
} else { // (blendAnimation and removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
deinterlacingConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
interpolatingConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe =
|
||||
MakePipe(colorManagementConfig, swizzleConfig, surfaceConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // (downscale is false)
|
||||
if (blendAnimation) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, blendAnimationConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, blendAnimationConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(blendAnimationConfig, surfaceConfig);
|
||||
} else { // (colorManagement is false)
|
||||
if (downscale) {
|
||||
MOZ_ASSERT(!blendAnimation);
|
||||
if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(swizzleConfig, deinterlacingConfig,
|
||||
removeFrameRectConfig, downscalingConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(swizzleConfig, interpolatingConfig,
|
||||
removeFrameRectConfig, downscalingConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(swizzleConfig, removeFrameRectConfig,
|
||||
downscalingConfig, surfaceConfig);
|
||||
}
|
||||
} else { // (removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(swizzleConfig, deinterlacingConfig,
|
||||
downscalingConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(swizzleConfig, interpolatingConfig,
|
||||
downscalingConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(swizzleConfig, downscalingConfig, surfaceConfig);
|
||||
}
|
||||
}
|
||||
} else if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(removeFrameRectConfig, surfaceConfig);
|
||||
} else { // (downscale is false)
|
||||
if (blendAnimation) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(swizzleConfig, deinterlacingConfig,
|
||||
blendAnimationConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(swizzleConfig, interpolatingConfig,
|
||||
blendAnimationConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe =
|
||||
MakePipe(swizzleConfig, blendAnimationConfig, surfaceConfig);
|
||||
}
|
||||
} else if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(swizzleConfig, deinterlacingConfig,
|
||||
removeFrameRectConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(swizzleConfig, interpolatingConfig,
|
||||
removeFrameRectConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe =
|
||||
MakePipe(swizzleConfig, removeFrameRectConfig, surfaceConfig);
|
||||
}
|
||||
} else { // (blendAnimation and removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe =
|
||||
MakePipe(swizzleConfig, deinterlacingConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe =
|
||||
MakePipe(swizzleConfig, interpolatingConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(swizzleConfig, surfaceConfig);
|
||||
}
|
||||
}
|
||||
} else { // (blendAnimation and removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(surfaceConfig);
|
||||
}
|
||||
}
|
||||
} else { // (unpackOrMaskSwizzle and swapOrAlphaSwizzle are false)
|
||||
if (colorManagement) {
|
||||
if (downscale) {
|
||||
MOZ_ASSERT(!blendAnimation);
|
||||
if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
|
||||
downscalingConfig, colorManagementConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
|
||||
downscalingConfig, colorManagementConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(removeFrameRectConfig, downscalingConfig,
|
||||
colorManagementConfig, surfaceConfig);
|
||||
}
|
||||
} else { // (removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, downscalingConfig,
|
||||
colorManagementConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, downscalingConfig,
|
||||
colorManagementConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(downscalingConfig, colorManagementConfig,
|
||||
surfaceConfig);
|
||||
}
|
||||
}
|
||||
} else { // (downscale is false)
|
||||
if (blendAnimation) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, colorManagementConfig,
|
||||
blendAnimationConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, colorManagementConfig,
|
||||
blendAnimationConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(colorManagementConfig, blendAnimationConfig,
|
||||
surfaceConfig);
|
||||
}
|
||||
} else if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, colorManagementConfig,
|
||||
removeFrameRectConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, colorManagementConfig,
|
||||
removeFrameRectConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(colorManagementConfig, removeFrameRectConfig,
|
||||
surfaceConfig);
|
||||
}
|
||||
} else { // (blendAnimation and removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, colorManagementConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, colorManagementConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(colorManagementConfig, surfaceConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // (colorManagement is false)
|
||||
if (downscale) {
|
||||
MOZ_ASSERT(!blendAnimation);
|
||||
if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
|
||||
downscalingConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
|
||||
downscalingConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(removeFrameRectConfig, downscalingConfig,
|
||||
surfaceConfig);
|
||||
}
|
||||
} else { // (removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, downscalingConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, downscalingConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(downscalingConfig, surfaceConfig);
|
||||
}
|
||||
}
|
||||
} else { // (downscale is false)
|
||||
if (blendAnimation) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, blendAnimationConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, blendAnimationConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(blendAnimationConfig, surfaceConfig);
|
||||
}
|
||||
} else if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(removeFrameRectConfig, surfaceConfig);
|
||||
}
|
||||
} else { // (blendAnimation and removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(surfaceConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,8 +193,8 @@ nsresult nsGIFDecoder2::BeginImageFrame(const IntRect& aFrameRect,
|
|||
}
|
||||
|
||||
Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe(
|
||||
this, Size(), OutputSize(), aFrameRect, format, animParams, mTransform,
|
||||
pipeFlags);
|
||||
this, Size(), OutputSize(), aFrameRect, format, format, animParams,
|
||||
mTransform, pipeFlags);
|
||||
mCurrentFrameIndex = mGIFStruct.images_decoded;
|
||||
|
||||
if (!pipe) {
|
||||
|
|
|
@ -68,6 +68,7 @@ LexerTransition<nsIconDecoder::State> nsIconDecoder::ReadHeader(
|
|||
MOZ_ASSERT(!mImageData, "Already have a buffer allocated?");
|
||||
Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe(
|
||||
this, Size(), OutputSize(), FullFrame(), SurfaceFormat::B8G8R8A8,
|
||||
SurfaceFormat::B8G8R8A8,
|
||||
/* aAnimParams */ Nothing(), mTransform, SurfacePipeFlags());
|
||||
if (!pipe) {
|
||||
return Transition::TerminateFailure();
|
||||
|
|
|
@ -357,7 +357,8 @@ LexerTransition<nsJPEGDecoder::State> nsJPEGDecoder::ReadJPEGData(
|
|||
|
||||
Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe(
|
||||
this, Size(), OutputSize(), FullFrame(), SurfaceFormat::B8G8R8X8,
|
||||
Nothing(), pipeTransform, SurfacePipeFlags());
|
||||
SurfaceFormat::B8G8R8X8, Nothing(), pipeTransform,
|
||||
SurfacePipeFlags());
|
||||
if (!pipe) {
|
||||
mState = JPEG_ERROR;
|
||||
MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
|
||||
|
|
|
@ -116,6 +116,7 @@ nsPNGDecoder::nsPNGDecoder(RasterImage* aImage)
|
|||
mFrameIsHidden(false),
|
||||
mDisablePremultipliedAlpha(false),
|
||||
mGotInfoCallback(false),
|
||||
mUsePipeTransform(false),
|
||||
mNumFrames(0) {}
|
||||
|
||||
nsPNGDecoder::~nsPNGDecoder() {
|
||||
|
@ -212,9 +213,29 @@ nsresult nsPNGDecoder::CreateFrame(const FrameInfo& aFrameInfo) {
|
|||
pipeFlags |= SurfacePipeFlags::PROGRESSIVE_DISPLAY;
|
||||
}
|
||||
|
||||
SurfaceFormat inFormat;
|
||||
if (mTransform && !mUsePipeTransform) {
|
||||
// QCMS will output in the correct format.
|
||||
inFormat = mFormat;
|
||||
} else if (transparency == TransparencyType::eAlpha) {
|
||||
// We are outputting directly as RGBA, so we need to swap at this step.
|
||||
inFormat = SurfaceFormat::R8G8B8A8;
|
||||
} else {
|
||||
// We have no alpha channel, so we need to unpack from RGB to BGRA.
|
||||
inFormat = SurfaceFormat::R8G8B8;
|
||||
}
|
||||
|
||||
// Only apply premultiplication if the frame has true alpha. If we ever
|
||||
// support downscaling animated images, we will need to premultiply for frame
|
||||
// rect transparency when downscaling as well.
|
||||
if (transparency == TransparencyType::eAlpha && !mDisablePremultipliedAlpha) {
|
||||
pipeFlags |= SurfacePipeFlags::PREMULTIPLY_ALPHA;
|
||||
}
|
||||
|
||||
qcms_transform* pipeTransform = mUsePipeTransform ? mTransform : nullptr;
|
||||
Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe(
|
||||
this, Size(), OutputSize(), aFrameInfo.mFrameRect, mFormat, animParams,
|
||||
/*aTransform*/ nullptr, pipeFlags);
|
||||
this, Size(), OutputSize(), aFrameInfo.mFrameRect, inFormat, mFormat,
|
||||
animParams, pipeTransform, pipeFlags);
|
||||
|
||||
if (!pipe) {
|
||||
mPipe = SurfacePipe();
|
||||
|
@ -413,8 +434,7 @@ static void PNGDoGammaCorrection(png_structp png_ptr, png_infop info_ptr) {
|
|||
|
||||
// Adapted from http://www.littlecms.com/pngchrm.c example code
|
||||
static qcms_profile* PNGGetColorProfile(png_structp png_ptr, png_infop info_ptr,
|
||||
int color_type, qcms_data_type* inType,
|
||||
uint32_t* intent) {
|
||||
int color_type, uint32_t* intent) {
|
||||
qcms_profile* profile = nullptr;
|
||||
*intent = QCMS_INTENT_PERCEPTUAL; // Our default
|
||||
|
||||
|
@ -492,24 +512,6 @@ static qcms_profile* PNGGetColorProfile(png_structp png_ptr, png_infop info_ptr,
|
|||
}
|
||||
}
|
||||
|
||||
if (profile) {
|
||||
uint32_t profileSpace = qcms_profile_get_color_space(profile);
|
||||
if (profileSpace == icSigGrayData) {
|
||||
if (color_type & PNG_COLOR_MASK_ALPHA) {
|
||||
*inType = QCMS_DATA_GRAYA_8;
|
||||
} else {
|
||||
*inType = QCMS_DATA_GRAY_8;
|
||||
}
|
||||
} else {
|
||||
if (color_type & PNG_COLOR_MASK_ALPHA ||
|
||||
png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
|
||||
*inType = QCMS_DATA_RGBA_8;
|
||||
} else {
|
||||
*inType = QCMS_DATA_RGB_8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
|
@ -590,14 +592,13 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) {
|
|||
// We only need to extract the color profile for non-metadata decodes. It is
|
||||
// fairly expensive to read the profile and create the transform so we should
|
||||
// avoid it if not necessary.
|
||||
qcms_data_type inType = QCMS_DATA_RGBA_8;
|
||||
uint32_t intent = -1;
|
||||
uint32_t pIntent;
|
||||
if (!decoder->IsMetadataDecode()) {
|
||||
if (decoder->mCMSMode != eCMSMode_Off) {
|
||||
intent = gfxPlatform::GetRenderingIntent();
|
||||
decoder->mInProfile =
|
||||
PNGGetColorProfile(png_ptr, info_ptr, color_type, &inType, &pIntent);
|
||||
PNGGetColorProfile(png_ptr, info_ptr, color_type, &pIntent);
|
||||
// If we're not mandating an intent, use the one from the image.
|
||||
if (intent == uint32_t(-1)) {
|
||||
intent = pIntent;
|
||||
|
@ -648,6 +649,7 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) {
|
|||
}
|
||||
#endif
|
||||
|
||||
auto transparency = decoder->GetTransparencyType(frameRect);
|
||||
if (decoder->IsMetadataDecode()) {
|
||||
// If we are animated then the first frame rect is either:
|
||||
// 1) the whole image if the IDAT chunk is part of the animation
|
||||
|
@ -656,7 +658,6 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) {
|
|||
// PostHasTransparency in the metadata decode if we need to. So it's
|
||||
// okay to pass IntRect(0, 0, width, height) here for animated images;
|
||||
// they will call with the proper first frame rect in the full decode.
|
||||
auto transparency = decoder->GetTransparencyType(frameRect);
|
||||
decoder->PostHasTransparencyIfNeeded(transparency);
|
||||
|
||||
// We have the metadata we're looking for, so stop here, before we allocate
|
||||
|
@ -665,23 +666,47 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) {
|
|||
}
|
||||
|
||||
if (decoder->mInProfile && gfxPlatform::GetCMSOutputProfile()) {
|
||||
qcms_data_type inType;
|
||||
qcms_data_type outType;
|
||||
|
||||
if (color_type & PNG_COLOR_MASK_ALPHA || num_trans) {
|
||||
outType = QCMS_DATA_RGBA_8;
|
||||
uint32_t profileSpace = qcms_profile_get_color_space(decoder->mInProfile);
|
||||
decoder->mUsePipeTransform = profileSpace != icSigGrayData;
|
||||
if (decoder->mUsePipeTransform) {
|
||||
// If the transform happens with SurfacePipe, it will be in RGBA if we
|
||||
// have an alpha channel, because the swizzle and premultiplication
|
||||
// happens after color management. Otherwise it will be in BGRA because
|
||||
// the swizzle happens at the start.
|
||||
if (transparency == TransparencyType::eAlpha) {
|
||||
inType = QCMS_DATA_RGBA_8;
|
||||
outType = QCMS_DATA_RGBA_8;
|
||||
} else {
|
||||
inType = QCMS_DATA_BGRA_8;
|
||||
outType = QCMS_DATA_BGRA_8;
|
||||
}
|
||||
} else {
|
||||
outType = QCMS_DATA_RGB_8;
|
||||
if (color_type & PNG_COLOR_MASK_ALPHA) {
|
||||
inType = QCMS_DATA_GRAYA_8;
|
||||
outType = QCMS_DATA_BGRA_8;
|
||||
} else {
|
||||
inType = QCMS_DATA_GRAY_8;
|
||||
outType = QCMS_DATA_BGRA_8;
|
||||
}
|
||||
}
|
||||
|
||||
decoder->mTransform = qcms_transform_create(
|
||||
decoder->mInProfile, inType, gfxPlatform::GetCMSOutputProfile(),
|
||||
outType, (qcms_intent)intent);
|
||||
} else if (decoder->mCMSMode == eCMSMode_All) {
|
||||
if (color_type & PNG_COLOR_MASK_ALPHA || num_trans) {
|
||||
// If the transform happens with SurfacePipe, it will be in RGBA if we
|
||||
// have an alpha channel, because the swizzle and premultiplication
|
||||
// happens after color management. Otherwise it will be in BGRA because
|
||||
// the swizzle happens at the start.
|
||||
if (transparency == TransparencyType::eAlpha) {
|
||||
decoder->mTransform = gfxPlatform::GetCMSRGBATransform();
|
||||
} else {
|
||||
decoder->mTransform = gfxPlatform::GetCMSRGBTransform();
|
||||
decoder->mTransform = gfxPlatform::GetCMSBGRATransform();
|
||||
}
|
||||
decoder->mUsePipeTransform = true;
|
||||
}
|
||||
|
||||
#ifdef PNG_APNG_SUPPORTED
|
||||
|
@ -703,10 +728,9 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) {
|
|||
}
|
||||
#endif
|
||||
|
||||
if (decoder->mTransform && (channels <= 2 || isInterlaced)) {
|
||||
uint32_t bpp[] = {0, 3, 4, 3, 4};
|
||||
if (decoder->mTransform && !decoder->mUsePipeTransform) {
|
||||
decoder->mCMSLine =
|
||||
static_cast<uint8_t*>(malloc(bpp[channels] * frameRect.Width()));
|
||||
static_cast<uint8_t*>(malloc(sizeof(uint32_t) * frameRect.Width()));
|
||||
if (!decoder->mCMSLine) {
|
||||
png_error(decoder->mPNG, "malloc of mCMSLine failed");
|
||||
}
|
||||
|
@ -740,29 +764,6 @@ void nsPNGDecoder::PostInvalidationIfNeeded() {
|
|||
Some(invalidRect->mOutputSpaceRect));
|
||||
}
|
||||
|
||||
static NextPixel<uint32_t> PackRGBPixelAndAdvance(uint8_t*& aRawPixelInOut) {
|
||||
const uint32_t pixel = gfxPackedPixel(0xFF, aRawPixelInOut[0],
|
||||
aRawPixelInOut[1], aRawPixelInOut[2]);
|
||||
aRawPixelInOut += 3;
|
||||
return AsVariant(pixel);
|
||||
}
|
||||
|
||||
static NextPixel<uint32_t> PackRGBAPixelAndAdvance(uint8_t*& aRawPixelInOut) {
|
||||
const uint32_t pixel = gfxPackedPixel(aRawPixelInOut[3], aRawPixelInOut[0],
|
||||
aRawPixelInOut[1], aRawPixelInOut[2]);
|
||||
aRawPixelInOut += 4;
|
||||
return AsVariant(pixel);
|
||||
}
|
||||
|
||||
static NextPixel<uint32_t> PackUnpremultipliedRGBAPixelAndAdvance(
|
||||
uint8_t*& aRawPixelInOut) {
|
||||
const uint32_t pixel =
|
||||
gfxPackedPixelNoPreMultiply(aRawPixelInOut[3], aRawPixelInOut[0],
|
||||
aRawPixelInOut[1], aRawPixelInOut[2]);
|
||||
aRawPixelInOut += 4;
|
||||
return AsVariant(pixel);
|
||||
}
|
||||
|
||||
void nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row,
|
||||
png_uint_32 row_num, int pass) {
|
||||
/* libpng comments:
|
||||
|
@ -847,38 +848,16 @@ void nsPNGDecoder::WriteRow(uint8_t* aRow) {
|
|||
uint32_t width = uint32_t(mFrameRect.Width());
|
||||
|
||||
// Apply color management to the row, if necessary, before writing it out.
|
||||
if (mTransform) {
|
||||
if (mCMSLine) {
|
||||
qcms_transform_data(mTransform, rowToWrite, mCMSLine, width);
|
||||
|
||||
// Copy alpha over.
|
||||
if (HasAlphaChannel()) {
|
||||
for (uint32_t i = 0; i < width; ++i) {
|
||||
mCMSLine[4 * i + 3] = rowToWrite[mChannels * i + mChannels - 1];
|
||||
}
|
||||
}
|
||||
|
||||
rowToWrite = mCMSLine;
|
||||
} else {
|
||||
qcms_transform_data(mTransform, rowToWrite, rowToWrite, width);
|
||||
}
|
||||
// This is only needed for grayscale images.
|
||||
if (mTransform && !mUsePipeTransform) {
|
||||
MOZ_ASSERT(mCMSLine);
|
||||
qcms_transform_data(mTransform, rowToWrite, mCMSLine, width);
|
||||
rowToWrite = mCMSLine;
|
||||
}
|
||||
|
||||
// Write this row to the SurfacePipe.
|
||||
DebugOnly<WriteState> result;
|
||||
if (HasAlphaChannel()) {
|
||||
if (mDisablePremultipliedAlpha) {
|
||||
result = mPipe.WritePixelsToRow<uint32_t>(
|
||||
[&] { return PackUnpremultipliedRGBAPixelAndAdvance(rowToWrite); });
|
||||
} else {
|
||||
result = mPipe.WritePixelsToRow<uint32_t>(
|
||||
[&] { return PackRGBAPixelAndAdvance(rowToWrite); });
|
||||
}
|
||||
} else {
|
||||
result = mPipe.WritePixelsToRow<uint32_t>(
|
||||
[&] { return PackRGBPixelAndAdvance(rowToWrite); });
|
||||
}
|
||||
|
||||
DebugOnly<WriteState> result =
|
||||
mPipe.WriteBuffer(reinterpret_cast<uint32_t*>(rowToWrite));
|
||||
MOZ_ASSERT(WriteState(result) != WriteState::FAILURE);
|
||||
|
||||
PostInvalidationIfNeeded();
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "png.h"
|
||||
#include "StreamingLexer.h"
|
||||
#include "SurfacePipe.h"
|
||||
#include "mozilla/gfx/Swizzle.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
|
@ -101,6 +102,7 @@ class nsPNGDecoder : public Decoder {
|
|||
bool mFrameIsHidden;
|
||||
bool mDisablePremultipliedAlpha;
|
||||
bool mGotInfoCallback;
|
||||
bool mUsePipeTransform;
|
||||
|
||||
struct AnimFrameInfo {
|
||||
AnimFrameInfo();
|
||||
|
|
|
@ -210,7 +210,7 @@ nsresult nsWebPDecoder::CreateFrame(const nsIntRect& aFrameRect) {
|
|||
}
|
||||
|
||||
WebPInitDecBuffer(&mBuffer);
|
||||
mBuffer.colorspace = MODE_RGBA;
|
||||
mBuffer.colorspace = MODE_BGRA;
|
||||
|
||||
mDecoder = WebPINewDecoder(&mBuffer);
|
||||
if (!mDecoder) {
|
||||
|
@ -220,7 +220,16 @@ nsresult nsWebPDecoder::CreateFrame(const nsIntRect& aFrameRect) {
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// WebP doesn't guarantee that the alpha generated matches the hint in the
|
||||
// header, so we always need to claim the input is BGRA. If the output is
|
||||
// BGRX, swizzling will mask off the alpha channel.
|
||||
SurfaceFormat inFormat = SurfaceFormat::B8G8R8A8;
|
||||
|
||||
SurfacePipeFlags pipeFlags = SurfacePipeFlags();
|
||||
if (mFormat == SurfaceFormat::B8G8R8A8 &&
|
||||
!(GetSurfaceFlags() & SurfaceFlags::NO_PREMULTIPLY_ALPHA)) {
|
||||
pipeFlags |= SurfacePipeFlags::PREMULTIPLY_ALPHA;
|
||||
}
|
||||
|
||||
Maybe<AnimationParams> animParams;
|
||||
if (!IsFirstFrameDecode()) {
|
||||
|
@ -228,8 +237,8 @@ nsresult nsWebPDecoder::CreateFrame(const nsIntRect& aFrameRect) {
|
|||
}
|
||||
|
||||
Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe(
|
||||
this, Size(), OutputSize(), aFrameRect, mFormat, animParams,
|
||||
/*aTransform*/ nullptr, pipeFlags);
|
||||
this, Size(), OutputSize(), aFrameRect, inFormat, mFormat, animParams,
|
||||
mTransform, pipeFlags);
|
||||
if (!pipe) {
|
||||
MOZ_LOG(sWebPLog, LogLevel::Error,
|
||||
("[this=%p] nsWebPDecoder::CreateFrame -- no pipe\n", this));
|
||||
|
@ -281,7 +290,7 @@ void nsWebPDecoder::ApplyColorProfile(const char* aProfile, size_t aLength) {
|
|||
("[this=%p] nsWebPDecoder::ApplyColorProfile -- not tagged, use "
|
||||
"sRGB transform\n",
|
||||
this));
|
||||
mTransform = gfxPlatform::GetCMSRGBATransform();
|
||||
mTransform = gfxPlatform::GetCMSBGRATransform();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -311,9 +320,9 @@ void nsWebPDecoder::ApplyColorProfile(const char* aProfile, size_t aLength) {
|
|||
}
|
||||
|
||||
// Create the color management transform.
|
||||
mTransform = qcms_transform_create(mInProfile, QCMS_DATA_RGBA_8,
|
||||
mTransform = qcms_transform_create(mInProfile, QCMS_DATA_BGRA_8,
|
||||
gfxPlatform::GetCMSOutputProfile(),
|
||||
QCMS_DATA_RGBA_8, (qcms_intent)intent);
|
||||
QCMS_DATA_BGRA_8, (qcms_intent)intent);
|
||||
MOZ_LOG(sWebPLog, LogLevel::Debug,
|
||||
("[this=%p] nsWebPDecoder::ApplyColorProfile -- use tagged "
|
||||
"transform\n",
|
||||
|
@ -458,43 +467,9 @@ LexerResult nsWebPDecoder::ReadSingle(const uint8_t* aData, size_t aLength,
|
|||
return LexerResult(TerminalState::FAILURE);
|
||||
}
|
||||
|
||||
const bool noPremultiply =
|
||||
bool(GetSurfaceFlags() & SurfaceFlags::NO_PREMULTIPLY_ALPHA);
|
||||
|
||||
for (int row = mLastRow; row < lastRow; row++) {
|
||||
uint8_t* src = rowStart + row * stride;
|
||||
if (mTransform) {
|
||||
qcms_transform_data(mTransform, src, src, width);
|
||||
}
|
||||
|
||||
WriteState result;
|
||||
if (mFormat == SurfaceFormat::B8G8R8A8) {
|
||||
if (noPremultiply) {
|
||||
result =
|
||||
mPipe.WritePixelsToRow<uint32_t>([&]() -> NextPixel<uint32_t> {
|
||||
const uint32_t pixel =
|
||||
gfxPackedPixelNoPreMultiply(src[3], src[0], src[1], src[2]);
|
||||
src += 4;
|
||||
return AsVariant(pixel);
|
||||
});
|
||||
} else {
|
||||
result =
|
||||
mPipe.WritePixelsToRow<uint32_t>([&]() -> NextPixel<uint32_t> {
|
||||
const uint32_t pixel =
|
||||
gfxPackedPixel(src[3], src[0], src[1], src[2]);
|
||||
src += 4;
|
||||
return AsVariant(pixel);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// We are producing a surface without transparency. Ignore the alpha
|
||||
// channel provided to us by the library.
|
||||
result = mPipe.WritePixelsToRow<uint32_t>([&]() -> NextPixel<uint32_t> {
|
||||
const uint32_t pixel = gfxPackedPixel(0xFF, src[0], src[1], src[2]);
|
||||
src += 4;
|
||||
return AsVariant(pixel);
|
||||
});
|
||||
}
|
||||
uint32_t* src = reinterpret_cast<uint32_t*>(rowStart + row * stride);
|
||||
WriteState result = mPipe.WriteBuffer(src);
|
||||
|
||||
Maybe<SurfaceInvalidRect> invalidRect = mPipe.TakeInvalidRect();
|
||||
if (invalidRect) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче