Small optimization in CJBig2_Image::SubImage()

We can use the memcpy() path whenever byte aligned.
Split code into helper methods.
Add test for fast path specifically.

Change-Id: I52f6129b0e788eb2da60536cfa6fce12a0609375
Reviewed-on: https://pdfium-review.googlesource.com/39432
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcodec/jbig2/JBig2_Image.cpp b/core/fxcodec/jbig2/JBig2_Image.cpp
index b64a4fd..f37a368 100644
--- a/core/fxcodec/jbig2/JBig2_Image.cpp
+++ b/core/fxcodec/jbig2/JBig2_Image.cpp
@@ -196,22 +196,36 @@
   if (x < 0 || x >= m_nWidth || y < 0 || y >= m_nHeight)
     return pImage;
 
+  // Fast case when byte-aligned, normal slow case otherwise.
+  if ((x & 7) == 0)
+    SubImageFast(x, y, w, h, pImage.get());
+  else
+    SubImageSlow(x, y, w, h, pImage.get());
+
+  return pImage;
+}
+
+void CJBig2_Image::SubImageFast(int32_t x,
+                                int32_t y,
+                                int32_t w,
+                                int32_t h,
+                                CJBig2_Image* pImage) {
+  int32_t m = BIT_INDEX_TO_BYTE(x);
+  int32_t bytes_to_copy = std::min(pImage->m_nStride, m_nStride - m);
+  int32_t lines_to_copy = std::min(pImage->m_nHeight, m_nHeight - y);
+  for (int32_t j = 0; j < lines_to_copy; j++)
+    memcpy(pImage->GetLineUnsafe(j), GetLineUnsafe(y + j) + m, bytes_to_copy);
+}
+
+void CJBig2_Image::SubImageSlow(int32_t x,
+                                int32_t y,
+                                int32_t w,
+                                int32_t h,
+                                CJBig2_Image* pImage) {
   int32_t m = BIT_INDEX_TO_ALIGNED_BYTE(x);
   int32_t n = x & 31;
   int32_t bytes_to_copy = std::min(pImage->m_nStride, m_nStride - m);
   int32_t lines_to_copy = std::min(pImage->m_nHeight, m_nHeight - y);
-
-  // Fast case when DWORD-aligned.
-  if (n == 0) {
-    for (int32_t j = 0; j < lines_to_copy; j++) {
-      const uint8_t* pLineSrc = GetLineUnsafe(y + j);
-      uint8_t* pLineDst = pImage->GetLineUnsafe(j);
-      memcpy(pLineDst, pLineSrc + m, bytes_to_copy);
-    }
-    return pImage;
-  }
-
-  // Normal slow case.
   for (int32_t j = 0; j < lines_to_copy; j++) {
     const uint8_t* pLineSrc = GetLineUnsafe(y + j);
     uint8_t* pLineDst = pImage->GetLineUnsafe(j);
@@ -225,7 +239,6 @@
       JBIG2_PUTDWORD(pDst, wTmp);
     }
   }
-  return pImage;
 }
 
 void CJBig2_Image::Expand(int32_t h, bool v) {
diff --git a/core/fxcodec/jbig2/JBig2_Image.h b/core/fxcodec/jbig2/JBig2_Image.h
index b61ce84..d593054 100644
--- a/core/fxcodec/jbig2/JBig2_Image.h
+++ b/core/fxcodec/jbig2/JBig2_Image.h
@@ -69,6 +69,17 @@
                          JBig2ComposeOp op);
 
  private:
+  void SubImageFast(int32_t x,
+                    int32_t y,
+                    int32_t w,
+                    int32_t h,
+                    CJBig2_Image* pImage);
+  void SubImageSlow(int32_t x,
+                    int32_t y,
+                    int32_t w,
+                    int32_t h,
+                    CJBig2_Image* pImage);
+
   bool ComposeToOpt2(CJBig2_Image* pDst,
                      int32_t x,
                      int32_t y,
diff --git a/core/fxcodec/jbig2/JBig2_Image_unittest.cpp b/core/fxcodec/jbig2/JBig2_Image_unittest.cpp
index 4b07832..13e6eb5 100644
--- a/core/fxcodec/jbig2/JBig2_Image_unittest.cpp
+++ b/core/fxcodec/jbig2/JBig2_Image_unittest.cpp
@@ -219,6 +219,15 @@
       {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
   };
 
+  // 1-px wide rectangle in image, offset 16 in x, 1 in y, padded.
+  uint8_t pattern161[5][8] = {
+      {0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+      {0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+      {0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+      {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+      {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+  };
+
   // Image size a nice clean power of two.
   auto img32 = pdfium::MakeUnique<CJBig2_Image>(
       32, 5, 8, reinterpret_cast<uint8_t*>(pattern));
@@ -234,6 +243,9 @@
   auto expected22 = pdfium::MakeUnique<CJBig2_Image>(
       30, 5, 8, reinterpret_cast<uint8_t*>(pattern22));
 
+  auto expected161 = pdfium::MakeUnique<CJBig2_Image>(
+      25, 5, 8, reinterpret_cast<uint8_t*>(pattern161));
+
   auto expected_zeros = pdfium::MakeUnique<CJBig2_Image>(32, 5);
 
   // Empty subimage.
@@ -259,6 +271,10 @@
   sub = img37->SubImage(2, 2, 30, 5);
   CheckImageEq(expected22.get(), sub.get(), __LINE__);
 
+  // Fast path.
+  sub = img37->SubImage(16, 1, 25, 5);
+  CheckImageEq(expected161.get(), sub.get(), __LINE__);
+
   // Aligned Sub-image including cruft in stride beyond width.
   sub = img37->SubImage(32, 0, 32, 5);
   CheckImageEq(expected_zeros.get(), sub.get(), __LINE__);