Clean up CFX_ImageStretcher.

Review-Url: https://codereview.chromium.org/1968273002
diff --git a/core/fxge/agg/fx_agg_driver.cpp b/core/fxge/agg/fx_agg_driver.cpp
index 3641855..ff254f0 100644
--- a/core/fxge/agg/fx_agg_driver.cpp
+++ b/core/fxge/agg/fx_agg_driver.cpp
@@ -1754,11 +1754,10 @@
                    FALSE, m_bRgbByteOrder, alpha_flag, pIccTransform,
                    blend_type);
   dest_clip.Offset(-dest_rect.left, -dest_rect.top);
-  CFX_ImageStretcher stretcher;
-  if (stretcher.Start(&composer, pSource, dest_width, dest_height, dest_clip,
-                      flags)) {
-    stretcher.Continue(NULL);
-  }
+  CFX_ImageStretcher stretcher(&composer, pSource, dest_width, dest_height,
+                               dest_clip, flags);
+  if (stretcher.Start())
+    stretcher.Continue(nullptr);
   return TRUE;
 }
 
diff --git a/core/fxge/dib/fx_dib_engine.cpp b/core/fxge/dib/fx_dib_engine.cpp
index 4604f1f..3bdff23 100644
--- a/core/fxge/dib/fx_dib_engine.cpp
+++ b/core/fxge/dib/fx_dib_engine.cpp
@@ -6,12 +6,19 @@
 
 #include <limits.h>
 
+#include <algorithm>
+
 #include "core/fxge/dib/dib_int.h"
 #include "core/fxge/include/fx_dib.h"
 #include "core/fxge/include/fx_ge.h"
 
 namespace {
 
+bool SourceSizeWithinLimit(int width, int height) {
+  const int kMaxProgressiveStretchPixels = 1000000;
+  return !height || width < kMaxProgressiveStretchPixels / height;
+}
+
 FXDIB_Format GetStretchedFormat(const CFX_DIBSource& src) {
   FXDIB_Format format = src.GetFormat();
   if (format == FXDIB_1bppMask)
@@ -770,40 +777,36 @@
   }
 }
 
-CFX_ImageStretcher::CFX_ImageStretcher()
-    : m_pStretchEngine(nullptr),
-      m_pScanline(nullptr),
-      m_pMaskScanline(nullptr) {}
+CFX_ImageStretcher::CFX_ImageStretcher(IFX_ScanlineComposer* pDest,
+                                       const CFX_DIBSource* pSource,
+                                       int dest_width,
+                                       int dest_height,
+                                       const FX_RECT& bitmap_rect,
+                                       uint32_t flags)
+    : m_pDest(pDest),
+      m_pSource(pSource),
+      m_Flags(flags),
+      m_bFlipX(FALSE),
+      m_bFlipY(FALSE),
+      m_DestWidth(dest_width),
+      m_DestHeight(dest_height),
+      m_ClipRect(bitmap_rect),
+      m_DestFormat(GetStretchedFormat(*pSource)),
+      m_DestBPP(m_DestFormat & 0xff),
+      m_LineIndex(0) {}
 
 CFX_ImageStretcher::~CFX_ImageStretcher() {
-  FX_Free(m_pScanline);
-  delete m_pStretchEngine;
-  FX_Free(m_pMaskScanline);
 }
 
-FX_BOOL CFX_ImageStretcher::Start(IFX_ScanlineComposer* pDest,
-                                  const CFX_DIBSource* pSource,
-                                  int dest_width,
-                                  int dest_height,
-                                  const FX_RECT& rect,
-                                  uint32_t flags) {
-  if (dest_width == 0 || dest_height == 0)
+FX_BOOL CFX_ImageStretcher::Start() {
+  if (m_DestWidth == 0 || m_DestHeight == 0)
     return FALSE;
 
-  m_DestFormat = GetStretchedFormat(*pSource);
-  m_DestBPP = m_DestFormat & 0xff;
-  m_pDest = pDest;
-  m_pSource = pSource;
-  m_DestWidth = dest_width;
-  m_DestHeight = dest_height;
-  m_ClipRect = rect;
-  m_Flags = flags;
-
-  if (pSource->GetFormat() == FXDIB_1bppRgb && pSource->GetPalette()) {
+  if (m_pSource->GetFormat() == FXDIB_1bppRgb && m_pSource->GetPalette()) {
     FX_ARGB pal[256];
     int a0, r0, g0, b0, a1, r1, g1, b1;
-    ArgbDecode(pSource->GetPaletteEntry(0), a0, r0, g0, b0);
-    ArgbDecode(pSource->GetPaletteEntry(1), a1, r1, g1, b1);
+    ArgbDecode(m_pSource->GetPaletteEntry(0), a0, r0, g0, b0);
+    ArgbDecode(m_pSource->GetPaletteEntry(1), a1, r1, g1, b1);
     for (int i = 0; i < 256; i++) {
       int a = a0 + (a1 - a0) * i / 255;
       int r = r0 + (r1 - r0) * i / 255;
@@ -811,14 +814,16 @@
       int b = b0 + (b1 - b0) * i / 255;
       pal[i] = ArgbEncode(a, r, g, b);
     }
-    if (!pDest->SetInfo(rect.Width(), rect.Height(), m_DestFormat, pal)) {
+    if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(), m_DestFormat,
+                          pal)) {
       return FALSE;
     }
-  } else if (pSource->GetFormat() == FXDIB_1bppCmyk && pSource->GetPalette()) {
+  } else if (m_pSource->GetFormat() == FXDIB_1bppCmyk &&
+             m_pSource->GetPalette()) {
     FX_CMYK pal[256];
     int c0, m0, y0, k0, c1, m1, y1, k1;
-    CmykDecode(pSource->GetPaletteEntry(0), c0, m0, y0, k0);
-    CmykDecode(pSource->GetPaletteEntry(1), c1, m1, y1, k1);
+    CmykDecode(m_pSource->GetPaletteEntry(0), c0, m0, y0, k0);
+    CmykDecode(m_pSource->GetPaletteEntry(1), c1, m1, y1, k1);
     for (int i = 0; i < 256; i++) {
       int c = c0 + (c1 - c0) * i / 255;
       int m = m0 + (m1 - m0) * i / 255;
@@ -826,14 +831,16 @@
       int k = k0 + (k1 - k0) * i / 255;
       pal[i] = CmykEncode(c, m, y, k);
     }
-    if (!pDest->SetInfo(rect.Width(), rect.Height(), m_DestFormat, pal)) {
+    if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(), m_DestFormat,
+                          pal)) {
       return FALSE;
     }
-  } else if (!pDest->SetInfo(rect.Width(), rect.Height(), m_DestFormat, NULL)) {
+  } else if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(),
+                               m_DestFormat, nullptr)) {
     return FALSE;
   }
 
-  if (flags & FXDIB_DOWNSAMPLE)
+  if (m_Flags & FXDIB_DOWNSAMPLE)
     return StartQuickStretch();
   return StartStretch();
 }
@@ -844,25 +851,23 @@
   return ContinueStretch(pPause);
 }
 
-#define MAX_PROGRESSIVE_STRETCH_PIXELS 1000000
 FX_BOOL CFX_ImageStretcher::StartStretch() {
-  m_pStretchEngine =
-      new CStretchEngine(m_pDest, m_DestFormat, m_DestWidth, m_DestHeight,
-                         m_ClipRect, m_pSource, m_Flags);
+  m_pStretchEngine.reset(new CStretchEngine(m_pDest, m_DestFormat, m_DestWidth,
+                                            m_DestHeight, m_ClipRect, m_pSource,
+                                            m_Flags));
   m_pStretchEngine->StartStretchHorz();
-  if (m_pSource->GetWidth() * m_pSource->GetHeight() <
-      MAX_PROGRESSIVE_STRETCH_PIXELS) {
-    m_pStretchEngine->Continue(NULL);
+  if (SourceSizeWithinLimit(m_pSource->GetWidth(), m_pSource->GetHeight())) {
+    m_pStretchEngine->Continue(nullptr);
     return FALSE;
   }
   return TRUE;
 }
+
 FX_BOOL CFX_ImageStretcher::ContinueStretch(IFX_Pause* pPause) {
   return m_pStretchEngine && m_pStretchEngine->Continue(pPause);
 }
+
 FX_BOOL CFX_ImageStretcher::StartQuickStretch() {
-  m_bFlipX = FALSE;
-  m_bFlipY = FALSE;
   if (m_DestWidth < 0) {
     m_bFlipX = TRUE;
     m_DestWidth = -m_DestWidth;
@@ -871,31 +876,32 @@
     m_bFlipY = TRUE;
     m_DestHeight = -m_DestHeight;
   }
-  m_LineIndex = 0;
   uint32_t size = m_ClipRect.Width();
   if (size && m_DestBPP > (int)(INT_MAX / size)) {
     return FALSE;
   }
   size *= m_DestBPP;
-  m_pScanline = FX_Alloc(uint8_t, (size / 8 + 3) / 4 * 4);
-  if (m_pSource->m_pAlphaMask) {
-    m_pMaskScanline = FX_Alloc(uint8_t, (m_ClipRect.Width() + 3) / 4 * 4);
-  }
-  if (m_pSource->GetWidth() * m_pSource->GetHeight() <
-      MAX_PROGRESSIVE_STRETCH_PIXELS) {
-    ContinueQuickStretch(NULL);
+  m_pScanline.reset(FX_Alloc(uint8_t, (size / 8 + 3) / 4 * 4));
+  if (m_pSource->m_pAlphaMask)
+    m_pMaskScanline.reset(FX_Alloc(uint8_t, (m_ClipRect.Width() + 3) / 4 * 4));
+
+  if (SourceSizeWithinLimit(m_pSource->GetWidth(), m_pSource->GetHeight())) {
+    ContinueQuickStretch(nullptr);
     return FALSE;
   }
   return TRUE;
 }
+
 FX_BOOL CFX_ImageStretcher::ContinueQuickStretch(IFX_Pause* pPause) {
-  if (!m_pScanline) {
+  if (!m_pScanline)
     return FALSE;
-  }
-  int result_width = m_ClipRect.Width(), result_height = m_ClipRect.Height();
+
+  int result_width = m_ClipRect.Width();
+  int result_height = m_ClipRect.Height();
   int src_height = m_pSource->GetHeight();
   for (; m_LineIndex < result_height; m_LineIndex++) {
-    int dest_y, src_y;
+    int dest_y;
+    int src_y;
     if (m_bFlipY) {
       dest_y = result_height - m_LineIndex - 1;
       src_y = (m_DestHeight - (dest_y + m_ClipRect.top) - 1) * src_height /
@@ -904,23 +910,20 @@
       dest_y = m_LineIndex;
       src_y = (dest_y + m_ClipRect.top) * src_height / m_DestHeight;
     }
-    if (src_y >= src_height) {
-      src_y = src_height - 1;
-    }
-    if (src_y < 0) {
-      src_y = 0;
-    }
-    if (m_pSource->SkipToScanline(src_y, pPause)) {
+    src_y = std::max(std::min(src_y, src_height - 1), 0);
+
+    if (m_pSource->SkipToScanline(src_y, pPause))
       return TRUE;
-    }
-    m_pSource->DownSampleScanline(src_y, m_pScanline, m_DestBPP, m_DestWidth,
-                                  m_bFlipX, m_ClipRect.left, result_width);
+
+    m_pSource->DownSampleScanline(src_y, m_pScanline.get(), m_DestBPP,
+                                  m_DestWidth, m_bFlipX, m_ClipRect.left,
+                                  result_width);
     if (m_pMaskScanline) {
       m_pSource->m_pAlphaMask->DownSampleScanline(
-          src_y, m_pMaskScanline, 1, m_DestWidth, m_bFlipX, m_ClipRect.left,
-          result_width);
+          src_y, m_pMaskScanline.get(), 1, m_DestWidth, m_bFlipX,
+          m_ClipRect.left, result_width);
     }
-    m_pDest->ComposeScanline(dest_y, m_pScanline, m_pMaskScanline);
+    m_pDest->ComposeScanline(dest_y, m_pScanline.get(), m_pMaskScanline.get());
   }
   return FALSE;
 }
diff --git a/core/fxge/dib/fx_dib_main.cpp b/core/fxge/dib/fx_dib_main.cpp
index f781392..bf8dd4e 100644
--- a/core/fxge/dib/fx_dib_main.cpp
+++ b/core/fxge/dib/fx_dib_main.cpp
@@ -1608,9 +1608,9 @@
   m_ClipBox = pClipRgn ? pClipRgn->GetBox() : FX_RECT(0, 0, pDevice->GetWidth(),
                                                       pDevice->GetHeight());
   m_ClipBox.Intersect(image_rect);
-  if (m_ClipBox.IsEmpty()) {
+  if (m_ClipBox.IsEmpty())
     return FALSE;
-  }
+
   m_pDevice = pDevice;
   m_pClipRgn = pClipRgn;
   m_MaskColor = mask_color;
@@ -1621,7 +1621,7 @@
   m_pIccTransform = pIccTransform;
   m_bRgbByteOrder = bRgbByteOrder;
   m_BlendType = blend_type;
-  FX_BOOL ret = TRUE;
+
   if ((FXSYS_fabs(m_Matrix.b) >= 0.5f || m_Matrix.a == 0) ||
       (FXSYS_fabs(m_Matrix.c) >= 0.5f || m_Matrix.d == 0)) {
     if (FXSYS_fabs(m_Matrix.a) < FXSYS_fabs(m_Matrix.b) / 20 &&
@@ -1636,10 +1636,12 @@
       m_Composer.Compose(pDevice, pClipRgn, bitmap_alpha, mask_color, m_ClipBox,
                          TRUE, m_Matrix.c > 0, m_Matrix.b < 0, m_bRgbByteOrder,
                          alpha_flag, pIccTransform, m_BlendType);
-      if (!m_Stretcher.Start(&m_Composer, pSource, dest_height, dest_width,
-                             bitmap_clip, dib_flags)) {
+      m_Stretcher.reset(new CFX_ImageStretcher(&m_Composer, pSource,
+                                               dest_height, dest_width,
+                                               bitmap_clip, dib_flags));
+      if (!m_Stretcher->Start())
         return FALSE;
-      }
+
       m_Status = 1;
       return TRUE;
     }
@@ -1648,31 +1650,33 @@
     m_pTransformer->Start(pSource, &m_Matrix, dib_flags, &m_ClipBox);
     return TRUE;
   }
+
   int dest_width = image_rect.Width();
-  if (m_Matrix.a < 0) {
+  if (m_Matrix.a < 0)
     dest_width = -dest_width;
-  }
+
   int dest_height = image_rect.Height();
-  if (m_Matrix.d > 0) {
+  if (m_Matrix.d > 0)
     dest_height = -dest_height;
-  }
-  if (dest_width == 0 || dest_height == 0) {
+
+  if (dest_width == 0 || dest_height == 0)
     return FALSE;
-  }
+
   FX_RECT bitmap_clip = m_ClipBox;
   bitmap_clip.Offset(-image_rect.left, -image_rect.top);
   m_Composer.Compose(pDevice, pClipRgn, bitmap_alpha, mask_color, m_ClipBox,
                      FALSE, FALSE, FALSE, m_bRgbByteOrder, alpha_flag,
                      pIccTransform, m_BlendType);
   m_Status = 1;
-  ret = m_Stretcher.Start(&m_Composer, pSource, dest_width, dest_height,
-                          bitmap_clip, dib_flags);
-  return ret;
+  m_Stretcher.reset(new CFX_ImageStretcher(
+      &m_Composer, pSource, dest_width, dest_height, bitmap_clip, dib_flags));
+  return m_Stretcher->Start();
 }
+
 FX_BOOL CFX_ImageRenderer::Continue(IFX_Pause* pPause) {
-  if (m_Status == 1) {
-    return m_Stretcher.Continue(pPause);
-  }
+  if (m_Status == 1)
+    return m_Stretcher->Continue(pPause);
+
   if (m_Status == 2) {
     if (m_pTransformer->Continue(pPause)) {
       return TRUE;
diff --git a/core/fxge/dib/fx_dib_transform.cpp b/core/fxge/dib/fx_dib_transform.cpp
index 18adcea..6aaaac2 100644
--- a/core/fxge/dib/fx_dib_transform.cpp
+++ b/core/fxge/dib/fx_dib_transform.cpp
@@ -309,33 +309,36 @@
   CFX_DIBitmap* pTransformed = transformer.m_Storer.Detach();
   return pTransformed;
 }
+
 CFX_DIBitmap* CFX_DIBSource::StretchTo(int dest_width,
                                        int dest_height,
                                        uint32_t flags,
                                        const FX_RECT* pClip) const {
   FX_RECT clip_rect(0, 0, FXSYS_abs(dest_width), FXSYS_abs(dest_height));
-  if (pClip) {
+  if (pClip)
     clip_rect.Intersect(*pClip);
-  }
-  if (clip_rect.IsEmpty()) {
-    return NULL;
-  }
-  if (dest_width == m_Width && dest_height == m_Height) {
+
+  if (clip_rect.IsEmpty())
+    return nullptr;
+
+  if (dest_width == m_Width && dest_height == m_Height)
     return Clone(&clip_rect);
-  }
-  CFX_ImageStretcher stretcher;
+
   CFX_BitmapStorer storer;
-  if (stretcher.Start(&storer, this, dest_width, dest_height, clip_rect,
-                      flags)) {
-    stretcher.Continue(NULL);
-  }
+  CFX_ImageStretcher stretcher(&storer, this, dest_width, dest_height,
+                               clip_rect, flags);
+  if (stretcher.Start())
+    stretcher.Continue(nullptr);
   return storer.Detach();
 }
+
 CFX_ImageTransformer::CFX_ImageTransformer() {
   m_Status = 0;
   m_pMatrix = NULL;
 }
+
 CFX_ImageTransformer::~CFX_ImageTransformer() {}
+
 FX_BOOL CFX_ImageTransformer::Start(const CFX_DIBSource* pSrc,
                                     const CFX_Matrix* pDestMatrix,
                                     int flags,
@@ -344,12 +347,12 @@
   CFX_FloatRect unit_rect = pDestMatrix->GetUnitRect();
   FX_RECT result_rect = unit_rect.GetClosestRect();
   FX_RECT result_clip = result_rect;
-  if (pDestClip) {
+  if (pDestClip)
     result_clip.Intersect(*pDestClip);
-  }
-  if (result_clip.IsEmpty()) {
+
+  if (result_clip.IsEmpty())
     return FALSE;
-  }
+
   m_ResultLeft = result_clip.left;
   m_ResultTop = result_clip.top;
   m_ResultWidth = result_clip.Width();
@@ -363,8 +366,9 @@
     result_clip.Offset(-result_rect.left, -result_rect.top);
     result_clip = FXDIB_SwapClipBox(result_clip, dest_width, dest_height,
                                     pDestMatrix->c > 0, pDestMatrix->b < 0);
-    m_Stretcher.Start(&m_Storer, pSrc, dest_height, dest_width, result_clip,
-                      flags);
+    m_Stretcher.reset(new CFX_ImageStretcher(&m_Storer, pSrc, dest_height,
+                                             dest_width, result_clip, flags));
+    m_Stretcher->Start();
     m_Status = 1;
     return TRUE;
   }
@@ -375,8 +379,9 @@
     int dest_height = pDestMatrix->d > 0 ? (int)-FXSYS_ceil(pDestMatrix->d)
                                          : (int)-FXSYS_floor(pDestMatrix->d);
     result_clip.Offset(-result_rect.left, -result_rect.top);
-    m_Stretcher.Start(&m_Storer, pSrc, dest_width, dest_height, result_clip,
-                      flags);
+    m_Stretcher.reset(new CFX_ImageStretcher(&m_Storer, pSrc, dest_width,
+                                             dest_height, result_clip, flags));
+    m_Stretcher->Start();
     m_Status = 2;
     return TRUE;
   }
@@ -395,53 +400,54 @@
   clip_rect_f.Transform(&m_dest2stretch);
   m_StretchClip = clip_rect_f.GetOutterRect();
   m_StretchClip.Intersect(0, 0, stretch_width, stretch_height);
-  m_Stretcher.Start(&m_Storer, pSrc, stretch_width, stretch_height,
-                    m_StretchClip, flags);
+  m_Stretcher.reset(new CFX_ImageStretcher(
+      &m_Storer, pSrc, stretch_width, stretch_height, m_StretchClip, flags));
+  m_Stretcher->Start();
   m_Status = 3;
   return TRUE;
 }
 
 FX_BOOL CFX_ImageTransformer::Continue(IFX_Pause* pPause) {
   if (m_Status == 1) {
-    if (m_Stretcher.Continue(pPause)) {
+    if (m_Stretcher->Continue(pPause))
       return TRUE;
-    }
+
     if (m_Storer.GetBitmap()) {
       m_Storer.Replace(
           m_Storer.GetBitmap()->SwapXY(m_pMatrix->c > 0, m_pMatrix->b < 0));
     }
     return FALSE;
   }
-  if (m_Status == 2) {
-    return m_Stretcher.Continue(pPause);
-  }
-  if (m_Status != 3) {
+
+  if (m_Status == 2)
+    return m_Stretcher->Continue(pPause);
+
+  if (m_Status != 3)
     return FALSE;
-  }
-  if (m_Stretcher.Continue(pPause)) {
+
+  if (m_Stretcher->Continue(pPause))
     return TRUE;
-  }
+
   int stretch_width = m_StretchClip.Width();
   int stretch_height = m_StretchClip.Height();
-  if (!m_Storer.GetBitmap()) {
+  if (!m_Storer.GetBitmap())
     return FALSE;
-  }
+
   const uint8_t* stretch_buf = m_Storer.GetBitmap()->GetBuffer();
-  const uint8_t* stretch_buf_mask = NULL;
-  if (m_Storer.GetBitmap()->m_pAlphaMask) {
+  const uint8_t* stretch_buf_mask = nullptr;
+  if (m_Storer.GetBitmap()->m_pAlphaMask)
     stretch_buf_mask = m_Storer.GetBitmap()->m_pAlphaMask->GetBuffer();
-  }
+
   int stretch_pitch = m_Storer.GetBitmap()->GetPitch();
-  CFX_DIBitmap* pTransformed = new CFX_DIBitmap;
-  FXDIB_Format transformF = GetTransformedFormat(m_Stretcher.m_pSource);
-  if (!pTransformed->Create(m_ResultWidth, m_ResultHeight, transformF)) {
-    delete pTransformed;
+  std::unique_ptr<CFX_DIBitmap> pTransformed(new CFX_DIBitmap);
+  FXDIB_Format transformF = GetTransformedFormat(m_Stretcher->source());
+  if (!pTransformed->Create(m_ResultWidth, m_ResultHeight, transformF))
     return FALSE;
-  }
+
   pTransformed->Clear(0);
-  if (pTransformed->m_pAlphaMask) {
+  if (pTransformed->m_pAlphaMask)
     pTransformed->m_pAlphaMask->Clear(0);
-  }
+
   CFX_Matrix result2stretch(1.0f, 0.0f, 0.0f, 1.0f, (FX_FLOAT)(m_ResultLeft),
                             (FX_FLOAT)(m_ResultTop));
   result2stretch.Concat(m_dest2stretch);
@@ -943,6 +949,6 @@
       }
     }
   }
-  m_Storer.Replace(pTransformed);
+  m_Storer.Replace(pTransformed.release());
   return FALSE;
 }
diff --git a/core/fxge/include/fx_dib.h b/core/fxge/include/fx_dib.h
index 4a9b295..fe185eb 100644
--- a/core/fxge/include/fx_dib.h
+++ b/core/fxge/include/fx_dib.h
@@ -7,6 +7,8 @@
 #ifndef CORE_FXGE_INCLUDE_FX_DIB_H_
 #define CORE_FXGE_INCLUDE_FX_DIB_H_
 
+#include <memory>
+
 #include "core/fxcrt/include/fx_basic.h"
 #include "core/fxcrt/include/fx_coordinates.h"
 
@@ -574,37 +576,41 @@
 
 class CFX_ImageStretcher {
  public:
-  CFX_ImageStretcher();
+  CFX_ImageStretcher(IFX_ScanlineComposer* pDest,
+                     const CFX_DIBSource* pSource,
+                     int dest_width,
+                     int dest_height,
+                     const FX_RECT& bitmap_rect,
+                     uint32_t flags);
   ~CFX_ImageStretcher();
 
-  FX_BOOL Start(IFX_ScanlineComposer* pDest,
-                const CFX_DIBSource* pBitmap,
-                int dest_width,
-                int dest_height,
-                const FX_RECT& bitmap_rect,
-                uint32_t flags);
-
+  FX_BOOL Start();
   FX_BOOL Continue(IFX_Pause* pPause);
+
+  const CFX_DIBSource* source() { return m_pSource; }
+
+ private:
   FX_BOOL StartQuickStretch();
   FX_BOOL StartStretch();
   FX_BOOL ContinueQuickStretch(IFX_Pause* pPause);
   FX_BOOL ContinueStretch(IFX_Pause* pPause);
 
-  IFX_ScanlineComposer* m_pDest;
-  const CFX_DIBSource* m_pSource;
-  CStretchEngine* m_pStretchEngine;
-  uint32_t m_Flags;
+  IFX_ScanlineComposer* const m_pDest;
+  const CFX_DIBSource* const m_pSource;
+  std::unique_ptr<CStretchEngine> m_pStretchEngine;
+  std::unique_ptr<uint8_t, FxFreeDeleter> m_pScanline;
+  std::unique_ptr<uint8_t, FxFreeDeleter> m_pMaskScanline;
+  const uint32_t m_Flags;
   FX_BOOL m_bFlipX;
   FX_BOOL m_bFlipY;
   int m_DestWidth;
   int m_DestHeight;
   FX_RECT m_ClipRect;
+  const FXDIB_Format m_DestFormat;
+  const int m_DestBPP;
   int m_LineIndex;
-  int m_DestBPP;
-  uint8_t* m_pScanline;
-  uint8_t* m_pMaskScanline;
-  FXDIB_Format m_DestFormat;
 };
+
 class CFX_ImageTransformer {
  public:
   CFX_ImageTransformer();
@@ -624,11 +630,12 @@
   int m_ResultWidth;
   int m_ResultHeight;
   CFX_Matrix m_dest2stretch;
-  CFX_ImageStretcher m_Stretcher;
+  std::unique_ptr<CFX_ImageStretcher> m_Stretcher;
   CFX_BitmapStorer m_Storer;
   uint32_t m_Flags;
   int m_Status;
 };
+
 class CFX_ImageRenderer {
  public:
   CFX_ImageRenderer();
@@ -655,7 +662,7 @@
   uint32_t m_MaskColor;
   CFX_Matrix m_Matrix;
   CFX_ImageTransformer* m_pTransformer;
-  CFX_ImageStretcher m_Stretcher;
+  std::unique_ptr<CFX_ImageStretcher> m_Stretcher;
   CFX_BitmapComposer m_Composer;
   int m_Status;
   FX_RECT m_ClipBox;