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)