Remove UNSAFE_TODOs in CPDF_DIB::LoadJpxBitmap()
Convert code to use spans. To help facilitate this, add templated
CFX_DIBBase::GetScanlineAs() and CFX_DIBitmap::GetWritableScanlineAs()
to allow converting bytes to structs defined in fx_dib.h.
Bug: 42271176
Change-Id: Iabd2afd211da4646e617d9bcbc95877d8354d284
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/120178
Reviewed-by: Thomas Sepez <tsepez@google.com>
Reviewed-by: Tom Sepez <tsepez@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 6b09d43..96ad994 100644
--- a/core/fpdfapi/page/cpdf_dib.cpp
+++ b/core/fpdfapi/page/cpdf_dib.cpp
@@ -759,36 +759,38 @@
       m_JpxInlineData.height = image_info.height;
       m_JpxInlineData.data.reserve(image_info.width * image_info.height);
       for (uint32_t row = 0; row < image_info.height; ++row) {
-        const uint8_t* src = result_bitmap->GetScanline(row).data();
-        uint8_t* dest = rgb_bitmap->GetWritableScanline(row).data();
-        UNSAFE_TODO({
-          for (uint32_t col = 0; col < image_info.width; ++col) {
-            uint8_t a = src[3];
-            m_JpxInlineData.data.push_back(a);
-            uint8_t na = 255 - a;
-            uint8_t b = (src[0] * a + 255 * na) / 255;
-            uint8_t g = (src[1] * a + 255 * na) / 255;
-            uint8_t r = (src[2] * a + 255 * na) / 255;
-            dest[0] = b;
-            dest[1] = g;
-            dest[2] = r;
-            src += 4;
-            dest += 3;
-          }
-        });
+        auto src =
+            result_bitmap->GetScanlineAs<FX_BGRA_STRUCT<uint8_t>>(row).first(
+                image_info.width);
+        auto dest =
+            rgb_bitmap->GetWritableScanlineAs<FX_BGR_STRUCT<uint8_t>>(row)
+                .first(image_info.width);
+        for (const auto& input : src) {
+          auto& output = dest.front();
+          m_JpxInlineData.data.push_back(input.alpha);
+          const uint8_t na = 255 - input.alpha;
+          output.blue = (input.blue * input.alpha + 255 * na) / 255;
+          output.green = (input.green * input.alpha + 255 * na) / 255;
+          output.red = (input.red * input.alpha + 255 * na) / 255;
+          dest = dest.subspan(1);
+        }
       }
     } else {
       // TODO(thestig): Is there existing code that does this already?
       for (uint32_t row = 0; row < image_info.height; ++row) {
-        const uint8_t* src = result_bitmap->GetScanline(row).data();
-        uint8_t* dest = rgb_bitmap->GetWritableScanline(row).data();
-        UNSAFE_TODO({
-          for (uint32_t col = 0; col < image_info.width; ++col) {
-            FXSYS_memcpy(dest, src, 3);
-            src += 4;
-            dest += 3;
-          }
-        });
+        auto src =
+            result_bitmap->GetScanlineAs<FX_BGRA_STRUCT<uint8_t>>(row).first(
+                image_info.width);
+        auto dest =
+            rgb_bitmap->GetWritableScanlineAs<FX_BGR_STRUCT<uint8_t>>(row)
+                .first(image_info.width);
+        for (const auto& input : src) {
+          auto& output = dest.front();
+          output.green = input.green;
+          output.red = input.red;
+          output.blue = input.blue;
+          dest = dest.subspan(1);
+        }
       }
     }
     result_bitmap = std::move(rgb_bitmap);
@@ -797,13 +799,11 @@
              m_bpc < 8) {
     int scale = 8 - m_bpc;
     for (uint32_t row = 0; row < image_info.height; ++row) {
-      uint8_t* scanline = result_bitmap->GetWritableScanline(row).data();
-      UNSAFE_TODO({
-        for (uint32_t col = 0; col < image_info.width; ++col) {
-          *scanline = (*scanline) >> scale;
-          ++scanline;
-        }
-      });
+      pdfium::span<uint8_t> scanline =
+          result_bitmap->GetWritableScanline(row).first(image_info.width);
+      for (auto& pixel : scanline) {
+        pixel >>= scale;
+      }
     }
   }
 
diff --git a/core/fxge/dib/cfx_dibbase.h b/core/fxge/dib/cfx_dibbase.h
index 12677ed..c5c3c4e 100644
--- a/core/fxge/dib/cfx_dibbase.h
+++ b/core/fxge/dib/cfx_dibbase.h
@@ -14,6 +14,7 @@
 #include "core/fxcrt/data_vector.h"
 #include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/span.h"
+#include "core/fxcrt/span_util.h"
 #include "core/fxge/dib/fx_dib.h"
 
 #if defined(PDF_USE_SKIA)
@@ -50,6 +51,11 @@
   virtual RetainPtr<const CFX_DIBitmap> RealizeIfNeeded() const;
 #endif
 
+  template <typename T>
+  pdfium::span<const T> GetScanlineAs(int line) const {
+    return fxcrt::truncating_reinterpret_span<const T>(GetScanline(line));
+  }
+
   int GetWidth() const { return m_Width; }
   int GetHeight() const { return m_Height; }
   uint32_t GetPitch() const { return m_Pitch; }
diff --git a/core/fxge/dib/cfx_dibitmap.h b/core/fxge/dib/cfx_dibitmap.h
index bd9d9b4..2af64ca 100644
--- a/core/fxge/dib/cfx_dibitmap.h
+++ b/core/fxge/dib/cfx_dibitmap.h
@@ -17,6 +17,7 @@
 #include "core/fxcrt/maybe_owned.h"
 #include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/span.h"
+#include "core/fxcrt/span_util.h"
 #include "core/fxge/dib/cfx_dibbase.h"
 #include "core/fxge/dib/fx_dib.h"
 
@@ -55,10 +56,16 @@
 
   pdfium::span<uint8_t> GetWritableScanline(int line) {
     pdfium::span<const uint8_t> src = GetScanline(line);
+    // SAFETY: const_cast<>() doesn't change size.
     return UNSAFE_BUFFERS(
         pdfium::make_span(const_cast<uint8_t*>(src.data()), src.size()));
   }
 
+  template <typename T>
+  pdfium::span<T> GetWritableScanlineAs(int line) {
+    return fxcrt::truncating_reinterpret_span<T>(GetWritableScanline(line));
+  }
+
   void TakeOver(RetainPtr<CFX_DIBitmap>&& pSrcBitmap);
   bool ConvertFormat(FXDIB_Format format);
   void Clear(uint32_t color);