Don't implement CPDF_DIB::GetBuffer() (try 2)
The first try [1] to just return an empty span in CPDF_DIB::GetBuffer()
did not work. This CL goes further and deletes CFX_DIBBase::GetBuffer()
altogether. Instead, only implement a non-virtual
CFX_DIBBitmap::GetBuffer(). To make this work, get rid of all
CFX_DIBBase::GetBuffer() callers:
- Switch to calling CFX_DIBBitmap::GetBuffer() when it easy to do so.
- Make CFX_DIBBase::RealizeIfNeeded() virtual, and change the default
implementation to just call Realize().
- Make RealizeIfNeeded() available for Skia-builds and use it in
CreateSkiaImageFromDib().
- Change CreateSkiaImageFromTransformedDib() to only use scanlines.
Fix other issues to make sure everything works:
- Avoid calling RealizeIfNeeded() on `CPDF_DIB::m_pCachedBitmap`, as
that gives the wrong answer, just like CPDF_DIB::GetBuffer().
- Make sure CreateSkiaImageFromDib() does not fail and leak memory.
- Give up on avoiding the CachedImage::SkipToScanline() call.
- Add a test case for a related bug.
[1] https://pdfium-review.googlesource.com/108850
Bug: chromium:1478366,pdfium:2050,pdfium:2051
Change-Id: Ia20d4d257d441dd971ee0a912733f48f29dafad1
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/111434
Reviewed-by: Nigi <nigi@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_dib.cpp b/core/fpdfapi/page/cpdf_dib.cpp
index c478d37..657cf16 100644
--- a/core/fpdfapi/page/cpdf_dib.cpp
+++ b/core/fpdfapi/page/cpdf_dib.cpp
@@ -1132,11 +1132,6 @@
return true;
}
-pdfium::span<const uint8_t> CPDF_DIB::GetBuffer() const {
- return m_pCachedBitmap ? m_pCachedBitmap->GetBuffer()
- : pdfium::span<const uint8_t>();
-}
-
pdfium::span<const uint8_t> CPDF_DIB::GetScanline(int line) const {
if (m_bpc == 0)
return pdfium::span<const uint8_t>();
diff --git a/core/fpdfapi/page/cpdf_dib.h b/core/fpdfapi/page/cpdf_dib.h
index 5206bf5..1ef656a 100644
--- a/core/fpdfapi/page/cpdf_dib.h
+++ b/core/fpdfapi/page/cpdf_dib.h
@@ -45,7 +45,6 @@
CONSTRUCT_VIA_MAKE_RETAIN;
// CFX_DIBBase:
- pdfium::span<const uint8_t> GetBuffer() const override;
pdfium::span<const uint8_t> GetScanline(int line) const override;
bool SkipToScanline(int line, PauseIndicatorIface* pPause) const override;
size_t GetEstimatedImageMemoryBurden() const override;
diff --git a/core/fpdfapi/page/cpdf_pageimagecache.cpp b/core/fpdfapi/page/cpdf_pageimagecache.cpp
index b36f089..30d6aa1 100644
--- a/core/fpdfapi/page/cpdf_pageimagecache.cpp
+++ b/core/fpdfapi/page/cpdf_pageimagecache.cpp
@@ -28,7 +28,6 @@
#if defined(_SKIA_SUPPORT_)
#include "core/fxcrt/data_vector.h"
#include "core/fxge/cfx_defaultrenderdevice.h"
-#include "third_party/base/notreached.h"
#include "third_party/skia/include/core/SkImage.h" // nogncheck
#include "third_party/skia/include/core/SkRefCnt.h" // nogncheck
#endif
@@ -63,15 +62,6 @@
}
}
- pdfium::span<const uint8_t> GetBuffer() const override {
- // TODO(crbug.com/pdfium/2051): Still needed for
- // CGdiDeviceDriver::GDI_StretchDIBits(). `CachedImage` is only used when
- // Skia is the default renderer, which should call `RealizeSkImage()`
- // instead. Consider removing this or making it `NOTREACHED_NORETURN()`
- // by reimplementing its caller when Skia is the default renderer.
- return image_->GetBuffer();
- }
-
pdfium::span<const uint8_t> GetScanline(int line) const override {
// TODO(crbug.com/pdfium/2050): Still needed for `Realize()` call in
// `CPDF_ImageRenderer`.
@@ -79,10 +69,6 @@
}
bool SkipToScanline(int line, PauseIndicatorIface* pause) const override {
- // TODO(crbug.com/pdfium/2051): `CachedImage` is only used by Skia, which
- // should call `RealizeSkImage()` instead. Consider removing this, or at
- // least making it `NOTREACHED_NORETURN()`.
- NOTREACHED();
return image_->SkipToScanline(line, pause);
}
@@ -91,6 +77,12 @@
return image_->GetEstimatedImageMemoryBurden();
}
+#if BUILDFLAG(IS_WIN) || defined(_SKIA_SUPPORT_)
+ RetainPtr<const CFX_DIBitmap> RealizeIfNeeded() const override {
+ return image_->RealizeIfNeeded();
+ }
+#endif
+
sk_sp<SkImage> RealizeSkImage() const override {
if (!cached_skia_image_) {
cached_skia_image_ = image_->RealizeSkImage();
@@ -111,15 +103,7 @@
bool realize_hint) {
#if defined(_SKIA_SUPPORT_)
if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
- // TODO(crbug.com/pdfium/2050): Ignore `realize_hint`, as `RealizeSkImage()`
- // doesn't benefit from it. The current behavior masks a bug in `CPDF_DIB`
- // in which `GetBuffer()` and `GetScanline()` don't give the same answer.
- if (realize_hint) {
- image = image->Realize();
- if (!image) {
- return nullptr;
- }
- }
+ // Ignore `realize_hint`, as `RealizeSkImage()` doesn't benefit from it.
return pdfium::MakeRetain<CachedImage>(std::move(image));
}
#endif // defined(_SKIA_SUPPORT_)
diff --git a/core/fxge/dib/cfx_dibbase.cpp b/core/fxge/dib/cfx_dibbase.cpp
index 2a80f89..bf823dc 100644
--- a/core/fxge/dib/cfx_dibbase.cpp
+++ b/core/fxge/dib/cfx_dibbase.cpp
@@ -617,10 +617,6 @@
CFX_DIBBase::~CFX_DIBBase() = default;
-pdfium::span<const uint8_t> CFX_DIBBase::GetBuffer() const {
- return pdfium::span<const uint8_t>();
-}
-
bool CFX_DIBBase::SkipToScanline(int line, PauseIndicatorIface* pPause) const {
return false;
}
@@ -629,12 +625,9 @@
return GetRequiredPaletteSize() * sizeof(uint32_t);
}
-#if BUILDFLAG(IS_WIN)
-RetainPtr<const CFX_DIBBase> CFX_DIBBase::RealizeIfNeeded() const {
- if (GetBuffer().empty()) {
- return Realize();
- }
- return pdfium::WrapRetain(this);
+#if BUILDFLAG(IS_WIN) || defined(_SKIA_SUPPORT_)
+RetainPtr<const CFX_DIBitmap> CFX_DIBBase::RealizeIfNeeded() const {
+ return Realize();
}
#endif
diff --git a/core/fxge/dib/cfx_dibbase.h b/core/fxge/dib/cfx_dibbase.h
index 6327888..98febad 100644
--- a/core/fxge/dib/cfx_dibbase.h
+++ b/core/fxge/dib/cfx_dibbase.h
@@ -41,10 +41,13 @@
static constexpr uint32_t kPaletteSize = 256;
- virtual pdfium::span<const uint8_t> GetBuffer() const;
virtual pdfium::span<const uint8_t> GetScanline(int line) const = 0;
virtual bool SkipToScanline(int line, PauseIndicatorIface* pPause) const;
virtual size_t GetEstimatedImageMemoryBurden() const;
+#if BUILDFLAG(IS_WIN) || defined(_SKIA_SUPPORT_)
+ // Calls Realize() if needed. Otherwise, return `this`.
+ virtual RetainPtr<const CFX_DIBitmap> RealizeIfNeeded() const;
+#endif
int GetWidth() const { return m_Width; }
int GetHeight() const { return m_Height; }
@@ -65,11 +68,6 @@
// Copies into internally-owned palette.
void SetPalette(pdfium::span<const uint32_t> src_palette);
-#if BUILDFLAG(IS_WIN)
- // Calls Realize() if needed. Otherwise, return `this`.
- RetainPtr<const CFX_DIBBase> RealizeIfNeeded() const;
-#endif
-
RetainPtr<CFX_DIBitmap> Realize() const;
RetainPtr<CFX_DIBitmap> ClipTo(const FX_RECT& rect) const;
RetainPtr<CFX_DIBitmap> ConvertTo(FXDIB_Format format) const;
diff --git a/core/fxge/dib/cfx_dibitmap.cpp b/core/fxge/dib/cfx_dibitmap.cpp
index 6df1eee..cf349c0 100644
--- a/core/fxge/dib/cfx_dibitmap.cpp
+++ b/core/fxge/dib/cfx_dibitmap.cpp
@@ -110,6 +110,15 @@
return result;
}
+#if BUILDFLAG(IS_WIN) || defined(_SKIA_SUPPORT_)
+RetainPtr<const CFX_DIBitmap> CFX_DIBitmap::RealizeIfNeeded() const {
+ if (GetBuffer().empty()) {
+ return Realize();
+ }
+ return pdfium::WrapRetain(this);
+}
+#endif
+
void CFX_DIBitmap::TakeOver(RetainPtr<CFX_DIBitmap>&& pSrcBitmap) {
m_pBuffer = std::move(pSrcBitmap->m_pBuffer);
m_palette = std::move(pSrcBitmap->m_palette);
diff --git a/core/fxge/dib/cfx_dibitmap.h b/core/fxge/dib/cfx_dibitmap.h
index 34f5887..e59644d 100644
--- a/core/fxge/dib/cfx_dibitmap.h
+++ b/core/fxge/dib/cfx_dibitmap.h
@@ -34,10 +34,13 @@
bool Copy(const RetainPtr<CFX_DIBBase>& pSrc);
// CFX_DIBBase
- pdfium::span<const uint8_t> GetBuffer() const override;
pdfium::span<const uint8_t> GetScanline(int line) const override;
size_t GetEstimatedImageMemoryBurden() const override;
+#if BUILDFLAG(IS_WIN) || defined(_SKIA_SUPPORT_)
+ RetainPtr<const CFX_DIBitmap> RealizeIfNeeded() const override;
+#endif
+ pdfium::span<const uint8_t> GetBuffer() const;
pdfium::span<uint8_t> GetWritableBuffer() {
pdfium::span<const uint8_t> src = GetBuffer();
return {const_cast<uint8_t*>(src.data()), src.size()};
diff --git a/core/fxge/skia/cfx_dibbase_skia.cpp b/core/fxge/skia/cfx_dibbase_skia.cpp
index 417aa93..8606e33 100644
--- a/core/fxge/skia/cfx_dibbase_skia.cpp
+++ b/core/fxge/skia/cfx_dibbase_skia.cpp
@@ -33,41 +33,35 @@
namespace {
-// Releases `CFX_DIBBase` "leaked" by `CreateSkiaImageFromDib()`.
+// Releases `CFX_DIBitmap` "leaked" by `CreateSkiaImageFromDib()`.
void ReleaseRetainedHeldBySkImage(const void* /*pixels*/,
SkImages::ReleaseContext context) {
- RetainPtr<const CFX_DIBBase> retained;
- retained.Unleak(reinterpret_cast<const CFX_DIBBase*>(context));
+ RetainPtr<const CFX_DIBitmap> realized_bitmap;
+ realized_bitmap.Unleak(reinterpret_cast<const CFX_DIBitmap*>(context));
}
-// Creates an `SkImage` from a `CFX_DIBBase`, sharing the underlying pixels if
-// possible.
-//
-// Note that an `SkImage` must be immutable, so if sharing pixels, they must not
-// be modified during the lifetime of the `SkImage`.
+// Creates an `SkImage` from a `CFX_DIBBase`.
sk_sp<SkImage> CreateSkiaImageFromDib(const CFX_DIBBase* source,
SkColorType color_type,
SkAlphaType alpha_type) {
// Make sure the DIB is backed by a buffer.
- RetainPtr<const CFX_DIBBase> retained;
- if (source->GetBuffer().empty()) {
- retained = source->Realize();
- if (!retained) {
- return nullptr;
- }
- DCHECK(!retained->GetBuffer().empty());
- } else {
- retained.Reset(source);
+ RetainPtr<const CFX_DIBitmap> realized_bitmap = source->RealizeIfNeeded();
+ if (!realized_bitmap) {
+ return nullptr;
}
+ CHECK(!realized_bitmap->GetBuffer().empty());
- // Convert unowned pointer to a retained pointer, then "leak" to `SkImage`.
- source = retained.Leak();
- SkImageInfo info = SkImageInfo::Make(source->GetWidth(), source->GetHeight(),
+ // Transfer ownership of `realized_bitmap` to `bitmap`, which will be freed by
+ // ReleaseRetainedHeldBySkImage().
+ const CFX_DIBitmap* bitmap = realized_bitmap.Leak();
+ SkImageInfo info = SkImageInfo::Make(bitmap->GetWidth(), bitmap->GetHeight(),
color_type, alpha_type);
- return SkImages::RasterFromPixmap(
- SkPixmap(info, source->GetBuffer().data(), source->GetPitch()),
+ auto result = SkImages::RasterFromPixmap(
+ SkPixmap(info, bitmap->GetBuffer().data(), bitmap->GetPitch()),
/*rasterReleaseProc=*/ReleaseRetainedHeldBySkImage,
- /*releaseContext=*/const_cast<CFX_DIBBase*>(source));
+ /*releaseContext=*/const_cast<CFX_DIBitmap*>(bitmap));
+ CHECK(result); // Otherwise, `bitmap` leaks.
+ return result;
}
// Releases allocated memory "leaked" by `CreateSkiaImageFromTransformedDib()`.
@@ -125,22 +119,6 @@
DCHECK_GE(scanline.size(), min_row_bytes);
}
-void ValidateBufferSize(pdfium::span<const uint8_t> buffer,
- const CFX_DIBBase& source) {
-#if DCHECK_IS_ON()
- if (source.GetHeight() == 0) {
- return;
- }
-
- FX_SAFE_SIZE_T buffer_size = source.GetHeight() - 1;
- buffer_size *= source.GetPitch();
- buffer_size += fxge::CalculatePitch8OrDie(source.GetBPP(), /*components=*/1,
- source.GetWidth());
-
- DCHECK_GE(buffer.size(), buffer_size.ValueOrDie());
-#endif // DCHECK_IS_ON()
-}
-
// Creates an `SkImage` from a `CFX_DIBBase`, transforming the source pixels
// using `pixel_transform`.
//
@@ -167,40 +145,21 @@
return nullptr;
}
- // Transform source pixels to output pixels.
- pdfium::span<const uint8_t> source_buffer = source.GetBuffer();
+ // Transform source pixels to output pixels. Iterate by individual scanline.
Result* output_cursor = reinterpret_cast<Result*>(output.get());
- if (source_buffer.empty()) {
- // No buffer; iterate by individual scanline.
- const size_t min_row_bytes =
- fxge::CalculatePitch8OrDie(source.GetBPP(), /*components=*/1, width);
- DCHECK_LE(min_row_bytes, source.GetPitch());
+ const size_t min_row_bytes =
+ fxge::CalculatePitch8OrDie(source.GetBPP(), /*components=*/1, width);
+ DCHECK_LE(min_row_bytes, source.GetPitch());
- int line = 0;
- for (int row = 0; row < height; ++row) {
- pdfium::span<const uint8_t> scanline = source.GetScanline(line++);
- ValidateScanlineSize(scanline, min_row_bytes);
+ int line = 0;
+ for (int row = 0; row < height; ++row) {
+ pdfium::span<const uint8_t> scanline = source.GetScanline(line++);
+ ValidateScanlineSize(scanline, min_row_bytes);
- for (int column = 0; column < width; ++column) {
- *output_cursor++ =
- Traits::Invoke(std::forward<PixelTransform>(pixel_transform),
- scanline.data(), column);
- }
- }
- } else {
- // Iterate over the entire buffer.
- ValidateBufferSize(source_buffer, source);
- const size_t row_bytes = source.GetPitch();
-
- const uint8_t* next_scanline = source_buffer.data();
- for (int row = 0; row < height; ++row) {
- const uint8_t* scanline = next_scanline;
- next_scanline += row_bytes;
-
- for (int column = 0; column < width; ++column) {
- *output_cursor++ = Traits::Invoke(
- std::forward<PixelTransform>(pixel_transform), scanline, column);
- }
+ for (int column = 0; column < width; ++column) {
+ *output_cursor++ =
+ Traits::Invoke(std::forward<PixelTransform>(pixel_transform),
+ scanline.data(), column);
}
}
diff --git a/core/fxge/win32/cgdi_device_driver.cpp b/core/fxge/win32/cgdi_device_driver.cpp
index e4c2b15..e6e2c21 100644
--- a/core/fxge/win32/cgdi_device_driver.cpp
+++ b/core/fxge/win32/cgdi_device_driver.cpp
@@ -394,7 +394,7 @@
int left,
int top) {
if (m_DeviceType == DeviceType::kPrinter) {
- RetainPtr<const CFX_DIBBase> flipped_source =
+ RetainPtr<const CFX_DIBitmap> flipped_source =
source->FlipImage(/*bXFlip=*/false, /*bYFlip=*/true);
if (!flipped_source) {
return false;
@@ -414,7 +414,7 @@
return true;
}
- RetainPtr<const CFX_DIBBase> realized_source = source->RealizeIfNeeded();
+ RetainPtr<const CFX_DIBitmap> realized_source = source->RealizeIfNeeded();
if (!realized_source) {
return false;
}
@@ -445,7 +445,7 @@
SetStretchBltMode(m_hDC, COLORONCOLOR);
}
- RetainPtr<const CFX_DIBBase> realized_source;
+ RetainPtr<const CFX_DIBitmap> realized_source;
if (m_DeviceType == DeviceType::kPrinter &&
((int64_t)source->GetWidth() * source->GetHeight() >
(int64_t)abs(dest_width) * abs(dest_height))) {
@@ -477,7 +477,7 @@
return false;
}
- RetainPtr<const CFX_DIBBase> realized_source = source->RealizeIfNeeded();
+ RetainPtr<const CFX_DIBitmap> realized_source = source->RealizeIfNeeded();
if (!realized_source) {
return false;
}
diff --git a/core/fxge/win32/cgdi_plus_ext.cpp b/core/fxge/win32/cgdi_plus_ext.cpp
index f6a9181..0cd0a37 100644
--- a/core/fxge/win32/cgdi_plus_ext.cpp
+++ b/core/fxge/win32/cgdi_plus_ext.cpp
@@ -223,7 +223,7 @@
return;
}
- RetainPtr<const CFX_DIBBase> realized_source = source->RealizeIfNeeded();
+ RetainPtr<const CFX_DIBitmap> realized_source = source->RealizeIfNeeded();
if (!realized_source) {
return;
}
diff --git a/testing/resources/pixel/bug_1478366.in b/testing/resources/pixel/bug_1478366.in
new file mode 100644
index 0000000..5749b52
--- /dev/null
+++ b/testing/resources/pixel/bug_1478366.in
@@ -0,0 +1,56 @@
+{{header}}
+{{object 1 0}} <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+endobj
+{{object 2 0}} <<
+ /Type /Pages
+ /Count 1
+ /Kids [3 0 R]
+>>
+endobj
+{{object 3 0}} <<
+ /Type /Page
+ /Parent 2 0 R
+ /Contents [4 0 R]
+ /MediaBox [0 0 200 200]
+ /Resources <<
+ /XObject <<
+ /X1 5 0 R
+ >>
+ >>
+>>
+endobj
+{{object 4 0}} <<
+ {{streamlen}}
+>>
+stream
+q
+200 0 0 200 0 0 cm
+/X1 Do
+Q
+endstream
+endobj
+{{object 5 0}} <<
+ /Type /XObject
+ /Subtype /Image
+ % The image needs to have a bitmap size that's at least `kHugeImageSize`.
+ /Width 4000
+ /Height 4000
+ /BitsPerComponent 1
+ /ColorSpace /DeviceGray
+ /Filter [/ASCIIHexDecode /JBIG2Decode]
+ /Mask [255 255]
+ {{streamlen}}
+>>
+stream
+000000003000010000001300000dea00000353000017110000171151000000000001260001000000
+3500000dea000003530000000000000000020003fffdff02fefefeff7f86530fb6c922cfff7fff7f
+ff7fff7fff7fff7fff7fff7fffac
+endstream
+endobj
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/bug_1478366_expected.pdf.0.png b/testing/resources/pixel/bug_1478366_expected.pdf.0.png
new file mode 100644
index 0000000..23e6296
--- /dev/null
+++ b/testing/resources/pixel/bug_1478366_expected.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/bug_1478366_expected_skia.pdf.0.png b/testing/resources/pixel/bug_1478366_expected_skia.pdf.0.png
new file mode 100644
index 0000000..baf8b4b
--- /dev/null
+++ b/testing/resources/pixel/bug_1478366_expected_skia.pdf.0.png
Binary files differ