Convert CPSOutput to an IFX_WriteStream

This Cl updates CPSOutput to inherit from IFX_WriteStream and converts
the CFX_PSRenderer to accept an IFX_WriteStream instead of a CPSOutput.

Change-Id: Ibde5c7da1c2f6df0a10cb6e9a470e18fbab167b8
Reviewed-on: https://pdfium-review.googlesource.com/5431
Reviewed-by: Nicolás Peña <npm@chromium.org>
Commit-Queue: dsinclair <dsinclair@chromium.org>
diff --git a/core/fxge/win32/cfx_psrenderer.cpp b/core/fxge/win32/cfx_psrenderer.cpp
index 46af337..ba027ba 100644
--- a/core/fxge/win32/cfx_psrenderer.cpp
+++ b/core/fxge/win32/cfx_psrenderer.cpp
@@ -19,6 +19,60 @@
 #include "core/fxge/win32/cpsoutput.h"
 #include "third_party/base/ptr_util.h"
 
+namespace {
+
+void FaxCompressData(uint8_t* src_buf,
+                     int width,
+                     int height,
+                     std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
+                     uint32_t* dest_size) {
+  if (width * height > 128) {
+    CCodec_FaxModule::FaxEncode(src_buf, width, height, (width + 7) / 8,
+                                dest_buf, dest_size);
+    FX_Free(src_buf);
+  } else {
+    dest_buf->reset(src_buf);
+    *dest_size = (width + 7) / 8 * height;
+  }
+}
+
+void PSCompressData(int PSLevel,
+                    uint8_t* src_buf,
+                    uint32_t src_size,
+                    uint8_t** output_buf,
+                    uint32_t* output_size,
+                    const char** filter) {
+  *output_buf = src_buf;
+  *output_size = src_size;
+  *filter = "";
+  if (src_size < 1024)
+    return;
+
+  CCodec_ModuleMgr* pEncoders = CFX_GEModule::Get()->GetCodecModule();
+  uint8_t* dest_buf = nullptr;
+  uint32_t dest_size = src_size;
+  if (PSLevel >= 3) {
+    if (pEncoders && pEncoders->GetFlateModule()->Encode(
+                         src_buf, src_size, &dest_buf, &dest_size)) {
+      *filter = "/FlateDecode filter ";
+    }
+  } else {
+    if (pEncoders && pEncoders->GetBasicModule()->RunLengthEncode(
+                         src_buf, src_size, &dest_buf, &dest_size)) {
+      *filter = "/RunLengthDecode filter ";
+    }
+  }
+  if (dest_size < src_size) {
+    *output_buf = dest_buf;
+    *output_size = dest_size;
+  } else {
+    *filter = nullptr;
+    FX_Free(dest_buf);
+  }
+}
+
+}  // namespace
+
 struct PSGlyph {
   CFX_Font* m_pFont;
   uint32_t m_GlyphIndex;
@@ -32,33 +86,32 @@
   int m_nGlyphs;
 };
 
-CFX_PSRenderer::CFX_PSRenderer() {
-  m_pOutput = nullptr;
-  m_bColorSet = m_bGraphStateSet = false;
-  m_bInited = false;
-}
+CFX_PSRenderer::CFX_PSRenderer()
+    : m_pStream(nullptr),
+      m_bGraphStateSet(false),
+      m_bColorSet(false),
+      m_bInited(false) {}
 
 CFX_PSRenderer::~CFX_PSRenderer() {}
 
-#define OUTPUT_PS(str) m_pOutput->OutputPS(str, sizeof(str) - 1)
-
-void CFX_PSRenderer::Init(CPSOutput* pOutput,
+void CFX_PSRenderer::Init(const CFX_RetainPtr<IFX_WriteStream>& pStream,
                           int pslevel,
                           int width,
                           int height,
                           bool bCmykOutput) {
   m_PSLevel = pslevel;
-  m_pOutput = pOutput;
-  m_ClipBox.left = m_ClipBox.top = 0;
+  m_pStream = pStream;
+  m_ClipBox.left = 0;
+  m_ClipBox.top = 0;
   m_ClipBox.right = width;
   m_ClipBox.bottom = height;
   m_bCmykOutput = bCmykOutput;
 }
 
 bool CFX_PSRenderer::StartRendering() {
-  if (m_bInited) {
+  if (m_bInited)
     return true;
-  }
+
   static const char init_str[] =
       "\nsave\n/im/initmatrix load def\n"
       "/n/newpath load def/m/moveto load def/l/lineto load def/c/curveto load "
@@ -73,30 +126,30 @@
       "load def\n"
       "/cm/concat load def/Cm/currentmatrix load def/mx/matrix load "
       "def/sm/setmatrix load def\n";
-  OUTPUT_PS(init_str);
+  m_pStream->WriteString(init_str);
   m_bInited = true;
   return true;
 }
 
 void CFX_PSRenderer::EndRendering() {
-  if (m_bInited) {
-    OUTPUT_PS("\nrestore\n");
-    m_bInited = false;
-  }
+  if (!m_bInited)
+    return;
+
+  m_pStream->WriteString("\nrestore\n");
+  m_bInited = false;
 }
 
 void CFX_PSRenderer::SaveState() {
   StartRendering();
-  OUTPUT_PS("q\n");
+  m_pStream->WriteString("q\n");
   m_ClipBoxStack.push_back(m_ClipBox);
 }
 
 void CFX_PSRenderer::RestoreState(bool bKeepSaved) {
   StartRendering();
+  m_pStream->WriteString("Q\n");
   if (bKeepSaved)
-    OUTPUT_PS("Q\nq\n");
-  else
-    OUTPUT_PS("Q\n");
+    m_pStream->WriteString("q\n");
 
   m_bColorSet = false;
   m_bGraphStateSet = false;
@@ -148,7 +201,7 @@
       }
     }
   }
-  m_pOutput->OutputPS((const char*)buf.GetBuffer(), buf.GetSize());
+  m_pStream->WriteBlock(buf.GetBuffer(), buf.GetSize());
 }
 
 void CFX_PSRenderer::SetClip_PathFill(const CFX_PathData* pPathData,
@@ -164,11 +217,11 @@
   m_ClipBox.right = static_cast<int>(rect.left + rect.right);
   m_ClipBox.top = static_cast<int>(rect.top + rect.bottom);
   m_ClipBox.bottom = static_cast<int>(rect.bottom);
-  if ((fill_mode & 3) == FXFILL_WINDING) {
-    OUTPUT_PS("W n\n");
-  } else {
-    OUTPUT_PS("W* n\n");
-  }
+
+  m_pStream->WriteString("W");
+  if ((fill_mode & 3) != FXFILL_WINDING)
+    m_pStream->WriteString("*");
+  m_pStream->WriteString(" n\n");
 }
 
 void CFX_PSRenderer::SetClip_PathStroke(const CFX_PathData* pPathData,
@@ -181,18 +234,19 @@
     buf << "mx Cm [" << pObject2Device->a << " " << pObject2Device->b << " "
         << pObject2Device->c << " " << pObject2Device->d << " "
         << pObject2Device->e << " " << pObject2Device->f << "]cm ";
-    m_pOutput->OutputPS((const char*)buf.GetBuffer(), buf.GetSize());
+    m_pStream->WriteBlock(buf.GetBuffer(), buf.GetSize());
   }
+
   OutputPath(pPathData, nullptr);
   CFX_FloatRect rect = pPathData->GetBoundingBox(pGraphState->m_LineWidth,
                                                  pGraphState->m_MiterLimit);
   pObject2Device->TransformRect(rect);
   m_ClipBox.Intersect(rect.GetOuterRect());
-  if (pObject2Device) {
-    OUTPUT_PS("strokepath W n sm\n");
-  } else {
-    OUTPUT_PS("strokepath W n\n");
-  }
+
+  m_pStream->WriteString("strokepath W n");
+  if (pObject2Device)
+    m_pStream->WriteString(" sm");
+  m_pStream->WriteString("\n");
 }
 
 bool CFX_PSRenderer::DrawPath(const CFX_PathData* pPathData,
@@ -204,15 +258,13 @@
   StartRendering();
   int fill_alpha = FXARGB_A(fill_color);
   int stroke_alpha = FXARGB_A(stroke_color);
-  if (fill_alpha && fill_alpha < 255) {
+  if (fill_alpha && fill_alpha < 255)
     return false;
-  }
-  if (stroke_alpha && stroke_alpha < 255) {
+  if (stroke_alpha && stroke_alpha < 255)
     return false;
-  }
-  if (fill_alpha == 0 && stroke_alpha == 0) {
+  if (fill_alpha == 0 && stroke_alpha == 0)
     return false;
-  }
+
   if (stroke_alpha) {
     SetGraphState(pGraphState);
     if (pObject2Device) {
@@ -220,35 +272,34 @@
       buf << "mx Cm [" << pObject2Device->a << " " << pObject2Device->b << " "
           << pObject2Device->c << " " << pObject2Device->d << " "
           << pObject2Device->e << " " << pObject2Device->f << "]cm ";
-      m_pOutput->OutputPS((const char*)buf.GetBuffer(), buf.GetSize());
+      m_pStream->WriteBlock(buf.GetBuffer(), buf.GetSize());
     }
   }
+
   OutputPath(pPathData, stroke_alpha ? nullptr : pObject2Device);
   if (fill_mode && fill_alpha) {
     SetColor(fill_color);
     if ((fill_mode & 3) == FXFILL_WINDING) {
-      if (stroke_alpha) {
-        OUTPUT_PS("q f Q ");
-      } else {
-        OUTPUT_PS("f");
-      }
+      if (stroke_alpha)
+        m_pStream->WriteString("q f Q ");
+      else
+        m_pStream->WriteString("f");
     } else if ((fill_mode & 3) == FXFILL_ALTERNATE) {
-      if (stroke_alpha) {
-        OUTPUT_PS("q F Q ");
-      } else {
-        OUTPUT_PS("F");
-      }
+      if (stroke_alpha)
+        m_pStream->WriteString("q F Q ");
+      else
+        m_pStream->WriteString("F");
     }
   }
+
   if (stroke_alpha) {
     SetColor(stroke_color);
-    if (pObject2Device) {
-      OUTPUT_PS("s sm");
-    } else {
-      OUTPUT_PS("s");
-    }
+    m_pStream->WriteString("s");
+    if (pObject2Device)
+      m_pStream->WriteString(" sm");
   }
-  OUTPUT_PS("\n");
+
+  m_pStream->WriteString("\n");
   return true;
 }
 
@@ -263,9 +314,9 @@
       memcmp(m_CurGraphState.m_DashArray, pGraphState->m_DashArray,
              sizeof(float) * m_CurGraphState.m_DashCount)) {
     buf << "[";
-    for (int i = 0; i < pGraphState->m_DashCount; ++i) {
+    for (int i = 0; i < pGraphState->m_DashCount; ++i)
       buf << pGraphState->m_DashArray[i] << " ";
-    }
+
     buf << "]" << pGraphState->m_DashPhase << " d\n";
   }
   if (!m_bGraphStateSet ||
@@ -282,61 +333,8 @@
   }
   m_CurGraphState.Copy(*pGraphState);
   m_bGraphStateSet = true;
-  if (buf.GetSize()) {
-    m_pOutput->OutputPS((const char*)buf.GetBuffer(), buf.GetSize());
-  }
-}
-
-static void FaxCompressData(uint8_t* src_buf,
-                            int width,
-                            int height,
-                            std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
-                            uint32_t* dest_size) {
-  if (width * height > 128) {
-    CCodec_FaxModule::FaxEncode(src_buf, width, height, (width + 7) / 8,
-                                dest_buf, dest_size);
-    FX_Free(src_buf);
-  } else {
-    dest_buf->reset(src_buf);
-    *dest_size = (width + 7) / 8 * height;
-  }
-}
-
-static void PSCompressData(int PSLevel,
-                           uint8_t* src_buf,
-                           uint32_t src_size,
-                           uint8_t** output_buf,
-                           uint32_t* output_size,
-                           const char** filter) {
-  *output_buf = src_buf;
-  *output_size = src_size;
-  *filter = "";
-  if (src_size < 1024) {
-    return;
-  }
-  CCodec_ModuleMgr* pEncoders = CFX_GEModule::Get()->GetCodecModule();
-  uint8_t* dest_buf = nullptr;
-  uint32_t dest_size = src_size;
-  if (PSLevel >= 3) {
-    if (pEncoders &&
-        pEncoders->GetFlateModule()->Encode(src_buf, src_size, &dest_buf,
-                                            &dest_size)) {
-      *filter = "/FlateDecode filter ";
-    }
-  } else {
-    if (pEncoders &&
-        pEncoders->GetBasicModule()->RunLengthEncode(src_buf, src_size,
-                                                     &dest_buf, &dest_size)) {
-      *filter = "/RunLengthDecode filter ";
-    }
-  }
-  if (dest_size < src_size) {
-    *output_buf = dest_buf;
-    *output_size = dest_size;
-  } else {
-    *filter = nullptr;
-    FX_Free(dest_buf);
-  }
+  if (buf.GetSize())
+    m_pStream->WriteBlock(buf.GetBuffer(), buf.GetSize());
 }
 
 bool CFX_PSRenderer::SetDIBits(const CFX_RetainPtr<CFX_DIBSource>& pSource,
@@ -372,20 +370,23 @@
       (pMatrix->c == 0 && pMatrix->d == 0)) {
     return true;
   }
-  if (pSource->HasAlpha()) {
+  if (pSource->HasAlpha())
     return false;
-  }
+
   int alpha = FXARGB_A(color);
   if (pSource->IsAlphaMask() && (alpha < 255 || pSource->GetBPP() != 1))
     return false;
 
-  OUTPUT_PS("q\n");
+  m_pStream->WriteString("q\n");
+
   CFX_ByteTextBuf buf;
   buf << "[" << pMatrix->a << " " << pMatrix->b << " " << pMatrix->c << " "
       << pMatrix->d << " " << pMatrix->e << " " << pMatrix->f << "]cm ";
+
   int width = pSource->GetWidth();
   int height = pSource->GetHeight();
   buf << width << " " << height;
+
   if (pSource->GetBPP() == 1 && !pSource->GetPalette()) {
     int pitch = (width + 7) / 8;
     uint32_t src_size = height * pitch;
@@ -394,6 +395,7 @@
       const uint8_t* src_scan = pSource->GetScanline(row);
       memcpy(src_buf + row * pitch, src_scan, pitch);
     }
+
     std::unique_ptr<uint8_t, FxFreeDeleter> output_buf;
     uint32_t output_size;
     FaxCompressData(src_buf, width, height, &output_buf, &output_size);
@@ -406,16 +408,17 @@
     }
     buf << width << " 0 0 -" << height << " 0 " << height
         << "]currentfile/ASCII85Decode filter ";
+
     if (output_buf.get() != src_buf) {
       buf << "<</K -1/EndOfBlock false/Columns " << width << "/Rows " << height
           << ">>/CCITTFaxDecode filter ";
     }
-    if (pSource->IsAlphaMask()) {
+    if (pSource->IsAlphaMask())
       buf << "iM\n";
-    } else {
+    else
       buf << "false 1 colorimage\n";
-    }
-    m_pOutput->OutputPS((const char*)buf.GetBuffer(), buf.GetSize());
+
+    m_pStream->WriteBlock(buf.GetBuffer(), buf.GetSize());
     WritePSBinary(output_buf.get(), output_size);
     output_buf.release();
   } else {
@@ -445,9 +448,10 @@
         break;
     }
     if (!pConverted) {
-      OUTPUT_PS("\nQ\n");
+      m_pStream->WriteString("\nQ\n");
       return false;
     }
+
     int bpp = pConverted->GetBPP() / 8;
     uint8_t* output_buf = nullptr;
     FX_STRSIZE output_size = 0;
@@ -478,25 +482,26 @@
       uint32_t compressed_size;
       PSCompressData(m_PSLevel, output_buf, output_size, &compressed_buf,
                      &compressed_size, &filter);
-      if (output_buf != compressed_buf) {
+      if (output_buf != compressed_buf)
         FX_Free(output_buf);
-      }
+
       output_buf = compressed_buf;
       output_size = compressed_size;
     }
     buf << " 8[";
     buf << width << " 0 0 -" << height << " 0 " << height << "]";
     buf << "currentfile/ASCII85Decode filter ";
-    if (filter) {
+    if (filter)
       buf << filter;
-    }
+
     buf << "false " << bpp;
     buf << " colorimage\n";
-    m_pOutput->OutputPS((const char*)buf.GetBuffer(), buf.GetSize());
+    m_pStream->WriteBlock(buf.GetBuffer(), buf.GetSize());
+
     WritePSBinary(output_buf, output_size);
     FX_Free(output_buf);
   }
-  OUTPUT_PS("\nQ\n");
+  m_pStream->WriteString("\nQ\n");
   return true;
 }
 
@@ -517,7 +522,7 @@
       m_bColorSet = true;
       m_LastColor = color;
     }
-    m_pOutput->OutputPS((const char*)buf.GetBuffer(), buf.GetSize());
+    m_pStream->WriteBlock(buf.GetBuffer(), buf.GetSize());
   }
 }
 
@@ -548,6 +553,7 @@
     }
     ++i;
   }
+
   if (m_PSFontList.empty() || m_PSFontList.back()->m_nGlyphs == 256) {
     m_PSFontList.push_back(pdfium::MakeUnique<CPSFont>());
     m_PSFontList.back()->m_nGlyphs = 0;
@@ -563,9 +569,10 @@
            "currentdict end\n";
     buf << "/X" << static_cast<uint32_t>(m_PSFontList.size() - 1)
         << " exch definefont pop\n";
-    m_pOutput->OutputPS((const char*)buf.GetBuffer(), buf.GetSize());
+    m_pStream->WriteBlock(buf.GetBuffer(), buf.GetSize());
     buf.Clear();
   }
+
   *ps_fontnum = m_PSFontList.size() - 1;
   CPSFont* pPSFont = m_PSFontList[*ps_fontnum].get();
   int glyphindex = pPSFont->m_nGlyphs;
@@ -624,7 +631,7 @@
   buf << "f}bind def end\n";
   buf << "/X" << *ps_fontnum << " Ff/Encoding get " << glyphindex << "/"
       << glyphindex << " put\n";
-  m_pOutput->OutputPS((const char*)buf.GetBuffer(), buf.GetSize());
+  m_pStream->WriteBlock(buf.GetBuffer(), buf.GetSize());
 }
 
 bool CFX_PSRenderer::DrawText(int nChars,
@@ -642,6 +649,7 @@
       (pObject2Device->c == 0 && pObject2Device->d == 0)) {
     return true;
   }
+
   SetColor(color);
   CFX_ByteTextBuf buf;
   buf << "q[" << pObject2Device->a << " " << pObject2Device->b << " "
@@ -665,7 +673,7 @@
     buf << hex.AsStringC() << "Tj\n";
   }
   buf << "Q\n";
-  m_pOutput->OutputPS((const char*)buf.GetBuffer(), buf.GetSize());
+  m_pStream->WriteBlock(buf.GetBuffer(), buf.GetSize());
   pCache->ReleaseCachedFace(pFont);
   return true;
 }
@@ -677,9 +685,9 @@
   if (pEncoders &&
       pEncoders->GetBasicModule()->A85Encode(data, len, &dest_buf,
                                              &dest_size)) {
-    m_pOutput->OutputPS((const char*)dest_buf, dest_size);
+    m_pStream->WriteBlock(dest_buf, dest_size);
     FX_Free(dest_buf);
   } else {
-    m_pOutput->OutputPS((const char*)data, len);
+    m_pStream->WriteBlock(data, len);
   }
 }
diff --git a/core/fxge/win32/cfx_psrenderer.h b/core/fxge/win32/cfx_psrenderer.h
index 5768d07..01a9001 100644
--- a/core/fxge/win32/cfx_psrenderer.h
+++ b/core/fxge/win32/cfx_psrenderer.h
@@ -10,10 +10,11 @@
 #include <memory>
 #include <vector>
 
+#include "core/fxcrt/cfx_retain_ptr.h"
 #include "core/fxcrt/fx_coordinates.h"
+#include "core/fxcrt/fx_stream.h"
 #include "core/fxcrt/fx_system.h"
 #include "core/fxge/cfx_graphstatedata.h"
-#include "core/fxge/win32/cpsoutput.h"
 
 class CFX_DIBSource;
 class CFX_FaceCache;
@@ -29,7 +30,7 @@
   CFX_PSRenderer();
   ~CFX_PSRenderer();
 
-  void Init(CPSOutput* pOutput,
+  void Init(const CFX_RetainPtr<IFX_WriteStream>& stream,
             int pslevel,
             int width,
             int height,
@@ -85,7 +86,7 @@
                        int* ps_glyphindex);
   void WritePSBinary(const uint8_t* data, int len);
 
-  CPSOutput* m_pOutput;
+  CFX_RetainPtr<IFX_WriteStream> m_pStream;
   int m_PSLevel;
   CFX_GraphStateData m_CurGraphState;
   bool m_bGraphStateSet;
diff --git a/core/fxge/win32/cpsoutput.cpp b/core/fxge/win32/cpsoutput.cpp
index 7a8434e..7139340 100644
--- a/core/fxge/win32/cpsoutput.cpp
+++ b/core/fxge/win32/cpsoutput.cpp
@@ -10,26 +10,17 @@
 
 #include "core/fxcrt/fx_system.h"
 
-CPSOutput::CPSOutput(HDC hDC) {
-  m_hDC = hDC;
-}
+CPSOutput::CPSOutput(HDC hDC) : m_hDC(hDC) {}
 
 CPSOutput::~CPSOutput() {}
 
-void CPSOutput::Release() {
-  delete this;
-}
-
-void CPSOutput::OutputPS(const char* str, int len) {
-  if (len < 0)
-    len = static_cast<int>(FXSYS_strlen(str));
-
+bool CPSOutput::WriteBlock(const void* str, size_t len) {
   int sent_len = 0;
   while (len > 0) {
     char buffer[1026];
-    int send_len = std::min(len, 1024);
+    size_t send_len = std::min(len, static_cast<size_t>(1024));
     *(reinterpret_cast<uint16_t*>(buffer)) = send_len;
-    memcpy(buffer + 2, str + sent_len, send_len);
+    memcpy(buffer + 2, static_cast<const char*>(str) + sent_len, send_len);
 
     // TODO(thestig/rbpotter): Do PASSTHROUGH for non-Chromium usage.
     // ExtEscape(m_hDC, PASSTHROUGH, send_len + 2, buffer, 0, nullptr);
@@ -37,4 +28,9 @@
     sent_len += send_len;
     len -= send_len;
   }
+  return true;
+}
+
+bool CPSOutput::WriteString(const CFX_ByteStringC& str) {
+  return WriteBlock(str.c_str(), str.GetLength());
 }
diff --git a/core/fxge/win32/cpsoutput.h b/core/fxge/win32/cpsoutput.h
index 1a4709b..42ad109 100644
--- a/core/fxge/win32/cpsoutput.h
+++ b/core/fxge/win32/cpsoutput.h
@@ -9,17 +9,19 @@
 
 #include <windows.h>
 
+#include "core/fxcrt/fx_stream.h"
 #include "core/fxcrt/fx_system.h"
 
-class CPSOutput {
+class CPSOutput : public IFX_WriteStream {
  public:
   explicit CPSOutput(HDC hDC);
-  ~CPSOutput();
+  ~CPSOutput() override;
 
-  // IFX_PSOutput
-  void Release();
-  void OutputPS(const char* str, int len);
+  // IFX_Writestream
+  bool WriteBlock(const void* str, size_t len) override;
+  bool WriteString(const CFX_ByteStringC& str) override;
 
+ private:
   HDC m_hDC;
 };
 
diff --git a/core/fxge/win32/fx_win32_print.cpp b/core/fxge/win32/fx_win32_print.cpp
index e036a8c..8f7cbf5 100644
--- a/core/fxge/win32/fx_win32_print.cpp
+++ b/core/fxge/win32/fx_win32_print.cpp
@@ -337,8 +337,9 @@
   m_Width = ::GetDeviceCaps(m_hDC, HORZRES);
   m_Height = ::GetDeviceCaps(m_hDC, VERTRES);
   m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
-  m_pPSOutput = pdfium::MakeUnique<CPSOutput>(m_hDC);
-  m_PSRenderer.Init(m_pPSOutput.get(), pslevel, m_Width, m_Height, bCmykOutput);
+
+  m_PSRenderer.Init(pdfium::MakeRetain<CPSOutput>(m_hDC), pslevel, m_Width,
+                    m_Height, bCmykOutput);
   HRGN hRgn = ::CreateRectRgn(0, 0, 1, 1);
   int ret = ::GetClipRgn(hDC, hRgn);
   if (ret == 1) {
diff --git a/core/fxge/win32/win32_int.h b/core/fxge/win32/win32_int.h
index 2f69c0e..d92d3b3 100644
--- a/core/fxge/win32/win32_int.h
+++ b/core/fxge/win32/win32_int.h
@@ -11,6 +11,7 @@
 
 #include <memory>
 
+#include "core/fxcrt/cfx_retain_ptr.h"
 #include "core/fxge/cfx_pathdata.h"
 #include "core/fxge/ifx_renderdevicedriver.h"
 #include "core/fxge/win32/cfx_psrenderer.h"
@@ -329,7 +330,6 @@
   int m_nBitsPerPixel;
   int m_HorzSize;
   int m_VertSize;
-  std::unique_ptr<CPSOutput> m_pPSOutput;
   CFX_PSRenderer m_PSRenderer;
 };