Add Skia support for 24 bpp FXDIB_Format
Skia doesn't support directly creating SkCanvas from bitmap that's 24
bits-per-pixel. Therefore convert such bitmaps to FXDIB_Format::kArgb
(32 bits-per-pixel) before creating SkCanvas.
Bug: pdfium:1489, pdfium:1953, chromium:1396325
Change-Id: Icdeacc99b161f32d63882118faed7e12459216e3
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/102773
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Nigi <nigi@chromium.org>
diff --git a/core/fxge/dib/cfx_dibitmap.cpp b/core/fxge/dib/cfx_dibitmap.cpp
index 9ce57f6..edd2d01 100644
--- a/core/fxge/dib/cfx_dibitmap.cpp
+++ b/core/fxge/dib/cfx_dibitmap.cpp
@@ -970,7 +970,8 @@
bool CFX_DIBitmap::ConvertFormat(FXDIB_Format dest_format) {
DCHECK(dest_format == FXDIB_Format::k8bppMask ||
dest_format == FXDIB_Format::kArgb ||
- dest_format == kPlatformRGBFormat);
+ dest_format == FXDIB_Format::kRgb32 ||
+ dest_format == FXDIB_Format::kRgb);
if (dest_format == m_Format)
return true;
diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp
index 76e99be..7f8034d 100644
--- a/core/fxge/skia/fx_skia_device.cpp
+++ b/core/fxge/skia/fx_skia_device.cpp
@@ -1343,6 +1343,9 @@
auto driver = pdfium::WrapUnique(
new CFX_SkiaDeviceDriver(std::move(pBitmap), bRgbByteOrder,
std::move(pBackdropBitmap), bGroupKnockout));
+ if (!driver->SkiaCanvas())
+ return nullptr;
+
return driver;
}
@@ -1364,6 +1367,21 @@
color_type = m_pBitmap->IsAlphaFormat() || m_pBitmap->IsMaskFormat()
? kAlpha_8_SkColorType
: kGray_8_SkColorType;
+ } else if (bpp == 24) {
+ DCHECK_EQ(m_pBitmap->GetFormat(), FXDIB_Format::kRgb);
+
+ // Save the input bitmap as `m_pOriginalBitmap` and save its 32 bpp
+ // equivalent at `m_pBitmap` for Skia's internal process.
+ m_pOriginalBitmap = std::move(m_pBitmap);
+ m_pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+ if (!m_pBitmap->Copy(m_pOriginalBitmap) ||
+ !m_pBitmap->ConvertFormat(FXDIB_Format::kArgb)) {
+ // Skip creating SkCanvas if we fail to create the 32 bpp bitmap to back
+ // it.
+ return;
+ }
+
+ color_type = Get32BitSkColorType(bRgbByteOrder);
} else {
DCHECK_EQ(bpp, 32);
color_type = Get32BitSkColorType(bRgbByteOrder);
@@ -1394,6 +1412,20 @@
CFX_SkiaDeviceDriver::~CFX_SkiaDeviceDriver() {
Flush();
+
+ // Convert and transfer the internal processed result to the original 24 bpp
+ // bitmap provided by the render device.
+ if (m_pOriginalBitmap && m_pBitmap->ConvertFormat(FXDIB_Format::kRgb)) {
+ int width = m_pOriginalBitmap->GetWidth();
+ int height = m_pOriginalBitmap->GetHeight();
+ DCHECK_EQ(width, m_pBitmap->GetWidth());
+ DCHECK_EQ(height, m_pBitmap->GetHeight());
+ DCHECK_EQ(FXDIB_Format::kRgb, m_pOriginalBitmap->GetFormat());
+ m_pOriginalBitmap->TransferBitmap(/*dest_left=*/0, /*dest_top=*/0, width,
+ height, m_pBitmap, /*src_left=*/0,
+ /*src_top=*/0);
+ }
+
if (!m_pRecorder)
delete m_pCanvas;
}
@@ -2221,6 +2253,9 @@
auto driver =
CFX_SkiaDeviceDriver::Create(std::move(pBitmap), bRgbByteOrder,
std::move(pBackdropBitmap), bGroupKnockout);
+ if (!driver)
+ return false;
+
SetDeviceDriver(std::move(driver));
return true;
}
@@ -2244,6 +2279,9 @@
SetBitmap(pBitmap);
auto driver = CFX_SkiaDeviceDriver::Create(std::move(pBitmap), false,
std::move(pBackdropBitmap), false);
+ if (!driver)
+ return false;
+
SetDeviceDriver(std::move(driver));
return true;
}
diff --git a/core/fxge/skia/fx_skia_device.h b/core/fxge/skia/fx_skia_device.h
index 06ff5ba..dc4269e 100644
--- a/core/fxge/skia/fx_skia_device.h
+++ b/core/fxge/skia/fx_skia_device.h
@@ -167,6 +167,11 @@
RetainPtr<CFX_DIBitmap> m_pBitmap;
RetainPtr<CFX_DIBitmap> m_pBackdropBitmap;
+
+ // The input bitmap passed by the render device. Only used when the input
+ // bitmap is 24 bpp and cannot be directly used as the back of a SkCanvas.
+ RetainPtr<CFX_DIBitmap> m_pOriginalBitmap;
+
SkCanvas* m_pCanvas;
SkPictureRecorder* const m_pRecorder;
std::unique_ptr<SkiaState> m_pCache;
diff --git a/core/fxge/skia/fx_skia_device_embeddertest.cpp b/core/fxge/skia/fx_skia_device_embeddertest.cpp
index dc51c1f..9b4005a 100644
--- a/core/fxge/skia/fx_skia_device_embeddertest.cpp
+++ b/core/fxge/skia/fx_skia_device_embeddertest.cpp
@@ -135,6 +135,7 @@
FPDFBitmap_FillRect(bitmap.get(), 0, 0, kWidth, kHeight, 0x00000000);
RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap.get()));
auto driver = CFX_SkiaDeviceDriver::Create(pBitmap, false, nullptr, false);
+ ASSERT_TRUE(driver);
(*Test)(driver.get(), state);
driver->Flush();
uint32_t pixel = pBitmap->GetPixel(0, 0);
diff --git a/fpdfsdk/fpdf_view_embeddertest.cpp b/fpdfsdk/fpdf_view_embeddertest.cpp
index bc7a506..4462154 100644
--- a/fpdfsdk/fpdf_view_embeddertest.cpp
+++ b/fpdfsdk/fpdf_view_embeddertest.cpp
@@ -1518,26 +1518,25 @@
FPDF_PAGE page = LoadPage(0);
ASSERT_TRUE(page);
+ const char* bgr_checksum = []() {
+ if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
+ return "4d52e5cc1d4a8067bf918b85b232fff0";
+ return "ab6312e04c0d3f4e46fb302a45173d05";
+ }();
+ static constexpr int kBgrStride = 600; // Width of 200 * 24 bits per pixel.
+ TestRenderPageBitmapWithInternalMemory(page, FPDFBitmap_BGR, bgr_checksum);
+ TestRenderPageBitmapWithInternalMemoryAndStride(page, FPDFBitmap_BGR,
+ kBgrStride, bgr_checksum);
+ TestRenderPageBitmapWithExternalMemory(page, FPDFBitmap_BGR, bgr_checksum);
+ TestRenderPageBitmapWithExternalMemoryAndNoStride(page, FPDFBitmap_BGR,
+ bgr_checksum);
+
const char* gray_checksum = []() {
if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
return "3dfe1fc3889123d68e1748fefac65e72";
return "b561c11edc44dc3972125a9b8744fa2f";
}();
- // TODO(crbug.com/pdfium/1489): Add a test for FPDFBitmap_BGR in Skia modes
- // once Skia provides support for BGR24 format.
- if (!CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
- static const char kBgrChecksum[] = "ab6312e04c0d3f4e46fb302a45173d05";
-
- static constexpr int kBgrStride = 600; // Width of 200 * 24 bits per pixel.
- TestRenderPageBitmapWithInternalMemory(page, FPDFBitmap_BGR, kBgrChecksum);
- TestRenderPageBitmapWithInternalMemoryAndStride(page, FPDFBitmap_BGR,
- kBgrStride, kBgrChecksum);
- TestRenderPageBitmapWithExternalMemory(page, FPDFBitmap_BGR, kBgrChecksum);
- TestRenderPageBitmapWithExternalMemoryAndNoStride(page, FPDFBitmap_BGR,
- kBgrChecksum);
- }
-
TestRenderPageBitmapWithInternalMemory(page, FPDFBitmap_Gray, gray_checksum);
static constexpr int kGrayStride = 200; // Width of 200 * 8 bits per pixel.
TestRenderPageBitmapWithInternalMemoryAndStride(page, FPDFBitmap_Gray,