Redo CFX_DIBitmap::CalculatePitchAndSize().

Remove the in-out parameters and replace them with
Optional<CFX_DIBitmap::PitchAndSize>, where PitchAndSize is a struct.
Clean up the callers and document the function behavior.

Change-Id: Iaee5ee4243328661a004e8885bb670a79d04945d
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/73391
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/render/cpdf_scaledrenderbuffer.cpp b/core/fpdfapi/render/cpdf_scaledrenderbuffer.cpp
index ab54d85..257fcfe 100644
--- a/core/fpdfapi/render/cpdf_scaledrenderbuffer.cpp
+++ b/core/fpdfapi/render/cpdf_scaledrenderbuffer.cpp
@@ -46,14 +46,13 @@
     int32_t width = bitmap_rect.Width();
     int32_t height = bitmap_rect.Height();
     // Set to 0 to make CalculatePitchAndSize() calculate it.
-    uint32_t pitch = 0;
-    uint32_t size;
-    if (!CFX_DIBitmap::CalculatePitchAndSize(width, height, dibFormat, &pitch,
-                                             &size)) {
+    constexpr uint32_t kNoPitch = 0;
+    Optional<CFX_DIBitmap::PitchAndSize> pitch_size =
+        CFX_DIBitmap::CalculatePitchAndSize(width, height, dibFormat, kNoPitch);
+    if (!pitch_size.has_value())
       return false;
-    }
 
-    if (size <= kImageSizeLimitBytes &&
+    if (pitch_size.value().size <= kImageSizeLimitBytes &&
         m_pBitmapDevice->Create(width, height, dibFormat, nullptr)) {
       break;
     }
diff --git a/core/fxcodec/progressive_decoder.cpp b/core/fxcodec/progressive_decoder.cpp
index c22fde0..7171f46 100644
--- a/core/fxcodec/progressive_decoder.cpp
+++ b/core/fxcodec/progressive_decoder.cpp
@@ -743,17 +743,19 @@
       return false;
   }
 
-  uint32_t pitch = 0;
-  uint32_t neededData = 0;
-  if (!CFX_DIBitmap::CalculatePitchAndSize(m_SrcWidth, m_SrcHeight, format,
-                                           &pitch, &neededData)) {
+  // Set to 0 to make CalculatePitchAndSize() calculate it.
+  constexpr uint32_t kNoPitch = 0;
+  Optional<CFX_DIBitmap::PitchAndSize> needed_data =
+      CFX_DIBitmap::CalculatePitchAndSize(m_SrcWidth, m_SrcHeight, format,
+                                          kNoPitch);
+  if (!needed_data.has_value()) {
     m_status = FXCODEC_STATUS_ERR_FORMAT;
     return false;
   }
 
-  uint32_t availableData = m_pFile->GetSize() - m_offSet +
-                           BmpDecoder::GetAvailInput(pBmpContext.get());
-  if (neededData > availableData) {
+  uint32_t available_data = m_pFile->GetSize() - m_offSet +
+                            BmpDecoder::GetAvailInput(pBmpContext.get());
+  if (needed_data.value().size > available_data) {
     m_status = FXCODEC_STATUS_ERR_FORMAT;
     return false;
   }
diff --git a/core/fxge/dib/cfx_dibitmap.cpp b/core/fxge/dib/cfx_dibitmap.cpp
index 8b0551c..ad12939 100644
--- a/core/fxge/dib/cfx_dibitmap.cpp
+++ b/core/fxge/dib/cfx_dibitmap.cpp
@@ -47,14 +47,15 @@
   m_Height = 0;
   m_Pitch = 0;
 
-  uint32_t calculatedSize;
-  if (!CalculatePitchAndSize(height, width, format, &pitch, &calculatedSize))
+  Optional<PitchAndSize> pitch_size =
+      CalculatePitchAndSize(height, width, format, pitch);
+  if (!pitch_size.has_value())
     return false;
 
   if (pBuffer) {
     m_pBuffer.Reset(pBuffer);
   } else {
-    size_t bufferSize = calculatedSize + 4;
+    size_t bufferSize = pitch_size.value().size + 4;
     if (bufferSize >= kMaxOOMLimit) {
       m_pBuffer = std::unique_ptr<uint8_t, FxFreeDeleter>(
           FX_TryAlloc(uint8_t, bufferSize));
@@ -67,7 +68,7 @@
   }
   m_Width = width;
   m_Height = height;
-  m_Pitch = pitch;
+  m_Pitch = pitch_size.value().pitch;
   if (!HasAlpha() || format == FXDIB_Argb)
     return true;
 
@@ -840,29 +841,30 @@
 }
 
 // static
-bool CFX_DIBitmap::CalculatePitchAndSize(int height,
-                                         int width,
-                                         FXDIB_Format format,
-                                         uint32_t* pitch,
-                                         uint32_t* size) {
+Optional<CFX_DIBitmap::PitchAndSize> CFX_DIBitmap::CalculatePitchAndSize(
+    int height,
+    int width,
+    FXDIB_Format format,
+    uint32_t pitch) {
   if (width <= 0 || height <= 0)
-    return false;
+    return pdfium::nullopt;
 
   int bpp = GetBppFromFormat(format);
   if (!bpp)
-    return false;
+    return pdfium::nullopt;
 
   if ((INT_MAX - 31) / width < bpp)
-    return false;
+    return pdfium::nullopt;
 
-  if (!*pitch)
-    *pitch = static_cast<uint32_t>((width * bpp + 31) / 32 * 4);
+  uint32_t actual_pitch = pitch;
+  if (actual_pitch == 0)
+    actual_pitch = static_cast<uint32_t>((width * bpp + 31) / 32 * 4);
 
-  if ((1 << 30) / *pitch < static_cast<uint32_t>(height))
-    return false;
+  if ((1 << 30) / actual_pitch < static_cast<uint32_t>(height))
+    return pdfium::nullopt;
 
-  *size = *pitch * static_cast<uint32_t>(height);
-  return true;
+  uint32_t size = actual_pitch * static_cast<uint32_t>(height);
+  return PitchAndSize{actual_pitch, size};
 }
 
 bool CFX_DIBitmap::CompositeBitmap(int dest_left,
diff --git a/core/fxge/dib/cfx_dibitmap.h b/core/fxge/dib/cfx_dibitmap.h
index 5c59c7a..27a8de0 100644
--- a/core/fxge/dib/cfx_dibitmap.h
+++ b/core/fxge/dib/cfx_dibitmap.h
@@ -13,9 +13,15 @@
 #include "core/fxcrt/retain_ptr.h"
 #include "core/fxge/dib/cfx_dibbase.h"
 #include "core/fxge/fx_dib.h"
+#include "third_party/base/optional.h"
 
 class CFX_DIBitmap : public CFX_DIBBase {
  public:
+  struct PitchAndSize {
+    uint32_t pitch;
+    uint32_t size;
+  };
+
   CONSTRUCT_VIA_MAKE_RETAIN;
 
   bool Create(int width, int height, FXDIB_Format format);
@@ -93,11 +99,17 @@
 
   bool ConvertColorScale(uint32_t forecolor, uint32_t backcolor);
 
-  static bool CalculatePitchAndSize(int height,
-                                    int width,
-                                    FXDIB_Format format,
-                                    uint32_t* pitch,
-                                    uint32_t* size);
+  // |width| and |height| must be greater than 0.
+  // |format| must have a valid bits per pixel count.
+  // If |pitch| is zero, then the actual pitch will be calculated based on
+  // |width| and |format|.
+  // If |pitch| is non-zero, then that be used as the actual pitch.
+  // The actual pitch will be used to calculate the size.
+  // Returns the calculated pitch and size on success, or nullopt on failure.
+  static Optional<PitchAndSize> CalculatePitchAndSize(int height,
+                                                      int width,
+                                                      FXDIB_Format format,
+                                                      uint32_t pitch);
 
 #if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
   void PreMultiply();