Original source: Jacek Piszczek diff --git a/Source/WebCore/platform/graphics/PixelBufferConversion.cpp b/Source/WebCore/platform/graphics/PixelBufferConversion.cpp index 9acf304d..618b7b26 100644 --- a/Source/WebCore/platform/graphics/PixelBufferConversion.cpp +++ b/Source/WebCore/platform/graphics/PixelBufferConversion.cpp @@ -140,9 +140,17 @@ static void convertImagePixelsAccelerated(const ConstPixelBufferConversionView& enum class PixelFormatConversion { None, Permute }; template +#if CPU(BIG_ENDIAN) +static void convertSinglePixelPremultipliedToPremultiplied(PixelFormat sourcePixelFormat, const uint8_t* sourcePixel, PixelFormat destinationPixelFormat, uint8_t* destinationPixel) +#else static void convertSinglePixelPremultipliedToPremultiplied(const uint8_t* sourcePixel, uint8_t* destinationPixel) +#endif { +#if CPU(BIG_ENDIAN) + uint8_t alpha = sourcePixel[sourcePixelFormat == PixelFormat::ARGB8 ? 0 : 3]; +#else uint8_t alpha = sourcePixel[3]; +#endif if (!alpha) { reinterpret_cast(destinationPixel)[0] = 0; return; @@ -151,23 +158,81 @@ static void convertSinglePixelPremultipliedToPremultiplied(const uint8_t* source if constexpr (pixelFormatConversion == PixelFormatConversion::None) reinterpret_cast(destinationPixel)[0] = reinterpret_cast(sourcePixel)[0]; else { +#if CPU(BIG_ENDIAN) + // Swap pixel channels ARGB <-> RGBA. + if (destinationPixelFormat == PixelFormat::ARGB8) + { + destinationPixel[0] = sourcePixel[3]; + destinationPixel[1] = sourcePixel[0]; + destinationPixel[2] = sourcePixel[1]; + destinationPixel[3] = sourcePixel[2]; + } + else + { + destinationPixel[0] = sourcePixel[1]; + destinationPixel[1] = sourcePixel[2]; + destinationPixel[2] = sourcePixel[3]; + destinationPixel[3] = sourcePixel[0]; + } +#else // Swap pixel channels BGRA <-> RGBA. destinationPixel[0] = sourcePixel[2]; destinationPixel[1] = sourcePixel[1]; destinationPixel[2] = sourcePixel[0]; destinationPixel[3] = sourcePixel[3]; +#endif } } template +#if CPU(BIG_ENDIAN) +static void convertSinglePixelPremultipliedToUnpremultiplied(PixelFormat sourcePixelFormat, const uint8_t* sourcePixel, PixelFormat destinationPixelFormat, uint8_t* destinationPixel) +#else static void convertSinglePixelPremultipliedToUnpremultiplied(const uint8_t* sourcePixel, uint8_t* destinationPixel) +#endif { +#if CPU(BIG_ENDIAN) + uint8_t alpha = sourcePixel[sourcePixelFormat == PixelFormat::ARGB8 ? 0 : 3]; +#else uint8_t alpha = sourcePixel[3]; +#endif if (!alpha || alpha == 255) { +#if CPU(BIG_ENDIAN) + convertSinglePixelPremultipliedToPremultiplied(sourcePixelFormat, sourcePixel, destinationPixelFormat, destinationPixel); +#else convertSinglePixelPremultipliedToPremultiplied(sourcePixel, destinationPixel); +#endif return; } +#if CPU(BIG_ENDIAN) + UNUSED_PARAM(destinationPixelFormat); + if constexpr (pixelFormatConversion == PixelFormatConversion::None) { + if (sourcePixelFormat == PixelFormat::ARGB8) { + destinationPixel[0] = alpha; + destinationPixel[1] = (sourcePixel[1] * 255) / alpha; + destinationPixel[2] = (sourcePixel[2] * 255) / alpha; + destinationPixel[3] = (sourcePixel[3] * 255) / alpha; + } else { + destinationPixel[0] = (sourcePixel[0] * 255) / alpha; + destinationPixel[1] = (sourcePixel[1] * 255) / alpha; + destinationPixel[2] = (sourcePixel[2] * 255) / alpha; + destinationPixel[3] = alpha; + } + } else { + if (sourcePixelFormat == PixelFormat::ARGB8) { + destinationPixel[0] = (sourcePixel[1] * 255) / alpha; + destinationPixel[1] = (sourcePixel[2] * 255) / alpha; + destinationPixel[2] = (sourcePixel[3] * 255) / alpha; + destinationPixel[3] = alpha; + } else { + destinationPixel[0] = alpha; + destinationPixel[1] = (sourcePixel[0] * 255) / alpha; + destinationPixel[2] = (sourcePixel[1] * 255) / alpha; + destinationPixel[3] = (sourcePixel[2] * 255) / alpha; + } + } +#else if constexpr (pixelFormatConversion == PixelFormatConversion::None) { destinationPixel[0] = (sourcePixel[0] * 255) / alpha; destinationPixel[1] = (sourcePixel[1] * 255) / alpha; @@ -180,17 +245,58 @@ static void convertSinglePixelPremultipliedToUnpremultiplied(const uint8_t* sour destinationPixel[2] = (sourcePixel[0] * 255) / alpha; destinationPixel[3] = alpha; } +#endif } template +#if CPU(BIG_ENDIAN) +static void convertSinglePixelUnpremultipliedToPremultiplied(PixelFormat sourcePixelFormat, const uint8_t* sourcePixel, PixelFormat destinationPixelFormat, uint8_t* destinationPixel) +#else static void convertSinglePixelUnpremultipliedToPremultiplied(const uint8_t* sourcePixel, uint8_t* destinationPixel) +#endif { +#if CPU(BIG_ENDIAN) + uint8_t alpha = sourcePixel[sourcePixelFormat == PixelFormat::ARGB8 ? 0 : 3]; +#else uint8_t alpha = sourcePixel[3]; +#endif if (!alpha || alpha == 255) { +#if CPU(BIG_ENDIAN) + convertSinglePixelPremultipliedToPremultiplied(sourcePixelFormat, sourcePixel, destinationPixelFormat, destinationPixel); +#else convertSinglePixelPremultipliedToPremultiplied(sourcePixel, destinationPixel); +#endif return; } +#if CPU(BIG_ENDIAN) + UNUSED_PARAM(destinationPixelFormat); + if constexpr (pixelFormatConversion == PixelFormatConversion::None) { + if (sourcePixelFormat == PixelFormat::ARGB8) { + destinationPixel[0] = alpha; + destinationPixel[1] = (sourcePixel[1] * alpha + 254) / 255; + destinationPixel[2] = (sourcePixel[2] * alpha + 254) / 255; + destinationPixel[3] = (sourcePixel[3] * alpha + 254) / 255; + } else { + destinationPixel[0] = (sourcePixel[0] * alpha + 254) / 255; + destinationPixel[1] = (sourcePixel[1] * alpha + 254) / 255; + destinationPixel[2] = (sourcePixel[2] * alpha + 254) / 255; + destinationPixel[3] = alpha; + } + } else { + if (sourcePixelFormat == PixelFormat::ARGB8) { + destinationPixel[0] = (sourcePixel[1] * alpha + 254) / 255; + destinationPixel[1] = (sourcePixel[2] * alpha + 254) / 255; + destinationPixel[2] = (sourcePixel[3] * alpha + 254) / 255; + destinationPixel[3] = alpha; + } else { + destinationPixel[0] = alpha; + destinationPixel[1] = (sourcePixel[0] * alpha + 254) / 255; + destinationPixel[2] = (sourcePixel[1] * alpha + 254) / 255; + destinationPixel[3] = (sourcePixel[2] * alpha + 254) / 255; + } + } +#else if constexpr (pixelFormatConversion == PixelFormatConversion::None) { destinationPixel[0] = (sourcePixel[0] * alpha + 254) / 255; destinationPixel[1] = (sourcePixel[1] * alpha + 254) / 255; @@ -203,23 +309,49 @@ static void convertSinglePixelUnpremultipliedToPremultiplied(const uint8_t* sour destinationPixel[2] = (sourcePixel[0] * alpha + 254) / 255; destinationPixel[3] = alpha; } +#endif } template +#if CPU(BIG_ENDIAN) +static void convertSinglePixelUnpremultipliedToUnpremultiplied(PixelFormat sourcePixelFormat, const uint8_t* sourcePixel, PixelFormat destinationPixelFormat, uint8_t* destinationPixel) +#else static void convertSinglePixelUnpremultipliedToUnpremultiplied(const uint8_t* sourcePixel, uint8_t* destinationPixel) +#endif { if constexpr (pixelFormatConversion == PixelFormatConversion::None) reinterpret_cast(destinationPixel)[0] = reinterpret_cast(sourcePixel)[0]; else { +#if CPU(BIG_ENDIAN) + UNUSED_PARAM(sourcePixelFormat); + // Swap pixel channels ARGB <-> RGBA. + if (destinationPixelFormat == PixelFormat::ARGB8) { + destinationPixel[0] = sourcePixel[3]; + destinationPixel[1] = sourcePixel[0]; + destinationPixel[2] = sourcePixel[1]; + destinationPixel[3] = sourcePixel[2]; + } + else { + destinationPixel[0] = sourcePixel[1]; + destinationPixel[1] = sourcePixel[2]; + destinationPixel[2] = sourcePixel[3]; + destinationPixel[3] = sourcePixel[0]; + } +#else // Swap pixel channels BGRA <-> RGBA. destinationPixel[0] = sourcePixel[2]; destinationPixel[1] = sourcePixel[1]; destinationPixel[2] = sourcePixel[0]; destinationPixel[3] = sourcePixel[3]; +#endif } } +#if CPU(BIG_ENDIAN) +template +#else template +#endif static void convertImagePixelsUnaccelerated(const ConstPixelBufferConversionView& source, const PixelBufferConversionView& destination, const IntSize& destinationSize) { const uint8_t* sourceRows = source.rows; @@ -228,7 +360,11 @@ static void convertImagePixelsUnaccelerated(const ConstPixelBufferConversionView size_t bytesPerRow = destinationSize.width() * 4; for (int y = 0; y < destinationSize.height(); ++y) { for (size_t x = 0; x < bytesPerRow; x += 4) +#if CPU(BIG_ENDIAN) + convertFunctor(source.format.pixelFormat, &sourceRows[x], destination.format.pixelFormat, &destinationRows[x]); +#else convertFunctor(&sourceRows[x], &destinationRows[x]); +#endif sourceRows += source.bytesPerRow; destinationRows += destination.bytesPerRow; } @@ -237,6 +373,7 @@ static void convertImagePixelsUnaccelerated(const ConstPixelBufferConversionView void convertImagePixels(const ConstPixelBufferConversionView& source, const PixelBufferConversionView& destination, const IntSize& destinationSize) { // We don't currently support converting pixel data with non-8-bit buffers. + // BGRA8 is actually ARGB8 on BIG_ENDIAN. ASSERT(source.format.pixelFormat == PixelFormat::RGBA8 || source.format.pixelFormat == PixelFormat::BGRA8); ASSERT(destination.format.pixelFormat == PixelFormat::RGBA8 || destination.format.pixelFormat == PixelFormat::BGRA8); diff --git a/Source/WebCore/platform/graphics/PixelFormat.h b/Source/WebCore/platform/graphics/PixelFormat.h index 1ca711b8..4a7168f8 100644 --- a/Source/WebCore/platform/graphics/PixelFormat.h +++ b/Source/WebCore/platform/graphics/PixelFormat.h @@ -33,6 +33,9 @@ namespace WebCore { enum class PixelFormat : uint8_t { RGBA8, BGRA8, +#if CPU(BIG_ENDIAN) + ARGB8 = BGRA8, // BGRA will actually be ARGB on BIG_ENDIAN +#endif RGB10, RGB10A8, };