blob: 7fb996ef428f5495f67353c2983b7c38cda0247a [file] [log] [blame]
// Copyright 2024 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/fxge/dib/cfx_scanlinecompositor.h"
#include <stdint.h>
#include <array>
#include "core/fxcrt/span.h"
#include "core/fxcrt/stl_util.h"
#include "core/fxge/dib/fx_dib.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::ElementsAreArray;
namespace {
constexpr FX_BGRA_STRUCT<uint8_t> kDestScan[] = {
{.blue = 255, .green = 100, .red = 0, .alpha = 0},
{.blue = 255, .green = 100, .red = 0, .alpha = 0},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 100},
{.blue = 255, .green = 100, .red = 0, .alpha = 100},
{.blue = 255, .green = 100, .red = 0, .alpha = 200},
{.blue = 255, .green = 100, .red = 0, .alpha = 200},
};
constexpr FX_BGRA_STRUCT<uint8_t> kSrcScan1[] = {
{.blue = 255, .green = 100, .red = 0, .alpha = 0},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 0},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 100},
{.blue = 255, .green = 100, .red = 0, .alpha = 200},
{.blue = 255, .green = 100, .red = 0, .alpha = 100},
{.blue = 255, .green = 100, .red = 0, .alpha = 200},
};
constexpr FX_BGRA_STRUCT<uint8_t> kSrcScan2[] = {
{.blue = 100, .green = 0, .red = 255, .alpha = 0},
{.blue = 100, .green = 0, .red = 255, .alpha = 255},
{.blue = 100, .green = 0, .red = 255, .alpha = 0},
{.blue = 100, .green = 0, .red = 255, .alpha = 255},
{.blue = 100, .green = 0, .red = 255, .alpha = 100},
{.blue = 100, .green = 0, .red = 255, .alpha = 200},
{.blue = 100, .green = 0, .red = 255, .alpha = 100},
{.blue = 100, .green = 0, .red = 255, .alpha = 200},
};
constexpr FX_BGRA_STRUCT<uint8_t> kSrcScan3[] = {
{.blue = 0, .green = 255, .red = 100, .alpha = 0},
{.blue = 0, .green = 255, .red = 100, .alpha = 255},
{.blue = 0, .green = 255, .red = 100, .alpha = 0},
{.blue = 0, .green = 255, .red = 100, .alpha = 255},
{.blue = 0, .green = 255, .red = 100, .alpha = 100},
{.blue = 0, .green = 255, .red = 100, .alpha = 200},
{.blue = 0, .green = 255, .red = 100, .alpha = 100},
{.blue = 0, .green = 255, .red = 100, .alpha = 200},
};
void RunTest(CFX_ScanlineCompositor& compositor,
pdfium::span<const FX_BGRA_STRUCT<uint8_t>> src_span,
pdfium::span<const FX_BGRA_STRUCT<uint8_t>> expectations) {
std::array<FX_BGRA_STRUCT<uint8_t>, 8> dest_scan;
fxcrt::Copy(kDestScan, dest_scan);
compositor.CompositeRgbBitmapLine(pdfium::as_writable_byte_span(dest_scan),
pdfium::as_bytes(src_span),
dest_scan.size(), {});
EXPECT_THAT(dest_scan, ElementsAreArray(expectations));
}
#if defined(PDF_USE_SKIA)
void PreMultiplyScanLine(pdfium::span<FX_BGRA_STRUCT<uint8_t>> scanline) {
for (auto& pixel : scanline) {
pixel = PreMultiplyColor(pixel);
}
}
void UnPreMultiplyScanLine(pdfium::span<FX_BGRA_STRUCT<uint8_t>> scanline) {
for (auto& pixel : scanline) {
pixel = UnPreMultiplyColor(pixel);
}
}
void RunPreMultiplyTest(
CFX_ScanlineCompositor& compositor,
pdfium::span<const FX_BGRA_STRUCT<uint8_t>> src_span,
pdfium::span<const FX_BGRA_STRUCT<uint8_t>> expectations) {
std::array<FX_BGRA_STRUCT<uint8_t>, 8> dest_scan;
fxcrt::Copy(kDestScan, dest_scan);
PreMultiplyScanLine(dest_scan);
std::array<FX_BGRA_STRUCT<uint8_t>, 8> src_scan;
fxcrt::Copy(src_span, src_scan);
PreMultiplyScanLine(src_scan);
compositor.CompositeRgbBitmapLine(pdfium::as_writable_byte_span(dest_scan),
pdfium::as_byte_span(src_scan),
dest_scan.size(), {});
UnPreMultiplyScanLine(dest_scan);
EXPECT_THAT(dest_scan, ElementsAreArray(expectations));
}
#endif // defined(PDF_USE_SKIA)
} // namespace
inline bool operator==(const FX_BGRA_STRUCT<uint8_t>& lhs,
const FX_BGRA_STRUCT<uint8_t>& rhs) {
return lhs.blue == rhs.blue && lhs.green == rhs.green && lhs.red == rhs.red &&
lhs.alpha == rhs.alpha;
}
TEST(ScanlineCompositorTest, CompositeRgbBitmapLineBgraNormal) {
CFX_ScanlineCompositor compositor;
ASSERT_TRUE(compositor.Init(/*dest_format=*/FXDIB_Format::kBgra,
/*src_format=*/FXDIB_Format::kBgra,
/*src_palette=*/{},
/*mask_color=*/0,
/*blend_type=*/BlendMode::kNormal,
/*bRgbByteOrder=*/false));
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations1[] = {
{.blue = 255, .green = 100, .red = 0, .alpha = 0},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 161},
{.blue = 255, .green = 100, .red = 0, .alpha = 222},
{.blue = 255, .green = 100, .red = 0, .alpha = 222},
{.blue = 255, .green = 100, .red = 0, .alpha = 244},
};
RunTest(compositor, kSrcScan1, kExpectations1);
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations2[] = {
{.blue = 100, .green = 0, .red = 255, .alpha = 0},
{.blue = 100, .green = 0, .red = 255, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 100, .green = 0, .red = 255, .alpha = 255},
{.blue = 158, .green = 38, .red = 158, .alpha = 161},
{.blue = 115, .green = 10, .red = 229, .alpha = 222},
{.blue = 185, .green = 55, .red = 114, .alpha = 222},
{.blue = 127, .green = 18, .red = 209, .alpha = 244},
};
RunTest(compositor, kSrcScan2, kExpectations2);
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations3[] = {
{.blue = 0, .green = 255, .red = 100, .alpha = 0},
{.blue = 0, .green = 255, .red = 100, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 0, .green = 255, .red = 100, .alpha = 255},
{.blue = 97, .green = 196, .red = 61, .alpha = 161},
{.blue = 26, .green = 239, .red = 89, .alpha = 222},
{.blue = 141, .green = 169, .red = 44, .alpha = 222},
{.blue = 46, .green = 227, .red = 81, .alpha = 244},
};
RunTest(compositor, kSrcScan3, kExpectations3);
}
TEST(ScanlineCompositorTest, CompositeRgbBitmapLineBgraDarken) {
CFX_ScanlineCompositor compositor;
ASSERT_TRUE(compositor.Init(/*dest_format=*/FXDIB_Format::kBgra,
/*src_format=*/FXDIB_Format::kBgra,
/*src_palette=*/{},
/*mask_color=*/0,
/*blend_type=*/BlendMode::kDarken,
/*bRgbByteOrder=*/false));
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations1[] = {
{.blue = 255, .green = 100, .red = 0, .alpha = 0},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 161},
{.blue = 255, .green = 100, .red = 0, .alpha = 222},
{.blue = 255, .green = 100, .red = 0, .alpha = 222},
{.blue = 255, .green = 100, .red = 0, .alpha = 244},
};
RunTest(compositor, kSrcScan1, kExpectations1);
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations2[] = {
{.blue = 100, .green = 0, .red = 255, .alpha = 0},
{.blue = 100, .green = 0, .red = 255, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 100, .green = 0, .red = 0, .alpha = 255},
{.blue = 158, .green = 38, .red = 96, .alpha = 161},
{.blue = 115, .green = 10, .red = 139, .alpha = 222},
{.blue = 185, .green = 55, .red = 24, .alpha = 222},
{.blue = 127, .green = 18, .red = 45, .alpha = 244},
};
RunTest(compositor, kSrcScan2, kExpectations2);
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations3[] = {
{.blue = 0, .green = 255, .red = 100, .alpha = 0},
{.blue = 0, .green = 255, .red = 100, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 0, .green = 100, .red = 0, .alpha = 255},
{.blue = 97, .green = 158, .red = 37, .alpha = 161},
{.blue = 26, .green = 184, .red = 53, .alpha = 222},
{.blue = 141, .green = 114, .red = 9, .alpha = 222},
{.blue = 46, .green = 127, .red = 17, .alpha = 244},
};
RunTest(compositor, kSrcScan3, kExpectations3);
}
TEST(ScanlineCompositorTest, CompositeRgbBitmapLineBgraHue) {
CFX_ScanlineCompositor compositor;
ASSERT_TRUE(compositor.Init(/*dest_format=*/FXDIB_Format::kBgra,
/*src_format=*/FXDIB_Format::kBgra,
/*src_palette=*/{},
/*mask_color=*/0,
/*blend_type=*/BlendMode::kHue,
/*bRgbByteOrder=*/false));
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations1[] = {
{.blue = 255, .green = 100, .red = 0, .alpha = 0},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 161},
{.blue = 255, .green = 100, .red = 0, .alpha = 222},
{.blue = 255, .green = 100, .red = 0, .alpha = 222},
{.blue = 255, .green = 100, .red = 0, .alpha = 244},
};
RunTest(compositor, kSrcScan1, kExpectations1);
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations2[] = {
{.blue = 100, .green = 0, .red = 255, .alpha = 0},
{.blue = 100, .green = 0, .red = 255, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 100, .green = 0, .red = 255, .alpha = 255},
{.blue = 158, .green = 38, .red = 158, .alpha = 161},
{.blue = 115, .green = 10, .red = 229, .alpha = 222},
{.blue = 185, .green = 55, .red = 114, .alpha = 222},
{.blue = 127, .green = 18, .red = 209, .alpha = 244},
};
RunTest(compositor, kSrcScan2, kExpectations2);
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations3[] = {
{.blue = 0, .green = 255, .red = 100, .alpha = 0},
{.blue = 0, .green = 255, .red = 100, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 0, .green = 123, .red = 49, .alpha = 255},
{.blue = 97, .green = 163, .red = 49, .alpha = 161},
{.blue = 26, .green = 192, .red = 71, .alpha = 222},
{.blue = 141, .green = 122, .red = 26, .alpha = 222},
{.blue = 46, .green = 141, .red = 49, .alpha = 244},
};
RunTest(compositor, kSrcScan3, kExpectations3);
}
#if defined(PDF_USE_SKIA)
TEST(ScanlineCompositorTest, CompositeRgbBitmapLineBgraPremulNormal) {
CFX_ScanlineCompositor compositor;
ASSERT_TRUE(compositor.Init(/*dest_format=*/FXDIB_Format::kBgraPremul,
/*src_format=*/FXDIB_Format::kBgraPremul,
/*src_palette=*/{},
/*mask_color=*/0,
/*blend_type=*/BlendMode::kNormal,
/*bRgbByteOrder=*/false));
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations1[] = {
{.blue = 0, .green = 0, .red = 0, .alpha = 0},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 253, .green = 98, .red = 0, .alpha = 161},
{.blue = 253, .green = 98, .red = 0, .alpha = 222},
{.blue = 253, .green = 98, .red = 0, .alpha = 222},
{.blue = 253, .green = 98, .red = 0, .alpha = 244},
};
RunPreMultiplyTest(compositor, kSrcScan1, kExpectations1);
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations2[] = {
{.blue = 0, .green = 0, .red = 0, .alpha = 0},
{.blue = 100, .green = 0, .red = 255, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 100, .green = 0, .red = 255, .alpha = 255},
{.blue = 156, .green = 36, .red = 158, .alpha = 161},
{.blue = 113, .green = 9, .red = 229, .alpha = 222},
{.blue = 183, .green = 53, .red = 114, .alpha = 222},
{.blue = 126, .green = 16, .red = 209, .alpha = 244},
};
RunPreMultiplyTest(compositor, kSrcScan2, kExpectations2);
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations3[] = {
{.blue = 0, .green = 0, .red = 0, .alpha = 0},
{.blue = 0, .green = 255, .red = 100, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 0, .green = 255, .red = 100, .alpha = 255},
{.blue = 95, .green = 194, .red = 61, .alpha = 161},
{.blue = 24, .green = 238, .red = 89, .alpha = 222},
{.blue = 138, .green = 168, .red = 44, .alpha = 222},
{.blue = 44, .green = 225, .red = 81, .alpha = 244},
};
RunPreMultiplyTest(compositor, kSrcScan3, kExpectations3);
}
TEST(ScanlineCompositorTest, CompositeRgbBitmapLineBgraPremulDarken) {
CFX_ScanlineCompositor compositor;
ASSERT_TRUE(compositor.Init(/*dest_format=*/FXDIB_Format::kBgraPremul,
/*src_format=*/FXDIB_Format::kBgraPremul,
/*src_palette=*/{},
/*mask_color=*/0,
/*blend_type=*/BlendMode::kDarken,
/*bRgbByteOrder=*/false));
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations1[] = {
{.blue = 0, .green = 0, .red = 0, .alpha = 0},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 253, .green = 98, .red = 0, .alpha = 161},
{.blue = 253, .green = 97, .red = 0, .alpha = 222},
{.blue = 253, .green = 97, .red = 0, .alpha = 222},
{.blue = 252, .green = 98, .red = 0, .alpha = 244},
};
RunPreMultiplyTest(compositor, kSrcScan1, kExpectations1);
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations2[] = {
{.blue = 0, .green = 0, .red = 0, .alpha = 0},
{.blue = 100, .green = 0, .red = 255, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 100, .green = 0, .red = 0, .alpha = 255},
{.blue = 156, .green = 36, .red = 95, .alpha = 161},
{.blue = 112, .green = 9, .red = 138, .alpha = 222},
{.blue = 182, .green = 53, .red = 24, .alpha = 222},
{.blue = 125, .green = 16, .red = 44, .alpha = 244},
};
RunPreMultiplyTest(compositor, kSrcScan2, kExpectations2);
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations3[] = {
{.blue = 0, .green = 0, .red = 0, .alpha = 0},
{.blue = 0, .green = 255, .red = 100, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 0, .green = 100, .red = 0, .alpha = 255},
{.blue = 95, .green = 156, .red = 36, .alpha = 161},
{.blue = 24, .green = 182, .red = 53, .alpha = 222},
{.blue = 138, .green = 112, .red = 9, .alpha = 222},
{.blue = 44, .green = 125, .red = 16, .alpha = 244},
};
RunPreMultiplyTest(compositor, kSrcScan3, kExpectations3);
}
TEST(ScanlineCompositorTest, CompositeRgbBitmapLineBgraPremulHue) {
CFX_ScanlineCompositor compositor;
ASSERT_TRUE(compositor.Init(/*dest_format=*/FXDIB_Format::kBgraPremul,
/*src_format=*/FXDIB_Format::kBgraPremul,
/*src_palette=*/{},
/*mask_color=*/0,
/*blend_type=*/BlendMode::kHue,
/*bRgbByteOrder=*/false));
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations1[] = {
{.blue = 0, .green = 0, .red = 0, .alpha = 0},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 253, .green = 98, .red = 0, .alpha = 161},
{.blue = 253, .green = 97, .red = 0, .alpha = 222},
{.blue = 253, .green = 97, .red = 0, .alpha = 222},
{.blue = 252, .green = 98, .red = 0, .alpha = 244},
};
RunPreMultiplyTest(compositor, kSrcScan1, kExpectations1);
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations2[] = {
{.blue = 0, .green = 0, .red = 0, .alpha = 0},
{.blue = 100, .green = 0, .red = 255, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 100, .green = 0, .red = 255, .alpha = 255},
{.blue = 156, .green = 36, .red = 156, .alpha = 161},
{.blue = 112, .green = 9, .red = 228, .alpha = 222},
{.blue = 182, .green = 53, .red = 113, .alpha = 222},
{.blue = 125, .green = 16, .red = 207, .alpha = 244},
};
RunPreMultiplyTest(compositor, kSrcScan2, kExpectations2);
static constexpr FX_BGRA_STRUCT<uint8_t> kExpectations3[] = {
{.blue = 0, .green = 0, .red = 0, .alpha = 0},
{.blue = 0, .green = 255, .red = 100, .alpha = 255},
{.blue = 255, .green = 100, .red = 0, .alpha = 255},
{.blue = 0, .green = 123, .red = 49, .alpha = 255},
{.blue = 95, .green = 161, .red = 49, .alpha = 161},
{.blue = 24, .green = 189, .red = 71, .alpha = 222},
{.blue = 138, .green = 119, .red = 26, .alpha = 222},
{.blue = 44, .green = 140, .red = 48, .alpha = 244},
};
RunPreMultiplyTest(compositor, kSrcScan3, kExpectations3);
}
#endif // defined(PDF_USE_SKIA)