Align fax encoder interface with JPEG encoder interface.

Just pass a bitmap in instead of multiple parameters that describe
various bitmap attributes. Along the way, do more checks to safeguard
against integer overflows and consolidate more CFX_PSRenderer fax
encoding code into FaxCompressData().

Also pass the bitmap around using a RetainPtr with move semantics,
instead of passing around a const-ref RetainPtr.

Change-Id: I2d0b4180541048f48f2f345b86cd4011761c3b68
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/98010
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcodec/fax/faxmodule.cpp b/core/fxcodec/fax/faxmodule.cpp
index 542a7dd..d5b8262 100644
--- a/core/fxcodec/fax/faxmodule.cpp
+++ b/core/fxcodec/fax/faxmodule.cpp
@@ -11,6 +11,7 @@
 #include <algorithm>
 #include <iterator>
 #include <memory>
+#include <utility>
 
 #include "build/build_config.h"
 #include "core/fxcodec/scanlinedecoder.h"
@@ -24,6 +25,11 @@
 #include "third_party/base/numerics/safe_conversions.h"
 #include "third_party/base/span.h"
 
+#if BUILDFLAG(IS_WIN)
+#include "core/fxcrt/span_util.h"
+#include "core/fxge/dib/cfx_dibbase.h"
+#endif
+
 namespace fxcodec {
 
 namespace {
@@ -675,10 +681,7 @@
 
 class FaxEncoder {
  public:
-  FaxEncoder(pdfium::span<const uint8_t> src_span,
-             int width,
-             int height,
-             int pitch);
+  explicit FaxEncoder(RetainPtr<CFX_DIBBase> src);
   ~FaxEncoder();
   DataVector<uint8_t> Encode();
 
@@ -687,8 +690,9 @@
   void FaxEncodeRun(int run, bool bWhite);
   void AddBitStream(int data, int bitlen);
 
+  // Must outlive `m_RefLineSpan`.
+  RetainPtr<CFX_DIBBase> const m_Src;
   int m_DestBitpos = 0;
-  const pdfium::span<const uint8_t> m_SrcSpan;
   const int m_Cols;
   const int m_Rows;
   const int m_Pitch;
@@ -699,17 +703,15 @@
   pdfium::span<const uint8_t> m_RefLineSpan;
 };
 
-FaxEncoder::FaxEncoder(pdfium::span<const uint8_t> src_span,
-                       int width,
-                       int height,
-                       int pitch)
-    : m_SrcSpan(src_span),
-      m_Cols(width),
-      m_Rows(height),
-      m_Pitch(pitch),
+FaxEncoder::FaxEncoder(RetainPtr<CFX_DIBBase> src)
+    : m_Src(std::move(src)),
+      m_Cols(m_Src->GetWidth()),
+      m_Rows(m_Src->GetHeight()),
+      m_Pitch(m_Src->GetPitch()),
       m_InitialRefLine(m_Pitch, 0xff),
       m_LineBuf(Fx2DSizeOrDie(8, m_Pitch)),
       m_RefLineSpan(m_InitialRefLine) {
+  DCHECK_EQ(1, m_Src->GetBPP());
   m_DestBuf.SetAllocStep(10240);
 }
 
@@ -798,8 +800,7 @@
   m_DestBitpos = 0;
   uint8_t last_byte = 0;
   for (int i = 0; i < m_Rows; ++i) {
-    pdfium::span<const uint8_t> scan_line =
-        m_SrcSpan.subspan(i * m_Pitch, m_Pitch);
+    pdfium::span<const uint8_t> scan_line = m_Src->GetScanline(i);
     std::fill(std::begin(m_LineBuf), std::end(m_LineBuf), 0);
     m_LineBuf[0] = last_byte;
     FaxEncode2DLine(scan_line);
@@ -816,11 +817,9 @@
 }  // namespace
 
 // static
-DataVector<uint8_t> FaxModule::FaxEncode(pdfium::span<const uint8_t> src_span,
-                                         int width,
-                                         int height,
-                                         int pitch) {
-  FaxEncoder encoder(src_span, width, height, pitch);
+DataVector<uint8_t> FaxModule::FaxEncode(RetainPtr<CFX_DIBBase> src) {
+  DCHECK_EQ(1, src->GetBPP());
+  FaxEncoder encoder(std::move(src));
   return encoder.Encode();
 }
 
diff --git a/core/fxcodec/fax/faxmodule.h b/core/fxcodec/fax/faxmodule.h
index 882cf05..f0028bf 100644
--- a/core/fxcodec/fax/faxmodule.h
+++ b/core/fxcodec/fax/faxmodule.h
@@ -16,8 +16,11 @@
 
 #if BUILDFLAG(IS_WIN)
 #include "core/fxcrt/data_vector.h"
+#include "core/fxcrt/retain_ptr.h"
 #endif
 
+class CFX_DIBBase;
+
 namespace fxcodec {
 
 class ScanlineDecoder;
@@ -45,10 +48,8 @@
                          uint8_t* dest_buf);
 
 #if BUILDFLAG(IS_WIN)
-  static DataVector<uint8_t> FaxEncode(pdfium::span<const uint8_t> src_span,
-                                       int width,
-                                       int height,
-                                       int pitch);
+  // `src` must have a BPP value of 1.
+  static DataVector<uint8_t> FaxEncode(RetainPtr<CFX_DIBBase> src);
 #endif  // BUILDFLAG(IS_WIN)
 
   FaxModule() = delete;
diff --git a/core/fxge/win32/cfx_psrenderer.cpp b/core/fxge/win32/cfx_psrenderer.cpp
index 243c038..c51ada6 100644
--- a/core/fxge/win32/cfx_psrenderer.cpp
+++ b/core/fxge/win32/cfx_psrenderer.cpp
@@ -19,6 +19,7 @@
 #include "core/fxcrt/fx_extension.h"
 #include "core/fxcrt/fx_memory.h"
 #include "core/fxcrt/fx_memory_wrappers.h"
+#include "core/fxcrt/fx_safe_types.h"
 #include "core/fxcrt/fx_stream.h"
 #include "core/fxcrt/span_util.h"
 #include "core/fxge/cfx_fillrenderoptions.h"
@@ -524,22 +525,13 @@
 
   const int width = pSource->GetWidth();
   const int height = pSource->GetHeight();
-  const int pitch = pSource->GetPitch();
   buf << width << " " << height;
 
   if (pSource->GetBPP() == 1 && !pSource->HasPalette()) {
-    const uint32_t src_size = height * pitch;
-    DataVector<uint8_t> src_buf(src_size);
-    {
-      auto src_buf_span = pdfium::make_span(src_buf);
-      for (int row = 0; row < height; row++) {
-        pdfium::span<const uint8_t> src_scan = pSource->GetScanline(row);
-        fxcrt::spancpy(src_buf_span.subspan(row * pitch, pitch), src_scan);
-      }
-    }
+    FaxCompressResult compress_result = FaxCompressData(pSource);
+    if (compress_result.data.empty())
+      return false;
 
-    FaxCompressResult compress_result =
-        FaxCompressData(std::move(src_buf), width, height, pitch);
     if (pSource->IsMaskFormat()) {
       SetColor(color);
       m_bColorSet = false;
@@ -843,20 +835,30 @@
 }
 
 CFX_PSRenderer::FaxCompressResult CFX_PSRenderer::FaxCompressData(
-    DataVector<uint8_t> src_buf,
-    int width,
-    int height,
-    int pitch) const {
+    RetainPtr<CFX_DIBBase> src) const {
+  DCHECK_EQ(1, src->GetBPP());
+
   FaxCompressResult result;
-  if (width * height <= 128) {
-    src_buf.resize(pitch * height);
-    result.data = std::move(src_buf);
-    result.compressed = false;
-  } else {
-    result.data =
-        m_pEncoderIface->pFaxEncodeFunc(src_buf, width, height, pitch);
+  const int height = src->GetHeight();
+  const int pitch = src->GetPitch();
+  FX_SAFE_UINT32 safe_size = pitch;
+  safe_size *= height;
+  if (!safe_size.IsValid())
+    return result;
+
+  if (safe_size.ValueOrDie() > 128) {
+    result.data = m_pEncoderIface->pFaxEncodeFunc(std::move(src));
     result.compressed = true;
+    return result;
   }
+
+  result.data.resize(safe_size.ValueOrDie());
+  auto dest_span = pdfium::make_span(result.data);
+  for (int row = 0; row < height; row++) {
+    pdfium::span<const uint8_t> src_scan = src->GetScanline(row);
+    fxcrt::spancpy(dest_span.subspan(row * pitch, pitch), src_scan);
+  }
+  result.compressed = false;
   return result;
 }
 
diff --git a/core/fxge/win32/cfx_psrenderer.h b/core/fxge/win32/cfx_psrenderer.h
index 31214de..ebe1b8c 100644
--- a/core/fxge/win32/cfx_psrenderer.h
+++ b/core/fxge/win32/cfx_psrenderer.h
@@ -37,10 +37,7 @@
 
 struct EncoderIface {
   DataVector<uint8_t> (*pA85EncodeFunc)(pdfium::span<const uint8_t> src_span);
-  DataVector<uint8_t> (*pFaxEncodeFunc)(pdfium::span<const uint8_t> src_span,
-                                        int width,
-                                        int height,
-                                        int pitch);
+  DataVector<uint8_t> (*pFaxEncodeFunc)(RetainPtr<CFX_DIBBase> src);
   DataVector<uint8_t> (*pFlateEncodeFunc)(pdfium::span<const uint8_t> src_span);
   bool (*pJpegEncodeFunc)(const RetainPtr<CFX_DIBBase>& pSource,
                           uint8_t** dest_buf,
@@ -159,10 +156,7 @@
                             CFX_Font* font,
                             float font_size,
                             fxcrt::ostringstream& buf);
-  FaxCompressResult FaxCompressData(DataVector<uint8_t> src_buf,
-                                    int width,
-                                    int height,
-                                    int pitch) const;
+  FaxCompressResult FaxCompressData(RetainPtr<CFX_DIBBase> src) const;
   absl::optional<PSCompressResult> PSCompressData(
       pdfium::span<const uint8_t> src_span) const;
   void WritePreambleString(ByteStringView str);