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)