Bound total pixels in JBig2 images to avoid overflows later.

Also make these private to ensure they aren't modified so as to
violate the bounds checks applied at creation time.

BUG=633002

Review-Url: https://codereview.chromium.org/2202013002
diff --git a/BUILD.gn b/BUILD.gn
index 4b6e658..60d656f 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1550,6 +1550,7 @@
     "core/fpdfdoc/cpdf_filespec_unittest.cpp",
     "core/fpdftext/fpdf_text_int_unittest.cpp",
     "core/fxcodec/codec/fx_codec_jpx_unittest.cpp",
+    "core/fxcodec/jbig2/JBig2_Image_unittest.cpp",
     "core/fxcrt/cfx_retain_ptr_unittest.cpp",
     "core/fxcrt/fx_basic_bstring_unittest.cpp",
     "core/fxcrt/fx_basic_gcc_unittest.cpp",
diff --git a/core/fxcodec/jbig2/JBig2_Context.cpp b/core/fxcodec/jbig2/JBig2_Context.cpp
index 256ce39..911eb0b 100644
--- a/core/fxcodec/jbig2/JBig2_Context.cpp
+++ b/core/fxcodec/jbig2/JBig2_Context.cpp
@@ -924,7 +924,7 @@
     if (!m_bBufSpecified) {
       JBig2PageInfo* pPageInfo = m_PageInfoList.back();
       if ((pPageInfo->m_bIsStriped == 1) &&
-          (ri.y + ri.height > m_pPage->m_nHeight)) {
+          (ri.y + ri.height > m_pPage->height())) {
         m_pPage->expand(ri.y + ri.height, (pPageInfo->m_cFlags & 4) ? 1 : 0);
       }
     }
@@ -1015,8 +1015,8 @@
 
   pHRD->HNUMPATS = pPatternDict->NUMPATS;
   pHRD->HPATS = pPatternDict->HDPATS;
-  pHRD->HPW = pPatternDict->HDPATS[0]->m_nWidth;
-  pHRD->HPH = pPatternDict->HDPATS[0]->m_nHeight;
+  pHRD->HPW = pPatternDict->HDPATS[0]->width();
+  pHRD->HPH = pPatternDict->HDPATS[0]->height();
   pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
   if (pHRD->HMMR == 0) {
     const size_t size = GetHuffContextSize(pHRD->HTEMPLATE);
@@ -1042,7 +1042,7 @@
     if (!m_bBufSpecified) {
       JBig2PageInfo* pPageInfo = m_PageInfoList.back();
       if (pPageInfo->m_bIsStriped == 1 &&
-          ri.y + ri.height > m_pPage->m_nHeight) {
+          ri.y + ri.height > m_pPage->height()) {
         m_pPage->expand(ri.y + ri.height, (pPageInfo->m_cFlags & 4) ? 1 : 0);
       }
     }
@@ -1108,7 +1108,7 @@
         if (!m_bBufSpecified) {
           JBig2PageInfo* pPageInfo = m_PageInfoList.back();
           if ((pPageInfo->m_bIsStriped == 1) &&
-              (m_ri.y + m_ri.height > m_pPage->m_nHeight)) {
+              (m_ri.y + m_ri.height > m_pPage->height())) {
             m_pPage->expand(m_ri.y + m_ri.height,
                             (pPageInfo->m_cFlags & 4) ? 1 : 0);
           }
@@ -1142,7 +1142,7 @@
     if (!m_bBufSpecified) {
       JBig2PageInfo* pPageInfo = m_PageInfoList.back();
       if ((pPageInfo->m_bIsStriped == 1) &&
-          (m_ri.y + m_ri.height > m_pPage->m_nHeight)) {
+          (m_ri.y + m_ri.height > m_pPage->height())) {
         m_pPage->expand(m_ri.y + m_ri.height,
                         (pPageInfo->m_cFlags & 4) ? 1 : 0);
       }
@@ -1215,7 +1215,7 @@
     if (!m_bBufSpecified) {
       JBig2PageInfo* pPageInfo = m_PageInfoList.back();
       if ((pPageInfo->m_bIsStriped == 1) &&
-          (ri.y + ri.height > m_pPage->m_nHeight)) {
+          (ri.y + ri.height > m_pPage->height())) {
         m_pPage->expand(ri.y + ri.height, (pPageInfo->m_cFlags & 4) ? 1 : 0);
       }
     }
diff --git a/core/fxcodec/jbig2/JBig2_GrdProc.cpp b/core/fxcodec/jbig2/JBig2_GrdProc.cpp
index 9527c1e..b692909 100644
--- a/core/fxcodec/jbig2/JBig2_GrdProc.cpp
+++ b/core/fxcodec/jbig2/JBig2_GrdProc.cpp
@@ -71,7 +71,7 @@
 
   FX_BOOL LTP = FALSE;
   uint8_t* pLine = GBREG->m_pData;
-  int32_t nStride = GBREG->m_nStride;
+  int32_t nStride = GBREG->stride();
   int32_t nStride2 = nStride << 1;
   int32_t nLineBytes = ((GBW + 7) >> 3) - 1;
   int32_t nBitsLeft = GBW - (nLineBytes << 3);
@@ -197,7 +197,7 @@
 
   FX_BOOL LTP = FALSE;
   uint8_t* pLine = GBREG->m_pData;
-  int32_t nStride = GBREG->m_nStride;
+  int32_t nStride = GBREG->stride();
   int32_t nStride2 = nStride << 1;
   int32_t nLineBytes = ((GBW + 7) >> 3) - 1;
   int32_t nBitsLeft = GBW - (nLineBytes << 3);
@@ -320,7 +320,7 @@
 
   FX_BOOL LTP = FALSE;
   uint8_t* pLine = GBREG->m_pData;
-  int32_t nStride = GBREG->m_nStride;
+  int32_t nStride = GBREG->stride();
   int32_t nStride2 = nStride << 1;
   int32_t nLineBytes = ((GBW + 7) >> 3) - 1;
   int32_t nBitsLeft = GBW - (nLineBytes << 3);
@@ -441,7 +441,7 @@
 
   FX_BOOL LTP = FALSE;
   uint8_t* pLine = GBREG->m_pData;
-  int32_t nStride = GBREG->m_nStride;
+  int32_t nStride = GBREG->stride();
   int32_t nLineBytes = ((GBW + 7) >> 3) - 1;
   int32_t nBitsLeft = GBW - (nLineBytes << 3);
   for (uint32_t h = 0; h < GBH; h++) {
@@ -602,7 +602,7 @@
     }
   }
   m_ReplaceRect.left = 0;
-  m_ReplaceRect.right = pImage->m_nWidth;
+  m_ReplaceRect.right = pImage->width();
   m_ReplaceRect.top = iline;
   m_ReplaceRect.bottom = m_loopIndex;
   if (m_ProssiveStatus == FXCODEC_STATUS_DECODE_FINISH) {
@@ -624,9 +624,9 @@
   }
   bitpos = (int)pStream->getBitPos();
   FaxG4Decode(pStream->getBuf(), pStream->getLength(), &bitpos,
-              (*pImage)->m_pData, GBW, GBH, (*pImage)->m_nStride);
+              (*pImage)->m_pData, GBW, GBH, (*pImage)->stride());
   pStream->setBitPos(bitpos);
-  for (i = 0; (uint32_t)i < (*pImage)->m_nStride * GBH; i++) {
+  for (i = 0; (uint32_t)i < (*pImage)->stride() * GBH; i++) {
     (*pImage)->m_pData[i] = ~(*pImage)->m_pData[i];
   }
   m_ProssiveStatus = FXCODEC_STATUS_DECODE_FINISH;
@@ -653,7 +653,7 @@
   if (!m_pLine) {
     m_pLine = pImage->m_pData;
   }
-  int32_t nStride = pImage->m_nStride;
+  int32_t nStride = pImage->stride();
   int32_t nStride2 = nStride << 1;
   int32_t nLineBytes = ((GBW + 7) >> 3) - 1;
   int32_t nBitsLeft = GBW - (nLineBytes << 3);
@@ -791,7 +791,7 @@
   if (!m_pLine) {
     m_pLine = pImage->m_pData;
   }
-  int32_t nStride = pImage->m_nStride;
+  int32_t nStride = pImage->stride();
   int32_t nStride2 = nStride << 1;
   int32_t nLineBytes = ((GBW + 7) >> 3) - 1;
   int32_t nBitsLeft = GBW - (nLineBytes << 3);
@@ -924,7 +924,7 @@
   if (!m_pLine) {
     m_pLine = pImage->m_pData;
   }
-  int32_t nStride = pImage->m_nStride;
+  int32_t nStride = pImage->stride();
   int32_t nStride2 = nStride << 1;
   int32_t nLineBytes = ((GBW + 7) >> 3) - 1;
   int32_t nBitsLeft = GBW - (nLineBytes << 3);
@@ -1057,7 +1057,7 @@
   if (!m_pLine)
     m_pLine = pImage->m_pData;
 
-  int32_t nStride = pImage->m_nStride;
+  int32_t nStride = pImage->stride();
   int32_t nLineBytes = ((GBW + 7) >> 3) - 1;
   int32_t nBitsLeft = GBW - (nLineBytes << 3);
   for (; m_loopIndex < GBH; m_loopIndex++) {
diff --git a/core/fxcodec/jbig2/JBig2_GrrdProc.cpp b/core/fxcodec/jbig2/JBig2_GrrdProc.cpp
index 25c9ea2..672692d 100644
--- a/core/fxcodec/jbig2/JBig2_GrrdProc.cpp
+++ b/core/fxcodec/jbig2/JBig2_GrrdProc.cpp
@@ -20,13 +20,13 @@
   if (GRTEMPLATE == 0) {
     if ((GRAT[0] == -1) && (GRAT[1] == -1) && (GRAT[2] == -1) &&
         (GRAT[3] == -1) && (GRREFERENCEDX == 0) &&
-        (GRW == (uint32_t)GRREFERENCE->m_nWidth)) {
+        (GRW == (uint32_t)GRREFERENCE->width())) {
       return decode_Template0_opt(pArithDecoder, grContext);
     }
     return decode_Template0_unopt(pArithDecoder, grContext);
   }
 
-  if ((GRREFERENCEDX == 0) && (GRW == (uint32_t)GRREFERENCE->m_nWidth))
+  if ((GRREFERENCEDX == 0) && (GRW == (uint32_t)GRREFERENCE->width()))
     return decode_Template1_opt(pArithDecoder, grContext);
   return decode_Template1_unopt(pArithDecoder, grContext);
 }
@@ -162,10 +162,10 @@
   FX_BOOL LTP = FALSE;
   uint8_t* pLine = GRREG->m_pData;
   uint8_t* pLineR = GRREFERENCE->m_pData;
-  intptr_t nStride = GRREG->m_nStride;
-  intptr_t nStrideR = GRREFERENCE->m_nStride;
-  int32_t GRWR = GRREFERENCE->m_nWidth;
-  int32_t GRHR = GRREFERENCE->m_nHeight;
+  intptr_t nStride = GRREG->stride();
+  intptr_t nStrideR = GRREFERENCE->stride();
+  int32_t GRWR = GRREFERENCE->width();
+  int32_t GRHR = GRREFERENCE->height();
   if (GRREFERENCEDY < -GRHR + 1 || GRREFERENCEDY > GRHR - 1)
     GRREFERENCEDY = 0;
   intptr_t nOffset = -GRREFERENCEDY * nStrideR;
@@ -396,10 +396,10 @@
   FX_BOOL LTP = FALSE;
   uint8_t* pLine = GRREG->m_pData;
   uint8_t* pLineR = GRREFERENCE->m_pData;
-  intptr_t nStride = GRREG->m_nStride;
-  intptr_t nStrideR = GRREFERENCE->m_nStride;
-  int32_t GRWR = GRREFERENCE->m_nWidth;
-  int32_t GRHR = GRREFERENCE->m_nHeight;
+  intptr_t nStride = GRREG->stride();
+  intptr_t nStrideR = GRREFERENCE->stride();
+  int32_t GRWR = GRREFERENCE->width();
+  int32_t GRHR = GRREFERENCE->height();
   if (GRREFERENCEDY < -GRHR + 1 || GRREFERENCEDY > GRHR - 1) {
     GRREFERENCEDY = 0;
   }
diff --git a/core/fxcodec/jbig2/JBig2_Image.cpp b/core/fxcodec/jbig2/JBig2_Image.cpp
index cf0ee3b..b8cb211 100644
--- a/core/fxcodec/jbig2/JBig2_Image.cpp
+++ b/core/fxcodec/jbig2/JBig2_Image.cpp
@@ -10,46 +10,65 @@
 #include "core/fxcrt/include/fx_coordinates.h"
 #include "core/fxcrt/include/fx_safe_types.h"
 
-CJBig2_Image::CJBig2_Image(int32_t w, int32_t h) {
+namespace {
+
+const int kMaxImagePixels = INT_MAX - 31;
+const int kMaxImageBytes = kMaxImagePixels / 8;
+
+}  // namespace
+
+CJBig2_Image::CJBig2_Image(int32_t w, int32_t h)
+    : m_pData(nullptr),
+      m_nWidth(0),
+      m_nHeight(0),
+      m_nStride(0),
+      m_bOwnsBuffer(true) {
+  if (w < 0 || h < 0 || w > kMaxImagePixels)
+    return;
+
+  int32_t stride_pixels = (w + 31) & ~31;
+  if (h > kMaxImagePixels / stride_pixels)
+    return;
+
   m_nWidth = w;
   m_nHeight = h;
-  if (m_nWidth <= 0 || m_nHeight <= 0 || m_nWidth > INT_MAX - 31) {
-    m_pData = nullptr;
-    m_bNeedFree = FALSE;
-    return;
-  }
-  m_nStride = ((w + 31) >> 5) << 2;
-  if (m_nStride * m_nHeight > 0 && 104857600 / (int)m_nStride > m_nHeight) {
-    m_pData = FX_Alloc2D(uint8_t, m_nStride, m_nHeight);
-  } else {
-    m_pData = nullptr;
-  }
-  m_bNeedFree = TRUE;
+  m_nStride = stride_pixels / 8;
+  m_pData = FX_Alloc2D(uint8_t, m_nStride, m_nHeight);
 }
-CJBig2_Image::CJBig2_Image(int32_t w,
-                           int32_t h,
-                           int32_t stride,
-                           uint8_t* pBuf) {
+
+CJBig2_Image::CJBig2_Image(int32_t w, int32_t h, int32_t stride, uint8_t* pBuf)
+    : m_pData(nullptr),
+      m_nWidth(0),
+      m_nHeight(0),
+      m_nStride(0),
+      m_bOwnsBuffer(false) {
+  if (w < 0 || h < 0 || stride < 0 || stride > kMaxImageBytes)
+    return;
+
+  int32_t stride_pixels = 8 * stride;
+  if (stride_pixels < w || h > kMaxImagePixels / stride_pixels)
+    return;
+
   m_nWidth = w;
   m_nHeight = h;
   m_nStride = stride;
   m_pData = pBuf;
-  m_bNeedFree = FALSE;
 }
-CJBig2_Image::CJBig2_Image(const CJBig2_Image& im) {
-  m_nWidth = im.m_nWidth;
-  m_nHeight = im.m_nHeight;
-  m_nStride = im.m_nStride;
-  if (im.m_pData) {
+
+CJBig2_Image::CJBig2_Image(const CJBig2_Image& other)
+    : m_pData(nullptr),
+      m_nWidth(other.m_nWidth),
+      m_nHeight(other.m_nHeight),
+      m_nStride(other.m_nStride),
+      m_bOwnsBuffer(true) {
+  if (other.m_pData) {
     m_pData = FX_Alloc2D(uint8_t, m_nStride, m_nHeight);
-    JBIG2_memcpy(m_pData, im.m_pData, m_nStride * m_nHeight);
-  } else {
-    m_pData = nullptr;
+    JBIG2_memcpy(m_pData, other.m_pData, m_nStride * m_nHeight);
   }
-  m_bNeedFree = TRUE;
 }
+
 CJBig2_Image::~CJBig2_Image() {
-  if (m_bNeedFree) {
+  if (m_bOwnsBuffer) {
     FX_Free(m_pData);
   }
 }
@@ -209,30 +228,24 @@
   }
   return pImage;
 }
-void CJBig2_Image::expand(int32_t h, FX_BOOL v) {
-  if (!m_pData || h <= m_nHeight) {
-    return;
-  }
-  uint32_t dwH = pdfium::base::checked_cast<uint32_t>(h);
-  uint32_t dwStride = pdfium::base::checked_cast<uint32_t>(m_nStride);
-  uint32_t dwHeight = pdfium::base::checked_cast<uint32_t>(m_nHeight);
-  FX_SAFE_UINT32 safeMemSize = dwH;
-  safeMemSize *= dwStride;
-  if (!safeMemSize.IsValid()) {
-    return;
-  }
-  // The guaranteed reallocated memory is to be < 4GB (unsigned int).
-  m_pData = FX_Realloc(uint8_t, m_pData, safeMemSize.ValueOrDie());
 
-  // The result of dwHeight * dwStride doesn't overflow after the
-  // checking of safeMemSize.
-  // The same as the result of (dwH - dwHeight) * dwStride) because
-  // dwH - dwHeight is always less than dwH(h) which is checked in
-  // the calculation of dwH * dwStride.
-  JBIG2_memset(m_pData + dwHeight * dwStride, v ? 0xff : 0,
-               (dwH - dwHeight) * dwStride);
+void CJBig2_Image::expand(int32_t h, FX_BOOL v) {
+  if (!m_pData || h <= m_nHeight || h > kMaxImageBytes / m_nStride)
+    return;
+
+  if (m_bOwnsBuffer) {
+    m_pData = FX_Realloc(uint8_t, m_pData, h * m_nStride);
+  } else {
+    uint8_t* pExternalBuffer = m_pData;
+    m_pData = FX_Alloc(uint8_t, h * m_nStride);
+    JBIG2_memcpy(m_pData, pExternalBuffer, m_nHeight * m_nStride);
+    m_bOwnsBuffer = true;
+  }
+  JBIG2_memset(m_pData + m_nHeight * m_nStride, v ? 0xff : 0,
+               (h - m_nHeight) * m_nStride);
   m_nHeight = h;
 }
+
 FX_BOOL CJBig2_Image::composeTo_opt2(CJBig2_Image* pDst,
                                      int32_t x,
                                      int32_t y,
diff --git a/core/fxcodec/jbig2/JBig2_Image.h b/core/fxcodec/jbig2/JBig2_Image.h
index a18a95d..f27b86e 100644
--- a/core/fxcodec/jbig2/JBig2_Image.h
+++ b/core/fxcodec/jbig2/JBig2_Image.h
@@ -9,6 +9,8 @@
 
 #include "core/fxcodec/jbig2/JBig2_Define.h"
 
+struct FX_RECT;
+
 enum JBig2ComposeOp {
   JBIG2_COMPOSE_OR = 0,
   JBIG2_COMPOSE_AND = 1,
@@ -17,23 +19,21 @@
   JBIG2_COMPOSE_REPLACE = 4
 };
 
-struct FX_RECT;
 class CJBig2_Image {
  public:
   CJBig2_Image(int32_t w, int32_t h);
-
   CJBig2_Image(int32_t w, int32_t h, int32_t stride, uint8_t* pBuf);
-
   CJBig2_Image(const CJBig2_Image& im);
-
   ~CJBig2_Image();
 
-  FX_BOOL getPixel(int32_t x, int32_t y);
+  int32_t width() const { return m_nWidth; }
+  int32_t height() const { return m_nHeight; }
+  int32_t stride() const { return m_nStride; }
 
+  FX_BOOL getPixel(int32_t x, int32_t y);
   int32_t setPixel(int32_t x, int32_t y, FX_BOOL v);
 
   void copyLine(int32_t hTo, int32_t hFrom);
-
   void fill(FX_BOOL v);
 
   FX_BOOL composeTo(CJBig2_Image* pDst,
@@ -67,19 +67,15 @@
                       const FX_RECT* pSrcRect);
 
   CJBig2_Image* subImage(int32_t x, int32_t y, int32_t w, int32_t h);
-
   void expand(int32_t h, FX_BOOL v);
 
- public:
-  int32_t m_nWidth;
-
-  int32_t m_nHeight;
-
-  int32_t m_nStride;
-
   uint8_t* m_pData;
 
-  FX_BOOL m_bNeedFree;
+ private:
+  int32_t m_nWidth;   // 1-bit pixels
+  int32_t m_nHeight;  // lines
+  int32_t m_nStride;  // bytes
+  bool m_bOwnsBuffer;
 };
 
 #endif  // CORE_FXCODEC_JBIG2_JBIG2_IMAGE_H_
diff --git a/core/fxcodec/jbig2/JBig2_Image_unittest.cpp b/core/fxcodec/jbig2/JBig2_Image_unittest.cpp
new file mode 100644
index 0000000..788f922
--- /dev/null
+++ b/core/fxcodec/jbig2/JBig2_Image_unittest.cpp
@@ -0,0 +1,105 @@
+// Copyright 2016 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// TODO(tsepez) this requires a lot more testing.
+
+#include <stdint.h>
+
+#include "core/fxcodec/jbig2/JBig2_Image.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const int32_t kWidthPixels = 80;
+const int32_t kWidthBytes = 10;
+const int32_t kStrideBytes = kWidthBytes + 1;  // For testing stride != width.
+const int32_t kHeightLines = 20;
+const int32_t kLargerHeightLines = 100;
+const int32_t kTooLargeHeightLines = 40000000;
+
+}  // namespace
+
+TEST(fxcodec, JBig2ImageCreate) {
+  CJBig2_Image img(kWidthPixels, kHeightLines);
+  img.setPixel(0, 0, true);
+  img.setPixel(kWidthPixels - 1, kHeightLines - 1, false);
+  EXPECT_EQ(kWidthPixels, img.width());
+  EXPECT_EQ(kHeightLines, img.height());
+  EXPECT_TRUE(img.getPixel(0, 0));
+  EXPECT_FALSE(img.getPixel(kWidthPixels - 1, kHeightLines - 1));
+}
+
+TEST(fxcodec, JBig2ImageCreateTooBig) {
+  CJBig2_Image img(kWidthPixels, kTooLargeHeightLines);
+  EXPECT_EQ(0, img.width());
+  EXPECT_EQ(0, img.height());
+  EXPECT_EQ(nullptr, img.m_pData);
+}
+
+TEST(fxcodec, JBig2ImageCreateExternal) {
+  uint8_t buf[kHeightLines * kStrideBytes];
+  CJBig2_Image img(kWidthPixels, kHeightLines, kStrideBytes, buf);
+  img.setPixel(0, 0, true);
+  img.setPixel(kWidthPixels - 1, kHeightLines - 1, false);
+  EXPECT_EQ(kWidthPixels, img.width());
+  EXPECT_EQ(kHeightLines, img.height());
+  EXPECT_TRUE(img.getPixel(0, 0));
+  EXPECT_FALSE(img.getPixel(kWidthPixels - 1, kHeightLines - 1));
+}
+
+TEST(fxcodec, JBig2ImageCreateExternalTooBig) {
+  uint8_t buf[kHeightLines * kStrideBytes];
+  CJBig2_Image img(kWidthPixels, kTooLargeHeightLines, kStrideBytes, buf);
+  EXPECT_EQ(0, img.width());
+  EXPECT_EQ(0, img.height());
+  EXPECT_EQ(nullptr, img.m_pData);
+}
+
+TEST(fxcodec, JBig2ImageExpand) {
+  CJBig2_Image img(kWidthPixels, kHeightLines);
+  img.setPixel(0, 0, true);
+  img.setPixel(kWidthPixels - 1, kHeightLines - 1, false);
+  img.expand(kLargerHeightLines, true);
+  EXPECT_EQ(kWidthPixels, img.width());
+  EXPECT_EQ(kLargerHeightLines, img.height());
+  EXPECT_TRUE(img.getPixel(0, 0));
+  EXPECT_FALSE(img.getPixel(kWidthPixels - 1, kHeightLines - 1));
+  EXPECT_TRUE(img.getPixel(kWidthPixels - 1, kLargerHeightLines - 1));
+}
+
+TEST(fxcodec, JBig2ImageExpandTooBig) {
+  CJBig2_Image img(kWidthPixels, kHeightLines);
+  img.setPixel(0, 0, true);
+  img.setPixel(kWidthPixels - 1, kHeightLines - 1, false);
+  img.expand(kTooLargeHeightLines, true);
+  EXPECT_EQ(kWidthPixels, img.width());
+  EXPECT_EQ(kHeightLines, img.height());
+  EXPECT_TRUE(img.getPixel(0, 0));
+  EXPECT_FALSE(img.getPixel(kWidthPixels - 1, kHeightLines - 1));
+}
+
+TEST(fxcodec, JBig2ImageExpandExternal) {
+  uint8_t buf[kHeightLines * kStrideBytes];
+  CJBig2_Image img(kWidthPixels, kHeightLines, kStrideBytes, buf);
+  img.setPixel(0, 0, true);
+  img.setPixel(kWidthPixels - 1, kHeightLines - 1, false);
+  img.expand(kLargerHeightLines, true);
+  EXPECT_EQ(kWidthPixels, img.width());
+  EXPECT_EQ(kLargerHeightLines, img.height());
+  EXPECT_TRUE(img.getPixel(0, 0));
+  EXPECT_FALSE(img.getPixel(kWidthPixels - 1, kHeightLines - 1));
+  EXPECT_TRUE(img.getPixel(kWidthPixels - 1, kLargerHeightLines - 1));
+}
+
+TEST(fxcodec, JBig2ImageExpandExternalTooBig) {
+  uint8_t buf[kHeightLines * kStrideBytes];
+  CJBig2_Image img(kWidthPixels, kHeightLines, kStrideBytes, buf);
+  img.setPixel(0, 0, true);
+  img.setPixel(kWidthPixels - 1, kHeightLines - 1, false);
+  img.expand(kTooLargeHeightLines, true);
+  EXPECT_EQ(kWidthPixels, img.width());
+  EXPECT_EQ(kHeightLines, img.height());
+  EXPECT_TRUE(img.getPixel(0, 0));
+  EXPECT_FALSE(img.getPixel(kWidthPixels - 1, kHeightLines - 1));
+}
diff --git a/core/fxcodec/jbig2/JBig2_SddProc.cpp b/core/fxcodec/jbig2/JBig2_SddProc.cpp
index 9ab6cb8..c6adfce 100644
--- a/core/fxcodec/jbig2/JBig2_SddProc.cpp
+++ b/core/fxcodec/jbig2/JBig2_SddProc.cpp
@@ -523,7 +523,7 @@
         if (pStream->getByteLeft() >= stride * HCHEIGHT) {
           BHC = new CJBig2_Image(TOTWIDTH, HCHEIGHT);
           for (I = 0; I < HCHEIGHT; I++) {
-            JBIG2_memcpy(BHC->m_pData + I * BHC->m_nStride,
+            JBIG2_memcpy(BHC->m_pData + I * BHC->stride(),
                          pStream->getPointer(), stride);
             pStream->offset(stride);
           }
diff --git a/core/fxcodec/jbig2/JBig2_TrdProc.cpp b/core/fxcodec/jbig2/JBig2_TrdProc.cpp
index 177db9d..f3dd6be 100644
--- a/core/fxcodec/jbig2/JBig2_TrdProc.cpp
+++ b/core/fxcodec/jbig2/JBig2_TrdProc.cpp
@@ -114,8 +114,8 @@
         if (!IBOI)
           return nullptr;
 
-        uint32_t WOI = IBOI->m_nWidth;
-        uint32_t HOI = IBOI->m_nHeight;
+        uint32_t WOI = IBOI->width();
+        uint32_t HOI = IBOI->height();
         if ((int)(WOI + RDWI) < 0 || (int)(HOI + RDHI) < 0)
           return nullptr;
 
@@ -150,8 +150,8 @@
       if (!IBI) {
         continue;
       }
-      uint32_t WI = IBI->m_nWidth;
-      uint32_t HI = IBI->m_nHeight;
+      uint32_t WI = IBI->width();
+      uint32_t HI = IBI->height();
       if (TRANSPOSED == 0 && ((REFCORNER == JBIG2_CORNER_TOPRIGHT) ||
                               (REFCORNER == JBIG2_CORNER_BOTTOMRIGHT))) {
         CURS = CURS + WI - 1;
@@ -327,8 +327,8 @@
         if (!IBOI)
           return nullptr;
 
-        uint32_t WOI = IBOI->m_nWidth;
-        uint32_t HOI = IBOI->m_nHeight;
+        uint32_t WOI = IBOI->width();
+        uint32_t HOI = IBOI->height();
         if ((int)(WOI + RDWI) < 0 || (int)(HOI + RDHI) < 0)
           return nullptr;
 
@@ -350,8 +350,8 @@
       if (!pIBI)
         return nullptr;
 
-      uint32_t WI = pIBI->m_nWidth;
-      uint32_t HI = pIBI->m_nHeight;
+      uint32_t WI = pIBI->width();
+      uint32_t HI = pIBI->height();
       if (TRANSPOSED == 0 && ((REFCORNER == JBIG2_CORNER_TOPRIGHT) ||
                               (REFCORNER == JBIG2_CORNER_BOTTOMRIGHT))) {
         CURS += WI - 1;