Consolidate code into CPDF_ImageRenderer::CalculateDrawImage()

Currently, CalculateDrawImage() requires the caller to create a bitmap
before calling it, and to do bitmap conversion after. Instead, move the
common caller code to within CalculateDrawImage(), and just return the
bitmap result.

Change-Id: Ib56d06028540db7b08d3e9af818a3eac72c1396d
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/115850
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/render/cpdf_imagerenderer.cpp b/core/fpdfapi/render/cpdf_imagerenderer.cpp
index 9ab7075..7f37161 100644
--- a/core/fpdfapi/render/cpdf_imagerenderer.cpp
+++ b/core/fpdfapi/render/cpdf_imagerenderer.cpp
@@ -221,46 +221,62 @@
   return new_matrix;
 }
 
-void CPDF_ImageRenderer::CalculateDrawImage(
+RetainPtr<const CFX_DIBitmap> CPDF_ImageRenderer::CalculateDrawImage(
     CFX_DefaultRenderDevice& bitmap_device,
-    CFX_DefaultRenderDevice& mask_device,
     RetainPtr<CFX_DIBBase> pDIBBase,
     const CFX_Matrix& mtNewMatrix,
     const FX_RECT& rect) const {
-  CPDF_RenderStatus mask_status(m_pRenderStatus->GetContext(), &mask_device);
-  mask_status.SetDropObjects(m_pRenderStatus->GetDropObjects());
-  mask_status.SetStdCS(true);
-  mask_status.Initialize(nullptr, nullptr);
-
-  CPDF_ImageRenderer mask_renderer(&mask_status);
-  if (mask_renderer.Start(std::move(pDIBBase), 0xffffffff, mtNewMatrix,
-                          m_ResampleOptions, true)) {
-    mask_renderer.Continue(nullptr);
+  auto mask_bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+  if (!mask_bitmap->Create(rect.Width(), rect.Height(),
+                           FXDIB_Format::k8bppRgb)) {
+    return nullptr;
   }
-  if (m_pLoader->MatteColor() == 0xffffffff)
-    return;
-  int matte_r = FXARGB_R(m_pLoader->MatteColor());
-  int matte_g = FXARGB_G(m_pLoader->MatteColor());
-  int matte_b = FXARGB_B(m_pLoader->MatteColor());
-  for (int row = 0; row < rect.Height(); row++) {
-    uint8_t* dest_scan =
-        bitmap_device.GetBitmap()->GetWritableScanline(row).data();
-    const uint8_t* mask_scan = mask_device.GetBitmap()->GetScanline(row).data();
-    for (int col = 0; col < rect.Width(); col++) {
-      int alpha = *mask_scan++;
-      if (!alpha) {
-        dest_scan += 4;
-        continue;
+
+  {
+    // Limit the scope of `mask_device`, so its dtor can flush out pending
+    // operations, if any, to `mask_bitmap`.
+    CFX_DefaultRenderDevice mask_device;
+    CHECK(mask_device.Attach(mask_bitmap));
+
+    CPDF_RenderStatus mask_status(m_pRenderStatus->GetContext(), &mask_device);
+    mask_status.SetDropObjects(m_pRenderStatus->GetDropObjects());
+    mask_status.SetStdCS(true);
+    mask_status.Initialize(nullptr, nullptr);
+
+    CPDF_ImageRenderer mask_renderer(&mask_status);
+    if (mask_renderer.Start(std::move(pDIBBase), 0xffffffff, mtNewMatrix,
+                            m_ResampleOptions, true)) {
+      mask_renderer.Continue(nullptr);
+    }
+    if (m_pLoader->MatteColor() != 0xffffffff) {
+      int matte_r = FXARGB_R(m_pLoader->MatteColor());
+      int matte_g = FXARGB_G(m_pLoader->MatteColor());
+      int matte_b = FXARGB_B(m_pLoader->MatteColor());
+      for (int row = 0; row < rect.Height(); row++) {
+        uint8_t* dest_scan =
+            bitmap_device.GetBitmap()->GetWritableScanline(row).data();
+        const uint8_t* mask_scan =
+            mask_device.GetBitmap()->GetScanline(row).data();
+        for (int col = 0; col < rect.Width(); col++) {
+          int alpha = *mask_scan++;
+          if (!alpha) {
+            dest_scan += 4;
+            continue;
+          }
+          int orig = (*dest_scan - matte_b) * 255 / alpha + matte_b;
+          *dest_scan++ = std::clamp(orig, 0, 255);
+          orig = (*dest_scan - matte_g) * 255 / alpha + matte_g;
+          *dest_scan++ = std::clamp(orig, 0, 255);
+          orig = (*dest_scan - matte_r) * 255 / alpha + matte_r;
+          *dest_scan++ = std::clamp(orig, 0, 255);
+          dest_scan++;
+        }
       }
-      int orig = (*dest_scan - matte_b) * 255 / alpha + matte_b;
-      *dest_scan++ = std::clamp(orig, 0, 255);
-      orig = (*dest_scan - matte_g) * 255 / alpha + matte_g;
-      *dest_scan++ = std::clamp(orig, 0, 255);
-      orig = (*dest_scan - matte_r) * 255 / alpha + matte_r;
-      *dest_scan++ = std::clamp(orig, 0, 255);
-      dest_scan++;
     }
   }
+  CHECK(!mask_bitmap->HasPalette());
+  mask_bitmap->ConvertFormat(FXDIB_Format::k8bppMask);
+  return mask_bitmap;
 }
 
 const CPDF_RenderOptions& CPDF_ImageRenderer::GetRenderOptions() const {
@@ -302,14 +318,13 @@
                                      pattern_matrix, false);
   }
 
-  CFX_DefaultRenderDevice mask_device;
-  if (!mask_device.Create(rect.Width(), rect.Height(), FXDIB_Format::k8bppRgb,
-                          nullptr)) {
+  RetainPtr<const CFX_DIBitmap> mask_bitmap =
+      CalculateDrawImage(bitmap_device, m_pDIBBase, new_matrix, rect);
+  if (!mask_bitmap) {
     return true;
   }
-  CalculateDrawImage(bitmap_device, mask_device, m_pDIBBase, new_matrix, rect);
-  mask_device.GetBitmap()->ConvertFormat(FXDIB_Format::k8bppMask);
-  bitmap_device.GetBitmap()->MultiplyAlphaMask(mask_device.GetBitmap());
+
+  bitmap_device.GetBitmap()->MultiplyAlphaMask(std::move(mask_bitmap));
   m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend(
       bitmap_device.GetBitmap(), rect.left, rect.top, m_BlendType);
   return false;
@@ -342,24 +357,21 @@
                             true)) {
     bitmap_renderer.Continue(nullptr);
   }
-  CFX_DefaultRenderDevice mask_device;
-  if (!mask_device.Create(rect.Width(), rect.Height(), FXDIB_Format::k8bppRgb,
-                          nullptr)) {
+  RetainPtr<const CFX_DIBitmap> mask_bitmap =
+      CalculateDrawImage(bitmap_device, m_pLoader->GetMask(), new_matrix, rect);
+  if (!mask_bitmap) {
     return true;
   }
-  CalculateDrawImage(bitmap_device, mask_device, m_pLoader->GetMask(),
-                     new_matrix, rect);
-  DCHECK(!mask_device.GetBitmap()->HasPalette());
-  mask_device.GetBitmap()->ConvertFormat(FXDIB_Format::k8bppMask);
+
 #if defined(PDF_USE_SKIA)
   if (CFX_DefaultRenderDevice::UseSkiaRenderer() &&
       m_pRenderStatus->GetRenderDevice()->SetBitsWithMask(
-          bitmap_device.GetBitmap(), mask_device.GetBitmap(), rect.left,
-          rect.top, m_Alpha, m_BlendType)) {
+          bitmap_device.GetBitmap(), mask_bitmap, rect.left, rect.top, m_Alpha,
+          m_BlendType)) {
     return false;
   }
 #endif
-  bitmap_device.GetBitmap()->MultiplyAlphaMask(mask_device.GetBitmap());
+  bitmap_device.GetBitmap()->MultiplyAlphaMask(std::move(mask_bitmap));
   bitmap_device.GetBitmap()->MultiplyAlpha(m_Alpha);
   m_pRenderStatus->GetRenderDevice()->SetDIBitsWithBlend(
       bitmap_device.GetBitmap(), rect.left, rect.top, m_BlendType);
diff --git a/core/fpdfapi/render/cpdf_imagerenderer.h b/core/fpdfapi/render/cpdf_imagerenderer.h
index 2a8585c..0bab169 100644
--- a/core/fpdfapi/render/cpdf_imagerenderer.h
+++ b/core/fpdfapi/render/cpdf_imagerenderer.h
@@ -64,11 +64,12 @@
   bool NotDrawing() const;
   FX_RECT GetDrawRect() const;
   CFX_Matrix GetDrawMatrix(const FX_RECT& rect) const;
-  void CalculateDrawImage(CFX_DefaultRenderDevice& bitmap_device,
-                          CFX_DefaultRenderDevice& mask_device,
-                          RetainPtr<CFX_DIBBase> pDIBBase,
-                          const CFX_Matrix& mtNewMatrix,
-                          const FX_RECT& rect) const;
+  // Returns the mask, or nullptr if the mask could not be created.
+  RetainPtr<const CFX_DIBitmap> CalculateDrawImage(
+      CFX_DefaultRenderDevice& bitmap_device,
+      RetainPtr<CFX_DIBBase> pDIBBase,
+      const CFX_Matrix& mtNewMatrix,
+      const FX_RECT& rect) const;
   const CPDF_RenderOptions& GetRenderOptions() const;
   void HandleFilters();
   absl::optional<FX_RECT> GetUnitRect() const;