Add FPDFBitmap_BGRA_Premul format Expose FXDIB_Format::kBgraPremul to embedders. Then embedders that prefer pre-multiplied alpha can create pre-multiplied bitmaps and use them with PDFium without the need to do back and forth conversions between pre-multiplied alpha and straight alpha formats. Bug: 42271033 Change-Id: I6c51cbf844c939856b4bc4a80b24a4de5bfac0ea Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/129013 Commit-Queue: Lei Zhang <thestig@chromium.org> Reviewed-by: Tom Sepez <tsepez@chromium.org> Reviewed-by: Thomas Sepez <tsepez@google.com>
diff --git a/core/fxge/dib/cfx_dibitmap.cpp b/core/fxge/dib/cfx_dibitmap.cpp index de5a5c4..17ca2d2 100644 --- a/core/fxge/dib/cfx_dibitmap.cpp +++ b/core/fxge/dib/cfx_dibitmap.cpp
@@ -963,17 +963,17 @@ CFX_DIBitmap::ScopedPremultiplier::ScopedPremultiplier( RetainPtr<CFX_DIBitmap> bitmap) : bitmap_(std::move(bitmap)), do_premultiply_(NeedToPremultiplyBitmap()) { - CHECK(!bitmap_->IsPremultiplied()); if (do_premultiply_) { + CHECK(!bitmap_->IsPremultiplied()); bitmap_->PreMultiply(); } } CFX_DIBitmap::ScopedPremultiplier::~ScopedPremultiplier() { if (do_premultiply_) { + CHECK(bitmap_->IsPremultiplied()); bitmap_->UnPreMultiply(); } - CHECK(!bitmap_->IsPremultiplied()); } bool CFX_DIBitmap::ScopedPremultiplier::NeedToPremultiplyBitmap() const {
diff --git a/core/fxge/dib/cfx_dibitmap.h b/core/fxge/dib/cfx_dibitmap.h index c5ef3aa..b051427 100644 --- a/core/fxge/dib/cfx_dibitmap.h +++ b/core/fxge/dib/cfx_dibitmap.h
@@ -33,7 +33,6 @@ // un-premultiplies in the dtor if pre-multiplication was required. class ScopedPremultiplier { public: - // `bitmap` must start out un-premultiplied. // ScopedPremultiplier is a no-op if `bitmap` does not need to be // pre-multiplied, as determined by NeedToPremultiplyBitmap(). explicit ScopedPremultiplier(RetainPtr<CFX_DIBitmap> bitmap);
diff --git a/fpdfsdk/cpdfsdk_helpers.cpp b/fpdfsdk/cpdfsdk_helpers.cpp index aff8aed..7454626 100644 --- a/fpdfsdk/cpdfsdk_helpers.cpp +++ b/fpdfsdk/cpdfsdk_helpers.cpp
@@ -31,6 +31,10 @@ #include "core/fxge/dib/cfx_dibitmap.h" #include "fpdfsdk/cpdfsdk_formfillenvironment.h" +#if defined(PDF_USE_SKIA) +#include "core/fxge/cfx_defaultrenderdevice.h" +#endif + namespace { constexpr char kQuadPoints[] = "QuadPoints"; @@ -225,13 +229,26 @@ return FXDIB_Format::kBgrx; case FPDFBitmap_BGRA: return FXDIB_Format::kBgra; +#if defined(PDF_USE_SKIA) + case FPDFBitmap_BGRA_Premul: + return CFX_DefaultRenderDevice::UseSkiaRenderer() + ? FXDIB_Format::kBgraPremul + : FXDIB_Format::kInvalid; +#endif default: return FXDIB_Format::kInvalid; } } void ValidateBitmapPremultiplyState(CFX_DIBitmap* bitmap) { +#if defined(PDF_USE_SKIA) + const bool should_be_premultiplied = + CFX_DefaultRenderDevice::UseSkiaRenderer() && + bitmap->GetFormat() == FXDIB_Format::kBgraPremul; + CHECK_EQ(should_be_premultiplied, bitmap->IsPremultiplied()); +#else CHECK(!bitmap->IsPremultiplied()); +#endif } CPDFSDK_InteractiveForm* FormHandleToInteractiveForm(FPDF_FORMHANDLE hHandle) {
diff --git a/fpdfsdk/cpdfsdk_helpers.h b/fpdfsdk/cpdfsdk_helpers.h index 9621092..90cdc96 100644 --- a/fpdfsdk/cpdfsdk_helpers.h +++ b/fpdfsdk/cpdfsdk_helpers.h
@@ -264,8 +264,12 @@ FXDIB_Format FXDIBFormatFromFPDFFormat(int format); -// CHECK() `bitmap` is not pre-multiplied, as PDFium does not take or hand out -// pre-multiplied bitmaps to the embedder. +// CHECK() the pre-multiplied state for bitmaps from the embedder, or handed to +// the embedder. +// - When Skia is available and enabled at runtime, make sure its format matches +// its pre-multiplied state. +// - When Skia is not available or not enabled at runtime, make sure `bitmap` is +// not pre-multiplied. void ValidateBitmapPremultiplyState(CFX_DIBitmap* bitmap); CPDFSDK_InteractiveForm* FormHandleToInteractiveForm(FPDF_FORMHANDLE hHandle);
diff --git a/fpdfsdk/fpdf_view.cpp b/fpdfsdk/fpdf_view.cpp index da464bc..8bd14aa 100644 --- a/fpdfsdk/fpdf_view.cpp +++ b/fpdfsdk/fpdf_view.cpp
@@ -936,6 +936,11 @@ return FPDFBitmap_BGRx; case FXDIB_Format::kBgra: return FPDFBitmap_BGRA; +#if defined(PDF_USE_SKIA) + case FXDIB_Format::kBgraPremul: + return CFX_DefaultRenderDevice::UseSkiaRenderer() ? FPDFBitmap_BGRA_Premul + : FPDFBitmap_Unknown; +#endif default: return FPDFBitmap_Unknown; }
diff --git a/fpdfsdk/fpdf_view_embeddertest.cpp b/fpdfsdk/fpdf_view_embeddertest.cpp index 8c42582..5eb5e97 100644 --- a/fpdfsdk/fpdf_view_embeddertest.cpp +++ b/fpdfsdk/fpdf_view_embeddertest.cpp
@@ -1632,6 +1632,20 @@ ManyRectanglesChecksum()); TestRenderPageBitmapWithExternalMemoryAndNoStride(page.get(), FPDFBitmap_BGRA, ManyRectanglesChecksum()); + +#if defined(PDF_USE_SKIA) + if (CFX_DefaultRenderDevice::UseSkiaRenderer()) { + TestRenderPageBitmapWithInternalMemory(page.get(), FPDFBitmap_BGRA_Premul, + ManyRectanglesChecksum()); + TestRenderPageBitmapWithInternalMemoryAndStride( + page.get(), FPDFBitmap_BGRA_Premul, kBgrxStride, + ManyRectanglesChecksum()); + TestRenderPageBitmapWithExternalMemory(page.get(), FPDFBitmap_BGRA_Premul, + ManyRectanglesChecksum()); + TestRenderPageBitmapWithExternalMemoryAndNoStride( + page.get(), FPDFBitmap_BGRA_Premul, ManyRectanglesChecksum()); + } +#endif } TEST_F(FPDFViewEmbedderTest, RenderHelloWorldWithFlags) { @@ -2207,3 +2221,16 @@ // Make sure null bitmap handle does not trigger a crash. ASSERT_FALSE(FPDFBitmap_FillRect(nullptr, 0, 0, kWidth, kHeight, 0xFF0000FF)); } + +TEST_F(FPDFViewEmbedderTest, BitmapBGRAPremulFormat) { + static constexpr int kWidth = 100; + static constexpr int kHeight = 200; + ScopedFPDFBitmap bitmap( + FPDFBitmap_CreateEx(kWidth, kHeight, FPDFBitmap_BGRA_Premul, nullptr, 0)); + if (CFX_DefaultRenderDevice::UseSkiaRenderer()) { + ASSERT_TRUE(bitmap); + EXPECT_EQ(FPDFBitmap_BGRA_Premul, FPDFBitmap_GetFormat(bitmap.get())); + } else { + ASSERT_FALSE(bitmap); + } +}
diff --git a/public/fpdfview.h b/public/fpdfview.h index 540d569..6922da9 100644 --- a/public/fpdfview.h +++ b/public/fpdfview.h
@@ -1088,7 +1088,13 @@ // 4 bytes per pixel, byte order: blue, green, red, unused. #define FPDFBitmap_BGRx 3 // 4 bytes per pixel, byte order: blue, green, red, alpha. +// Pixel components are independent of alpha. #define FPDFBitmap_BGRA 4 +// 4 bytes per pixel, byte order: blue, green, red, alpha. +// Pixel components are premultiplied by alpha. +// Note that this is experimental and only supported when rendering with +// |FPDF_RENDERER_TYPE| is set to |FPDF_RENDERERTYPE_SKIA|. +#define FPDFBitmap_BGRA_Premul 5 // Function: FPDFBitmap_CreateEx // Create a device independent bitmap (FXDIB)