Make CFX_DIBitmap::GetScanlineAs() work correctly for 24-bpp bitmaps
Add a test case that demonstrates CFX_DIBitmap allocates memory with a
stride of 12 when the bitmap width is 3 and the format is 24-bpp. The
test case then shows the 12 bytes gets reinterpreted as 4 pixels of 3
bytes each by GetScanlineAs(). Fix GetScanlineAs() to only return the
actual pixels and not the unused space.
Do the same for GetWritableScanlineAs().
Change-Id: I3181bc5dbb5175b91671a995168ff3be21615389
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/123210
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@google.com>
diff --git a/core/fxge/dib/cfx_dibbase.h b/core/fxge/dib/cfx_dibbase.h
index 905d283..66fd6a8 100644
--- a/core/fxge/dib/cfx_dibbase.h
+++ b/core/fxge/dib/cfx_dibbase.h
@@ -45,6 +45,7 @@
static constexpr uint32_t kPaletteSize = 256;
+ // Note that the returned scanline includes unused space at the end, if any.
virtual pdfium::span<const uint8_t> GetScanline(int line) const = 0;
virtual bool SkipToScanline(int line, PauseIndicatorIface* pPause) const;
virtual size_t GetEstimatedImageMemoryBurden() const;
@@ -53,9 +54,12 @@
virtual RetainPtr<const CFX_DIBitmap> RealizeIfNeeded() const;
#endif
+ // Note that the returned scanline does not include unused space at the end,
+ // if any.
template <typename T>
pdfium::span<const T> GetScanlineAs(int line) const {
- return fxcrt::reinterpret_span<const T>(GetScanline(line));
+ return fxcrt::reinterpret_span<const T>(GetScanline(line))
+ .first(GetWidth());
}
int GetWidth() const { return width_; }
diff --git a/core/fxge/dib/cfx_dibitmap.h b/core/fxge/dib/cfx_dibitmap.h
index 53e646f..b98ae8f 100644
--- a/core/fxge/dib/cfx_dibitmap.h
+++ b/core/fxge/dib/cfx_dibitmap.h
@@ -70,6 +70,7 @@
pdfium::make_span(const_cast<uint8_t*>(src.data()), src.size()));
}
+ // Note that the returned scanline includes unused space at the end, if any.
pdfium::span<uint8_t> GetWritableScanline(int line) {
pdfium::span<const uint8_t> src = GetScanline(line);
// SAFETY: const_cast<>() doesn't change size.
@@ -77,9 +78,12 @@
pdfium::make_span(const_cast<uint8_t*>(src.data()), src.size()));
}
+ // Note that the returned scanline does not include unused space at the end,
+ // if any.
template <typename T>
pdfium::span<T> GetWritableScanlineAs(int line) {
- return fxcrt::reinterpret_span<T>(GetWritableScanline(line));
+ return fxcrt::reinterpret_span<T>(GetWritableScanline(line))
+ .first(GetWidth());
}
void TakeOver(RetainPtr<CFX_DIBitmap>&& pSrcBitmap);
diff --git a/core/fxge/dib/cfx_dibitmap_unittest.cpp b/core/fxge/dib/cfx_dibitmap_unittest.cpp
index c46110f..e728060 100644
--- a/core/fxge/dib/cfx_dibitmap_unittest.cpp
+++ b/core/fxge/dib/cfx_dibitmap_unittest.cpp
@@ -118,6 +118,22 @@
FXDIB_Format::k8bppRgb, 0));
}
+TEST(CFXDIBitmapTest, GetScanlineAsWith24Bpp) {
+ auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+ ASSERT_TRUE(bitmap->Create(3, 3, FXDIB_Format::kRgb));
+ EXPECT_EQ(3, bitmap->GetWidth());
+ EXPECT_EQ(12u, bitmap->GetPitch());
+
+ EXPECT_EQ(36u, bitmap->GetBuffer().size());
+ EXPECT_EQ(12u, bitmap->GetScanline(0).size());
+ EXPECT_EQ(3u, bitmap->GetScanlineAs<FX_BGR_STRUCT<uint8_t>>(0).size());
+
+ EXPECT_EQ(36u, bitmap->GetWritableBuffer().size());
+ EXPECT_EQ(12u, bitmap->GetWritableScanline(0).size());
+ EXPECT_EQ(3u,
+ bitmap->GetWritableScanlineAs<FX_BGR_STRUCT<uint8_t>>(0).size());
+}
+
#if defined(PDF_USE_SKIA)
TEST(CFXDIBitmapTest, UnPreMultiplyFromPreMultiplied) {
auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();