Check `FXDIB_Format::kArgbPremul` in CFX_DIBBase::IsPremultiplied()
Remove `CFX_DIBitmap::m_nFormat` and use `CFX_DIBBase::m_Format` as the
canonical source of bitmap format information. Also remove
CFX_DIBitmap::ForcePreMultiply(), as bitmaps can be pre-multiplied to
start with if they are of `FXDIB_Format::kArgbPremul`.
Update some test expectations to match this change. Most of the changes
are off by 1 pixel values due to rounding errors. When comparing the
old and new bitmaps, they are not pixel perfect according to
pdfium_diff, but will pass with --fuzzy.
Also update DEPS with new corpus test expectations to match this change:
https://pdfium.googlesource.com/pdfium_tests/+log/a062df7af5b3..8c3dc126d92c
Bug: 42271020
Change-Id: I7726b3915602c0ca1845a19e28f9d2d6cc107faf
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/122893
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@google.com>
diff --git a/DEPS b/DEPS
index 75e8198..6e7c9cc 100644
--- a/DEPS
+++ b/DEPS
@@ -174,7 +174,7 @@
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling pdfium_tests
# and whatever else without interference from each other.
- 'pdfium_tests_revision': 'a062df7af5b34db1aaf40424176e1c1914f6d31f',
+ 'pdfium_tests_revision': '8c3dc126d92cfad8b32830404398c6119be598a5',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling resultdb
# and whatever else without interference from each other.
diff --git a/core/fpdfapi/render/cpdf_renderstatus.cpp b/core/fpdfapi/render/cpdf_renderstatus.cpp
index 58a86fa..b45b6a3 100644
--- a/core/fpdfapi/render/cpdf_renderstatus.cpp
+++ b/core/fpdfapi/render/cpdf_renderstatus.cpp
@@ -642,10 +642,8 @@
return true;
m_pDevice->GetDIBits(backdrop, rect.left, rect.top);
}
- // TODO(crbug.com/42271020): Consider adding support for
- // `FXDIB_Format::kArgbPremul`
- if (!bitmap_device.CreateWithBackdrop(width, height, FXDIB_Format::kArgb,
- backdrop)) {
+ if (!bitmap_device.CreateWithBackdrop(
+ width, height, GetCompatibleArgbFormat(), std::move(backdrop))) {
return true;
}
@@ -684,13 +682,6 @@
bitmap_render.SetInGroup(transparency.IsGroup());
bitmap_render.Initialize(nullptr, nullptr);
bitmap_render.ProcessObjectNoClip(pPageObj, new_matrix);
-#if defined(PDF_USE_SKIA)
- if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
- // Safe because `CFX_SkiaDeviceDriver` always uses pre-multiplied alpha.
- // TODO(crbug.com/42271020): Remove the need for this.
- bitmap_device.GetBitmap()->ForcePreMultiply();
- }
-#endif
m_bStopped = bitmap_render.m_bStopped;
if (pSMaskDict) {
CFX_Matrix smask_matrix =
@@ -714,11 +705,6 @@
if (pPageObj->IsForm()) {
transparency.SetGroup();
}
-#if defined(PDF_USE_SKIA)
- if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
- bitmap_device.GetBitmap()->UnPreMultiply();
- }
-#endif
CompositeDIBitmap(bitmap_device.GetBitmap(), rect.left, rect.top,
/*mask_argb=*/0, /*alpha=*/1.0f, blend_type, transparency);
return true;
@@ -1494,3 +1480,12 @@
static_cast<int>(rgb.green * 255),
static_cast<int>(rgb.blue * 255));
}
+
+FXDIB_Format CPDF_RenderStatus::GetCompatibleArgbFormat() const {
+#if defined(PDF_USE_SKIA)
+ if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_PREMULTIPLIED_ALPHA) {
+ return FXDIB_Format::kArgbPremul;
+ }
+#endif
+ return FXDIB_Format::kArgb;
+}
diff --git a/core/fpdfapi/render/cpdf_renderstatus.h b/core/fpdfapi/render/cpdf_renderstatus.h
index ef94e35..9df2711 100644
--- a/core/fpdfapi/render/cpdf_renderstatus.h
+++ b/core/fpdfapi/render/cpdf_renderstatus.h
@@ -184,6 +184,8 @@
FX_ARGB GetStrokeArgb(CPDF_PageObject* pObj) const;
FX_RECT GetObjectClippedRect(const CPDF_PageObject* pObj,
const CFX_Matrix& mtObj2Device) const;
+ // Returns the format that is compatible with `m_pDevice`.
+ FXDIB_Format GetCompatibleArgbFormat() const;
CPDF_RenderOptions m_Options;
RetainPtr<const CPDF_Dictionary> m_pFormResource;
diff --git a/core/fpdfapi/render/cpdf_rendertiling.cpp b/core/fpdfapi/render/cpdf_rendertiling.cpp
index cc18e10..8c88d32 100644
--- a/core/fpdfapi/render/cpdf_rendertiling.cpp
+++ b/core/fpdfapi/render/cpdf_rendertiling.cpp
@@ -63,11 +63,6 @@
context.AppendLayer(pPatternForm, mtPattern2Bitmap);
context.Render(&bitmap_device, nullptr, &options, nullptr);
-#if defined(PDF_USE_SKIA)
- if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
- pBitmap->UnPreMultiply();
- }
-#endif // defined(PDF_USE_SKIA)
return pBitmap;
}
diff --git a/core/fxge/cfx_renderdevice.cpp b/core/fxge/cfx_renderdevice.cpp
index a46b9ab..1f5013f 100644
--- a/core/fxge/cfx_renderdevice.cpp
+++ b/core/fxge/cfx_renderdevice.cpp
@@ -215,6 +215,8 @@
bool normalize,
int x_subpixel,
const FX_BGRA_STRUCT<uint8_t>& bgra) {
+ // TODO(crbug.com/42271020): Add support for `FXDIB_Format::kArgbPremul`.
+ CHECK(!bitmap->IsPremultiplied());
const bool has_alpha = bitmap->IsAlphaFormat();
const int Bpp = has_alpha ? 4 : bitmap->GetBPP() / 8;
for (int row = 0; row < nrows; ++row) {
@@ -467,13 +469,17 @@
return new_path_size != 0;
}
-FXDIB_Format GetCreateCompatibleBitmapFormat(int render_caps) {
+FXDIB_Format GetCreateCompatibleBitmapFormat(int render_caps,
+ bool use_argb_premul) {
if (render_caps & FXRC_BYTEMASK_OUTPUT) {
return FXDIB_Format::k8bppMask;
}
+#if defined(PDF_USE_SKIA)
+ if (use_argb_premul && (render_caps & FXRC_PREMULTIPLIED_ALPHA)) {
+ return FXDIB_Format::kArgbPremul;
+ }
+#endif
if (render_caps & FXRC_ALPHA_OUTPUT) {
- // TODO(crbug.com/42271020): Consider adding support for
- // `FXDIB_Format::kArgbPremul`
return FXDIB_Format::kArgb;
}
return CFX_DIBBase::kPlatformRGBFormat;
@@ -543,8 +549,9 @@
const RetainPtr<CFX_DIBitmap>& pDIB,
int width,
int height) const {
- return pDIB->Create(width, height,
- GetCreateCompatibleBitmapFormat(m_RenderCaps));
+ return pDIB->Create(
+ width, height,
+ GetCreateCompatibleBitmapFormat(m_RenderCaps, /*use_argb_premul=*/true));
}
void CFX_RenderDevice::SetBaseClip(const FX_RECT& rect) {
@@ -1181,8 +1188,13 @@
if (!bitmap->Create(pixel_width, pixel_height, FXDIB_Format::k8bppMask))
return false;
} else {
- if (!CreateCompatibleBitmap(bitmap, pixel_width, pixel_height))
+ // TODO(crbug.com/42271020): Switch to CreateCompatibleBitmap() once
+ // DrawNormalTextHelper() supports `FXDIB_Format::kArgbPremul`.
+ if (!bitmap->Create(pixel_width, pixel_height,
+ GetCreateCompatibleBitmapFormat(
+ m_RenderCaps, /*use_argb_premul=*/false))) {
return false;
+ }
}
if (!bitmap->IsAlphaFormat() && !bitmap->IsMaskFormat()) {
bitmap->Clear(0xFFFFFFFF);
diff --git a/core/fxge/dib/cfx_dibbase.cpp b/core/fxge/dib/cfx_dibbase.cpp
index 1e285e3..55354ab 100644
--- a/core/fxge/dib/cfx_dibbase.cpp
+++ b/core/fxge/dib/cfx_dibbase.cpp
@@ -1130,7 +1130,3 @@
#endif
}
}
-
-bool CFX_DIBBase::IsPremultiplied() const {
- return false;
-}
diff --git a/core/fxge/dib/cfx_dibbase.h b/core/fxge/dib/cfx_dibbase.h
index 6e70dd5..905d283 100644
--- a/core/fxge/dib/cfx_dibbase.h
+++ b/core/fxge/dib/cfx_dibbase.h
@@ -107,8 +107,13 @@
int& src_top,
const CFX_ClipRgn* pClipRgn) const;
- // Whether alpha is premultiplied (if `IsAlphaFormat()`).
- virtual bool IsPremultiplied() const;
+ bool IsPremultiplied() const {
+#if defined(PDF_USE_SKIA)
+ return GetFormat() == FXDIB_Format::kArgbPremul;
+#else
+ return false;
+#endif
+ }
#if defined(PDF_USE_SKIA)
// Realizes an `SkImage` from this DIB.
diff --git a/core/fxge/dib/cfx_dibitmap.cpp b/core/fxge/dib/cfx_dibitmap.cpp
index b8f9c18..918dd86 100644
--- a/core/fxge/dib/cfx_dibitmap.cpp
+++ b/core/fxge/dib/cfx_dibitmap.cpp
@@ -14,6 +14,7 @@
#include "core/fxcrt/check.h"
#include "core/fxcrt/check_op.h"
#include "core/fxcrt/compiler_specific.h"
+#include "core/fxcrt/containers/contains.h"
#include "core/fxcrt/data_vector.h"
#include "core/fxcrt/fx_coordinates.h"
#include "core/fxcrt/fx_memcpy_wrappers.h"
@@ -867,27 +868,58 @@
}
bool CFX_DIBitmap::ConvertFormat(FXDIB_Format dest_format) {
- // TODO(crbug.com/42271020): Consider adding support for
- // `FXDIB_Format::kArgbPremul`
- DCHECK(dest_format == FXDIB_Format::k8bppMask ||
- dest_format == FXDIB_Format::kArgb ||
- dest_format == FXDIB_Format::kRgb);
+ static constexpr FXDIB_Format kAllowedDestFormats[] = {
+ FXDIB_Format::k8bppMask,
+ FXDIB_Format::kArgb,
+#if defined(PDF_USE_SKIA)
+ FXDIB_Format::kArgbPremul,
+#endif
+ FXDIB_Format::kRgb,
+ };
+ CHECK(pdfium::Contains(kAllowedDestFormats, dest_format));
if (dest_format == GetFormat()) {
return true;
}
- if (dest_format == FXDIB_Format::k8bppMask &&
- GetFormat() == FXDIB_Format::k8bppRgb && !HasPalette()) {
- SetFormat(FXDIB_Format::k8bppMask);
- return true;
- }
+ switch (dest_format) {
+ case FXDIB_Format::k8bppMask:
+ if (GetFormat() == FXDIB_Format::k8bppRgb && !HasPalette()) {
+ SetFormat(FXDIB_Format::k8bppMask);
+ return true;
+ }
+ break;
- if (dest_format == FXDIB_Format::kArgb &&
- GetFormat() == FXDIB_Format::kRgb32) {
- SetFormat(FXDIB_Format::kArgb);
- SetUniformOpaqueAlpha();
- return true;
+ case FXDIB_Format::kArgb:
+ if (GetFormat() == FXDIB_Format::kRgb32) {
+ SetFormat(FXDIB_Format::kArgb);
+ SetUniformOpaqueAlpha();
+ return true;
+ }
+#if defined(PDF_USE_SKIA)
+ if (GetFormat() == FXDIB_Format::kArgbPremul) {
+ UnPreMultiply();
+ return true;
+ }
+#endif // defined(PDF_USE_SKIA)
+ break;
+
+#if defined(PDF_USE_SKIA)
+ case FXDIB_Format::kArgbPremul:
+ if (GetFormat() == FXDIB_Format::kRgb32) {
+ SetFormat(FXDIB_Format::kArgbPremul);
+ SetUniformOpaqueAlpha();
+ return true;
+ }
+ if (GetFormat() == FXDIB_Format::kArgb) {
+ PreMultiply();
+ return true;
+ }
+ break;
+#endif // defined(PDF_USE_SKIA)
+
+ default:
+ break;
}
std::optional<PitchAndSize> pitch_size =
diff --git a/core/fxge/dib/cfx_dibitmap.h b/core/fxge/dib/cfx_dibitmap.h
index 7b55f04..53e646f 100644
--- a/core/fxge/dib/cfx_dibitmap.h
+++ b/core/fxge/dib/cfx_dibitmap.h
@@ -161,22 +161,11 @@
// Converts from/to un-pre-multiplied alpha if necessary.
void PreMultiply();
void UnPreMultiply();
-
- // Forces pre-multiplied alpha without conversion.
- // TODO(crbug.com/42271020): Remove the need for this.
- void ForcePreMultiply();
-
- // CFX_DIBBase:
- bool IsPremultiplied() const override;
#endif // defined(PDF_USE_SKIA)
private:
enum class Channel : uint8_t { kRed, kAlpha };
-#if defined(PDF_USE_SKIA)
- enum class Format { kCleared, kPreMultiplied, kUnPreMultiplied };
-#endif
-
CFX_DIBitmap();
CFX_DIBitmap(const CFX_DIBitmap& src);
~CFX_DIBitmap() override;
@@ -206,9 +195,6 @@
int src_top);
MaybeOwned<uint8_t, FxFreeDeleter> m_pBuffer;
-#if defined(PDF_USE_SKIA)
- Format m_nFormat = Format::kCleared;
-#endif
};
#endif // CORE_FXGE_DIB_CFX_DIBITMAP_H_
diff --git a/core/fxge/dib/cfx_dibitmap_unittest.cpp b/core/fxge/dib/cfx_dibitmap_unittest.cpp
index b40f47c..c46110f 100644
--- a/core/fxge/dib/cfx_dibitmap_unittest.cpp
+++ b/core/fxge/dib/cfx_dibitmap_unittest.cpp
@@ -119,24 +119,9 @@
}
#if defined(PDF_USE_SKIA)
-TEST(CFXDIBitmapTest, UnPreMultiplyFromCleared) {
- auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
- ASSERT_TRUE(bitmap->Create(1, 1, FXDIB_Format::kArgb));
- // TODO(crbug.com/42271020): This is wrong. Either IsPremultiplied() should
- // return true, or UnPreMultiply() should do nothing.
- EXPECT_FALSE(bitmap->IsPremultiplied());
- UNSAFE_TODO(FXARGB_SetDIB(bitmap->GetWritableBuffer().data(), 0x7f'7f'7f'7f));
-
- bitmap->UnPreMultiply();
- EXPECT_FALSE(bitmap->IsPremultiplied());
- EXPECT_THAT(bitmap->GetBuffer(), ElementsAre(0xff, 0xff, 0xff, 0x7f));
-}
-
TEST(CFXDIBitmapTest, UnPreMultiplyFromPreMultiplied) {
auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
- ASSERT_TRUE(bitmap->Create(1, 1, FXDIB_Format::kArgb));
- EXPECT_FALSE(bitmap->IsPremultiplied());
- bitmap->ForcePreMultiply();
+ ASSERT_TRUE(bitmap->Create(1, 1, FXDIB_Format::kArgbPremul));
EXPECT_TRUE(bitmap->IsPremultiplied());
UNSAFE_TODO(FXARGB_SetDIB(bitmap->GetWritableBuffer().data(), 0x7f'7f'7f'7f));
@@ -149,12 +134,32 @@
auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
ASSERT_TRUE(bitmap->Create(1, 1, FXDIB_Format::kArgb));
EXPECT_FALSE(bitmap->IsPremultiplied());
- bitmap->UnPreMultiply();
- EXPECT_FALSE(bitmap->IsPremultiplied());
UNSAFE_TODO(FXARGB_SetDIB(bitmap->GetWritableBuffer().data(), 0x7f'ff'ff'ff));
bitmap->UnPreMultiply();
EXPECT_FALSE(bitmap->IsPremultiplied());
EXPECT_THAT(bitmap->GetBuffer(), ElementsAre(0xff, 0xff, 0xff, 0x7f));
}
+
+TEST(CFXDIBitmapTest, PreMultiplyFromUnPreMultiplied) {
+ auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+ ASSERT_TRUE(bitmap->Create(1, 1, FXDIB_Format::kArgb));
+ EXPECT_FALSE(bitmap->IsPremultiplied());
+ UNSAFE_TODO(FXARGB_SetDIB(bitmap->GetWritableBuffer().data(), 0x7f'ff'ff'ff));
+
+ bitmap->PreMultiply();
+ EXPECT_TRUE(bitmap->IsPremultiplied());
+ EXPECT_THAT(bitmap->GetBuffer(), ElementsAre(0x7f, 0x7f, 0x7f, 0x7f));
+}
+
+TEST(CFXDIBitmapTest, PreMultiplyFromPreMultiplied) {
+ auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+ ASSERT_TRUE(bitmap->Create(1, 1, FXDIB_Format::kArgbPremul));
+ EXPECT_TRUE(bitmap->IsPremultiplied());
+ UNSAFE_TODO(FXARGB_SetDIB(bitmap->GetWritableBuffer().data(), 0x7f'7f'7f'7f));
+
+ bitmap->PreMultiply();
+ EXPECT_TRUE(bitmap->IsPremultiplied());
+ EXPECT_THAT(bitmap->GetBuffer(), ElementsAre(0x7f, 0x7f, 0x7f, 0x7f));
+}
#endif // defined(PDF_USE_SKIA)
diff --git a/core/fxge/render_defines.h b/core/fxge/render_defines.h
index 1b20ca0..98858de 100644
--- a/core/fxge/render_defines.h
+++ b/core/fxge/render_defines.h
@@ -26,6 +26,7 @@
#if defined(PDF_USE_SKIA)
#define FXRC_FILLSTROKE_PATH 0x80
#define FXRC_SHADING 0x100
+#define FXRC_PREMULTIPLIED_ALPHA 0x200
#endif
#endif // CORE_FXGE_RENDER_DEFINES_H_
diff --git a/core/fxge/skia/cfx_dibbase_skia.cpp b/core/fxge/skia/cfx_dibbase_skia.cpp
index 7d122c2..e1564b8 100644
--- a/core/fxge/skia/cfx_dibbase_skia.cpp
+++ b/core/fxge/skia/cfx_dibbase_skia.cpp
@@ -248,20 +248,23 @@
});
case 32:
- if (GetFormat() == FXDIB_Format::kRgb32) {
- return CreateSkiaImageFromTransformedDib</*source_bits_per_pixel=*/32>(
- *this, kBGRA_8888_SkColorType, kOpaque_SkAlphaType,
- [](uint8_t red, uint8_t green, uint8_t blue) {
- return SkPackARGB32(0xFF, red, green, blue);
- });
+ switch (GetFormat()) {
+ case FXDIB_Format::kRgb32:
+ return CreateSkiaImageFromTransformedDib<
+ /*source_bits_per_pixel=*/32>(
+ *this, kBGRA_8888_SkColorType, kOpaque_SkAlphaType,
+ [](uint8_t red, uint8_t green, uint8_t blue) {
+ return SkPackARGB32(0xFF, red, green, blue);
+ });
+ case FXDIB_Format::kArgb:
+ return CreateSkiaImageFromDib(this, kBGRA_8888_SkColorType,
+ kUnpremul_SkAlphaType);
+ case FXDIB_Format::kArgbPremul:
+ return CreateSkiaImageFromDib(this, kBGRA_8888_SkColorType,
+ kPremul_SkAlphaType);
+ default:
+ NOTREACHED_NORETURN();
}
- // TODO(crbug.com/42271020): Consider adding support for
- // `FXDIB_Format::kArgbPremul`
- CHECK_EQ(GetFormat(), FXDIB_Format::kArgb);
- return CreateSkiaImageFromDib(
- this, kBGRA_8888_SkColorType,
- IsPremultiplied() ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
-
default:
NOTREACHED_NORETURN();
}
diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp
index a8ca2f0..b6e2671 100644
--- a/core/fxge/skia/fx_skia_device.cpp
+++ b/core/fxge/skia/fx_skia_device.cpp
@@ -701,6 +701,7 @@
m_bGroupKnockout(bGroupKnockout) {
SkColorType color_type;
const int bpp = m_pBitmap->GetBPP();
+ SkAlphaType alpha_type = kPremul_SkAlphaType;
if (bpp == 8) {
color_type = m_pBitmap->IsAlphaFormat() || m_pBitmap->IsMaskFormat()
? kAlpha_8_SkColorType
@@ -715,9 +716,7 @@
const int height = m_pOriginalBitmap->GetHeight();
m_pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
- // TODO(crbug.com/42271020): Consider adding support for
- // `FXDIB_Format::kArgbPremul`
- if (!m_pBitmap->Create(width, height, FXDIB_Format::kArgb) ||
+ if (!m_pBitmap->Create(width, height, FXDIB_Format::kArgbPremul) ||
!m_pBitmap->TransferBitmap(width, height, m_pOriginalBitmap,
/*src_left=*/0, /*src_top=*/0)) {
// Skip creating SkCanvas if the 32-bpp bitmap creation fails.
@@ -733,11 +732,16 @@
} else {
DCHECK_EQ(bpp, 32);
color_type = Get32BitSkColorType(bRgbByteOrder);
+ FXDIB_Format format = m_pBitmap->GetFormat();
+ if (format == FXDIB_Format::kRgb32) {
+ alpha_type = kOpaque_SkAlphaType;
+ } else if (format == FXDIB_Format::kArgb) {
+ alpha_type = kUnpremul_SkAlphaType;
+ }
}
- SkImageInfo imageInfo =
- SkImageInfo::Make(m_pBitmap->GetWidth(), m_pBitmap->GetHeight(),
- color_type, kPremul_SkAlphaType);
+ SkImageInfo imageInfo = SkImageInfo::Make(
+ m_pBitmap->GetWidth(), m_pBitmap->GetHeight(), color_type, alpha_type);
surface_ = SkSurfaces::WrapPixels(
imageInfo, m_pBitmap->GetWritableBuffer().data(), m_pBitmap->GetPitch());
m_pCanvas = surface_->getCanvas();
@@ -1013,7 +1017,7 @@
case FXDC_RENDER_CAPS:
return FXRC_GET_BITS | FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE |
FXRC_BLEND_MODE | FXRC_SOFT_CLIP | FXRC_ALPHA_OUTPUT |
- FXRC_FILLSTROKE_PATH | FXRC_SHADING;
+ FXRC_FILLSTROKE_PATH | FXRC_SHADING | FXRC_PREMULTIPLIED_ALPHA;
default:
NOTREACHED_NORETURN();
}
@@ -1374,16 +1378,16 @@
uint8_t* output_buffer = bitmap->GetWritableBuffer().data();
DCHECK(output_buffer);
- SkImageInfo input_info =
- SkImageInfo::Make(m_pBitmap->GetWidth(), m_pBitmap->GetHeight(),
- SkColorType::kN32_SkColorType, kPremul_SkAlphaType);
+ SkImageInfo input_info = m_pCanvas->imageInfo();
sk_sp<SkImage> input = SkImages::RasterFromPixmap(
SkPixmap(input_info, input_buffer, m_pBitmap->GetPitch()),
/*rasterReleaseProc=*/nullptr, /*releaseContext=*/nullptr);
+ CHECK_EQ(32, bitmap->GetBPP());
SkImageInfo output_info = SkImageInfo::Make(
bitmap->GetWidth(), bitmap->GetHeight(),
- Get32BitSkColorType(m_bRgbByteOrder), kPremul_SkAlphaType);
+ Get32BitSkColorType(m_bRgbByteOrder),
+ bitmap->IsPremultiplied() ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
sk_sp<SkSurface> output =
SkSurfaces::WrapPixels(output_info, output_buffer, bitmap->GetPitch());
@@ -1458,11 +1462,8 @@
}
void CFX_DIBitmap::PreMultiply() {
- // TODO(crbug.com/42271020): Implement.
-}
-
-void CFX_DIBitmap::UnPreMultiply() {
- if (m_nFormat == Format::kUnPreMultiplied || GetBPP() != 32) {
+ CHECK(CFX_DefaultRenderDevice::UseSkiaRenderer());
+ if (GetFormat() != FXDIB_Format::kArgb) {
return;
}
@@ -1471,7 +1472,31 @@
return;
}
- m_nFormat = Format::kUnPreMultiplied;
+ SetFormat(FXDIB_Format::kArgbPremul);
+ int height = GetHeight();
+ int width = GetWidth();
+ int row_bytes = GetPitch();
+ SkImageInfo premultiplied_info =
+ SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
+ SkPixmap premultiplied(premultiplied_info, buffer, row_bytes);
+ SkImageInfo unpremultiplied_info =
+ SkImageInfo::Make(width, height, kN32_SkColorType, kUnpremul_SkAlphaType);
+ SkPixmap unpremultiplied(unpremultiplied_info, buffer, row_bytes);
+ unpremultiplied.readPixels(premultiplied);
+}
+
+void CFX_DIBitmap::UnPreMultiply() {
+ CHECK(CFX_DefaultRenderDevice::UseSkiaRenderer());
+ if (GetFormat() != FXDIB_Format::kArgbPremul) {
+ return;
+ }
+
+ void* buffer = GetWritableBuffer().data();
+ if (!buffer) {
+ return;
+ }
+
+ SetFormat(FXDIB_Format::kArgb);
int height = GetHeight();
int width = GetWidth();
int row_bytes = GetPitch();
@@ -1484,14 +1509,6 @@
premultiplied.readPixels(unpremultiplied);
}
-void CFX_DIBitmap::ForcePreMultiply() {
- m_nFormat = Format::kPreMultiplied;
-}
-
-bool CFX_DIBitmap::IsPremultiplied() const {
- return m_nFormat == Format::kPreMultiplied;
-}
-
bool CFX_SkiaDeviceDriver::DrawBitsWithMask(RetainPtr<const CFX_DIBBase> bitmap,
RetainPtr<const CFX_DIBBase> mask,
float alpha,
diff --git a/fpdfsdk/fpdf_edit_embeddertest.cpp b/fpdfsdk/fpdf_edit_embeddertest.cpp
index 0b1d327..2aac797 100644
--- a/fpdfsdk/fpdf_edit_embeddertest.cpp
+++ b/fpdfsdk/fpdf_edit_embeddertest.cpp
@@ -4635,13 +4635,13 @@
const char* smask_checksum = []() {
if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
- return "0653a18f3bf9b4d8413a2aa10bc11c38";
+ return "a85ca0183ac6aee8851c30c5bdc2f594";
}
return "5a3ae4a660ce919e29c42ec2258142f1";
}();
const char* no_smask_checksum = []() {
if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
- return "0da49e63e7d6337aca78b19938e3bf65";
+ return "712f832dcbfb6cefc74f39bef459bea4";
}
return "67504e83f5d78214ea00efc19082c5c1";
}();
@@ -4975,7 +4975,7 @@
const char* checksum = []() {
if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
#if BUILDFLAG(IS_WIN)
- return "5cef5b3e56e91e1a66b6780fb26bb5e3";
+ return "764e3503960ef0b176796faa3543b9c7";
#elif BUILDFLAG(IS_APPLE)
return "9e7774173acee966fcaa72e599eb9a93";
#else
@@ -5031,7 +5031,7 @@
const char* checksum = []() {
if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
#if BUILDFLAG(IS_WIN)
- return "336be21110c795cefcab9bbdbc3afcdd";
+ return "4cdba7492317bcae2643bd4090e18812";
#elif BUILDFLAG(IS_APPLE)
return "0b9efedcb8f5aa9246c52e90811cb046";
#else
@@ -5155,7 +5155,7 @@
ASSERT_TRUE(bitmap);
const char* checksum = []() {
if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
- return "1d74731d23a056c0e3fb88f2f85b2581";
+ return "2a45a0034911f21b528621bebe0aab4b";
}
return "e8154fa8ededf4d9b8b35b5260897b6c";
}();
@@ -5181,7 +5181,7 @@
const char* checksum = []() {
if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
#if BUILDFLAG(IS_WIN)
- return "ef501232372617a545ae35d7664fd9ec";
+ return "6d88537a49fa2dccfa0f58ac325c5b75";
#elif BUILDFLAG(IS_APPLE)
return "a637d62f2e8ae10c3267b2ff5fcc2246";
#else
diff --git a/fpdfsdk/fpdf_editimg.cpp b/fpdfsdk/fpdf_editimg.cpp
index f29bc4a..1eb2b23 100644
--- a/fpdfsdk/fpdf_editimg.cpp
+++ b/fpdfsdk/fpdf_editimg.cpp
@@ -338,11 +338,7 @@
if (!renderer.GetResult())
return nullptr;
-#if defined(PDF_USE_SKIA)
- if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
- result_bitmap->UnPreMultiply();
- }
-#endif
+ CHECK(!result_bitmap->IsPremultiplied());
// Caller takes ownership.
return FPDFBitmapFromCFXDIBitmap(result_bitmap.Leak());
diff --git a/fpdfsdk/fpdf_formfill.cpp b/fpdfsdk/fpdf_formfill.cpp
index 19a79ba..8e794a5 100644
--- a/fpdfsdk/fpdf_formfill.cpp
+++ b/fpdfsdk/fpdf_formfill.cpp
@@ -211,7 +211,6 @@
if (dest_is_bitmap) {
holder.Reset(absl::get<CFX_DIBitmap*>(dest));
CHECK(holder);
- CHECK(!holder->IsPremultiplied());
} else {
#if defined(PDF_USE_SKIA)
if (!CFX_DefaultRenderDevice::UseSkiaRenderer()) {
@@ -733,6 +732,10 @@
return;
}
+#if defined(PDF_USE_SKIA)
+ CFX_DIBitmap::ScopedPremultiplier scoped_premultiplier(
+ pdfium::WrapRetain(cbitmap), CFX_DefaultRenderDevice::UseSkiaRenderer());
+#endif
FFLCommon(hHandle, page, cbitmap, start_x, start_y, size_x, size_y, rotate,
flags);
}
diff --git a/fpdfsdk/fpdf_progressive.cpp b/fpdfsdk/fpdf_progressive.cpp
index 455d42d..150b46a 100644
--- a/fpdfsdk/fpdf_progressive.cpp
+++ b/fpdfsdk/fpdf_progressive.cpp
@@ -68,6 +68,12 @@
CPDF_PageRenderContext* context = owned_context.get();
pPage->SetRenderContext(std::move(owned_context));
+#if defined(PDF_USE_SKIA)
+ if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
+ pBitmap->PreMultiply();
+ }
+#endif
+
auto device = std::make_unique<CFX_DefaultRenderDevice>();
device->AttachWithRgbByteOrder(pBitmap, !!(flags & FPDF_REVERSE_BYTE_ORDER));
context->m_pDevice = std::move(device);
@@ -77,17 +83,37 @@
size_y, rotate, flags, color_scheme,
/*need_to_restore=*/false, &pause_adapter);
+ if (!context->m_pRenderer) {
+#if defined(PDF_USE_SKIA)
+ if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
+ pBitmap->UnPreMultiply();
+ }
+#endif // defined(PDF_USE_SKIA)
+
+ return FPDF_RENDER_FAILED;
+ }
+
+ int status = ToFPDFStatus(context->m_pRenderer->GetStatus());
+ if (status == FPDF_RENDER_TOBECONTINUED) {
+ // Note that `pBitmap` is still pre-multiplied here, as the caller is
+ // expected to pass it to FPDF_RenderPage_Continue(). Then
+ // FPDF_RenderPage_Continue() can continue rendering into it without doing
+ // another round of (un)pre-multiplication. FPDF_RenderPage_Continue() will
+ // call UnPreMultiply() when done.
+ //
+ // Normally, PDFium would not return a pre-multiplied bitmap to the caller,
+ // but in this case, the bitmap is in an indeterminate state while it is
+ // being progressively rendered. So many an exception here, as it can
+ // greatly improve performance.
+ return FPDF_RENDER_TOBECONTINUED;
+ }
+
#if defined(PDF_USE_SKIA)
if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
pBitmap->UnPreMultiply();
}
#endif // defined(PDF_USE_SKIA)
-
- if (!context->m_pRenderer) {
- return FPDF_RENDER_FAILED;
- }
-
- return ToFPDFStatus(context->m_pRenderer->GetStatus());
+ return status;
}
FPDF_EXPORT int FPDF_CALLCONV FPDF_RenderPageBitmap_Start(FPDF_BITMAP bitmap,
@@ -121,12 +147,17 @@
CPDFSDK_PauseAdapter pause_adapter(pause);
pContext->m_pRenderer->Continue(&pause_adapter);
+ int status = ToFPDFStatus(pContext->m_pRenderer->GetStatus());
+ if (status == FPDF_RENDER_TOBECONTINUED) {
+ return FPDF_RENDER_TOBECONTINUED;
+ }
+
#if defined(PDF_USE_SKIA)
if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
pContext->m_pDevice->GetBitmap()->UnPreMultiply();
}
#endif // defined(PDF_USE_SKIA)
- return ToFPDFStatus(pContext->m_pRenderer->GetStatus());
+ return status;
}
FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPage_Close(FPDF_PAGE page) {
diff --git a/fpdfsdk/fpdf_view.cpp b/fpdfsdk/fpdf_view.cpp
index 458b604..2fb04a7 100644
--- a/fpdfsdk/fpdf_view.cpp
+++ b/fpdfsdk/fpdf_view.cpp
@@ -629,12 +629,6 @@
/*need_to_restore=*/true,
/*pause=*/nullptr);
-#if defined(PDF_USE_SKIA)
- if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
- pBitmap->UnPreMultiply();
- }
-#endif
-
if (!bHasMask) {
CPDF_WindowsRenderDevice win_dc(dc, render_data->GetPSFontTracker());
bool bitsStretched = false;
@@ -719,20 +713,19 @@
CPDF_Page::RenderContextClearer clearer(pPage);
pPage->SetRenderContext(std::move(owned_context));
+#if defined(PDF_USE_SKIA)
+ CFX_DIBitmap::ScopedPremultiplier scoped_premultiplier(
+ pBitmap, CFX_DefaultRenderDevice::UseSkiaRenderer());
+#endif
auto device = std::make_unique<CFX_DefaultRenderDevice>();
- device->AttachWithRgbByteOrder(pBitmap, !!(flags & FPDF_REVERSE_BYTE_ORDER));
+ device->AttachWithRgbByteOrder(std::move(pBitmap),
+ !!(flags & FPDF_REVERSE_BYTE_ORDER));
context->m_pDevice = std::move(device);
CPDFSDK_RenderPageWithContext(context, pPage, start_x, start_y, size_x,
size_y, rotate, flags, /*color_scheme=*/nullptr,
/*need_to_restore=*/true,
/*pause=*/nullptr);
-
-#if defined(PDF_USE_SKIA)
- if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
- pBitmap->UnPreMultiply();
- }
-#endif
}
FPDF_EXPORT void FPDF_CALLCONV
@@ -757,6 +750,10 @@
CPDF_Page::RenderContextClearer clearer(pPage);
pPage->SetRenderContext(std::move(owned_context));
+#if defined(PDF_USE_SKIA)
+ CFX_DIBitmap::ScopedPremultiplier scoped_premultiplier(
+ pBitmap, CFX_DefaultRenderDevice::UseSkiaRenderer());
+#endif
auto device = std::make_unique<CFX_DefaultRenderDevice>();
device->AttachWithRgbByteOrder(std::move(pBitmap),
!!(flags & FPDF_REVERSE_BYTE_ORDER));
diff --git a/testing/SUPPRESSIONS_EXACT_MATCHING b/testing/SUPPRESSIONS_EXACT_MATCHING
index b9734d9..494d784 100644
--- a/testing/SUPPRESSIONS_EXACT_MATCHING
+++ b/testing/SUPPRESSIONS_EXACT_MATCHING
@@ -20,9 +20,20 @@
# Try to keep the file alphabetized within each category of test.
#
+# Pixel tests
+#
+
+# Sensitive to transparency code changes.
+bug_1258968.in * * * skia
+
+#
# Corpus tests
#
+# Sensitive to transparency code changes.
+1_10_watermark.pdf * * * skia
+
# Device-specific ColorBurn differences (see pdfium:1959).
+xfermodes.pdf * * * skia
xfermodes2.pdf * * * skia
xfermodes3.pdf * * * skia
diff --git a/testing/resources/pixel/bug_1161_expected_skia.pdf.0.png b/testing/resources/pixel/bug_1161_expected_skia.pdf.0.png
index 4197dcb..e83cf25 100644
--- a/testing/resources/pixel/bug_1161_expected_skia.pdf.0.png
+++ b/testing/resources/pixel/bug_1161_expected_skia.pdf.0.png
Binary files differ
diff --git a/xfa/fde/cfde_textout_unittest.cpp b/xfa/fde/cfde_textout_unittest.cpp
index 85c24f0..79536cf 100644
--- a/xfa/fde/cfde_textout_unittest.cpp
+++ b/xfa/fde/cfde_textout_unittest.cpp
@@ -97,7 +97,7 @@
const char* checksum = []() {
#if BUILDFLAG(IS_WIN)
if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
- return "cdd8f00144e421bf18f22d09896838b0";
+ return "bc1f736237b08d13db06c09f6becc9f7";
}
#endif
return "b26f1c171fcdbf185823364185adacf0";
@@ -134,7 +134,7 @@
const char* GetLargeTextBlobChecksum() {
if (CFX_DefaultRenderDevice::UseSkiaRenderer()) {
- return "cd357c6afbf17bb2ac48817df5d9eaad";
+ return "6181929583fd7651169306852397806f";
}
return "268b71a8660b51e31c6bf30fc7ff1e08";
}