Fix span calculation in CPDF_DIB::GetScanline()

Ideally, the span size would match the calculated src_pitch_value, but
some spans are actually larger than we think. In cases when there is a
decoder or a cached bitmap, rely on the bounds being correctly set from
those spans, rather than recalculating them based on the current notion
of pitch.

Try to return spans representing only the initialized portion of a
buffer when we copy into one.

Having landed this CL, we should be able to re-enable the spancpy()
in CFX_DIBBase::Clone() that was reverted in a prior CL.

-- take a branch out of a for-loop while at it since I was confused
   for a moment if both halves advanced the same amount.

Change-Id: I557880b610af75f8bc68592d462b05cd8be964f2
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/85851
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_dib.cpp b/core/fpdfapi/page/cpdf_dib.cpp
index 586c8af..27be60a 100644
--- a/core/fpdfapi/page/cpdf_dib.cpp
+++ b/core/fpdfapi/page/cpdf_dib.cpp
@@ -1083,88 +1083,93 @@
     return pdfium::span<const uint8_t>();
 
   uint32_t src_pitch_value = src_pitch.value();
-  const uint8_t* pSrcLine = nullptr;
+  pdfium::span<const uint8_t> pSrcLine;
   if (m_pCachedBitmap && src_pitch_value <= m_pCachedBitmap->GetPitch()) {
-    if (line >= m_pCachedBitmap->GetHeight()) {
+    if (line >= m_pCachedBitmap->GetHeight())
       line = m_pCachedBitmap->GetHeight() - 1;
-    }
-    pSrcLine = m_pCachedBitmap->GetScanline(line).data();
+    pSrcLine = m_pCachedBitmap->GetScanline(line);
   } else if (m_pDecoder) {
-    pSrcLine = m_pDecoder->GetScanline(line).data();
+    pSrcLine = m_pDecoder->GetScanline(line);
   } else if (m_pStreamAcc->GetSize() >= (line + 1) * src_pitch_value) {
-    pSrcLine = m_pStreamAcc->GetData() + line * src_pitch_value;
+    pSrcLine = m_pStreamAcc->GetSpan().subspan(line * src_pitch_value,
+                                               src_pitch_value);
   }
-  if (!pSrcLine) {
-    pdfium::span<uint8_t> pLineBuf = !m_MaskBuf.empty() ? m_MaskBuf : m_LineBuf;
-    fxcrt::spanset(pLineBuf, 0xFF);
-    return pLineBuf;
+  if (pSrcLine.empty()) {
+    pdfium::span<uint8_t> result = !m_MaskBuf.empty() ? m_MaskBuf : m_LineBuf;
+    fxcrt::spanset(result, 0xFF);
+    return result;
   }
-
   if (m_bpc * m_nComponents == 1) {
     if (m_bImageMask && m_bDefaultDecode) {
-      for (uint32_t i = 0; i < src_pitch_value; i++)
-        m_LineBuf[i] = ~pSrcLine[i];
-      return m_LineBuf;
+      for (uint32_t i = 0; i < src_pitch_value; i++) {
+        // TODO(tsepez): Bounds check if cost is acceptable.
+        m_LineBuf[i] = ~pSrcLine.data()[i];
+      }
+      return pdfium::make_span(m_LineBuf).first(src_pitch_value);
     }
-
     if (!m_bColorKey) {
-      fxcrt::spancpy(pdfium::make_span(m_LineBuf),
-                     pdfium::make_span(pSrcLine, src_pitch_value));
-      return m_LineBuf;
+      pdfium::span<uint8_t> result = m_LineBuf;
+      fxcrt::spancpy(result, pSrcLine.first(src_pitch_value));
+      return result.first(src_pitch_value);
     }
-
     uint32_t reset_argb = Get1BitResetValue();
     uint32_t set_argb = Get1BitSetValue();
     uint32_t* dest_scan = reinterpret_cast<uint32_t*>(m_MaskBuf.data());
-    for (int col = 0; col < m_Width; col++) {
-      *dest_scan = GetBitValue(pSrcLine, col) ? set_argb : reset_argb;
-      dest_scan++;
+    for (int col = 0; col < m_Width; col++, dest_scan++) {
+      *dest_scan = GetBitValue(pSrcLine.data(), col) ? set_argb : reset_argb;
     }
-    return m_MaskBuf;
+    return pdfium::make_span(m_MaskBuf).first(m_Width * sizeof(uint32_t));
   }
   if (m_bpc * m_nComponents <= 8) {
+    pdfium::span<uint8_t> result = m_LineBuf;
     if (m_bpc == 8) {
-      fxcrt::spancpy(pdfium::make_span(m_LineBuf),
-                     pdfium::make_span(pSrcLine, src_pitch_value));
+      fxcrt::spancpy(result, pSrcLine.first(src_pitch_value));
+      result = result.first(src_pitch_value);
     } else {
       uint64_t src_bit_pos = 0;
       for (int col = 0; col < m_Width; col++) {
         unsigned int color_index = 0;
         for (uint32_t color = 0; color < m_nComponents; color++) {
-          unsigned int data = GetBits8(pSrcLine, src_bit_pos, m_bpc);
+          unsigned int data = GetBits8(pSrcLine.data(), src_bit_pos, m_bpc);
           color_index |= data << (color * m_bpc);
           src_bit_pos += m_bpc;
         }
         m_LineBuf[col] = color_index;
       }
+      result = result.first(m_Width);
     }
     if (!m_bColorKey)
-      return m_LineBuf;
+      return result;
 
     uint8_t* pDestPixel = m_MaskBuf.data();
     const uint8_t* pSrcPixel = m_LineBuf.data();
     pdfium::span<const uint32_t> palette = GetPaletteSpan();
-    for (int col = 0; col < m_Width; col++) {
-      uint8_t index = *pSrcPixel++;
-      if (HasPalette()) {
+    if (HasPalette()) {
+      for (int col = 0; col < m_Width; col++) {
+        uint8_t index = *pSrcPixel++;
         *pDestPixel++ = FXARGB_B(palette[index]);
         *pDestPixel++ = FXARGB_G(palette[index]);
         *pDestPixel++ = FXARGB_R(palette[index]);
-      } else {
-        *pDestPixel++ = index;
-        *pDestPixel++ = index;
-        *pDestPixel++ = index;
+        *pDestPixel++ =
+            IsColorIndexOutOfBounds(index, m_CompData[0]) ? 0xFF : 0;
       }
-      *pDestPixel = IsColorIndexOutOfBounds(index, m_CompData[0]) ? 0xFF : 0;
-      pDestPixel++;
+    } else {
+      for (int col = 0; col < m_Width; col++) {
+        uint8_t index = *pSrcPixel++;
+        *pDestPixel++ = index;
+        *pDestPixel++ = index;
+        *pDestPixel++ = index;
+        *pDestPixel++ =
+            IsColorIndexOutOfBounds(index, m_CompData[0]) ? 0xFF : 0;
+      }
     }
-    return m_MaskBuf;
+    return pdfium::make_span(m_MaskBuf).first(4 * m_Width);
   }
   if (m_bColorKey) {
     if (m_nComponents == 3 && m_bpc == 8) {
       uint8_t* alpha_channel = m_MaskBuf.data() + 3;
       for (int col = 0; col < m_Width; col++) {
-        const uint8_t* pPixel = pSrcLine + col * 3;
+        const uint8_t* pPixel = pSrcLine.data() + col * 3;
         alpha_channel[col * 4] =
             AreColorIndicesOutOfBounds(pPixel, m_CompData.data(), 3) ? 0xFF : 0;
       }
@@ -1173,14 +1178,15 @@
     }
   }
   if (m_pColorSpace) {
-    TranslateScanline24bpp(m_LineBuf.data(), pSrcLine);
-    pSrcLine = m_LineBuf.data();
+    TranslateScanline24bpp(m_LineBuf.data(), pSrcLine.data());
     src_pitch_value = 3 * m_Width;
+    pSrcLine = pdfium::make_span(m_LineBuf).first(src_pitch_value);
   }
   if (!m_bColorKey)
-    return {pSrcLine, src_pitch_value};
+    return pSrcLine;
 
-  const uint8_t* pSrcPixel = pSrcLine;
+  // TODO(tsepez): Bounds check if cost is acceptable.
+  const uint8_t* pSrcPixel = pSrcLine.data();
   uint8_t* pDestPixel = m_MaskBuf.data();
   for (int col = 0; col < m_Width; col++) {
     *pDestPixel++ = *pSrcPixel++;
@@ -1188,7 +1194,7 @@
     *pDestPixel++ = *pSrcPixel++;
     pDestPixel++;
   }
-  return m_MaskBuf;
+  return pdfium::make_span(m_MaskBuf).first(4 * m_Width);
 }
 
 bool CPDF_DIB::SkipToScanline(int line, PauseIndicatorIface* pPause) const {