зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 8 changesets (bug 1551088) for causing build bustages. CLOSED TREE
Backed out changeset 02d9dc4d39a5 (bug 1551088) Backed out changeset d7684ca35c0d (bug 1551088) Backed out changeset b061b1bf8281 (bug 1551088) Backed out changeset 4760b8b22ffd (bug 1551088) Backed out changeset 4685fc022257 (bug 1551088) Backed out changeset 91300f9f99bb (bug 1551088) Backed out changeset 6da767c8d55c (bug 1551088) Backed out changeset ec69be661551 (bug 1551088)
This commit is contained in:
Родитель
8c8d2ae1df
Коммит
69acba5002
|
@ -41,10 +41,6 @@ namespace gfx {
|
|||
#define FORMAT_CASE(aSrcFormat, aDstFormat, ...) \
|
||||
FORMAT_CASE_EXPR(aSrcFormat, aDstFormat, FORMAT_CASE_CALL(__VA_ARGS__))
|
||||
|
||||
#define FORMAT_CASE_ROW(aSrcFormat, aDstFormat, ...) \
|
||||
case FORMAT_KEY(aSrcFormat, aDstFormat): \
|
||||
return &__VA_ARGS__;
|
||||
|
||||
/**
|
||||
* Constexpr functions for analyzing format attributes in templates.
|
||||
*/
|
||||
|
@ -118,15 +114,6 @@ void Premultiply_SSE2(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize);
|
|||
Premultiply_SSE2<ShouldSwapRB(aSrcFormat, aDstFormat), \
|
||||
ShouldForceOpaque(aSrcFormat, aDstFormat)>)
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
void PremultiplyRow_SSE2(const uint8_t*, uint8_t*, int32_t);
|
||||
|
||||
# define PREMULTIPLY_ROW_SSE2(aSrcFormat, aDstFormat) \
|
||||
FORMAT_CASE_ROW( \
|
||||
aSrcFormat, aDstFormat, \
|
||||
PremultiplyRow_SSE2<ShouldSwapRB(aSrcFormat, aDstFormat), \
|
||||
ShouldForceOpaque(aSrcFormat, aDstFormat)>)
|
||||
|
||||
template <bool aSwapRB>
|
||||
void Unpremultiply_SSE2(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize);
|
||||
|
||||
|
@ -142,29 +129,6 @@ void Swizzle_SSE2(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize);
|
|||
Swizzle_SSE2<ShouldSwapRB(aSrcFormat, aDstFormat), \
|
||||
ShouldForceOpaque(aSrcFormat, aDstFormat)>)
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
void SwizzleRow_SSE2(const uint8_t*, uint8_t*, int32_t);
|
||||
|
||||
# define SWIZZLE_ROW_SSE2(aSrcFormat, aDstFormat) \
|
||||
FORMAT_CASE_ROW( \
|
||||
aSrcFormat, aDstFormat, \
|
||||
SwizzleRow_SSE2<ShouldSwapRB(aSrcFormat, aDstFormat), \
|
||||
ShouldForceOpaque(aSrcFormat, aDstFormat)>)
|
||||
|
||||
template <bool aSwapRB>
|
||||
void UnpackRowRGB24_SSSE3(const uint8_t*, uint8_t*, int32_t);
|
||||
|
||||
#define UNPACK_ROW_RGB_SSSE3(aDstFormat) \
|
||||
FORMAT_CASE_ROW(SurfaceFormat::R8G8B8, aDstFormat, \
|
||||
UnpackRowRGB24_SSSE3<ShouldSwapRB(SurfaceFormat::R8G8B8, aDstFormat)>)
|
||||
|
||||
template <bool aSwapRB>
|
||||
void UnpackRowRGB24_AVX2(const uint8_t*, uint8_t*, int32_t);
|
||||
|
||||
#define UNPACK_ROW_RGB_AVX2(aDstFormat) \
|
||||
FORMAT_CASE_ROW(SurfaceFormat::R8G8B8, aDstFormat, \
|
||||
UnpackRowRGB24_AVX2<ShouldSwapRB(SurfaceFormat::R8G8B8, aDstFormat)>)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_NEON
|
||||
|
@ -180,15 +144,6 @@ void Premultiply_NEON(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize);
|
|||
Premultiply_NEON<ShouldSwapRB(aSrcFormat, aDstFormat), \
|
||||
ShouldForceOpaque(aSrcFormat, aDstFormat)>)
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
void PremultiplyRow_NEON(const uint8_t*, uint8_t*, int32_t);
|
||||
|
||||
# define PREMULTIPLY_ROW_NEON(aSrcFormat, aDstFormat) \
|
||||
FORMAT_CASE_ROW( \
|
||||
aSrcFormat, aDstFormat, \
|
||||
PremultiplyRow_NEON<ShouldSwapRB(aSrcFormat, aDstFormat), \
|
||||
ShouldForceOpaque(aSrcFormat, aDstFormat)>)
|
||||
|
||||
template <bool aSwapRB>
|
||||
void Unpremultiply_NEON(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize);
|
||||
|
||||
|
@ -204,14 +159,6 @@ void Swizzle_NEON(const uint8_t*, int32_t, uint8_t*, int32_t, IntSize);
|
|||
Swizzle_NEON<ShouldSwapRB(aSrcFormat, aDstFormat), \
|
||||
ShouldForceOpaque(aSrcFormat, aDstFormat)>)
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
void SwizzleRow_NEON(const uint8_t*, uint8_t*, int32_t);
|
||||
|
||||
# define SWIZZLE_ROW_NEON(aSrcFormat, aDstFormat) \
|
||||
FORMAT_CASE_ROW( \
|
||||
aSrcFormat, aDstFormat, \
|
||||
SwizzleRow_NEON<ShouldSwapRB(aSrcFormat, aDstFormat), \
|
||||
ShouldForceOpaque(aSrcFormat, aDstFormat)>)
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -224,65 +171,51 @@ void SwizzleRow_NEON(const uint8_t*, uint8_t*, int32_t);
|
|||
// 2-component vectors. Otherwise, an approximation if divide-by-255 is used
|
||||
// which is faster than an actual division. These optimizations are also used
|
||||
// for the SSE2 and NEON implementations.
|
||||
template <bool aSwapRB, bool aOpaqueAlpha, uint32_t aSrcRGBShift,
|
||||
uint32_t aSrcAShift, uint32_t aDstRGBShift, uint32_t aDstAShift>
|
||||
static void PremultiplyChunkFallback(const uint8_t*& aSrc, uint8_t*& aDst,
|
||||
int32_t aLength) {
|
||||
const uint8_t* end = aSrc + 4 * aLength;
|
||||
do {
|
||||
// Load and process 1 entire pixel at a time.
|
||||
uint32_t color = *reinterpret_cast<const uint32_t*>(aSrc);
|
||||
|
||||
uint32_t a = aSrcAShift ? color >> aSrcAShift : color & 0xFF;
|
||||
|
||||
// Isolate the R and B components.
|
||||
uint32_t rb = (color >> aSrcRGBShift) & 0x00FF00FF;
|
||||
// Swap the order of R and B if necessary.
|
||||
if (aSwapRB) {
|
||||
rb = (rb >> 16) | (rb << 16);
|
||||
}
|
||||
// Approximate the multiply by alpha and divide by 255 which is
|
||||
// essentially:
|
||||
// c = c*a + 255; c = (c + (c >> 8)) >> 8;
|
||||
// However, we omit the final >> 8 to fold it with the final shift into
|
||||
// place depending on desired output format.
|
||||
rb = rb * a + 0x00FF00FF;
|
||||
rb = (rb + ((rb >> 8) & 0x00FF00FF)) & 0xFF00FF00;
|
||||
|
||||
// Use same approximation as above, but G is shifted 8 bits left.
|
||||
// Alpha is left out and handled separately.
|
||||
uint32_t g = color & (0xFF00 << aSrcRGBShift);
|
||||
g = g * a + (0xFF00 << aSrcRGBShift);
|
||||
g = (g + (g >> 8)) & (0xFF0000 << aSrcRGBShift);
|
||||
|
||||
// The above math leaves RGB shifted left by 8 bits.
|
||||
// Shift them right if required for the output format.
|
||||
// then combine them back together to produce output pixel.
|
||||
// Add the alpha back on if the output format is not opaque.
|
||||
*reinterpret_cast<uint32_t*>(aDst) =
|
||||
(rb >> (8 - aDstRGBShift)) | (g >> (8 + aSrcRGBShift - aDstRGBShift)) |
|
||||
(aOpaqueAlpha ? 0xFF << aDstAShift : a << aDstAShift);
|
||||
|
||||
aSrc += 4;
|
||||
aDst += 4;
|
||||
} while (aSrc < end);
|
||||
}
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha, uint32_t aSrcRGBShift,
|
||||
uint32_t aSrcAShift, uint32_t aDstRGBShift, uint32_t aDstAShift>
|
||||
static void PremultiplyRowFallback(const uint8_t* aSrc, uint8_t* aDst,
|
||||
int32_t aLength) {
|
||||
PremultiplyChunkFallback<aSwapRB, aOpaqueAlpha, aSrcRGBShift, aSrcAShift,
|
||||
aDstRGBShift, aDstAShift>(aSrc, aDst, aLength);
|
||||
}
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha, uint32_t aSrcRGBShift,
|
||||
uint32_t aSrcAShift, uint32_t aDstRGBShift, uint32_t aDstAShift>
|
||||
static void PremultiplyFallback(const uint8_t* aSrc, int32_t aSrcGap,
|
||||
uint8_t* aDst, int32_t aDstGap, IntSize aSize) {
|
||||
for (int32_t height = aSize.height; height > 0; height--) {
|
||||
PremultiplyChunkFallback<aSwapRB, aOpaqueAlpha, aSrcRGBShift, aSrcAShift,
|
||||
aDstRGBShift, aDstAShift>(aSrc, aDst, aSize.width);
|
||||
const uint8_t* end = aSrc + 4 * aSize.width;
|
||||
do {
|
||||
// Load and process 1 entire pixel at a time.
|
||||
uint32_t color = *reinterpret_cast<const uint32_t*>(aSrc);
|
||||
|
||||
uint32_t a = aSrcAShift ? color >> aSrcAShift : color & 0xFF;
|
||||
|
||||
// Isolate the R and B components.
|
||||
uint32_t rb = (color >> aSrcRGBShift) & 0x00FF00FF;
|
||||
// Swap the order of R and B if necessary.
|
||||
if (aSwapRB) {
|
||||
rb = (rb >> 16) | (rb << 16);
|
||||
}
|
||||
// Approximate the multiply by alpha and divide by 255 which is
|
||||
// essentially:
|
||||
// c = c*a + 255; c = (c + (c >> 8)) >> 8;
|
||||
// However, we omit the final >> 8 to fold it with the final shift into
|
||||
// place depending on desired output format.
|
||||
rb = rb * a + 0x00FF00FF;
|
||||
rb = (rb + ((rb >> 8) & 0x00FF00FF)) & 0xFF00FF00;
|
||||
|
||||
// Use same approximation as above, but G is shifted 8 bits left.
|
||||
// Alpha is left out and handled separately.
|
||||
uint32_t g = color & (0xFF00 << aSrcRGBShift);
|
||||
g = g * a + (0xFF00 << aSrcRGBShift);
|
||||
g = (g + (g >> 8)) & (0xFF0000 << aSrcRGBShift);
|
||||
|
||||
// The above math leaves RGB shifted left by 8 bits.
|
||||
// Shift them right if required for the output format.
|
||||
// then combine them back together to produce output pixel.
|
||||
// Add the alpha back on if the output format is not opaque.
|
||||
*reinterpret_cast<uint32_t*>(aDst) =
|
||||
(rb >> (8 - aDstRGBShift)) |
|
||||
(g >> (8 + aSrcRGBShift - aDstRGBShift)) |
|
||||
(aOpaqueAlpha ? 0xFF << aDstAShift : a << aDstAShift);
|
||||
|
||||
aSrc += 4;
|
||||
aDst += 4;
|
||||
} while (aSrc < end);
|
||||
|
||||
aSrc += aSrcGap;
|
||||
aDst += aDstGap;
|
||||
}
|
||||
|
@ -304,22 +237,6 @@ static void PremultiplyFallback(const uint8_t* aSrc, int32_t aSrcGap,
|
|||
PREMULTIPLY_FALLBACK_CASE(aSrcFormat, SurfaceFormat::A8R8G8B8) \
|
||||
PREMULTIPLY_FALLBACK_CASE(aSrcFormat, SurfaceFormat::X8R8G8B8)
|
||||
|
||||
#define PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, aDstFormat) \
|
||||
FORMAT_CASE_ROW(aSrcFormat, aDstFormat, \
|
||||
PremultiplyRowFallback< \
|
||||
ShouldSwapRB(aSrcFormat, aDstFormat), \
|
||||
ShouldForceOpaque(aSrcFormat, aDstFormat), \
|
||||
RGBBitShift(aSrcFormat), AlphaBitShift(aSrcFormat), \
|
||||
RGBBitShift(aDstFormat), AlphaBitShift(aDstFormat)>)
|
||||
|
||||
#define PREMULTIPLY_ROW_FALLBACK(aSrcFormat) \
|
||||
PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::B8G8R8A8) \
|
||||
PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::B8G8R8X8) \
|
||||
PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::R8G8B8A8) \
|
||||
PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::R8G8B8X8) \
|
||||
PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::A8R8G8B8) \
|
||||
PREMULTIPLY_ROW_FALLBACK_CASE(aSrcFormat, SurfaceFormat::X8R8G8B8)
|
||||
|
||||
// If rows are tightly packed, and the size of the total area will fit within
|
||||
// the precision range of a single row, then process all the data as if it was
|
||||
// a single row.
|
||||
|
@ -406,50 +323,6 @@ bool PremultiplyData(const uint8_t* aSrc, int32_t aSrcStride,
|
|||
return false;
|
||||
}
|
||||
|
||||
SwizzleRowFn PremultiplyRow(SurfaceFormat aSrcFormat,
|
||||
SurfaceFormat aDstFormat) {
|
||||
#ifdef USE_SSE2
|
||||
if (mozilla::supports_sse2()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
|
||||
PREMULTIPLY_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8)
|
||||
PREMULTIPLY_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8X8)
|
||||
PREMULTIPLY_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8)
|
||||
PREMULTIPLY_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8)
|
||||
PREMULTIPLY_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8A8)
|
||||
PREMULTIPLY_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8)
|
||||
PREMULTIPLY_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8)
|
||||
PREMULTIPLY_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_NEON
|
||||
if (mozilla::supports_neon()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
|
||||
PREMULTIPLY_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8)
|
||||
PREMULTIPLY_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8X8)
|
||||
PREMULTIPLY_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8)
|
||||
PREMULTIPLY_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8)
|
||||
PREMULTIPLY_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8A8)
|
||||
PREMULTIPLY_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8)
|
||||
PREMULTIPLY_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8)
|
||||
PREMULTIPLY_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
|
||||
PREMULTIPLY_ROW_FALLBACK(SurfaceFormat::B8G8R8A8)
|
||||
PREMULTIPLY_ROW_FALLBACK(SurfaceFormat::R8G8B8A8)
|
||||
PREMULTIPLY_ROW_FALLBACK(SurfaceFormat::A8R8G8B8)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_UNREACHABLE("Unsupported premultiply formats");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpremultiplying
|
||||
*/
|
||||
|
@ -584,54 +457,39 @@ bool UnpremultiplyData(const uint8_t* aSrc, int32_t aSrcStride,
|
|||
|
||||
// Fallback swizzle implementation that uses shifting and masking to reorder
|
||||
// pixels.
|
||||
template <bool aSwapRB, bool aOpaqueAlpha, uint32_t aSrcRGBShift,
|
||||
uint32_t aSrcAShift, uint32_t aDstRGBShift, uint32_t aDstAShift>
|
||||
static void SwizzleChunkFallback(const uint8_t*& aSrc, uint8_t*& aDst,
|
||||
int32_t aLength) {
|
||||
const uint8_t* end = aSrc + 4 * aLength;
|
||||
do {
|
||||
uint32_t rgba = *reinterpret_cast<const uint32_t*>(aSrc);
|
||||
|
||||
if (aSwapRB) {
|
||||
// Handle R and B swaps by exchanging words and masking.
|
||||
uint32_t rb =
|
||||
((rgba << 16) | (rgba >> 16)) & (0x00FF00FF << aSrcRGBShift);
|
||||
uint32_t ga = rgba & ((0xFF << aSrcAShift) | (0xFF00 << aSrcRGBShift));
|
||||
rgba = rb | ga;
|
||||
}
|
||||
|
||||
// If src and dst shifts differ, rotate left or right to move RGB into
|
||||
// place, i.e. ARGB -> RGBA or ARGB -> RGBA.
|
||||
if (aDstRGBShift > aSrcRGBShift) {
|
||||
rgba = (rgba << 8) | (aOpaqueAlpha ? 0x000000FF : rgba >> 24);
|
||||
} else if (aSrcRGBShift > aDstRGBShift) {
|
||||
rgba = (rgba >> 8) | (aOpaqueAlpha ? 0xFF000000 : rgba << 24);
|
||||
} else if (aOpaqueAlpha) {
|
||||
rgba |= 0xFF << aDstAShift;
|
||||
}
|
||||
|
||||
*reinterpret_cast<uint32_t*>(aDst) = rgba;
|
||||
|
||||
aSrc += 4;
|
||||
aDst += 4;
|
||||
} while (aSrc < end);
|
||||
}
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha, uint32_t aSrcRGBShift,
|
||||
uint32_t aSrcAShift, uint32_t aDstRGBShift, uint32_t aDstAShift>
|
||||
static void SwizzleRowFallback(const uint8_t* aSrc, uint8_t* aDst,
|
||||
int32_t aLength) {
|
||||
SwizzleChunkFallback<aSwapRB, aOpaqueAlpha, aSrcRGBShift, aSrcAShift,
|
||||
aDstRGBShift, aDstAShift>(aSrc, aDst, aLength);
|
||||
}
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha, uint32_t aSrcRGBShift,
|
||||
uint32_t aSrcAShift, uint32_t aDstRGBShift, uint32_t aDstAShift>
|
||||
static void SwizzleFallback(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
||||
int32_t aDstGap, IntSize aSize) {
|
||||
for (int32_t height = aSize.height; height > 0; height--) {
|
||||
SwizzleChunkFallback<aSwapRB, aOpaqueAlpha, aSrcRGBShift, aSrcAShift,
|
||||
aDstRGBShift, aDstAShift>(aSrc, aDst, aSize.width);
|
||||
const uint8_t* end = aSrc + 4 * aSize.width;
|
||||
do {
|
||||
uint32_t rgba = *reinterpret_cast<const uint32_t*>(aSrc);
|
||||
|
||||
if (aSwapRB) {
|
||||
// Handle R and B swaps by exchanging words and masking.
|
||||
uint32_t rb =
|
||||
((rgba << 16) | (rgba >> 16)) & (0x00FF00FF << aSrcRGBShift);
|
||||
uint32_t ga = rgba & ((0xFF << aSrcAShift) | (0xFF00 << aSrcRGBShift));
|
||||
rgba = rb | ga;
|
||||
}
|
||||
|
||||
// If src and dst shifts differ, rotate left or right to move RGB into
|
||||
// place, i.e. ARGB -> RGBA or ARGB -> RGBA.
|
||||
if (aDstRGBShift > aSrcRGBShift) {
|
||||
rgba = (rgba << 8) | (aOpaqueAlpha ? 0x000000FF : rgba >> 24);
|
||||
} else if (aSrcRGBShift > aDstRGBShift) {
|
||||
rgba = (rgba >> 8) | (aOpaqueAlpha ? 0xFF000000 : rgba << 24);
|
||||
} else if (aOpaqueAlpha) {
|
||||
rgba |= 0xFF << aDstAShift;
|
||||
}
|
||||
|
||||
*reinterpret_cast<uint32_t*>(aDst) = rgba;
|
||||
|
||||
aSrc += 4;
|
||||
aDst += 4;
|
||||
} while (aSrc < end);
|
||||
|
||||
aSrc += aSrcGap;
|
||||
aDst += aDstGap;
|
||||
}
|
||||
|
@ -645,14 +503,6 @@ static void SwizzleFallback(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
|||
RGBBitShift(aSrcFormat), AlphaBitShift(aSrcFormat), \
|
||||
RGBBitShift(aDstFormat), AlphaBitShift(aDstFormat)>)
|
||||
|
||||
#define SWIZZLE_ROW_FALLBACK(aSrcFormat, aDstFormat) \
|
||||
FORMAT_CASE_ROW( \
|
||||
aSrcFormat, aDstFormat, \
|
||||
SwizzleRowFallback<ShouldSwapRB(aSrcFormat, aDstFormat), \
|
||||
ShouldForceOpaque(aSrcFormat, aDstFormat), \
|
||||
RGBBitShift(aSrcFormat), AlphaBitShift(aSrcFormat), \
|
||||
RGBBitShift(aDstFormat), AlphaBitShift(aDstFormat)>)
|
||||
|
||||
// Fast-path for matching formats.
|
||||
static void SwizzleCopy(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
||||
int32_t aDstGap, IntSize aSize, int32_t aBPP) {
|
||||
|
@ -667,39 +517,26 @@ static void SwizzleCopy(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
|||
}
|
||||
|
||||
// Fast-path for conversions that swap all bytes.
|
||||
template <bool aOpaqueAlpha, uint32_t aSrcAShift, uint32_t aDstAShift>
|
||||
static void SwizzleChunkSwap(const uint8_t*& aSrc, uint8_t*& aDst,
|
||||
int32_t aLength) {
|
||||
const uint8_t* end = aSrc + 4 * aLength;
|
||||
do {
|
||||
// Use an endian swap to move the bytes, i.e. BGRA -> ARGB.
|
||||
uint32_t rgba = *reinterpret_cast<const uint32_t*>(aSrc);
|
||||
#if MOZ_LITTLE_ENDIAN
|
||||
rgba = NativeEndian::swapToBigEndian(rgba);
|
||||
#else
|
||||
rgba = NativeEndian::swapToLittleEndian(rgba);
|
||||
#endif
|
||||
if (aOpaqueAlpha) {
|
||||
rgba |= 0xFF << aDstAShift;
|
||||
}
|
||||
*reinterpret_cast<uint32_t*>(aDst) = rgba;
|
||||
aSrc += 4;
|
||||
aDst += 4;
|
||||
} while (aSrc < end);
|
||||
}
|
||||
|
||||
template <bool aOpaqueAlpha, uint32_t aSrcAShift, uint32_t aDstAShift>
|
||||
static void SwizzleRowSwap(const uint8_t* aSrc, uint8_t* aDst,
|
||||
int32_t aLength) {
|
||||
SwizzleChunkSwap<aOpaqueAlpha, aSrcAShift, aDstAShift>(aSrc, aDst, aLength);
|
||||
}
|
||||
|
||||
template <bool aOpaqueAlpha, uint32_t aSrcAShift, uint32_t aDstAShift>
|
||||
static void SwizzleSwap(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
||||
int32_t aDstGap, IntSize aSize) {
|
||||
for (int32_t height = aSize.height; height > 0; height--) {
|
||||
SwizzleChunkSwap<aOpaqueAlpha, aSrcAShift, aDstAShift>(aSrc, aDst,
|
||||
aSize.width);
|
||||
const uint8_t* end = aSrc + 4 * aSize.width;
|
||||
do {
|
||||
// Use an endian swap to move the bytes, i.e. BGRA -> ARGB.
|
||||
uint32_t rgba = *reinterpret_cast<const uint32_t*>(aSrc);
|
||||
#if MOZ_LITTLE_ENDIAN
|
||||
rgba = NativeEndian::swapToBigEndian(rgba);
|
||||
#else
|
||||
rgba = NativeEndian::swapToLittleEndian(rgba);
|
||||
#endif
|
||||
if (aOpaqueAlpha) {
|
||||
rgba |= 0xFF << aDstAShift;
|
||||
}
|
||||
*reinterpret_cast<uint32_t*>(aDst) = rgba;
|
||||
aSrc += 4;
|
||||
aDst += 4;
|
||||
} while (aSrc < end);
|
||||
aSrc += aSrcGap;
|
||||
aDst += aDstGap;
|
||||
}
|
||||
|
@ -711,61 +548,34 @@ static void SwizzleSwap(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
|||
SwizzleSwap<ShouldForceOpaque(aSrcFormat, aDstFormat), \
|
||||
AlphaBitShift(aSrcFormat), AlphaBitShift(aDstFormat)>)
|
||||
|
||||
#define SWIZZLE_ROW_SWAP(aSrcFormat, aDstFormat) \
|
||||
FORMAT_CASE_ROW( \
|
||||
aSrcFormat, aDstFormat, \
|
||||
SwizzleRowSwap<ShouldForceOpaque(aSrcFormat, aDstFormat), \
|
||||
AlphaBitShift(aSrcFormat), AlphaBitShift(aDstFormat)>)
|
||||
|
||||
// Fast-path for conversions that force alpha to opaque.
|
||||
template <uint32_t aDstAShift>
|
||||
static void SwizzleChunkOpaqueUpdate(uint8_t*& aBuffer, int32_t aLength) {
|
||||
const uint8_t* end = aBuffer + 4 * aLength;
|
||||
do {
|
||||
uint32_t rgba = *reinterpret_cast<const uint32_t*>(aBuffer);
|
||||
// Just add on the alpha bits to the source.
|
||||
rgba |= 0xFF << aDstAShift;
|
||||
*reinterpret_cast<uint32_t*>(aBuffer) = rgba;
|
||||
aBuffer += 4;
|
||||
} while (aBuffer < end);
|
||||
}
|
||||
|
||||
template <uint32_t aDstAShift>
|
||||
static void SwizzleChunkOpaqueCopy(const uint8_t*& aSrc, uint8_t* aDst,
|
||||
int32_t aLength) {
|
||||
const uint8_t* end = aSrc + 4 * aLength;
|
||||
do {
|
||||
uint32_t rgba = *reinterpret_cast<const uint32_t*>(aSrc);
|
||||
// Just add on the alpha bits to the source.
|
||||
rgba |= 0xFF << aDstAShift;
|
||||
*reinterpret_cast<uint32_t*>(aDst) = rgba;
|
||||
aSrc += 4;
|
||||
aDst += 4;
|
||||
} while (aSrc < end);
|
||||
}
|
||||
|
||||
template <uint32_t aDstAShift>
|
||||
static void SwizzleRowOpaque(const uint8_t* aSrc, uint8_t* aDst,
|
||||
int32_t aLength) {
|
||||
if (aSrc == aDst) {
|
||||
SwizzleChunkOpaqueUpdate<aDstAShift>(aDst, aLength);
|
||||
} else {
|
||||
SwizzleChunkOpaqueCopy<aDstAShift>(aSrc, aDst, aLength);
|
||||
}
|
||||
}
|
||||
|
||||
template <uint32_t aDstAShift>
|
||||
static void SwizzleOpaque(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
||||
int32_t aDstGap, IntSize aSize) {
|
||||
if (aSrc == aDst) {
|
||||
// Modifying in-place, so just write out the alpha.
|
||||
for (int32_t height = aSize.height; height > 0; height--) {
|
||||
SwizzleChunkOpaqueUpdate<aDstAShift>(aDst, aSize.width);
|
||||
const uint8_t* end = aDst + 4 * aSize.width;
|
||||
do {
|
||||
// ORing directly onto destination memory profiles faster than writing
|
||||
// individually to the alpha byte and also profiles equivalently to a
|
||||
// SSE2 implementation.
|
||||
*reinterpret_cast<uint32_t*>(aDst) |= 0xFF << aDstAShift;
|
||||
aDst += 4;
|
||||
} while (aDst < end);
|
||||
aDst += aDstGap;
|
||||
}
|
||||
} else {
|
||||
for (int32_t height = aSize.height; height > 0; height--) {
|
||||
SwizzleChunkOpaqueCopy<aDstAShift>(aSrc, aDst, aSize.width);
|
||||
const uint8_t* end = aSrc + 4 * aSize.width;
|
||||
do {
|
||||
uint32_t rgba = *reinterpret_cast<const uint32_t*>(aSrc);
|
||||
// Just add on the alpha bits to the source.
|
||||
rgba |= 0xFF << aDstAShift;
|
||||
*reinterpret_cast<uint32_t*>(aDst) = rgba;
|
||||
aSrc += 4;
|
||||
aDst += 4;
|
||||
} while (aSrc < end);
|
||||
aSrc += aSrcGap;
|
||||
aDst += aDstGap;
|
||||
}
|
||||
|
@ -775,10 +585,6 @@ static void SwizzleOpaque(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
|||
#define SWIZZLE_OPAQUE(aSrcFormat, aDstFormat) \
|
||||
FORMAT_CASE(aSrcFormat, aDstFormat, SwizzleOpaque<AlphaBitShift(aDstFormat)>)
|
||||
|
||||
#define SWIZZLE_ROW_OPAQUE(aSrcFormat, aDstFormat) \
|
||||
FORMAT_CASE_ROW(aSrcFormat, aDstFormat, \
|
||||
SwizzleRowOpaque<AlphaBitShift(aDstFormat)>)
|
||||
|
||||
// Packing of 32-bit formats to RGB565.
|
||||
template <bool aSwapRB, uint32_t aSrcRGBShift, uint32_t aSrcRGBIndex>
|
||||
static void PackToRGB565(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
||||
|
@ -872,31 +678,6 @@ static void PackToA8(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
|||
PACK_ALPHA_CASE(SurfaceFormat::R8G8B8A8, aDstFormat, aPackFunc) \
|
||||
PACK_ALPHA_CASE(SurfaceFormat::A8R8G8B8, aDstFormat, aPackFunc)
|
||||
|
||||
template <bool aSwapRB>
|
||||
void UnpackRowRGB24(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) {
|
||||
// Because we are expanding, we can only process the data back to front in
|
||||
// case we are performing this in place.
|
||||
const uint8_t* src = aSrc + 3 * (aLength - 1);
|
||||
uint8_t* dst = aDst + 4 * (aLength - 1);
|
||||
while (src >= aSrc) {
|
||||
uint8_t r = src[aSwapRB ? 2 : 0];
|
||||
uint8_t g = src[1];
|
||||
uint8_t b = src[aSwapRB ? 0 : 2];
|
||||
|
||||
dst[0] = r;
|
||||
dst[1] = g;
|
||||
dst[2] = b;
|
||||
dst[3] = 0xFF;
|
||||
|
||||
src -= 3;
|
||||
dst -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
#define UNPACK_ROW_RGB(aDstFormat) \
|
||||
FORMAT_CASE_ROW(SurfaceFormat::R8G8B8, aDstFormat, \
|
||||
UnpackRowRGB24<ShouldSwapRB(SurfaceFormat::R8G8B8, aDstFormat)>)
|
||||
|
||||
bool SwizzleData(const uint8_t* aSrc, int32_t aSrcStride,
|
||||
SurfaceFormat aSrcFormat, uint8_t* aDst, int32_t aDstStride,
|
||||
SurfaceFormat aDstFormat, const IntSize& aSize) {
|
||||
|
@ -999,83 +780,5 @@ bool SwizzleData(const uint8_t* aSrc, int32_t aSrcStride,
|
|||
return false;
|
||||
}
|
||||
|
||||
SwizzleRowFn SwizzleRow(SurfaceFormat aSrcFormat, SurfaceFormat aDstFormat) {
|
||||
#ifdef USE_SSE2
|
||||
if (mozilla::supports_avx2()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
|
||||
UNPACK_ROW_RGB_AVX2(SurfaceFormat::R8G8B8X8)
|
||||
UNPACK_ROW_RGB_AVX2(SurfaceFormat::R8G8B8A8)
|
||||
UNPACK_ROW_RGB_AVX2(SurfaceFormat::B8G8R8X8)
|
||||
UNPACK_ROW_RGB_AVX2(SurfaceFormat::B8G8R8A8)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (mozilla::supports_ssse3()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
|
||||
UNPACK_ROW_RGB_SSSE3(SurfaceFormat::R8G8B8X8)
|
||||
UNPACK_ROW_RGB_SSSE3(SurfaceFormat::R8G8B8A8)
|
||||
UNPACK_ROW_RGB_SSSE3(SurfaceFormat::B8G8R8X8)
|
||||
UNPACK_ROW_RGB_SSSE3(SurfaceFormat::B8G8R8A8)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (mozilla::supports_sse2()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
|
||||
SWIZZLE_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8)
|
||||
SWIZZLE_ROW_SSE2(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8X8)
|
||||
SWIZZLE_ROW_SSE2(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8)
|
||||
SWIZZLE_ROW_SSE2(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8A8)
|
||||
SWIZZLE_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8)
|
||||
SWIZZLE_ROW_SSE2(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8X8)
|
||||
SWIZZLE_ROW_SSE2(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8)
|
||||
SWIZZLE_ROW_SSE2(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8A8)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_NEON
|
||||
if (mozilla::supports_neon()) switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
|
||||
SWIZZLE_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8)
|
||||
SWIZZLE_ROW_NEON(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8X8)
|
||||
SWIZZLE_ROW_NEON(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8)
|
||||
SWIZZLE_ROW_NEON(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8A8)
|
||||
SWIZZLE_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8)
|
||||
SWIZZLE_ROW_NEON(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8X8)
|
||||
SWIZZLE_ROW_NEON(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8)
|
||||
SWIZZLE_ROW_NEON(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8A8)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (FORMAT_KEY(aSrcFormat, aDstFormat)) {
|
||||
SWIZZLE_ROW_FALLBACK(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8)
|
||||
SWIZZLE_ROW_FALLBACK(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8X8)
|
||||
SWIZZLE_ROW_FALLBACK(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8)
|
||||
SWIZZLE_ROW_FALLBACK(SurfaceFormat::B8G8R8X8, SurfaceFormat::R8G8B8A8)
|
||||
|
||||
SWIZZLE_ROW_FALLBACK(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8)
|
||||
SWIZZLE_ROW_FALLBACK(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8X8)
|
||||
SWIZZLE_ROW_FALLBACK(SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8)
|
||||
SWIZZLE_ROW_FALLBACK(SurfaceFormat::R8G8B8X8, SurfaceFormat::B8G8R8A8)
|
||||
|
||||
SWIZZLE_ROW_OPAQUE(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8X8)
|
||||
SWIZZLE_ROW_OPAQUE(SurfaceFormat::B8G8R8X8, SurfaceFormat::B8G8R8A8)
|
||||
SWIZZLE_ROW_OPAQUE(SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8)
|
||||
SWIZZLE_ROW_OPAQUE(SurfaceFormat::R8G8B8X8, SurfaceFormat::R8G8B8A8)
|
||||
|
||||
UNPACK_ROW_RGB(SurfaceFormat::R8G8B8X8)
|
||||
UNPACK_ROW_RGB(SurfaceFormat::R8G8B8A8)
|
||||
UNPACK_ROW_RGB(SurfaceFormat::B8G8R8X8)
|
||||
UNPACK_ROW_RGB(SurfaceFormat::B8G8R8A8)
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_UNREACHABLE("Unsupported swizzle formats");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -41,22 +41,6 @@ GFX2D_API bool SwizzleData(const uint8_t* aSrc, int32_t aSrcStride,
|
|||
int32_t aDstStride, SurfaceFormat aDstFormat,
|
||||
const IntSize& aSize);
|
||||
|
||||
/**
|
||||
* Swizzles source and writes it to destination. Source and destination may be
|
||||
* the same to swizzle in-place.
|
||||
*/
|
||||
typedef void (*SwizzleRowFn)(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength);
|
||||
|
||||
/**
|
||||
* Get a function pointer to perform premultiplication between two formats.
|
||||
*/
|
||||
GFX2D_API SwizzleRowFn PremultiplyRow(SurfaceFormat aSrcFormat, SurfaceFormat aDstFormat);
|
||||
|
||||
/**
|
||||
* Get a function pointer to perform swizzling between two formats.
|
||||
*/
|
||||
GFX2D_API SwizzleRowFn SwizzleRow(SurfaceFormat aSrcFormat, SurfaceFormat aDstFormat);
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "Swizzle.h"
|
||||
|
||||
#include <immintrin.h>
|
||||
#include <tmmintrin.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
template <bool aSwapRB>
|
||||
void UnpackRowRGB24_SSSE3(const uint8_t*, uint8_t*, int32_t);
|
||||
|
||||
template <bool aSwapRB>
|
||||
void UnpackRowRGB24_AVX2(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) {
|
||||
// Because this implementation will read an additional 8 bytes of data that
|
||||
// is ignored and masked over, we cannot use the accelerated version for the
|
||||
// last 1-8 bytes to guarantee we don't access memory outside the buffer.
|
||||
if (aLength < 9) {
|
||||
UnpackRowRGB24_SSSE3<aSwapRB>(aSrc, aDst, aLength);
|
||||
return;
|
||||
}
|
||||
|
||||
// Because we are expanding, we can only process the data back to front in
|
||||
// case we are performing this in place.
|
||||
int32_t alignedRow = (aLength - 1) & ~7;
|
||||
int32_t remainder = aLength - alignedRow;
|
||||
|
||||
const uint8_t* src = aSrc + alignedRow * 3;
|
||||
uint8_t* dst = aDst + alignedRow * 4;
|
||||
|
||||
// Handle any 1-8 remaining pixels.
|
||||
UnpackRowRGB24_SSSE3<aSwapRB>(src, dst, remainder);
|
||||
|
||||
// Used to shuffle the two final 32-bit words which we ignore into the last
|
||||
// 32-bit word of each 128-bit lane, such that
|
||||
// RGBR GBRG BRGB RGBR GBRG BRGB RGBR GBRG
|
||||
// BRGB RGBR GBRG BRGB ZZZZ ZZZZ ZZZZ ZZZZ
|
||||
// becomes
|
||||
// RGBR GBRG BRGB RGBR GBRG BRGB ZZZZ ZZZZ
|
||||
// RGBR GBRG BRGB RGBR GBRG BRGB ZZZZ ZZZZ
|
||||
const __m256i discardMask = _mm256_set_epi32(7, 5, 4, 3, 6, 2, 1, 0);
|
||||
|
||||
// Used to shuffle 8-bit words within a 128-bit lane, such that we transform
|
||||
// RGBR GBRG BRGB RGBR GBRG BRGB ZZZZ ZZZZ
|
||||
// into
|
||||
// RGBZ RGBZ RGBZ RGBZ RGBZ RGBZ RGBZ RGBZ
|
||||
// or
|
||||
// BGRZ BGRZ BGRZ BGRZ BGRZ BGRZ BGRZ BGRZ
|
||||
const __m256i colorMask =
|
||||
aSwapRB ? _mm256_set_epi8(15, 9, 10, 11, 14, 6, 7, 8, 13, 3, 4, 5, 12, 0,
|
||||
1, 2, 15, 9, 10, 11, 14, 6, 7, 8, 13, 3, 4, 5,
|
||||
12, 0, 1, 2)
|
||||
: _mm256_set_epi8(15, 11, 10, 9, 14, 8, 7, 6, 13, 5, 4, 3, 12, 2,
|
||||
1, 0, 15, 11, 10, 9, 14, 8, 7, 6, 13, 5, 4, 3,
|
||||
12, 2, 1, 0);
|
||||
|
||||
// Used to transform RGBZ/BGRZ to RGBX/BGRX, or force the alpha opaque.
|
||||
const __m256i alphaMask = _mm256_set1_epi32(0xFF000000);
|
||||
|
||||
// Process all 8-pixel chunks as one vector.
|
||||
src -= 8 * 3;
|
||||
dst -= 8 * 4;
|
||||
while (src >= aSrc) {
|
||||
__m256i px = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(src));
|
||||
px = _mm256_permutevar8x32_epi32(px, discardMask);
|
||||
px = _mm256_shuffle_epi8(px, colorMask);
|
||||
px = _mm256_or_si256(px, alphaMask);
|
||||
_mm256_storeu_si256(reinterpret_cast<__m256i*>(dst), px);
|
||||
src -= 8 * 3;
|
||||
dst -= 8 * 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Force instantiation of swizzle variants here.
|
||||
template void UnpackRowRGB24_AVX2<false>(const uint8_t*, uint8_t*, int32_t);
|
||||
template void UnpackRowRGB24_AVX2<true>(const uint8_t*, uint8_t*, int32_t);
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
|
@ -85,36 +85,6 @@ PremultiplyVector_NEON(const uint16x8_t& aSrc) {
|
|||
return vsriq_n_u16(ga, rb, 8);
|
||||
}
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
static MOZ_ALWAYS_INLINE void PremultiplyChunk_NEON(const uint8_t*& aSrc,
|
||||
uint8_t*& aDst,
|
||||
int32_t aAlignedRow,
|
||||
int32_t aRemainder) {
|
||||
// Process all 4-pixel chunks as one vector.
|
||||
for (const uint8_t* end = aSrc + aAlignedRow; aSrc < end;) {
|
||||
uint16x8_t px = vld1q_u16(reinterpret_cast<const uint16_t*>(aSrc));
|
||||
px = PremultiplyVector_NEON<aSwapRB, aOpaqueAlpha>(px);
|
||||
vst1q_u16(reinterpret_cast<uint16_t*>(aDst), px);
|
||||
aSrc += 4 * 4;
|
||||
aDst += 4 * 4;
|
||||
}
|
||||
|
||||
// Handle any 1-3 remaining pixels.
|
||||
if (aRemainder) {
|
||||
uint16x8_t px = LoadRemainder_NEON(aSrc, aRemainder);
|
||||
px = PremultiplyVector_NEON<aSwapRB, aOpaqueAlpha>(px);
|
||||
StoreRemainder_NEON(aDst, aRemainder, px);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
void PremultiplyRow_NEON(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) {
|
||||
int32_t alignedRow = 4 * (aLength & ~3);
|
||||
int32_t remainder = aLength & 3;
|
||||
PremultiplyChunk_NEON<aSwapRB, aOpaqueAlpha>(aSrc, aDst, alignedRow,
|
||||
remainder);
|
||||
}
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
void Premultiply_NEON(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
||||
int32_t aDstGap, IntSize aSize) {
|
||||
|
@ -125,22 +95,28 @@ void Premultiply_NEON(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
|||
aDstGap += 4 * remainder;
|
||||
|
||||
for (int32_t height = aSize.height; height > 0; height--) {
|
||||
PremultiplyChunk_NEON<aSwapRB, aOpaqueAlpha>(aSrc, aDst, alignedRow,
|
||||
remainder);
|
||||
// Process all 4-pixel chunks as one vector.
|
||||
for (const uint8_t* end = aSrc + alignedRow; aSrc < end;) {
|
||||
uint16x8_t px = vld1q_u16(reinterpret_cast<const uint16_t*>(aSrc));
|
||||
px = PremultiplyVector_NEON<aSwapRB, aOpaqueAlpha>(px);
|
||||
vst1q_u16(reinterpret_cast<uint16_t*>(aDst), px);
|
||||
aSrc += 4 * 4;
|
||||
aDst += 4 * 4;
|
||||
}
|
||||
|
||||
// Handle any 1-3 remaining pixels.
|
||||
if (remainder) {
|
||||
uint16x8_t px = LoadRemainder_NEON(aSrc, remainder);
|
||||
px = PremultiplyVector_NEON<aSwapRB, aOpaqueAlpha>(px);
|
||||
StoreRemainder_NEON(aDst, remainder, px);
|
||||
}
|
||||
|
||||
aSrc += aSrcGap;
|
||||
aDst += aDstGap;
|
||||
}
|
||||
}
|
||||
|
||||
// Force instantiation of premultiply variants here.
|
||||
template void PremultiplyRow_NEON<false, false>(const uint8_t*, uint8_t*,
|
||||
int32_t);
|
||||
template void PremultiplyRow_NEON<false, true>(const uint8_t*, uint8_t*,
|
||||
int32_t);
|
||||
template void PremultiplyRow_NEON<true, false>(const uint8_t*, uint8_t*,
|
||||
int32_t);
|
||||
template void PremultiplyRow_NEON<true, true>(const uint8_t*, uint8_t*,
|
||||
int32_t);
|
||||
template void Premultiply_NEON<false, false>(const uint8_t*, int32_t, uint8_t*,
|
||||
int32_t, IntSize);
|
||||
template void Premultiply_NEON<false, true>(const uint8_t*, int32_t, uint8_t*,
|
||||
|
@ -282,7 +258,7 @@ template void Unpremultiply_NEON<true>(const uint8_t*, int32_t, uint8_t*,
|
|||
|
||||
// Swizzle a vector of 4 pixels providing swaps and opaquifying.
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
static MOZ_ALWAYS_INLINE uint16x8_t SwizzleVector_NEON(const uint16x8_t& aSrc) {
|
||||
MOZ_ALWAYS_INLINE uint16x8_t SwizzleVector_NEON(const uint16x8_t& aSrc) {
|
||||
// Swap R and B, then add to G and A (forced to 255):
|
||||
// (((src>>16) | (src << 16)) & 0x00FF00FF) |
|
||||
// ((src | 0xFF000000) & ~0x00FF00FF)
|
||||
|
@ -299,7 +275,7 @@ static MOZ_ALWAYS_INLINE uint16x8_t SwizzleVector_NEON(const uint16x8_t& aSrc) {
|
|||
|
||||
// Optimized implementations for when there is no R and B swap.
|
||||
template<>
|
||||
static MOZ_ALWAYS_INLINE uint16x8_t
|
||||
MOZ_ALWAYS_INLINE uint16x8_t
|
||||
SwizzleVector_NEON<false, true>(const uint16x8_t& aSrc)
|
||||
{
|
||||
// Force alpha to 255.
|
||||
|
@ -307,42 +283,13 @@ SwizzleVector_NEON<false, true>(const uint16x8_t& aSrc)
|
|||
}
|
||||
|
||||
template<>
|
||||
static MOZ_ALWAYS_INLINE uint16x8_t
|
||||
MOZ_ALWAYS_INLINE uint16x8_t
|
||||
SwizzleVector_NEON<false, false>(const uint16x8_t& aSrc)
|
||||
{
|
||||
return aSrc;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
static MOZ_ALWAYS_INLINE void SwizzleChunk_NEON(const uint8_t*& aSrc,
|
||||
uint8_t*& aDst,
|
||||
int32_t aAlignedRow,
|
||||
int32_t aRemainder) {
|
||||
// Process all 4-pixel chunks as one vector.
|
||||
for (const uint8_t* end = aSrc + aAlignedRow; aSrc < end;) {
|
||||
uint16x8_t px = vld1q_u16(reinterpret_cast<const uint16_t*>(aSrc));
|
||||
px = SwizzleVector_NEON<aSwapRB, aOpaqueAlpha>(px);
|
||||
vst1q_u16(reinterpret_cast<uint16_t*>(aDst), px);
|
||||
aSrc += 4 * 4;
|
||||
aDst += 4 * 4;
|
||||
}
|
||||
|
||||
// Handle any 1-3 remaining pixels.
|
||||
if (aRemainder) {
|
||||
uint16x8_t px = LoadRemainder_NEON(aSrc, aRemainder);
|
||||
px = SwizzleVector_NEON<aSwapRB, aOpaqueAlpha>(px);
|
||||
StoreRemainder_NEON(aDst, aRemainder, px);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
void SwizzleRow_NEON(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) {
|
||||
int32_t alignedRow = 4 * (aLength & ~3);
|
||||
int32_t remainder = aLength & 3;
|
||||
SwizzleChunk_NEON<aSwapRB, aOpaqueAlpha>(aSrc, aDst, alignedRow, remainder);
|
||||
}
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
void Swizzle_NEON(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
||||
int32_t aDstGap, IntSize aSize) {
|
||||
|
@ -353,16 +300,28 @@ void Swizzle_NEON(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
|||
aDstGap += 4 * remainder;
|
||||
|
||||
for (int32_t height = aSize.height; height > 0; height--) {
|
||||
SwizzleChunk_NEON<aSwapRB, aOpaqueAlpha>(aSrc, aDst, alignedRow,
|
||||
remainder);
|
||||
// Process all 4-pixel chunks as one vector.
|
||||
for (const uint8_t* end = aSrc + alignedRow; aSrc < end;) {
|
||||
uint16x8_t px = vld1q_u16(reinterpret_cast<const uint16_t*>(aSrc));
|
||||
px = SwizzleVector_NEON<aSwapRB, aOpaqueAlpha>(px);
|
||||
vst1q_u16(reinterpret_cast<uint16_t*>(aDst), px);
|
||||
aSrc += 4 * 4;
|
||||
aDst += 4 * 4;
|
||||
}
|
||||
|
||||
// Handle any 1-3 remaining pixels.
|
||||
if (remainder) {
|
||||
uint16x8_t px = LoadRemainder_NEON(aSrc, remainder);
|
||||
px = SwizzleVector_NEON<aSwapRB, aOpaqueAlpha>(px);
|
||||
StoreRemainder_NEON(aDst, remainder, px);
|
||||
}
|
||||
|
||||
aSrc += aSrcGap;
|
||||
aDst += aDstGap;
|
||||
}
|
||||
}
|
||||
|
||||
// Force instantiation of swizzle variants here.
|
||||
template void SwizzleRow_NEON<true, false>(const uint8_t*, uint8_t*, int32_t);
|
||||
template void SwizzleRow_NEON<true, true>(const uint8_t*, uint8_t*, int32_t);
|
||||
template void Swizzle_NEON<true, false>(const uint8_t*, int32_t, uint8_t*,
|
||||
int32_t, IntSize);
|
||||
template void Swizzle_NEON<true, true>(const uint8_t*, int32_t, uint8_t*,
|
||||
|
|
|
@ -88,38 +88,6 @@ static MOZ_ALWAYS_INLINE __m128i PremultiplyVector_SSE2(const __m128i& aSrc) {
|
|||
return _mm_or_si128(rb, ga);
|
||||
}
|
||||
|
||||
// Premultiply vector of aAlignedRow + aRemainder pixels.
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
static MOZ_ALWAYS_INLINE void PremultiplyChunk_SSE2(const uint8_t*& aSrc,
|
||||
uint8_t*& aDst,
|
||||
int32_t aAlignedRow,
|
||||
int32_t aRemainder) {
|
||||
// Process all 4-pixel chunks as one vector.
|
||||
for (const uint8_t* end = aSrc + aAlignedRow; aSrc < end;) {
|
||||
__m128i px = _mm_loadu_si128(reinterpret_cast<const __m128i*>(aSrc));
|
||||
px = PremultiplyVector_SSE2<aSwapRB, aOpaqueAlpha>(px);
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i*>(aDst), px);
|
||||
aSrc += 4 * 4;
|
||||
aDst += 4 * 4;
|
||||
}
|
||||
|
||||
// Handle any 1-3 remaining pixels.
|
||||
if (aRemainder) {
|
||||
__m128i px = LoadRemainder_SSE2(aSrc, aRemainder);
|
||||
px = PremultiplyVector_SSE2<aSwapRB, aOpaqueAlpha>(px);
|
||||
StoreRemainder_SSE2(aDst, aRemainder, px);
|
||||
}
|
||||
}
|
||||
|
||||
// Premultiply vector of aLength pixels.
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
void PremultiplyRow_SSE2(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) {
|
||||
int32_t alignedRow = 4 * (aLength & ~3);
|
||||
int32_t remainder = aLength & 3;
|
||||
PremultiplyChunk_SSE2<aSwapRB, aOpaqueAlpha>(aSrc, aDst, alignedRow,
|
||||
remainder);
|
||||
}
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
void Premultiply_SSE2(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
||||
int32_t aDstGap, IntSize aSize) {
|
||||
|
@ -130,22 +98,28 @@ void Premultiply_SSE2(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
|||
aDstGap += 4 * remainder;
|
||||
|
||||
for (int32_t height = aSize.height; height > 0; height--) {
|
||||
PremultiplyChunk_SSE2<aSwapRB, aOpaqueAlpha>(aSrc, aDst, alignedRow,
|
||||
remainder);
|
||||
// Process all 4-pixel chunks as one vector.
|
||||
for (const uint8_t* end = aSrc + alignedRow; aSrc < end;) {
|
||||
__m128i px = _mm_loadu_si128(reinterpret_cast<const __m128i*>(aSrc));
|
||||
px = PremultiplyVector_SSE2<aSwapRB, aOpaqueAlpha>(px);
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i*>(aDst), px);
|
||||
aSrc += 4 * 4;
|
||||
aDst += 4 * 4;
|
||||
}
|
||||
|
||||
// Handle any 1-3 remaining pixels.
|
||||
if (remainder) {
|
||||
__m128i px = LoadRemainder_SSE2(aSrc, remainder);
|
||||
px = PremultiplyVector_SSE2<aSwapRB, aOpaqueAlpha>(px);
|
||||
StoreRemainder_SSE2(aDst, remainder, px);
|
||||
}
|
||||
|
||||
aSrc += aSrcGap;
|
||||
aDst += aDstGap;
|
||||
}
|
||||
}
|
||||
|
||||
// Force instantiation of premultiply variants here.
|
||||
template void PremultiplyRow_SSE2<false, false>(const uint8_t*, uint8_t*,
|
||||
int32_t);
|
||||
template void PremultiplyRow_SSE2<false, true>(const uint8_t*, uint8_t*,
|
||||
int32_t);
|
||||
template void PremultiplyRow_SSE2<true, false>(const uint8_t*, uint8_t*,
|
||||
int32_t);
|
||||
template void PremultiplyRow_SSE2<true, true>(const uint8_t*, uint8_t*,
|
||||
int32_t);
|
||||
template void Premultiply_SSE2<false, false>(const uint8_t*, int32_t, uint8_t*,
|
||||
int32_t, IntSize);
|
||||
template void Premultiply_SSE2<false, true>(const uint8_t*, int32_t, uint8_t*,
|
||||
|
@ -319,35 +293,6 @@ SwizzleVector_SSE2<false, false>(const __m128i& aSrc)
|
|||
}
|
||||
#endif
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
static MOZ_ALWAYS_INLINE void SwizzleChunk_SSE2(const uint8_t*& aSrc,
|
||||
uint8_t*& aDst,
|
||||
int32_t aAlignedRow,
|
||||
int32_t aRemainder) {
|
||||
// Process all 4-pixel chunks as one vector.
|
||||
for (const uint8_t* end = aSrc + aAlignedRow; aSrc < end;) {
|
||||
__m128i px = _mm_loadu_si128(reinterpret_cast<const __m128i*>(aSrc));
|
||||
px = SwizzleVector_SSE2<aSwapRB, aOpaqueAlpha>(px);
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i*>(aDst), px);
|
||||
aSrc += 4 * 4;
|
||||
aDst += 4 * 4;
|
||||
}
|
||||
|
||||
// Handle any 1-3 remaining pixels.
|
||||
if (aRemainder) {
|
||||
__m128i px = LoadRemainder_SSE2(aSrc, aRemainder);
|
||||
px = SwizzleVector_SSE2<aSwapRB, aOpaqueAlpha>(px);
|
||||
StoreRemainder_SSE2(aDst, aRemainder, px);
|
||||
}
|
||||
}
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
void SwizzleRow_SSE2(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) {
|
||||
int32_t alignedRow = 4 * (aLength & ~3);
|
||||
int32_t remainder = aLength & 3;
|
||||
SwizzleChunk_SSE2<aSwapRB, aOpaqueAlpha>(aSrc, aDst, alignedRow, remainder);
|
||||
}
|
||||
|
||||
template <bool aSwapRB, bool aOpaqueAlpha>
|
||||
void Swizzle_SSE2(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
||||
int32_t aDstGap, IntSize aSize) {
|
||||
|
@ -358,15 +303,28 @@ void Swizzle_SSE2(const uint8_t* aSrc, int32_t aSrcGap, uint8_t* aDst,
|
|||
aDstGap += 4 * remainder;
|
||||
|
||||
for (int32_t height = aSize.height; height > 0; height--) {
|
||||
SwizzleChunk_SSE2<aSwapRB, aOpaqueAlpha>(aSrc, aDst, alignedRow, remainder);
|
||||
// Process all 4-pixel chunks as one vector.
|
||||
for (const uint8_t* end = aSrc + alignedRow; aSrc < end;) {
|
||||
__m128i px = _mm_loadu_si128(reinterpret_cast<const __m128i*>(aSrc));
|
||||
px = SwizzleVector_SSE2<aSwapRB, aOpaqueAlpha>(px);
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i*>(aDst), px);
|
||||
aSrc += 4 * 4;
|
||||
aDst += 4 * 4;
|
||||
}
|
||||
|
||||
// Handle any 1-3 remaining pixels.
|
||||
if (remainder) {
|
||||
__m128i px = LoadRemainder_SSE2(aSrc, remainder);
|
||||
px = SwizzleVector_SSE2<aSwapRB, aOpaqueAlpha>(px);
|
||||
StoreRemainder_SSE2(aDst, remainder, px);
|
||||
}
|
||||
|
||||
aSrc += aSrcGap;
|
||||
aDst += aDstGap;
|
||||
}
|
||||
}
|
||||
|
||||
// Force instantiation of swizzle variants here.
|
||||
template void SwizzleRow_SSE2<true, false>(const uint8_t*, uint8_t*, int32_t);
|
||||
template void SwizzleRow_SSE2<true, true>(const uint8_t*, uint8_t*, int32_t);
|
||||
template void Swizzle_SSE2<true, false>(const uint8_t*, int32_t, uint8_t*,
|
||||
int32_t, IntSize);
|
||||
template void Swizzle_SSE2<true, true>(const uint8_t*, int32_t, uint8_t*,
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "Swizzle.h"
|
||||
|
||||
#include <emmintrin.h>
|
||||
#include <tmmintrin.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
template <bool aSwapRB>
|
||||
void UnpackRowRGB24(const uint8_t*, uint8_t*, int32_t);
|
||||
|
||||
template <bool aSwapRB>
|
||||
void UnpackRowRGB24_SSSE3(const uint8_t* aSrc, uint8_t* aDst, int32_t aLength) {
|
||||
// Because this implementation will read an additional 4 bytes of data that
|
||||
// is ignored and masked over, we cannot use the accelerated version for the
|
||||
// last 1-4 bytes to guarantee we don't access memory outside the buffer.
|
||||
if (aLength < 5) {
|
||||
UnpackRowRGB24<aSwapRB>(aSrc, aDst, aLength);
|
||||
return;
|
||||
}
|
||||
|
||||
// Because we are expanding, we can only process the data back to front in
|
||||
// case we are performing this in place.
|
||||
int32_t alignedRow = (aLength - 1) & ~3;
|
||||
int32_t remainder = aLength - alignedRow;
|
||||
|
||||
const uint8_t* src = aSrc + alignedRow * 3;
|
||||
uint8_t* dst = aDst + alignedRow * 4;
|
||||
|
||||
// Handle 1-4 remaining pixels.
|
||||
UnpackRowRGB24<aSwapRB>(src, dst, remainder);
|
||||
|
||||
__m128i mask;
|
||||
if (aSwapRB) {
|
||||
mask = _mm_set_epi8(15, 9, 10, 11, 14, 6, 7, 8, 13, 3, 4, 5, 12, 0, 1, 2);
|
||||
} else {
|
||||
mask = _mm_set_epi8(15, 11, 10, 9, 14, 8, 7, 6, 13, 5, 4, 3, 12, 2, 1, 0);
|
||||
}
|
||||
|
||||
__m128i alpha = _mm_set1_epi32(0xFF000000);
|
||||
|
||||
// Process all 4-pixel chunks as one vector.
|
||||
src -= 4 * 3;
|
||||
dst -= 4 * 4;
|
||||
while (src >= aSrc) {
|
||||
__m128i px = _mm_loadu_si128(reinterpret_cast<const __m128i*>(src));
|
||||
px = _mm_shuffle_epi8(px, mask);
|
||||
px = _mm_or_si128(px, alpha);
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i*>(dst), px);
|
||||
src -= 4 * 3;
|
||||
dst -= 4 * 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Force instantiation of swizzle variants here.
|
||||
template void UnpackRowRGB24_SSSE3<false>(const uint8_t*, uint8_t*, int32_t);
|
||||
template void UnpackRowRGB24_SSSE3<true>(const uint8_t*, uint8_t*, int32_t);
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
|
@ -145,9 +145,7 @@ if CONFIG['INTEL_ARCHITECTURE']:
|
|||
'FilterProcessingSSE2.cpp',
|
||||
'ImageScalingSSE2.cpp',
|
||||
'ssse3-scaler.c',
|
||||
'SwizzleAVX2.cpp',
|
||||
'SwizzleSSE2.cpp',
|
||||
'SwizzleSSSE3.cpp',
|
||||
]
|
||||
DEFINES['USE_SSE2'] = True
|
||||
# The file uses SSE2 intrinsics, so it needs special compile flags on some
|
||||
|
@ -155,9 +153,7 @@ if CONFIG['INTEL_ARCHITECTURE']:
|
|||
SOURCES['BlurSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
|
||||
SOURCES['FilterProcessingSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
|
||||
SOURCES['ImageScalingSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
|
||||
SOURCES['SwizzleAVX2.cpp'].flags += ['-mavx2']
|
||||
SOURCES['SwizzleSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
|
||||
SOURCES['SwizzleSSSE3.cpp'].flags += CONFIG['SSSE3_FLAGS']
|
||||
SOURCES['ssse3-scaler.c'].flags += CONFIG['SSSE3_FLAGS']
|
||||
elif CONFIG['CPU_ARCH'].startswith('mips'):
|
||||
SOURCES += [
|
||||
|
|
|
@ -45,34 +45,6 @@ TEST(Moz2D, PremultiplyData)
|
|||
EXPECT_TRUE(ArrayEqual(out, check_argb));
|
||||
}
|
||||
|
||||
TEST(Moz2D, PremultiplyRow)
|
||||
{
|
||||
const uint8_t in_bgra[5 * 4] = {
|
||||
255, 255, 0, 255, // verify 255 alpha leaves RGB unchanged
|
||||
0, 0, 255, 255,
|
||||
0, 255, 255, 0, // verify 0 alpha zeroes out RGB
|
||||
0, 0, 0, 0,
|
||||
255, 0, 0, 128, // verify that 255 RGB maps to alpha
|
||||
};
|
||||
uint8_t out[5 * 4];
|
||||
const uint8_t check_bgra[5 * 4] = {
|
||||
255, 255, 0, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 128,
|
||||
};
|
||||
// check swizzled output
|
||||
const uint8_t check_rgba[5 * 4] = {
|
||||
0, 255, 255, 255, 255, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128,
|
||||
};
|
||||
|
||||
SwizzleRowFn func =
|
||||
PremultiplyRow(SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8);
|
||||
func(in_bgra, out, 5);
|
||||
EXPECT_TRUE(ArrayEqual(out, check_bgra));
|
||||
|
||||
func = PremultiplyRow(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8);
|
||||
func(in_bgra, out, 5);
|
||||
EXPECT_TRUE(ArrayEqual(out, check_rgba));
|
||||
}
|
||||
|
||||
TEST(Moz2D, UnpremultiplyData)
|
||||
{
|
||||
const uint8_t in_bgra[5 * 4] = {
|
||||
|
@ -183,68 +155,3 @@ TEST(Moz2D, SwizzleData)
|
|||
SurfaceFormat::R5G6B5_UINT16, IntSize(5, 1));
|
||||
EXPECT_TRUE(ArrayEqual(out16, check_16));
|
||||
}
|
||||
|
||||
TEST(Moz2D, SwizzleRow)
|
||||
{
|
||||
const uint8_t in_bgra[5 * 4] = {
|
||||
253, 254, 0, 255, 0, 0, 255, 255, 0, 0, 0, 0, 1, 2, 3, 64, 127, 0, 9, 128,
|
||||
|
||||
};
|
||||
uint8_t out[5 * 4];
|
||||
// check swaps
|
||||
const uint8_t check_rgba[5 * 4] = {
|
||||
0, 254, 253, 255, 255, 0, 0, 255, 0, 0, 0, 0, 3, 2, 1, 64, 9, 0, 127, 128,
|
||||
};
|
||||
// check opaquifying
|
||||
const uint8_t check_rgbx[5 * 4] = {
|
||||
0, 254, 253, 255, 255, 0, 0, 255, 0, 0,
|
||||
0, 255, 3, 2, 1, 255, 9, 0, 127, 255,
|
||||
};
|
||||
// check unpacking
|
||||
uint8_t out_unpack[16 * 4];
|
||||
const uint8_t in_rgb[16 * 3] = {
|
||||
0, 254, 253, 255, 0, 0, 0, 0, 0, 3, 2, 1,
|
||||
9, 0, 127, 4, 5, 6, 9, 8, 7, 10, 11, 12,
|
||||
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
|
||||
};
|
||||
const uint8_t check_unpack_rgbx[16 * 4] = {
|
||||
0, 254, 253, 255, 255, 0, 0, 255, 0, 0, 0, 255, 3, 2, 1, 255,
|
||||
9, 0, 127, 255, 4, 5, 6, 255, 9, 8, 7, 255, 10, 11, 12, 255,
|
||||
13, 14, 15, 255, 16, 17, 18, 255, 19, 20, 21, 255, 22, 23, 24, 255,
|
||||
25, 26, 27, 255, 28, 29, 30, 255, 31, 32, 33, 255, 34, 35, 36, 255,
|
||||
};
|
||||
const uint8_t check_unpack_bgrx[16 * 4] = {
|
||||
253, 254, 0, 255, 0, 0, 255, 255, 0, 0, 0, 255, 1, 2, 3, 255,
|
||||
127, 0, 9, 255, 6, 5, 4, 255, 7, 8, 9, 255, 12, 11, 10, 255,
|
||||
15, 14, 13, 255, 18, 17, 16, 255, 21, 20, 19, 255, 24, 23, 22, 255,
|
||||
27, 26, 25, 255, 30, 29, 28, 255, 33, 32, 31, 255, 36, 35, 34, 255,
|
||||
};
|
||||
|
||||
SwizzleRowFn func =
|
||||
SwizzleRow(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8A8);
|
||||
func(in_bgra, out, 5);
|
||||
EXPECT_TRUE(ArrayEqual(out, check_rgba));
|
||||
|
||||
func = SwizzleRow(SurfaceFormat::B8G8R8A8, SurfaceFormat::R8G8B8X8);
|
||||
func(in_bgra, out, 5);
|
||||
EXPECT_TRUE(ArrayEqual(out, check_rgbx));
|
||||
|
||||
func = SwizzleRow(SurfaceFormat::R8G8B8, SurfaceFormat::B8G8R8X8);
|
||||
func(in_rgb, out_unpack, 16);
|
||||
EXPECT_TRUE(ArrayEqual(out_unpack, check_unpack_bgrx));
|
||||
|
||||
memset(out_unpack, 0xE5, sizeof(out_unpack));
|
||||
memcpy(out_unpack, in_rgb, sizeof(in_rgb));
|
||||
func(out_unpack, out_unpack, 16);
|
||||
EXPECT_TRUE(ArrayEqual(out_unpack, check_unpack_bgrx));
|
||||
|
||||
func = SwizzleRow(SurfaceFormat::R8G8B8, SurfaceFormat::R8G8B8X8);
|
||||
func(in_rgb, out_unpack, 16);
|
||||
EXPECT_TRUE(ArrayEqual(out_unpack, check_unpack_rgbx));
|
||||
|
||||
memset(out_unpack, 0xE5, sizeof(out_unpack));
|
||||
memcpy(out_unpack, in_rgb, sizeof(in_rgb));
|
||||
func(out_unpack, out_unpack, 16);
|
||||
EXPECT_TRUE(ArrayEqual(out_unpack, check_unpack_rgbx));
|
||||
}
|
||||
|
|
|
@ -78,10 +78,6 @@ class DownscalingFilter final : public SurfaceFilter {
|
|||
MOZ_CRASH();
|
||||
return nullptr;
|
||||
}
|
||||
uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override {
|
||||
MOZ_CRASH();
|
||||
return nullptr;
|
||||
}
|
||||
uint8_t* DoAdvanceRow() override {
|
||||
MOZ_CRASH();
|
||||
return nullptr;
|
||||
|
@ -210,7 +206,7 @@ class DownscalingFilter final : public SurfaceFilter {
|
|||
return GetRowPointer();
|
||||
}
|
||||
|
||||
uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override {
|
||||
uint8_t* DoAdvanceRow() override {
|
||||
if (mInputRow >= mInputSize.height) {
|
||||
NS_WARNING("Advancing DownscalingFilter past the end of the input");
|
||||
return nullptr;
|
||||
|
@ -230,7 +226,7 @@ class DownscalingFilter final : public SurfaceFilter {
|
|||
if (mInputRow == inputRowToRead) {
|
||||
MOZ_RELEASE_ASSERT(mRowsInWindow < mWindowCapacity,
|
||||
"Need more rows than capacity!");
|
||||
mXFilter.ConvolveHorizontally(aInputRow, mWindow[mRowsInWindow++],
|
||||
mXFilter.ConvolveHorizontally(mRowBuffer.get(), mWindow[mRowsInWindow++],
|
||||
mHasAlpha);
|
||||
}
|
||||
|
||||
|
@ -253,10 +249,6 @@ class DownscalingFilter final : public SurfaceFilter {
|
|||
return mInputRow < mInputSize.height ? GetRowPointer() : nullptr;
|
||||
}
|
||||
|
||||
uint8_t* DoAdvanceRow() override {
|
||||
return DoAdvanceRowFromBuffer(mRowBuffer.get());
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t* GetRowPointer() const { return mRowBuffer.get(); }
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#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"
|
||||
|
@ -30,83 +29,6 @@
|
|||
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
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -158,14 +80,10 @@ class ColorManagementFilter final : public SurfaceFilter {
|
|||
protected:
|
||||
uint8_t* DoResetToFirstRow() override { return mNext.ResetToFirstRow(); }
|
||||
|
||||
uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override {
|
||||
qcms_transform_data(mTransform, aInputRow, mNext.CurrentRowPointer(),
|
||||
mNext.InputSize().width);
|
||||
return mNext.AdvanceRow();
|
||||
}
|
||||
|
||||
uint8_t* DoAdvanceRow() override {
|
||||
return DoAdvanceRowFromBuffer(mNext.CurrentRowPointer());
|
||||
uint8_t* rowPtr = mNext.CurrentRowPointer();
|
||||
qcms_transform_data(mTransform, rowPtr, rowPtr, mNext.InputSize().width);
|
||||
return mNext.AdvanceRow();
|
||||
}
|
||||
|
||||
Next mNext; /// The next SurfaceFilter in the chain.
|
||||
|
@ -264,11 +182,6 @@ class DeinterlacingFilter final : public SurfaceFilter {
|
|||
return GetRowPointer(mOutputRow);
|
||||
}
|
||||
|
||||
uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override {
|
||||
CopyInputRow(aInputRow);
|
||||
return DoAdvanceRow();
|
||||
}
|
||||
|
||||
uint8_t* DoAdvanceRow() override {
|
||||
if (mPass >= 4) {
|
||||
return nullptr; // We already finished all passes.
|
||||
|
@ -725,11 +638,6 @@ class BlendAnimationFilter final : public SurfaceFilter {
|
|||
return nullptr; // We're done.
|
||||
}
|
||||
|
||||
uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override {
|
||||
CopyInputRow(aInputRow);
|
||||
return DoAdvanceRow();
|
||||
}
|
||||
|
||||
uint8_t* DoAdvanceRow() override {
|
||||
uint8_t* rowPtr = nullptr;
|
||||
|
||||
|
@ -1004,11 +912,6 @@ class RemoveFrameRectFilter final : public SurfaceFilter {
|
|||
return nullptr; // We're done.
|
||||
}
|
||||
|
||||
uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override {
|
||||
CopyInputRow(aInputRow);
|
||||
return DoAdvanceRow();
|
||||
}
|
||||
|
||||
uint8_t* DoAdvanceRow() override {
|
||||
uint8_t* rowPtr = nullptr;
|
||||
|
||||
|
@ -1194,11 +1097,6 @@ class ADAM7InterpolatingFilter final : public SurfaceFilter {
|
|||
return mCurrentRow.get();
|
||||
}
|
||||
|
||||
uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) override {
|
||||
CopyInputRow(aInputRow);
|
||||
return DoAdvanceRow();
|
||||
}
|
||||
|
||||
uint8_t* DoAdvanceRow() override {
|
||||
MOZ_ASSERT(0 < mPass && mPass <= 7, "Invalid pass");
|
||||
|
||||
|
|
|
@ -36,11 +36,6 @@ uint8_t* AbstractSurfaceSink::DoResetToFirstRow() {
|
|||
return GetRowPointer();
|
||||
}
|
||||
|
||||
uint8_t* AbstractSurfaceSink::DoAdvanceRowFromBuffer(const uint8_t* aInputRow) {
|
||||
CopyInputRow(aInputRow);
|
||||
return DoAdvanceRow();
|
||||
}
|
||||
|
||||
uint8_t* AbstractSurfaceSink::DoAdvanceRow() {
|
||||
if (mRow >= uint32_t(InputSize().height)) {
|
||||
return nullptr;
|
||||
|
|
|
@ -127,19 +127,6 @@ class SurfaceFilter {
|
|||
return mRowPointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by WriteBuffer() to advance this filter to the next row, if the
|
||||
* supplied row is a full row.
|
||||
*
|
||||
* @return a pointer to the buffer for the next row, or nullptr to indicate
|
||||
* that we've finished the entire surface.
|
||||
*/
|
||||
uint8_t* AdvanceRow(const uint8_t* aInputRow) {
|
||||
mCol = 0;
|
||||
mRowPointer = DoAdvanceRowFromBuffer(aInputRow);
|
||||
return mRowPointer;
|
||||
}
|
||||
|
||||
/// @return a pointer to the buffer for the current row.
|
||||
uint8_t* CurrentRowPointer() const { return mRowPointer; }
|
||||
|
||||
|
@ -282,22 +269,7 @@ class SurfaceFilter {
|
|||
*/
|
||||
template <typename PixelType>
|
||||
WriteState WriteBuffer(const PixelType* aSource) {
|
||||
MOZ_ASSERT(mPixelSize == 1 || mPixelSize == 4);
|
||||
MOZ_ASSERT_IF(mPixelSize == 1, sizeof(PixelType) == sizeof(uint8_t));
|
||||
MOZ_ASSERT_IF(mPixelSize == 4, sizeof(PixelType) == sizeof(uint32_t));
|
||||
|
||||
if (IsSurfaceFinished()) {
|
||||
return WriteState::FINISHED; // Already done.
|
||||
}
|
||||
|
||||
if (MOZ_UNLIKELY(!aSource)) {
|
||||
NS_WARNING("Passed a null pointer to WriteBuffer");
|
||||
return WriteState::FAILURE;
|
||||
}
|
||||
|
||||
AdvanceRow(reinterpret_cast<const uint8_t*>(aSource));
|
||||
return IsSurfaceFinished() ? WriteState::FINISHED
|
||||
: WriteState::NEED_MORE_DATA;
|
||||
return WriteBuffer(aSource, 0, mInputSize.width);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -468,16 +440,6 @@ class SurfaceFilter {
|
|||
*/
|
||||
virtual uint8_t* DoResetToFirstRow() = 0;
|
||||
|
||||
/**
|
||||
* Called by AdvanceRow() to actually advance this filter to the next row.
|
||||
*
|
||||
* @param aInputRow The input row supplied by the decoder.
|
||||
*
|
||||
* @return a pointer to the buffer for the next row, or nullptr to indicate
|
||||
* that we've finished the entire surface.
|
||||
*/
|
||||
virtual uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) = 0;
|
||||
|
||||
/**
|
||||
* Called by AdvanceRow() to actually advance this filter to the next row.
|
||||
*
|
||||
|
@ -508,20 +470,6 @@ class SurfaceFilter {
|
|||
ResetToFirstRow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by subclasses' DoAdvanceRowFromBuffer() methods to copy a decoder
|
||||
* supplied row buffer into its internal row pointer. Ideally filters at the
|
||||
* top of the filter pipeline are able to consume the decoder row buffer
|
||||
* directly without the extra copy prior to performing its transformation.
|
||||
*
|
||||
* @param aInputRow The input row supplied by the decoder.
|
||||
*/
|
||||
void CopyInputRow(const uint8_t* aInputRow) {
|
||||
MOZ_ASSERT(aInputRow);
|
||||
MOZ_ASSERT(mCol == 0);
|
||||
memcpy(mRowPointer, aInputRow, mPixelSize * mInputSize.width);
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* An internal method used to implement WritePixelBlocks. This method writes
|
||||
|
@ -771,7 +719,6 @@ class AbstractSurfaceSink : public SurfaceFilter {
|
|||
|
||||
protected:
|
||||
uint8_t* DoResetToFirstRow() final;
|
||||
uint8_t* DoAdvanceRowFromBuffer(const uint8_t* aInputRow) final;
|
||||
uint8_t* DoAdvanceRow() final;
|
||||
virtual uint8_t* GetRowPointer() const = 0;
|
||||
|
||||
|
|
|
@ -59,9 +59,6 @@ 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)
|
||||
|
||||
|
@ -91,9 +88,8 @@ class SurfacePipeFactory {
|
|||
static Maybe<SurfacePipe> CreateSurfacePipe(
|
||||
Decoder* aDecoder, const nsIntSize& aInputSize,
|
||||
const nsIntSize& aOutputSize, const nsIntRect& aFrameRect,
|
||||
gfx::SurfaceFormat aInFormat, gfx::SurfaceFormat aOutFormat,
|
||||
const Maybe<AnimationParams>& aAnimParams, qcms_transform* aTransform,
|
||||
SurfacePipeFlags aFlags) {
|
||||
gfx::SurfaceFormat aFormat, const Maybe<AnimationParams>& aAnimParams,
|
||||
qcms_transform* aTransform, SurfacePipeFlags aFlags) {
|
||||
const bool deinterlace = bool(aFlags & SurfacePipeFlags::DEINTERLACE);
|
||||
const bool flipVertically =
|
||||
bool(aFlags & SurfacePipeFlags::FLIP_VERTICALLY);
|
||||
|
@ -104,46 +100,6 @@ 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, but the image's
|
||||
// alpha channel will always be opaque.
|
||||
bool earlySwizzle = 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.
|
||||
bool lateSwizzle = ((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 (earlySwizzle && lateSwizzle) {
|
||||
MOZ_ASSERT_UNREACHABLE("Early and late swizzles not supported");
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
if (!earlySwizzle && !lateSwizzle && 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
|
||||
|
@ -168,402 +124,129 @@ class SurfacePipeFactory {
|
|||
ADAM7InterpolatingConfig interpolatingConfig;
|
||||
RemoveFrameRectConfig removeFrameRectConfig{aFrameRect};
|
||||
BlendAnimationConfig blendAnimationConfig{aDecoder};
|
||||
DownscalingConfig downscalingConfig{aInputSize, aOutFormat};
|
||||
DownscalingConfig downscalingConfig{aInputSize, aFormat};
|
||||
ColorManagementConfig colorManagementConfig{aTransform};
|
||||
SwizzleConfig swizzleConfig{aInFormat, aOutFormat, premultiplyAlpha};
|
||||
SurfaceConfig surfaceConfig{aDecoder, aOutputSize, aOutFormat,
|
||||
flipVertically, aAnimParams};
|
||||
SurfaceConfig surfaceConfig{aDecoder, aOutputSize, aFormat, flipVertically,
|
||||
aAnimParams};
|
||||
|
||||
Maybe<SurfacePipe> pipe;
|
||||
|
||||
if (earlySwizzle) {
|
||||
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);
|
||||
}
|
||||
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 { // (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 { // (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 { // (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 { // (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 { // (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 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 if (lateSwizzle) {
|
||||
if (colorManagement) {
|
||||
if (downscale) {
|
||||
MOZ_ASSERT(!blendAnimation);
|
||||
if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
|
||||
downscalingConfig, colorManagementConfig,
|
||||
swizzleConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, removeFrameRectConfig,
|
||||
downscalingConfig, colorManagementConfig,
|
||||
swizzleConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe =
|
||||
MakePipe(removeFrameRectConfig, downscalingConfig,
|
||||
colorManagementConfig, swizzleConfig, surfaceConfig);
|
||||
}
|
||||
} else { // (removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe =
|
||||
MakePipe(deinterlacingConfig, downscalingConfig,
|
||||
colorManagementConfig, swizzleConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe =
|
||||
MakePipe(interpolatingConfig, downscalingConfig,
|
||||
colorManagementConfig, swizzleConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(downscalingConfig, colorManagementConfig,
|
||||
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 { // (downscale is false)
|
||||
if (blendAnimation) {
|
||||
if (deinterlace) {
|
||||
pipe =
|
||||
MakePipe(deinterlacingConfig, colorManagementConfig,
|
||||
swizzleConfig, blendAnimationConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, colorManagementConfig,
|
||||
swizzleConfig, blendAnimationConfig,
|
||||
swizzleConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
blendAnimationConfig, surfaceConfig);
|
||||
}
|
||||
} else if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe =
|
||||
MakePipe(deinterlacingConfig, colorManagementConfig,
|
||||
swizzleConfig, removeFrameRectConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe =
|
||||
MakePipe(interpolatingConfig, colorManagementConfig,
|
||||
swizzleConfig, removeFrameRectConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(colorManagementConfig, swizzleConfig,
|
||||
removeFrameRectConfig, surfaceConfig);
|
||||
}
|
||||
} else { // (blendAnimation and removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, colorManagementConfig,
|
||||
swizzleConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, colorManagementConfig,
|
||||
swizzleConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe =
|
||||
MakePipe(colorManagementConfig, swizzleConfig, 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 { // (colorManagement is false)
|
||||
if (downscale) {
|
||||
MOZ_ASSERT(!blendAnimation);
|
||||
if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, swizzleConfig,
|
||||
removeFrameRectConfig, downscalingConfig,
|
||||
surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, swizzleConfig,
|
||||
removeFrameRectConfig, downscalingConfig,
|
||||
surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(swizzleConfig, removeFrameRectConfig,
|
||||
downscalingConfig, surfaceConfig);
|
||||
}
|
||||
} else { // (removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, downscalingConfig,
|
||||
swizzleConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, downscalingConfig,
|
||||
swizzleConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(downscalingConfig, 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 { // (downscale is false)
|
||||
if (blendAnimation) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, swizzleConfig,
|
||||
blendAnimationConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, swizzleConfig,
|
||||
blendAnimationConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe =
|
||||
MakePipe(swizzleConfig, blendAnimationConfig, surfaceConfig);
|
||||
}
|
||||
} else if (removeFrameRect) {
|
||||
if (deinterlace) {
|
||||
pipe = MakePipe(deinterlacingConfig, swizzleConfig,
|
||||
removeFrameRectConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe = MakePipe(interpolatingConfig, swizzleConfig,
|
||||
removeFrameRectConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe =
|
||||
MakePipe(swizzleConfig, removeFrameRectConfig, surfaceConfig);
|
||||
}
|
||||
} else { // (blendAnimation and removeFrameRect is false)
|
||||
if (deinterlace) {
|
||||
pipe =
|
||||
MakePipe(deinterlacingConfig, swizzleConfig, surfaceConfig);
|
||||
} else if (adam7Interpolate) {
|
||||
pipe =
|
||||
MakePipe(interpolatingConfig, swizzleConfig, surfaceConfig);
|
||||
} else { // (deinterlace and adam7Interpolate are false)
|
||||
pipe = MakePipe(swizzleConfig, 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 { // (earlySwizzle and lateSwizzle 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);
|
||||
}
|
||||
} 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, format, animParams,
|
||||
mTransform, pipeFlags);
|
||||
this, Size(), OutputSize(), aFrameRect, format, animParams, mTransform,
|
||||
pipeFlags);
|
||||
mCurrentFrameIndex = mGIFStruct.images_decoded;
|
||||
|
||||
if (!pipe) {
|
||||
|
|
|
@ -68,7 +68,6 @@ 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,8 +357,7 @@ LexerTransition<nsJPEGDecoder::State> nsJPEGDecoder::ReadJPEGData(
|
|||
|
||||
Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe(
|
||||
this, Size(), OutputSize(), FullFrame(), SurfaceFormat::B8G8R8X8,
|
||||
SurfaceFormat::B8G8R8X8, Nothing(), pipeTransform,
|
||||
SurfacePipeFlags());
|
||||
Nothing(), pipeTransform, SurfacePipeFlags());
|
||||
if (!pipe) {
|
||||
mState = JPEG_ERROR;
|
||||
MOZ_LOG(sJPEGDecoderAccountingLog, LogLevel::Debug,
|
||||
|
|
|
@ -116,7 +116,6 @@ nsPNGDecoder::nsPNGDecoder(RasterImage* aImage)
|
|||
mFrameIsHidden(false),
|
||||
mDisablePremultipliedAlpha(false),
|
||||
mGotInfoCallback(false),
|
||||
mUsePipeTransform(false),
|
||||
mNumFrames(0) {}
|
||||
|
||||
nsPNGDecoder::~nsPNGDecoder() {
|
||||
|
@ -213,29 +212,9 @@ 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, inFormat, mFormat,
|
||||
animParams, pipeTransform, pipeFlags);
|
||||
this, Size(), OutputSize(), aFrameInfo.mFrameRect, mFormat, animParams,
|
||||
/*aTransform*/ nullptr, pipeFlags);
|
||||
|
||||
if (!pipe) {
|
||||
mPipe = SurfacePipe();
|
||||
|
@ -434,7 +413,8 @@ 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, uint32_t* intent) {
|
||||
int color_type, qcms_data_type* inType,
|
||||
uint32_t* intent) {
|
||||
qcms_profile* profile = nullptr;
|
||||
*intent = QCMS_INTENT_PERCEPTUAL; // Our default
|
||||
|
||||
|
@ -512,6 +492,24 @@ 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;
|
||||
}
|
||||
|
||||
|
@ -592,13 +590,14 @@ 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, &pIntent);
|
||||
PNGGetColorProfile(png_ptr, info_ptr, color_type, &inType, &pIntent);
|
||||
// If we're not mandating an intent, use the one from the image.
|
||||
if (intent == uint32_t(-1)) {
|
||||
intent = pIntent;
|
||||
|
@ -649,7 +648,6 @@ 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
|
||||
|
@ -658,6 +656,7 @@ 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
|
||||
|
@ -666,47 +665,23 @@ 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;
|
||||
|
||||
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;
|
||||
}
|
||||
if (color_type & PNG_COLOR_MASK_ALPHA || num_trans) {
|
||||
outType = QCMS_DATA_RGBA_8;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
outType = QCMS_DATA_RGB_8;
|
||||
}
|
||||
|
||||
decoder->mTransform = qcms_transform_create(
|
||||
decoder->mInProfile, inType, gfxPlatform::GetCMSOutputProfile(),
|
||||
outType, (qcms_intent)intent);
|
||||
} else if (decoder->mCMSMode == eCMSMode_All) {
|
||||
// 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) {
|
||||
if (color_type & PNG_COLOR_MASK_ALPHA || num_trans) {
|
||||
decoder->mTransform = gfxPlatform::GetCMSRGBATransform();
|
||||
} else {
|
||||
decoder->mTransform = gfxPlatform::GetCMSBGRATransform();
|
||||
decoder->mTransform = gfxPlatform::GetCMSRGBTransform();
|
||||
}
|
||||
decoder->mUsePipeTransform = true;
|
||||
}
|
||||
|
||||
#ifdef PNG_APNG_SUPPORTED
|
||||
|
@ -728,8 +703,8 @@ void nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr) {
|
|||
}
|
||||
#endif
|
||||
|
||||
if (decoder->mTransform && !decoder->mUsePipeTransform) {
|
||||
uint32_t bpp[] = {0, 3, 4};
|
||||
if (decoder->mTransform && (channels <= 2 || isInterlaced)) {
|
||||
uint32_t bpp[] = {0, 3, 4, 3, 4};
|
||||
decoder->mCMSLine =
|
||||
static_cast<uint8_t*>(malloc(bpp[channels] * frameRect.Width()));
|
||||
if (!decoder->mCMSLine) {
|
||||
|
@ -765,6 +740,29 @@ 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:
|
||||
|
@ -849,16 +847,38 @@ 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.
|
||||
// This is only needed for grayscale images.
|
||||
if (mTransform && !mUsePipeTransform) {
|
||||
MOZ_ASSERT(mCMSLine);
|
||||
qcms_transform_data(mTransform, rowToWrite, mCMSLine, width);
|
||||
rowToWrite = mCMSLine;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Write this row to the SurfacePipe.
|
||||
DebugOnly<WriteState> result =
|
||||
mPipe.WriteBuffer(reinterpret_cast<uint32_t*>(rowToWrite));
|
||||
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); });
|
||||
}
|
||||
|
||||
MOZ_ASSERT(WriteState(result) != WriteState::FAILURE);
|
||||
|
||||
PostInvalidationIfNeeded();
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "png.h"
|
||||
#include "StreamingLexer.h"
|
||||
#include "SurfacePipe.h"
|
||||
#include "mozilla/gfx/Swizzle.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
|
@ -102,7 +101,6 @@ 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_BGRA;
|
||||
mBuffer.colorspace = MODE_RGBA;
|
||||
|
||||
mDecoder = WebPINewDecoder(&mBuffer);
|
||||
if (!mDecoder) {
|
||||
|
@ -220,16 +220,7 @@ 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()) {
|
||||
|
@ -237,8 +228,8 @@ nsresult nsWebPDecoder::CreateFrame(const nsIntRect& aFrameRect) {
|
|||
}
|
||||
|
||||
Maybe<SurfacePipe> pipe = SurfacePipeFactory::CreateSurfacePipe(
|
||||
this, Size(), OutputSize(), aFrameRect, inFormat, mFormat, animParams,
|
||||
mTransform, pipeFlags);
|
||||
this, Size(), OutputSize(), aFrameRect, mFormat, animParams,
|
||||
/*aTransform*/ nullptr, pipeFlags);
|
||||
if (!pipe) {
|
||||
MOZ_LOG(sWebPLog, LogLevel::Error,
|
||||
("[this=%p] nsWebPDecoder::CreateFrame -- no pipe\n", this));
|
||||
|
@ -290,7 +281,7 @@ void nsWebPDecoder::ApplyColorProfile(const char* aProfile, size_t aLength) {
|
|||
("[this=%p] nsWebPDecoder::ApplyColorProfile -- not tagged, use "
|
||||
"sRGB transform\n",
|
||||
this));
|
||||
mTransform = gfxPlatform::GetCMSBGRATransform();
|
||||
mTransform = gfxPlatform::GetCMSRGBATransform();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -320,9 +311,9 @@ void nsWebPDecoder::ApplyColorProfile(const char* aProfile, size_t aLength) {
|
|||
}
|
||||
|
||||
// Create the color management transform.
|
||||
mTransform = qcms_transform_create(mInProfile, QCMS_DATA_BGRA_8,
|
||||
mTransform = qcms_transform_create(mInProfile, QCMS_DATA_RGBA_8,
|
||||
gfxPlatform::GetCMSOutputProfile(),
|
||||
QCMS_DATA_BGRA_8, (qcms_intent)intent);
|
||||
QCMS_DATA_RGBA_8, (qcms_intent)intent);
|
||||
MOZ_LOG(sWebPLog, LogLevel::Debug,
|
||||
("[this=%p] nsWebPDecoder::ApplyColorProfile -- use tagged "
|
||||
"transform\n",
|
||||
|
@ -467,9 +458,43 @@ 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++) {
|
||||
uint32_t* src = reinterpret_cast<uint32_t*>(rowStart + row * stride);
|
||||
WriteState result = mPipe.WriteBuffer(src);
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
Maybe<SurfaceInvalidRect> invalidRect = mPipe.TakeInvalidRect();
|
||||
if (invalidRect) {
|
||||
|
|
|
@ -167,6 +167,11 @@ bool IsSolidColor(SourceSurface* aSurface, BGRAColor aColor,
|
|||
aColor, aFuzz);
|
||||
}
|
||||
|
||||
bool IsSolidPalettedColor(Decoder* aDecoder, uint8_t aColor) {
|
||||
RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
|
||||
return PalettedRectIsSolidColor(aDecoder, currentFrame->GetRect(), aColor);
|
||||
}
|
||||
|
||||
bool RowsAreSolidColor(SourceSurface* aSurface, int32_t aStartRow,
|
||||
int32_t aRowCount, BGRAColor aColor,
|
||||
uint8_t aFuzz /* = 0 */) {
|
||||
|
@ -175,6 +180,15 @@ bool RowsAreSolidColor(SourceSurface* aSurface, int32_t aStartRow,
|
|||
aSurface, IntRect(0, aStartRow, size.width, aRowCount), aColor, aFuzz);
|
||||
}
|
||||
|
||||
bool PalettedRowsAreSolidColor(Decoder* aDecoder, int32_t aStartRow,
|
||||
int32_t aRowCount, uint8_t aColor) {
|
||||
RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
|
||||
IntRect frameRect = currentFrame->GetRect();
|
||||
IntRect solidColorRect(frameRect.X(), aStartRow, frameRect.Width(),
|
||||
aRowCount);
|
||||
return PalettedRectIsSolidColor(aDecoder, solidColorRect, aColor);
|
||||
}
|
||||
|
||||
bool RectIsSolidColor(SourceSurface* aSurface, const IntRect& aRect,
|
||||
BGRAColor aColor, uint8_t aFuzz /* = 0 */) {
|
||||
IntSize surfaceSize = aSurface->GetSize();
|
||||
|
@ -214,6 +228,42 @@ bool RectIsSolidColor(SourceSurface* aSurface, const IntRect& aRect,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool PalettedRectIsSolidColor(Decoder* aDecoder, const IntRect& aRect,
|
||||
uint8_t aColor) {
|
||||
RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
|
||||
uint8_t* imageData;
|
||||
uint32_t imageLength;
|
||||
currentFrame->GetImageData(&imageData, &imageLength);
|
||||
ASSERT_TRUE_OR_RETURN(imageData, false);
|
||||
|
||||
// Clamp to the frame rect. If any pixels outside the frame rect are included,
|
||||
// we immediately fail, because such pixels don't have any "color" in the
|
||||
// sense this function measures - they're transparent, and that doesn't
|
||||
// necessarily correspond to any color palette index at all.
|
||||
IntRect frameRect = currentFrame->GetRect();
|
||||
ASSERT_EQ_OR_RETURN(imageLength, uint32_t(frameRect.Area()), false);
|
||||
IntRect rect = aRect.Intersect(frameRect);
|
||||
ASSERT_EQ_OR_RETURN(rect.Area(), aRect.Area(), false);
|
||||
|
||||
// Translate |rect| by |frameRect.TopLeft()| to reflect the fact that the
|
||||
// frame rect's offset doesn't actually mean anything in terms of the
|
||||
// in-memory representation of the surface. The image data starts at the upper
|
||||
// left corner of the frame rect, in other words.
|
||||
rect -= frameRect.TopLeft();
|
||||
|
||||
// Walk through the image data and make sure that the entire rect has the
|
||||
// palette index |aColor|.
|
||||
int32_t rowLength = frameRect.Width();
|
||||
for (int32_t row = rect.Y(); row < rect.YMost(); ++row) {
|
||||
for (int32_t col = rect.X(); col < rect.XMost(); ++col) {
|
||||
int32_t i = row * rowLength + col;
|
||||
ASSERT_EQ_OR_RETURN(aColor, imageData[i], false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RowHasPixels(SourceSurface* aSurface, int32_t aRow,
|
||||
const vector<BGRAColor>& aPixels) {
|
||||
ASSERT_GE_OR_RETURN(aRow, 0, false);
|
||||
|
@ -322,20 +372,93 @@ void CheckGeneratedSurface(SourceSurface* aSurface, const IntRect& aRect,
|
|||
aOuterColor, aFuzz));
|
||||
}
|
||||
|
||||
void CheckGeneratedPalettedImage(Decoder* aDecoder, const IntRect& aRect) {
|
||||
RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
|
||||
IntSize imageSize = currentFrame->GetSize();
|
||||
|
||||
// This diagram shows how the surface is divided into regions that the code
|
||||
// below tests for the correct content. The output rect is the bounds of the
|
||||
// region labeled 'C'.
|
||||
//
|
||||
// +---------------------------+
|
||||
// | A |
|
||||
// +---------+--------+--------+
|
||||
// | B | C | D |
|
||||
// +---------+--------+--------+
|
||||
// | E |
|
||||
// +---------------------------+
|
||||
|
||||
// Check that the output rect itself is all 255's. (Region 'C'.)
|
||||
EXPECT_TRUE(PalettedRectIsSolidColor(aDecoder, aRect, 255));
|
||||
|
||||
// Check that the area above the output rect is all 0's. (Region 'A'.)
|
||||
EXPECT_TRUE(PalettedRectIsSolidColor(
|
||||
aDecoder, IntRect(0, 0, imageSize.width, aRect.Y()), 0));
|
||||
|
||||
// Check that the area to the left of the output rect is all 0's. (Region
|
||||
// 'B'.)
|
||||
EXPECT_TRUE(PalettedRectIsSolidColor(
|
||||
aDecoder, IntRect(0, aRect.Y(), aRect.X(), aRect.YMost()), 0));
|
||||
|
||||
// Check that the area to the right of the output rect is all 0's. (Region
|
||||
// 'D'.)
|
||||
const int32_t widthOnRight = imageSize.width - aRect.XMost();
|
||||
EXPECT_TRUE(PalettedRectIsSolidColor(
|
||||
aDecoder, IntRect(aRect.XMost(), aRect.Y(), widthOnRight, aRect.YMost()),
|
||||
0));
|
||||
|
||||
// Check that the area below the output rect is transparent. (Region 'E'.)
|
||||
const int32_t heightBelow = imageSize.height - aRect.YMost();
|
||||
EXPECT_TRUE(PalettedRectIsSolidColor(
|
||||
aDecoder, IntRect(0, aRect.YMost(), imageSize.width, heightBelow), 0));
|
||||
}
|
||||
|
||||
void CheckWritePixels(Decoder* aDecoder, SurfaceFilter* aFilter,
|
||||
const Maybe<IntRect>& aOutputRect /* = Nothing() */,
|
||||
const Maybe<IntRect>& aInputRect /* = Nothing() */,
|
||||
const Maybe<IntRect>& aInputWriteRect /* = Nothing() */,
|
||||
const Maybe<IntRect>& aOutputWriteRect /* = Nothing() */,
|
||||
uint8_t aFuzz /* = 0 */) {
|
||||
CheckTransformedWritePixels(aDecoder, aFilter, BGRAColor::Green(),
|
||||
BGRAColor::Green(), aOutputRect, aInputRect,
|
||||
aInputWriteRect, aOutputWriteRect, aFuzz);
|
||||
IntRect outputRect = aOutputRect.valueOr(IntRect(0, 0, 100, 100));
|
||||
IntRect inputRect = aInputRect.valueOr(IntRect(0, 0, 100, 100));
|
||||
IntRect inputWriteRect = aInputWriteRect.valueOr(inputRect);
|
||||
IntRect outputWriteRect = aOutputWriteRect.valueOr(outputRect);
|
||||
|
||||
// Fill the image.
|
||||
int32_t count = 0;
|
||||
auto result = aFilter->WritePixels<uint32_t>([&] {
|
||||
++count;
|
||||
return AsVariant(BGRAColor::Green().AsPixel());
|
||||
});
|
||||
EXPECT_EQ(WriteState::FINISHED, result);
|
||||
EXPECT_EQ(inputWriteRect.Width() * inputWriteRect.Height(), count);
|
||||
|
||||
AssertCorrectPipelineFinalState(aFilter, inputRect, outputRect);
|
||||
|
||||
// Attempt to write more data and make sure nothing changes.
|
||||
const int32_t oldCount = count;
|
||||
result = aFilter->WritePixels<uint32_t>([&] {
|
||||
++count;
|
||||
return AsVariant(BGRAColor::Green().AsPixel());
|
||||
});
|
||||
EXPECT_EQ(oldCount, count);
|
||||
EXPECT_EQ(WriteState::FINISHED, result);
|
||||
EXPECT_TRUE(aFilter->IsSurfaceFinished());
|
||||
Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
|
||||
EXPECT_TRUE(invalidRect.isNothing());
|
||||
|
||||
// Attempt to advance to the next row and make sure nothing changes.
|
||||
aFilter->AdvanceRow();
|
||||
EXPECT_TRUE(aFilter->IsSurfaceFinished());
|
||||
invalidRect = aFilter->TakeInvalidRect();
|
||||
EXPECT_TRUE(invalidRect.isNothing());
|
||||
|
||||
// Check that the generated image is correct.
|
||||
CheckGeneratedImage(aDecoder, outputWriteRect, aFuzz);
|
||||
}
|
||||
|
||||
void CheckTransformedWritePixels(
|
||||
Decoder* aDecoder, SurfaceFilter* aFilter, const BGRAColor& aInputColor,
|
||||
const BGRAColor& aOutputColor,
|
||||
void CheckPalettedWritePixels(
|
||||
Decoder* aDecoder, SurfaceFilter* aFilter,
|
||||
const Maybe<IntRect>& aOutputRect /* = Nothing() */,
|
||||
const Maybe<IntRect>& aInputRect /* = Nothing() */,
|
||||
const Maybe<IntRect>& aInputWriteRect /* = Nothing() */,
|
||||
|
@ -348,9 +471,9 @@ void CheckTransformedWritePixels(
|
|||
|
||||
// Fill the image.
|
||||
int32_t count = 0;
|
||||
auto result = aFilter->WritePixels<uint32_t>([&] {
|
||||
auto result = aFilter->WritePixels<uint8_t>([&] {
|
||||
++count;
|
||||
return AsVariant(aInputColor.AsPixel());
|
||||
return AsVariant(uint8_t(255));
|
||||
});
|
||||
EXPECT_EQ(WriteState::FINISHED, result);
|
||||
EXPECT_EQ(inputWriteRect.Width() * inputWriteRect.Height(), count);
|
||||
|
@ -359,9 +482,9 @@ void CheckTransformedWritePixels(
|
|||
|
||||
// Attempt to write more data and make sure nothing changes.
|
||||
const int32_t oldCount = count;
|
||||
result = aFilter->WritePixels<uint32_t>([&] {
|
||||
result = aFilter->WritePixels<uint8_t>([&] {
|
||||
++count;
|
||||
return AsVariant(aInputColor.AsPixel());
|
||||
return AsVariant(uint8_t(255));
|
||||
});
|
||||
EXPECT_EQ(oldCount, count);
|
||||
EXPECT_EQ(WriteState::FINISHED, result);
|
||||
|
@ -377,9 +500,15 @@ void CheckTransformedWritePixels(
|
|||
|
||||
// Check that the generated image is correct.
|
||||
RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
|
||||
RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
|
||||
CheckGeneratedSurface(surface, outputWriteRect, aOutputColor,
|
||||
BGRAColor::Transparent(), aFuzz);
|
||||
uint8_t* imageData;
|
||||
uint32_t imageLength;
|
||||
currentFrame->GetImageData(&imageData, &imageLength);
|
||||
ASSERT_TRUE(imageData != nullptr);
|
||||
ASSERT_EQ(outputWriteRect.Width() * outputWriteRect.Height(),
|
||||
int32_t(imageLength));
|
||||
for (uint32_t i = 0; i < imageLength; ++i) {
|
||||
ASSERT_EQ(uint8_t(255), imageData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -158,6 +158,12 @@ already_AddRefed<nsIInputStream> LoadFile(const char* aRelativePath);
|
|||
bool IsSolidColor(gfx::SourceSurface* aSurface, BGRAColor aColor,
|
||||
uint8_t aFuzz = 0);
|
||||
|
||||
/**
|
||||
* @returns true if every pixel of @aDecoder's surface has the palette index
|
||||
* specified by @aColor.
|
||||
*/
|
||||
bool IsSolidPalettedColor(Decoder* aDecoder, uint8_t aColor);
|
||||
|
||||
/**
|
||||
* @returns true if every pixel in the range of rows specified by @aStartRow and
|
||||
* @aRowCount of @aSurface is @aColor.
|
||||
|
@ -169,6 +175,13 @@ bool IsSolidColor(gfx::SourceSurface* aSurface, BGRAColor aColor,
|
|||
bool RowsAreSolidColor(gfx::SourceSurface* aSurface, int32_t aStartRow,
|
||||
int32_t aRowCount, BGRAColor aColor, uint8_t aFuzz = 0);
|
||||
|
||||
/**
|
||||
* @returns true if every pixel in the range of rows specified by @aStartRow and
|
||||
* @aRowCount of @aDecoder's surface has the palette index specified by @aColor.
|
||||
*/
|
||||
bool PalettedRowsAreSolidColor(Decoder* aDecoder, int32_t aStartRow,
|
||||
int32_t aRowCount, uint8_t aColor);
|
||||
|
||||
/**
|
||||
* @returns true if every pixel in the rect specified by @aRect is @aColor.
|
||||
*
|
||||
|
@ -179,6 +192,13 @@ bool RowsAreSolidColor(gfx::SourceSurface* aSurface, int32_t aStartRow,
|
|||
bool RectIsSolidColor(gfx::SourceSurface* aSurface, const gfx::IntRect& aRect,
|
||||
BGRAColor aColor, uint8_t aFuzz = 0);
|
||||
|
||||
/**
|
||||
* @returns true if every pixel in the rect specified by @aRect has the palette
|
||||
* index specified by @aColor.
|
||||
*/
|
||||
bool PalettedRectIsSolidColor(Decoder* aDecoder, const gfx::IntRect& aRect,
|
||||
uint8_t aColor);
|
||||
|
||||
/**
|
||||
* @returns true if the pixels in @aRow of @aSurface match the pixels given in
|
||||
* @aPixels.
|
||||
|
@ -224,9 +244,9 @@ class CountResumes : public IResumable {
|
|||
* that requires a decoder to initialize or to allocate surfaces but doesn't
|
||||
* actually need the decoder to do any decoding.
|
||||
*
|
||||
* XXX(seth): We only need this because SurfaceSink defer to the decoder for
|
||||
* surface allocation. Once all decoders use SurfacePipe we won't need to do
|
||||
* that anymore and we can remove this function.
|
||||
* XXX(seth): We only need this because SurfaceSink and PalettedSurfaceSink
|
||||
* defer to the decoder for surface allocation. Once all decoders use
|
||||
* SurfacePipe we won't need to do that anymore and we can remove this function.
|
||||
*/
|
||||
already_AddRefed<Decoder> CreateTrivialDecoder();
|
||||
|
||||
|
@ -329,6 +349,19 @@ void CheckGeneratedSurface(gfx::SourceSurface* aSurface,
|
|||
const BGRAColor& aInnerColor,
|
||||
const BGRAColor& aOuterColor, uint8_t aFuzz = 0);
|
||||
|
||||
/**
|
||||
* Checks a generated paletted image for correctness. Reports any unexpected
|
||||
* deviation from the expected image as GTest failures.
|
||||
*
|
||||
* @param aDecoder The decoder which contains the image. The decoder's current
|
||||
* frame will be checked.
|
||||
* @param aRect The region in the space of the output surface that the filter
|
||||
* pipeline will actually write to. It's expected that pixels in
|
||||
* this region have a palette index of 255, while pixels outside
|
||||
* this region have a palette index of 0.
|
||||
*/
|
||||
void CheckGeneratedPalettedImage(Decoder* aDecoder, const gfx::IntRect& aRect);
|
||||
|
||||
/**
|
||||
* Tests the result of calling WritePixels() using the provided SurfaceFilter
|
||||
* pipeline. The pipeline must be a normal (i.e., non-paletted) pipeline.
|
||||
|
@ -366,13 +399,11 @@ void CheckWritePixels(Decoder* aDecoder, SurfaceFilter* aFilter,
|
|||
|
||||
/**
|
||||
* Tests the result of calling WritePixels() using the provided SurfaceFilter
|
||||
* pipeline. Allows for control over the input color to write, and the expected
|
||||
* output color.
|
||||
* pipeline. The pipeline must be a paletted pipeline.
|
||||
* @see CheckWritePixels() for documentation of the arguments.
|
||||
*/
|
||||
void CheckTransformedWritePixels(
|
||||
Decoder* aDecoder, SurfaceFilter* aFilter, const BGRAColor& aInputColor,
|
||||
const BGRAColor& aOutputColor,
|
||||
void CheckPalettedWritePixels(
|
||||
Decoder* aDecoder, SurfaceFilter* aFilter,
|
||||
const Maybe<gfx::IntRect>& aOutputRect = Nothing(),
|
||||
const Maybe<gfx::IntRect>& aInputRect = Nothing(),
|
||||
const Maybe<gfx::IntRect>& aInputWriteRect = Nothing(),
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "Common.h"
|
||||
#include "Decoder.h"
|
||||
#include "DecoderFactory.h"
|
||||
#include "SurfaceFilters.h"
|
||||
#include "SurfacePipe.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::image;
|
||||
|
||||
template <typename Func>
|
||||
void WithSwizzleFilter(const IntSize& aSize, SurfaceFormat aInputFormat,
|
||||
SurfaceFormat aOutputFormat, bool aPremultiplyAlpha,
|
||||
Func aFunc) {
|
||||
RefPtr<Decoder> decoder = CreateTrivialDecoder();
|
||||
ASSERT_TRUE(decoder != nullptr);
|
||||
|
||||
WithFilterPipeline(
|
||||
decoder, std::forward<Func>(aFunc),
|
||||
SwizzleConfig{aInputFormat, aOutputFormat, aPremultiplyAlpha},
|
||||
SurfaceConfig{decoder, aSize, aOutputFormat, false});
|
||||
}
|
||||
|
||||
TEST(ImageSwizzleFilter, WritePixels_RGBA_to_BGRA)
|
||||
{
|
||||
WithSwizzleFilter(
|
||||
IntSize(100, 100), SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8,
|
||||
false, [](Decoder* aDecoder, SurfaceFilter* aFilter) {
|
||||
CheckTransformedWritePixels(aDecoder, aFilter, BGRAColor::Blue(),
|
||||
BGRAColor::Red());
|
||||
});
|
||||
}
|
||||
|
||||
TEST(ImageSwizzleFilter, WritePixels_RGBA_to_Premultiplied_BGRA)
|
||||
{
|
||||
WithSwizzleFilter(
|
||||
IntSize(100, 100), SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8A8, true,
|
||||
[](Decoder* aDecoder, SurfaceFilter* aFilter) {
|
||||
CheckTransformedWritePixels(
|
||||
aDecoder, aFilter, BGRAColor(0x26, 0x00, 0x00, 0x7F, true),
|
||||
BGRAColor(0x00, 0x00, 0x26, 0x7F), Nothing(), Nothing(), Nothing(),
|
||||
Nothing(), /* aFuzz */ 1);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(ImageSwizzleFilter, WritePixels_RGBA_to_BGRX)
|
||||
{
|
||||
WithSwizzleFilter(
|
||||
IntSize(100, 100), SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8,
|
||||
false, [](Decoder* aDecoder, SurfaceFilter* aFilter) {
|
||||
CheckTransformedWritePixels(aDecoder, aFilter,
|
||||
BGRAColor(0x26, 0x00, 0x00, 0x7F, true),
|
||||
BGRAColor(0x00, 0x00, 0x26, 0xFF));
|
||||
});
|
||||
}
|
||||
|
||||
TEST(ImageSwizzleFilter, WritePixels_RGBA_to_Premultiplied_BGRX)
|
||||
{
|
||||
WithSwizzleFilter(
|
||||
IntSize(100, 100), SurfaceFormat::R8G8B8A8, SurfaceFormat::B8G8R8X8, true,
|
||||
[](Decoder* aDecoder, SurfaceFilter* aFilter) {
|
||||
CheckTransformedWritePixels(aDecoder, aFilter,
|
||||
BGRAColor(0x26, 0x00, 0x00, 0x7F, true),
|
||||
BGRAColor(0x00, 0x00, 0x13, 0xFF));
|
||||
});
|
||||
}
|
||||
|
||||
TEST(ImageSwizzleFilter, WritePixels_RGBA_to_RGBX)
|
||||
{
|
||||
WithSwizzleFilter(
|
||||
IntSize(100, 100), SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8,
|
||||
false, [](Decoder* aDecoder, SurfaceFilter* aFilter) {
|
||||
CheckTransformedWritePixels(aDecoder, aFilter,
|
||||
BGRAColor(0x00, 0x00, 0x26, 0x7F, true),
|
||||
BGRAColor(0x00, 0x00, 0x26, 0xFF));
|
||||
});
|
||||
}
|
||||
|
||||
TEST(ImageSwizzleFilter, WritePixels_RGBA_to_Premultiplied_RGRX)
|
||||
{
|
||||
WithSwizzleFilter(
|
||||
IntSize(100, 100), SurfaceFormat::R8G8B8A8, SurfaceFormat::R8G8B8X8, true,
|
||||
[](Decoder* aDecoder, SurfaceFilter* aFilter) {
|
||||
CheckTransformedWritePixels(aDecoder, aFilter,
|
||||
BGRAColor(0x00, 0x00, 0x26, 0x7F, true),
|
||||
BGRAColor(0x00, 0x00, 0x13, 0xFF));
|
||||
});
|
||||
}
|
||||
|
||||
TEST(ImageSwizzleFilter, WritePixels_BGRA_to_BGRX)
|
||||
{
|
||||
WithSwizzleFilter(
|
||||
IntSize(100, 100), SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8X8,
|
||||
false, [](Decoder* aDecoder, SurfaceFilter* aFilter) {
|
||||
CheckTransformedWritePixels(aDecoder, aFilter,
|
||||
BGRAColor(0x10, 0x26, 0x00, 0x7F, true),
|
||||
BGRAColor(0x10, 0x26, 0x00, 0xFF));
|
||||
});
|
||||
}
|
||||
|
||||
TEST(ImageSwizzleFilter, WritePixels_BGRA_to_Premultiplied_BGRA)
|
||||
{
|
||||
WithSwizzleFilter(
|
||||
IntSize(100, 100), SurfaceFormat::B8G8R8A8, SurfaceFormat::B8G8R8A8, true,
|
||||
[](Decoder* aDecoder, SurfaceFilter* aFilter) {
|
||||
CheckTransformedWritePixels(
|
||||
aDecoder, aFilter, BGRAColor(0x10, 0x26, 0x00, 0x7F, true),
|
||||
BGRAColor(0x10, 0x26, 0x00, 0x7F), Nothing(), Nothing(), Nothing(),
|
||||
Nothing(), /* aFuzz */ 1);
|
||||
});
|
||||
}
|
|
@ -19,7 +19,6 @@ UNIFIED_SOURCES = [
|
|||
'TestRemoveFrameRectFilter.cpp',
|
||||
'TestStreamingLexer.cpp',
|
||||
'TestSurfaceSink.cpp',
|
||||
'TestSwizzleFilter.cpp',
|
||||
]
|
||||
|
||||
# skip the test on windows10-aarch64, aarch64 due to 1544961
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# ICO BMP and PNG mixed tests
|
||||
|
||||
fuzzy(1-1,67-67) == wrapper.html?pointer.cur wrapper.html?pointer.png
|
||||
== wrapper.html?pointer.cur wrapper.html?pointer.png
|
||||
|
||||
|
|
|
@ -19,4 +19,4 @@
|
|||
== ico-size-256x256-32bpp.ico ico-size-256x256-32bpp.png
|
||||
== ico-partial-transparent-32bpp.ico ico-partial-transparent-32bpp.png
|
||||
== ico-transparent-32bpp.ico ico-transparent-32bpp.png
|
||||
fuzzy(1-1,81-81) == ico-not-square-transparent-32bpp.ico ico-not-square-transparent-32bpp.png
|
||||
== ico-not-square-transparent-32bpp.ico ico-not-square-transparent-32bpp.png
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# ICO BMP and PNG mixed tests
|
||||
|
||||
fuzzy(1-1,407-407) == mixed-bmp-png.ico mixed-bmp-png48.png
|
||||
== mixed-bmp-png.ico mixed-bmp-png48.png
|
||||
|
|
|
@ -25,5 +25,5 @@
|
|||
== wrapper.html?xcrn0g04.ico about:blank
|
||||
|
||||
# Test ICO PNG transparency
|
||||
fuzzy(1-1,29-29) == transparent-png.ico transparent-png.png
|
||||
== transparent-png.ico transparent-png.png
|
||||
|
||||
|
|
|
@ -5,18 +5,18 @@
|
|||
# identically and thus share common reference HTML files.
|
||||
|
||||
# bgai4a08 - 8 bit grayscale, alpha, no background chunk, interlaced
|
||||
fuzzy(1-2,0-1024) == wrapper.html?bgai4a08.png bg__4a08.html
|
||||
fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bgai4a08.png bg__4a08.html
|
||||
# bgai4a16 - 16 bit grayscale, alpha, no background chunk, interlaced
|
||||
fuzzy(1-2,0-1024) == wrapper.html?bgai4a16.png bg__4a16.html
|
||||
fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bgai4a16.png bg__4a16.html
|
||||
# bgan6a08 - 3x8 bits rgb color, alpha, no background chunk
|
||||
fuzzy(1-2,0-1024) == wrapper.html?bgan6a08.png bg__6a08.html
|
||||
fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bgan6a08.png bg__6a08.html
|
||||
# bgan6a16 - 3x16 bits rgb color, alpha, no background chunk
|
||||
fuzzy(1-2,0-1024) == wrapper.html?bgan6a16.png bg__6a16.html
|
||||
fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bgan6a16.png bg__6a16.html
|
||||
# bgbn4a08 - 8 bit grayscale, alpha, black background chunk
|
||||
fuzzy(1-2,0-1024) == wrapper.html?bgbn4a08.png bg__4a08.html
|
||||
fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bgbn4a08.png bg__4a08.html
|
||||
# bggn4a16 - 16 bit grayscale, alpha, gray background chunk
|
||||
fuzzy(1-2,0-1024) == wrapper.html?bggn4a16.png bg__4a16.html
|
||||
fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bggn4a16.png bg__4a16.html
|
||||
# bgwn6a08 - 3x8 bits rgb color, alpha, white background chunk
|
||||
fuzzy(1-2,0-1024) == wrapper.html?bgwn6a08.png bg__6a08.html
|
||||
fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bgwn6a08.png bg__6a08.html
|
||||
# bgyn6a16 - 3x16 bits rgb color, alpha, yellow background chunk
|
||||
fuzzy(1-2,0-1024) == wrapper.html?bgyn6a16.png bg__6a16.html
|
||||
fuzzy-if(cocoaWidget||skiaContent,0-1,0-1024) == wrapper.html?bgyn6a16.png bg__6a16.html
|
||||
|
|
|
@ -318,7 +318,7 @@ fuzzy-if(Android,0-3,0-50) fuzzy-if(skiaContent,0-1,0-133) == 273681-1.html 2736
|
|||
== 283686-2.html 283686-2-ref.html
|
||||
== 283686-3.html about:blank
|
||||
== 289384-1.xhtml 289384-ref.xhtml
|
||||
random-if(d2d) fuzzy(0-1,0-16) fuzzy-if(Android,0-8,0-1439) fuzzy-if(webrender,0-9,0-2024) HTTP == 289480.html#top 289480-ref.html # basically-verbatim acid2 test, HTTP for a 404 page -- bug 578114 for the d2d failures
|
||||
random-if(d2d) fuzzy-if(Android,0-8,0-1439) fuzzy-if(webrender,0-9,0-2024) HTTP == 289480.html#top 289480-ref.html # basically-verbatim acid2 test, HTTP for a 404 page -- bug 578114 for the d2d failures
|
||||
== 290129-1.html 290129-1-ref.html
|
||||
== 291078-1.html 291078-1-ref.html
|
||||
== 291078-2.html 291078-2-ref.html
|
||||
|
|
Загрузка…
Ссылка в новой задаче