Split CGdiDeviceDriver into its own file.

Bug: pdfium:1474
Change-Id: Ibb199865223473ab31d14afc04665bcaad52daf6
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/74810
Reviewed-by: Daniel Hosseinian <dhoss@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxge/BUILD.gn b/core/fxge/BUILD.gn
index 5baca04..7ed98a4 100644
--- a/core/fxge/BUILD.gn
+++ b/core/fxge/BUILD.gn
@@ -183,6 +183,8 @@
       "win32/cfx_psrenderer.cpp",
       "win32/cfx_psrenderer.h",
       "win32/cfx_windowsdib.h",
+      "win32/cgdi_device_driver.cpp",
+      "win32/cgdi_device_driver.h",
       "win32/cgdi_display_driver.cpp",
       "win32/cgdi_display_driver.h",
       "win32/cgdi_plus_ext.cpp",
diff --git a/core/fxge/win32/DEPS b/core/fxge/win32/DEPS
index 5d1d2b3..fa830d1 100644
--- a/core/fxge/win32/DEPS
+++ b/core/fxge/win32/DEPS
@@ -1,5 +1,5 @@
 specific_include_rules = {
-  'fx_win32_device.cpp': [
+  'cgdi_device_driver.cpp': [
     '+third_party/agg23/agg_clip_liang_barsky.h',
   ]
 }
diff --git a/core/fxge/win32/cgdi_device_driver.cpp b/core/fxge/win32/cgdi_device_driver.cpp
new file mode 100644
index 0000000..af5b57d
--- /dev/null
+++ b/core/fxge/win32/cgdi_device_driver.cpp
@@ -0,0 +1,695 @@
+// Copyright 2020 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "core/fxge/win32/cgdi_device_driver.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "core/fxcrt/fx_string.h"
+#include "core/fxge/cfx_fillrenderoptions.h"
+#include "core/fxge/cfx_graphstatedata.h"
+#include "core/fxge/cfx_pathdata.h"
+#include "core/fxge/render_defines.h"
+#include "core/fxge/win32/cfx_windowsdib.h"
+#include "core/fxge/win32/win32_int.h"
+#include "third_party/base/notreached.h"
+
+#if !defined(_SKIA_SUPPORT_)
+#include "core/fxge/agg/fx_agg_driver.h"
+#include "third_party/agg23/agg_clip_liang_barsky.h"
+#endif
+
+namespace {
+
+constexpr int FillTypeToGdiFillType(CFX_FillRenderOptions::FillType fill_type) {
+  return static_cast<int>(fill_type);
+}
+
+static_assert(FillTypeToGdiFillType(
+                  CFX_FillRenderOptions::FillType::kEvenOdd) == ALTERNATE,
+              "CFX_FillRenderOptions::FillType::kEvenOdd value mismatch");
+
+static_assert(
+    FillTypeToGdiFillType(CFX_FillRenderOptions::FillType::kWinding) == WINDING,
+    "CFX_FillRenderOptions::FillType::kWinding value mismatch");
+
+HPEN CreateExtPen(const CFX_GraphStateData* pGraphState,
+                  const CFX_Matrix* pMatrix,
+                  uint32_t argb) {
+  ASSERT(pGraphState);
+
+  float scale = 1.0f;
+  if (pMatrix) {
+    scale = fabs(pMatrix->a) > fabs(pMatrix->b) ? fabs(pMatrix->a)
+                                                : fabs(pMatrix->b);
+  }
+  float width = std::max(scale * pGraphState->m_LineWidth, 1.0f);
+
+  uint32_t PenStyle = PS_GEOMETRIC;
+  if (!pGraphState->m_DashArray.empty())
+    PenStyle |= PS_USERSTYLE;
+  else
+    PenStyle |= PS_SOLID;
+
+  switch (pGraphState->m_LineCap) {
+    case CFX_GraphStateData::LineCapButt:
+      PenStyle |= PS_ENDCAP_FLAT;
+      break;
+    case CFX_GraphStateData::LineCapRound:
+      PenStyle |= PS_ENDCAP_ROUND;
+      break;
+    case CFX_GraphStateData::LineCapSquare:
+      PenStyle |= PS_ENDCAP_SQUARE;
+      break;
+  }
+  switch (pGraphState->m_LineJoin) {
+    case CFX_GraphStateData::LineJoinMiter:
+      PenStyle |= PS_JOIN_MITER;
+      break;
+    case CFX_GraphStateData::LineJoinRound:
+      PenStyle |= PS_JOIN_ROUND;
+      break;
+    case CFX_GraphStateData::LineJoinBevel:
+      PenStyle |= PS_JOIN_BEVEL;
+      break;
+  }
+
+  FX_COLORREF colorref = ArgbToColorRef(argb);
+  LOGBRUSH lb;
+  lb.lbColor = colorref;
+  lb.lbStyle = BS_SOLID;
+  lb.lbHatch = 0;
+  std::vector<uint32_t> dashes;
+  if (!pGraphState->m_DashArray.empty()) {
+    dashes.resize(pGraphState->m_DashArray.size());
+    for (size_t i = 0; i < pGraphState->m_DashArray.size(); i++) {
+      dashes[i] = FXSYS_roundf(
+          pMatrix ? pMatrix->TransformDistance(pGraphState->m_DashArray[i])
+                  : pGraphState->m_DashArray[i]);
+      dashes[i] = std::max(dashes[i], 1U);
+    }
+  }
+  return ExtCreatePen(PenStyle, (DWORD)ceil(width), &lb,
+                      pGraphState->m_DashArray.size(),
+                      reinterpret_cast<const DWORD*>(dashes.data()));
+}
+
+HBRUSH CreateBrush(uint32_t argb) {
+  return CreateSolidBrush(ArgbToColorRef(argb));
+}
+
+void SetPathToDC(HDC hDC,
+                 const CFX_PathData* pPathData,
+                 const CFX_Matrix* pMatrix) {
+  BeginPath(hDC);
+
+  pdfium::span<const FX_PATHPOINT> points = pPathData->GetPoints();
+  for (size_t i = 0; i < points.size(); ++i) {
+    CFX_PointF pos = points[i].m_Point;
+    if (pMatrix)
+      pos = pMatrix->Transform(pos);
+
+    CFX_Point screen(FXSYS_roundf(pos.x), FXSYS_roundf(pos.y));
+    FXPT_TYPE point_type = points[i].m_Type;
+    if (point_type == FXPT_TYPE::MoveTo) {
+      MoveToEx(hDC, screen.x, screen.y, nullptr);
+    } else if (point_type == FXPT_TYPE::LineTo) {
+      if (points[i].m_Point == points[i - 1].m_Point)
+        screen.x++;
+
+      LineTo(hDC, screen.x, screen.y);
+    } else if (point_type == FXPT_TYPE::BezierTo) {
+      POINT lppt[3];
+      lppt[0].x = screen.x;
+      lppt[0].y = screen.y;
+
+      pos = points[i + 1].m_Point;
+      if (pMatrix)
+        pos = pMatrix->Transform(pos);
+
+      lppt[1].x = FXSYS_roundf(pos.x);
+      lppt[1].y = FXSYS_roundf(pos.y);
+
+      pos = points[i + 2].m_Point;
+      if (pMatrix)
+        pos = pMatrix->Transform(pos);
+
+      lppt[2].x = FXSYS_roundf(pos.x);
+      lppt[2].y = FXSYS_roundf(pos.y);
+      PolyBezierTo(hDC, lppt, 3);
+      i += 2;
+    }
+    if (points[i].m_CloseFigure)
+      CloseFigure(hDC);
+  }
+  EndPath(hDC);
+}
+
+#if defined(_SKIA_SUPPORT_)
+// TODO(caryclark)  This antigrain function is duplicated here to permit
+// removing the last remaining dependency. Eventually, this will be elminiated
+// altogether and replace by Skia code.
+
+struct rect_base {
+  float x1;
+  float y1;
+  float x2;
+  float y2;
+};
+
+unsigned clip_liang_barsky(float x1,
+                           float y1,
+                           float x2,
+                           float y2,
+                           const rect_base& clip_box,
+                           float* x,
+                           float* y) {
+  const float nearzero = 1e-30f;
+  float deltax = x2 - x1;
+  float deltay = y2 - y1;
+  unsigned np = 0;
+  if (deltax == 0)
+    deltax = (x1 > clip_box.x1) ? -nearzero : nearzero;
+  float xin, xout;
+  if (deltax > 0) {
+    xin = clip_box.x1;
+    xout = clip_box.x2;
+  } else {
+    xin = clip_box.x2;
+    xout = clip_box.x1;
+  }
+  float tinx = (xin - x1) / deltax;
+  if (deltay == 0)
+    deltay = (y1 > clip_box.y1) ? -nearzero : nearzero;
+  float yin, yout;
+  if (deltay > 0) {
+    yin = clip_box.y1;
+    yout = clip_box.y2;
+  } else {
+    yin = clip_box.y2;
+    yout = clip_box.y1;
+  }
+  float tiny = (yin - y1) / deltay;
+  float tin1, tin2;
+  if (tinx < tiny) {
+    tin1 = tinx;
+    tin2 = tiny;
+  } else {
+    tin1 = tiny;
+    tin2 = tinx;
+  }
+  if (tin1 <= 1.0f) {
+    if (0 < tin1) {
+      *x++ = xin;
+      *y++ = yin;
+      ++np;
+    }
+    if (tin2 <= 1.0f) {
+      float toutx = (xout - x1) / deltax;
+      float touty = (yout - y1) / deltay;
+      float tout1 = (toutx < touty) ? toutx : touty;
+      if (tin2 > 0 || tout1 > 0) {
+        if (tin2 <= tout1) {
+          if (tin2 > 0) {
+            if (tinx > tiny) {
+              *x++ = xin;
+              *y++ = y1 + (deltay * tinx);
+            } else {
+              *x++ = x1 + (deltax * tiny);
+              *y++ = yin;
+            }
+            ++np;
+          }
+          if (tout1 < 1.0f) {
+            if (toutx < touty) {
+              *x++ = xout;
+              *y++ = y1 + (deltay * toutx);
+            } else {
+              *x++ = x1 + (deltax * touty);
+              *y++ = yout;
+            }
+          } else {
+            *x++ = x2;
+            *y++ = y2;
+          }
+          ++np;
+        } else {
+          if (tinx > tiny) {
+            *x++ = xin;
+            *y++ = yout;
+          } else {
+            *x++ = xout;
+            *y++ = yin;
+          }
+          ++np;
+        }
+      }
+    }
+  }
+  return np;
+}
+#endif  //  defined(_SKIA_SUPPORT_)
+
+}  // namespace
+
+CGdiDeviceDriver::CGdiDeviceDriver(HDC hDC, DeviceType device_type)
+    : m_hDC(hDC), m_DeviceType(device_type) {
+  auto* pPlatform =
+      static_cast<CWin32Platform*>(CFX_GEModule::Get()->GetPlatform());
+  SetStretchBltMode(m_hDC, pPlatform->m_bHalfTone ? HALFTONE : COLORONCOLOR);
+  DWORD obj_type = GetObjectType(m_hDC);
+  m_bMetafileDCType = obj_type == OBJ_ENHMETADC || obj_type == OBJ_ENHMETAFILE;
+  if (obj_type == OBJ_MEMDC) {
+    HBITMAP hBitmap = CreateBitmap(1, 1, 1, 1, nullptr);
+    hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap);
+    BITMAP bitmap;
+    GetObject(hBitmap, sizeof bitmap, &bitmap);
+    m_nBitsPerPixel = bitmap.bmBitsPixel;
+    m_Width = bitmap.bmWidth;
+    m_Height = abs(bitmap.bmHeight);
+    hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap);
+    DeleteObject(hBitmap);
+  } else {
+    m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
+    m_Width = ::GetDeviceCaps(m_hDC, HORZRES);
+    m_Height = ::GetDeviceCaps(m_hDC, VERTRES);
+  }
+  if (m_DeviceType != DeviceType::kDisplay) {
+    m_RenderCaps = FXRC_BIT_MASK;
+  } else {
+    m_RenderCaps = FXRC_GET_BITS | FXRC_BIT_MASK;
+  }
+}
+
+CGdiDeviceDriver::~CGdiDeviceDriver() = default;
+
+DeviceType CGdiDeviceDriver::GetDeviceType() const {
+  return m_DeviceType;
+}
+
+int CGdiDeviceDriver::GetDeviceCaps(int caps_id) const {
+  switch (caps_id) {
+    case FXDC_PIXEL_WIDTH:
+      return m_Width;
+    case FXDC_PIXEL_HEIGHT:
+      return m_Height;
+    case FXDC_BITS_PIXEL:
+      return m_nBitsPerPixel;
+    case FXDC_RENDER_CAPS:
+      return m_RenderCaps;
+    default:
+      NOTREACHED();
+      return 0;
+  }
+}
+
+void CGdiDeviceDriver::SaveState() {
+  SaveDC(m_hDC);
+}
+
+void CGdiDeviceDriver::RestoreState(bool bKeepSaved) {
+  RestoreDC(m_hDC, -1);
+  if (bKeepSaved)
+    SaveDC(m_hDC);
+}
+
+bool CGdiDeviceDriver::GDI_SetDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap1,
+                                     const FX_RECT& src_rect,
+                                     int left,
+                                     int top) {
+  if (m_DeviceType == DeviceType::kPrinter) {
+    RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1->FlipImage(false, true);
+    if (!pBitmap)
+      return false;
+
+    if (pBitmap->IsCmykImage() && !pBitmap->ConvertFormat(FXDIB_Rgb))
+      return false;
+
+    LPBYTE pBuffer = pBitmap->GetBuffer();
+    ByteString info = CFX_WindowsDIB::GetBitmapInfo(pBitmap);
+    ((BITMAPINFOHEADER*)info.c_str())->biHeight *= -1;
+    FX_RECT dst_rect(0, 0, src_rect.Width(), src_rect.Height());
+    dst_rect.Intersect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
+    int dst_width = dst_rect.Width();
+    int dst_height = dst_rect.Height();
+    ::StretchDIBits(m_hDC, left, top, dst_width, dst_height, 0, 0, dst_width,
+                    dst_height, pBuffer, (BITMAPINFO*)info.c_str(),
+                    DIB_RGB_COLORS, SRCCOPY);
+    return true;
+  }
+
+  RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1;
+  if (pBitmap->IsCmykImage()) {
+    pBitmap = pBitmap->CloneConvert(FXDIB_Rgb);
+    if (!pBitmap)
+      return false;
+  }
+  LPBYTE pBuffer = pBitmap->GetBuffer();
+  ByteString info = CFX_WindowsDIB::GetBitmapInfo(pBitmap);
+  ::SetDIBitsToDevice(m_hDC, left, top, src_rect.Width(), src_rect.Height(),
+                      src_rect.left, pBitmap->GetHeight() - src_rect.bottom, 0,
+                      pBitmap->GetHeight(), pBuffer, (BITMAPINFO*)info.c_str(),
+                      DIB_RGB_COLORS);
+  return true;
+}
+
+bool CGdiDeviceDriver::GDI_StretchDIBits(
+    const RetainPtr<CFX_DIBitmap>& pBitmap1,
+    int dest_left,
+    int dest_top,
+    int dest_width,
+    int dest_height,
+    const FXDIB_ResampleOptions& options) {
+  RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1;
+  if (!pBitmap || dest_width == 0 || dest_height == 0)
+    return false;
+
+  if (pBitmap->IsCmykImage() && !pBitmap->ConvertFormat(FXDIB_Rgb))
+    return false;
+
+  ByteString info = CFX_WindowsDIB::GetBitmapInfo(pBitmap);
+  if ((int64_t)abs(dest_width) * abs(dest_height) <
+          (int64_t)pBitmap1->GetWidth() * pBitmap1->GetHeight() * 4 ||
+      options.bInterpolateBilinear || options.bInterpolateBicubic) {
+    SetStretchBltMode(m_hDC, HALFTONE);
+  } else {
+    SetStretchBltMode(m_hDC, COLORONCOLOR);
+  }
+  RetainPtr<CFX_DIBitmap> pToStrechBitmap = pBitmap;
+  if (m_DeviceType == DeviceType::kPrinter &&
+      ((int64_t)pBitmap->GetWidth() * pBitmap->GetHeight() >
+       (int64_t)abs(dest_width) * abs(dest_height))) {
+    pToStrechBitmap = pBitmap->StretchTo(dest_width, dest_height,
+                                         FXDIB_ResampleOptions(), nullptr);
+  }
+  ByteString toStrechBitmapInfo =
+      CFX_WindowsDIB::GetBitmapInfo(pToStrechBitmap);
+  ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height, 0, 0,
+                  pToStrechBitmap->GetWidth(), pToStrechBitmap->GetHeight(),
+                  pToStrechBitmap->GetBuffer(),
+                  (BITMAPINFO*)toStrechBitmapInfo.c_str(), DIB_RGB_COLORS,
+                  SRCCOPY);
+  return true;
+}
+
+bool CGdiDeviceDriver::GDI_StretchBitMask(
+    const RetainPtr<CFX_DIBitmap>& pBitmap1,
+    int dest_left,
+    int dest_top,
+    int dest_width,
+    int dest_height,
+    uint32_t bitmap_color) {
+  RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1;
+  if (!pBitmap || dest_width == 0 || dest_height == 0)
+    return false;
+
+  int width = pBitmap->GetWidth(), height = pBitmap->GetHeight();
+  struct {
+    BITMAPINFOHEADER bmiHeader;
+    uint32_t bmiColors[2];
+  } bmi;
+  memset(&bmi.bmiHeader, 0, sizeof(BITMAPINFOHEADER));
+  bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+  bmi.bmiHeader.biBitCount = 1;
+  bmi.bmiHeader.biCompression = BI_RGB;
+  bmi.bmiHeader.biHeight = -height;
+  bmi.bmiHeader.biPlanes = 1;
+  bmi.bmiHeader.biWidth = width;
+  if (m_nBitsPerPixel != 1) {
+    SetStretchBltMode(m_hDC, HALFTONE);
+  }
+  bmi.bmiColors[0] = 0xffffff;
+  bmi.bmiColors[1] = 0;
+
+  HBRUSH hPattern = CreateBrush(bitmap_color);
+  HBRUSH hOld = (HBRUSH)SelectObject(m_hDC, hPattern);
+
+  // In PDF, when image mask is 1, use device bitmap; when mask is 0, use brush
+  // bitmap.
+  // A complete list of the boolen operations is as follows:
+
+  /* P(bitmap_color)    S(ImageMask)    D(DeviceBitmap)    Result
+   *        0                 0                0              0
+   *        0                 0                1              0
+   *        0                 1                0              0
+   *        0                 1                1              1
+   *        1                 0                0              1
+   *        1                 0                1              1
+   *        1                 1                0              0
+   *        1                 1                1              1
+   */
+  // The boolen codes is B8. Based on
+  // http://msdn.microsoft.com/en-us/library/aa932106.aspx, the ROP3 code is
+  // 0xB8074A
+
+  ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height, 0, 0,
+                  width, height, pBitmap->GetBuffer(), (BITMAPINFO*)&bmi,
+                  DIB_RGB_COLORS, 0xB8074A);
+
+  SelectObject(m_hDC, hOld);
+  DeleteObject(hPattern);
+
+  return true;
+}
+
+bool CGdiDeviceDriver::GetClipBox(FX_RECT* pRect) {
+  return !!(::GetClipBox(m_hDC, (RECT*)pRect));
+}
+
+void CGdiDeviceDriver::DrawLine(float x1, float y1, float x2, float y2) {
+  if (!m_bMetafileDCType) {  // EMF drawing is not bound to the DC.
+    int startOutOfBoundsFlag = (x1 < 0) | ((x1 > m_Width) << 1) |
+                               ((y1 < 0) << 2) | ((y1 > m_Height) << 3);
+    int endOutOfBoundsFlag = (x2 < 0) | ((x2 > m_Width) << 1) |
+                             ((y2 < 0) << 2) | ((y2 > m_Height) << 3);
+    if (startOutOfBoundsFlag & endOutOfBoundsFlag)
+      return;
+
+    if (startOutOfBoundsFlag || endOutOfBoundsFlag) {
+      float x[2];
+      float y[2];
+      int np;
+#if defined(_SKIA_SUPPORT_)
+      // TODO(caryclark) temporary replacement of antigrain in line function
+      // to permit removing antigrain altogether
+      rect_base rect = {0.0f, 0.0f, (float)(m_Width), (float)(m_Height)};
+      np = clip_liang_barsky(x1, y1, x2, y2, rect, x, y);
+#else
+      pdfium::agg::rect_base<float> rect(0.0f, 0.0f, (float)(m_Width),
+                                         (float)(m_Height));
+      np = pdfium::agg::clip_liang_barsky<float>(x1, y1, x2, y2, rect, x, y);
+#endif
+      if (np == 0)
+        return;
+
+      if (np == 1) {
+        x2 = x[0];
+        y2 = y[0];
+      } else {
+        ASSERT(np == 2);
+        x1 = x[0];
+        y1 = y[0];
+        x2 = x[1];
+        y2 = y[1];
+      }
+    }
+  }
+
+  MoveToEx(m_hDC, FXSYS_roundf(x1), FXSYS_roundf(y1), nullptr);
+  LineTo(m_hDC, FXSYS_roundf(x2), FXSYS_roundf(y2));
+}
+
+bool CGdiDeviceDriver::DrawPath(const CFX_PathData* pPathData,
+                                const CFX_Matrix* pMatrix,
+                                const CFX_GraphStateData* pGraphState,
+                                uint32_t fill_color,
+                                uint32_t stroke_color,
+                                const CFX_FillRenderOptions& fill_options,
+                                BlendMode blend_type) {
+  if (blend_type != BlendMode::kNormal)
+    return false;
+
+  auto* pPlatform =
+      static_cast<CWin32Platform*>(CFX_GEModule::Get()->GetPlatform());
+  if (!(pGraphState || stroke_color == 0) &&
+      !pPlatform->m_GdiplusExt.IsAvailable()) {
+    CFX_FloatRect bbox_f = pPathData->GetBoundingBox();
+    if (pMatrix)
+      bbox_f = pMatrix->TransformRect(bbox_f);
+
+    FX_RECT bbox = bbox_f.GetInnerRect();
+    if (bbox.Width() <= 0) {
+      return DrawCosmeticLine(CFX_PointF(bbox.left, bbox.top),
+                              CFX_PointF(bbox.left, bbox.bottom + 1),
+                              fill_color, BlendMode::kNormal);
+    }
+    if (bbox.Height() <= 0) {
+      return DrawCosmeticLine(CFX_PointF(bbox.left, bbox.top),
+                              CFX_PointF(bbox.right + 1, bbox.top), fill_color,
+                              BlendMode::kNormal);
+    }
+  }
+  int fill_alpha = FXARGB_A(fill_color);
+  int stroke_alpha = FXARGB_A(stroke_color);
+  bool bDrawAlpha = (fill_alpha > 0 && fill_alpha < 255) ||
+                    (stroke_alpha > 0 && stroke_alpha < 255 && pGraphState);
+  if (!pPlatform->m_GdiplusExt.IsAvailable() && bDrawAlpha)
+    return false;
+
+  if (pPlatform->m_GdiplusExt.IsAvailable()) {
+    if (bDrawAlpha ||
+        ((m_DeviceType != DeviceType::kPrinter && !fill_options.full_cover) ||
+         (pGraphState && !pGraphState->m_DashArray.empty()))) {
+      if (!((!pMatrix || !pMatrix->WillScale()) && pGraphState &&
+            pGraphState->m_LineWidth == 1.0f &&
+            (pPathData->GetPoints().size() == 5 ||
+             pPathData->GetPoints().size() == 4) &&
+            pPathData->IsRect())) {
+        if (pPlatform->m_GdiplusExt.DrawPath(m_hDC, pPathData, pMatrix,
+                                             pGraphState, fill_color,
+                                             stroke_color, fill_options)) {
+          return true;
+        }
+      }
+    }
+  }
+  const bool fill =
+      fill_options.fill_type != CFX_FillRenderOptions::FillType::kNoFill;
+  HPEN hPen = nullptr;
+  HBRUSH hBrush = nullptr;
+  if (pGraphState && stroke_alpha) {
+    SetMiterLimit(m_hDC, pGraphState->m_MiterLimit, nullptr);
+    hPen = CreateExtPen(pGraphState, pMatrix, stroke_color);
+    hPen = (HPEN)SelectObject(m_hDC, hPen);
+  }
+  if (fill && fill_alpha) {
+    SetPolyFillMode(m_hDC, FillTypeToGdiFillType(fill_options.fill_type));
+    hBrush = CreateBrush(fill_color);
+    hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
+  }
+  if (pPathData->GetPoints().size() == 2 && pGraphState &&
+      !pGraphState->m_DashArray.empty()) {
+    CFX_PointF pos1 = pPathData->GetPoint(0);
+    CFX_PointF pos2 = pPathData->GetPoint(1);
+    if (pMatrix) {
+      pos1 = pMatrix->Transform(pos1);
+      pos2 = pMatrix->Transform(pos2);
+    }
+    DrawLine(pos1.x, pos1.y, pos2.x, pos2.y);
+  } else {
+    SetPathToDC(m_hDC, pPathData, pMatrix);
+    if (pGraphState && stroke_alpha) {
+      if (fill && fill_alpha) {
+        if (fill_options.text_mode) {
+          StrokeAndFillPath(m_hDC);
+        } else {
+          FillPath(m_hDC);
+          SetPathToDC(m_hDC, pPathData, pMatrix);
+          StrokePath(m_hDC);
+        }
+      } else {
+        StrokePath(m_hDC);
+      }
+    } else if (fill && fill_alpha) {
+      FillPath(m_hDC);
+    }
+  }
+  if (hPen) {
+    hPen = (HPEN)SelectObject(m_hDC, hPen);
+    DeleteObject(hPen);
+  }
+  if (hBrush) {
+    hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
+    DeleteObject(hBrush);
+  }
+  return true;
+}
+
+bool CGdiDeviceDriver::FillRectWithBlend(const FX_RECT& rect,
+                                         uint32_t fill_color,
+                                         BlendMode blend_type) {
+  if (blend_type != BlendMode::kNormal)
+    return false;
+
+  int alpha;
+  FX_COLORREF colorref;
+  std::tie(alpha, colorref) = ArgbToAlphaAndColorRef(fill_color);
+  if (alpha == 0)
+    return true;
+
+  if (alpha < 255)
+    return false;
+
+  HBRUSH hBrush = CreateSolidBrush(colorref);
+  const RECT* pRect = reinterpret_cast<const RECT*>(&rect);
+  ::FillRect(m_hDC, pRect, hBrush);
+  DeleteObject(hBrush);
+  return true;
+}
+
+void CGdiDeviceDriver::SetBaseClip(const FX_RECT& rect) {
+  m_BaseClipBox = rect;
+}
+
+bool CGdiDeviceDriver::SetClip_PathFill(
+    const CFX_PathData* pPathData,
+    const CFX_Matrix* pMatrix,
+    const CFX_FillRenderOptions& fill_options) {
+  if (pPathData->GetPoints().size() == 5) {
+    Optional<CFX_FloatRect> maybe_rectf = pPathData->GetRect(pMatrix);
+    if (maybe_rectf.has_value()) {
+      FX_RECT rect = maybe_rectf.value().GetOuterRect();
+      // Can easily apply base clip to protect against wildly large rectangular
+      // clips. crbug.com/1019026
+      if (m_BaseClipBox.has_value())
+        rect.Intersect(m_BaseClipBox.value());
+      return IntersectClipRect(m_hDC, rect.left, rect.top, rect.right,
+                               rect.bottom) != ERROR;
+    }
+  }
+  SetPathToDC(m_hDC, pPathData, pMatrix);
+  SetPolyFillMode(m_hDC, FillTypeToGdiFillType(fill_options.fill_type));
+  SelectClipPath(m_hDC, RGN_AND);
+  return true;
+}
+
+bool CGdiDeviceDriver::SetClip_PathStroke(
+    const CFX_PathData* pPathData,
+    const CFX_Matrix* pMatrix,
+    const CFX_GraphStateData* pGraphState) {
+  HPEN hPen = CreateExtPen(pGraphState, pMatrix, 0xff000000);
+  hPen = (HPEN)SelectObject(m_hDC, hPen);
+  SetPathToDC(m_hDC, pPathData, pMatrix);
+  WidenPath(m_hDC);
+  SetPolyFillMode(m_hDC, WINDING);
+  bool ret = !!SelectClipPath(m_hDC, RGN_AND);
+  hPen = (HPEN)SelectObject(m_hDC, hPen);
+  DeleteObject(hPen);
+  return ret;
+}
+
+bool CGdiDeviceDriver::DrawCosmeticLine(const CFX_PointF& ptMoveTo,
+                                        const CFX_PointF& ptLineTo,
+                                        uint32_t color,
+                                        BlendMode blend_type) {
+  if (blend_type != BlendMode::kNormal)
+    return false;
+
+  int alpha;
+  FX_COLORREF colorref;
+  std::tie(alpha, colorref) = ArgbToAlphaAndColorRef(color);
+  if (alpha == 0)
+    return true;
+
+  HPEN hPen = CreatePen(PS_SOLID, 1, colorref);
+  hPen = (HPEN)SelectObject(m_hDC, hPen);
+  MoveToEx(m_hDC, FXSYS_roundf(ptMoveTo.x), FXSYS_roundf(ptMoveTo.y), nullptr);
+  LineTo(m_hDC, FXSYS_roundf(ptLineTo.x), FXSYS_roundf(ptLineTo.y));
+  hPen = (HPEN)SelectObject(m_hDC, hPen);
+  DeleteObject(hPen);
+  return true;
+}
diff --git a/core/fxge/win32/cgdi_device_driver.h b/core/fxge/win32/cgdi_device_driver.h
new file mode 100644
index 0000000..34c7d4c
--- /dev/null
+++ b/core/fxge/win32/cgdi_device_driver.h
@@ -0,0 +1,78 @@
+// Copyright 2020 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.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef CORE_FXGE_WIN32_CGDI_DEVICE_DRIVER_H_
+#define CORE_FXGE_WIN32_CGDI_DEVICE_DRIVER_H_
+
+#include <windows.h>
+
+#include "core/fxcrt/retain_ptr.h"
+#include "core/fxge/renderdevicedriver_iface.h"
+#include "third_party/base/optional.h"
+
+class CGdiDeviceDriver : public RenderDeviceDriverIface {
+ protected:
+  CGdiDeviceDriver(HDC hDC, DeviceType device_type);
+  ~CGdiDeviceDriver() override;
+
+  // RenderDeviceDriverIface:
+  DeviceType GetDeviceType() const override;
+  int GetDeviceCaps(int caps_id) const override;
+  void SaveState() override;
+  void RestoreState(bool bKeepSaved) override;
+  void SetBaseClip(const FX_RECT& rect) override;
+  bool SetClip_PathFill(const CFX_PathData* pPathData,
+                        const CFX_Matrix* pObject2Device,
+                        const CFX_FillRenderOptions& fill_options) override;
+  bool SetClip_PathStroke(const CFX_PathData* pPathData,
+                          const CFX_Matrix* pObject2Device,
+                          const CFX_GraphStateData* pGraphState) override;
+  bool DrawPath(const CFX_PathData* pPathData,
+                const CFX_Matrix* pObject2Device,
+                const CFX_GraphStateData* pGraphState,
+                uint32_t fill_color,
+                uint32_t stroke_color,
+                const CFX_FillRenderOptions& fill_options,
+                BlendMode blend_type) override;
+  bool FillRectWithBlend(const FX_RECT& rect,
+                         uint32_t fill_color,
+                         BlendMode blend_type) override;
+  bool DrawCosmeticLine(const CFX_PointF& ptMoveTo,
+                        const CFX_PointF& ptLineTo,
+                        uint32_t color,
+                        BlendMode blend_type) override;
+  bool GetClipBox(FX_RECT* pRect) override;
+
+  void DrawLine(float x1, float y1, float x2, float y2);
+
+  bool GDI_SetDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap,
+                     const FX_RECT& src_rect,
+                     int left,
+                     int top);
+  bool GDI_StretchDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap,
+                         int dest_left,
+                         int dest_top,
+                         int dest_width,
+                         int dest_height,
+                         const FXDIB_ResampleOptions& options);
+  bool GDI_StretchBitMask(const RetainPtr<CFX_DIBitmap>& pBitmap,
+                          int dest_left,
+                          int dest_top,
+                          int dest_width,
+                          int dest_height,
+                          uint32_t bitmap_color);
+
+  const HDC m_hDC;
+  bool m_bMetafileDCType;
+  int m_Width;
+  int m_Height;
+  int m_nBitsPerPixel;
+  const DeviceType m_DeviceType;
+  int m_RenderCaps;
+  pdfium::Optional<FX_RECT> m_BaseClipBox;
+};
+
+#endif  // CORE_FXGE_WIN32_CGDI_DEVICE_DRIVER_H_
diff --git a/core/fxge/win32/cgdi_display_driver.cpp b/core/fxge/win32/cgdi_display_driver.cpp
index 1c25f40..c353e73 100644
--- a/core/fxge/win32/cgdi_display_driver.cpp
+++ b/core/fxge/win32/cgdi_display_driver.cpp
@@ -10,6 +10,8 @@
 #include "core/fxcrt/fx_system.h"
 #include "core/fxge/dib/cfx_dibextractor.h"
 #include "core/fxge/dib/cfx_dibitmap.h"
+#include "core/fxge/render_defines.h"
+#include "core/fxge/win32/win32_int.h"
 
 CGdiDisplayDriver::CGdiDisplayDriver(HDC hDC)
     : CGdiDeviceDriver(hDC, DeviceType::kDisplay) {
diff --git a/core/fxge/win32/cgdi_display_driver.h b/core/fxge/win32/cgdi_display_driver.h
index fbe3351..ac9d004 100644
--- a/core/fxge/win32/cgdi_display_driver.h
+++ b/core/fxge/win32/cgdi_display_driver.h
@@ -13,7 +13,7 @@
 #include <memory>
 
 #include "core/fxcrt/retain_ptr.h"
-#include "core/fxge/win32/win32_int.h"
+#include "core/fxge/win32/cgdi_device_driver.h"
 
 class CFX_DIBBase;
 struct FXDIB_ResampleOptions;
diff --git a/core/fxge/win32/cgdi_printer_driver.cpp b/core/fxge/win32/cgdi_printer_driver.cpp
index 3c38698..11888ea 100644
--- a/core/fxge/win32/cgdi_printer_driver.cpp
+++ b/core/fxge/win32/cgdi_printer_driver.cpp
@@ -15,8 +15,10 @@
 #include "core/fxcrt/fx_system.h"
 #include "core/fxcrt/retain_ptr.h"
 #include "core/fxge/cfx_font.h"
+#include "core/fxge/cfx_windowsrenderdevice.h"
 #include "core/fxge/dib/cfx_dibextractor.h"
 #include "core/fxge/dib/cfx_dibitmap.h"
+#include "core/fxge/render_defines.h"
 #include "core/fxge/text_char_pos.h"
 
 #if defined(PDFIUM_PRINT_TEXT_WITH_GDI)
diff --git a/core/fxge/win32/cgdi_printer_driver.h b/core/fxge/win32/cgdi_printer_driver.h
index d1e2b3a..e558603 100644
--- a/core/fxge/win32/cgdi_printer_driver.h
+++ b/core/fxge/win32/cgdi_printer_driver.h
@@ -11,7 +11,7 @@
 
 #include <memory>
 
-#include "core/fxge/win32/win32_int.h"
+#include "core/fxge/win32/cgdi_device_driver.h"
 
 class CGdiPrinterDriver final : public CGdiDeviceDriver {
  public:
diff --git a/core/fxge/win32/fx_win32_device.cpp b/core/fxge/win32/fx_win32_device.cpp
index 558c6c3..bbf907e 100644
--- a/core/fxge/win32/fx_win32_device.cpp
+++ b/core/fxge/win32/fx_win32_device.cpp
@@ -4,43 +4,23 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#include <crtdbg.h>
+#include "core/fxge/win32/win32_int.h"
 
-#include <algorithm>
 #include <memory>
-#include <vector>
 
 #include "core/fxcrt/fx_codepage.h"
-#include "core/fxcrt/fx_system.h"
-#include "core/fxcrt/maybe_owned.h"
-#include "core/fxge/cfx_fillrenderoptions.h"
 #include "core/fxge/cfx_folderfontinfo.h"
-#include "core/fxge/cfx_fontmgr.h"
 #include "core/fxge/cfx_gemodule.h"
-#include "core/fxge/cfx_graphstatedata.h"
 #include "core/fxge/cfx_windowsrenderdevice.h"
-#include "core/fxge/dib/cfx_imagerenderer.h"
-#include "core/fxge/dib/cstretchengine.h"
-#include "core/fxge/fx_font.h"
-#include "core/fxge/fx_freetype.h"
 #include "core/fxge/systemfontinfo_iface.h"
-#include "core/fxge/win32/cfx_windowsdib.h"
 #include "core/fxge/win32/cgdi_display_driver.h"
 #include "core/fxge/win32/cgdi_printer_driver.h"
 #include "core/fxge/win32/cps_printer_driver.h"
 #include "core/fxge/win32/ctext_only_printer_driver.h"
-#include "core/fxge/win32/win32_int.h"
-#include "third_party/base/notreached.h"
 #include "third_party/base/ptr_util.h"
-#include "third_party/base/span.h"
 #include "third_party/base/stl_util.h"
 #include "third_party/base/win/win_util.h"
 
-#if !defined(_SKIA_SUPPORT_)
-#include "core/fxge/agg/fx_agg_driver.h"
-#include "third_party/agg23/agg_clip_liang_barsky.h"
-#endif
-
 namespace {
 
 const struct {
@@ -89,235 +69,6 @@
   return false;
 }
 
-constexpr int FillTypeToGdiFillType(CFX_FillRenderOptions::FillType fill_type) {
-  return static_cast<int>(fill_type);
-}
-
-static_assert(FillTypeToGdiFillType(
-                  CFX_FillRenderOptions::FillType::kEvenOdd) == ALTERNATE,
-              "CFX_FillRenderOptions::FillType::kEvenOdd value mismatch");
-
-static_assert(
-    FillTypeToGdiFillType(CFX_FillRenderOptions::FillType::kWinding) == WINDING,
-    "CFX_FillRenderOptions::FillType::kWinding value mismatch");
-
-HPEN CreateExtPen(const CFX_GraphStateData* pGraphState,
-                  const CFX_Matrix* pMatrix,
-                  uint32_t argb) {
-  ASSERT(pGraphState);
-
-  float scale = 1.0f;
-  if (pMatrix) {
-    scale = fabs(pMatrix->a) > fabs(pMatrix->b) ? fabs(pMatrix->a)
-                                                : fabs(pMatrix->b);
-  }
-  float width = std::max(scale * pGraphState->m_LineWidth, 1.0f);
-
-  uint32_t PenStyle = PS_GEOMETRIC;
-  if (!pGraphState->m_DashArray.empty())
-    PenStyle |= PS_USERSTYLE;
-  else
-    PenStyle |= PS_SOLID;
-
-  switch (pGraphState->m_LineCap) {
-    case CFX_GraphStateData::LineCapButt:
-      PenStyle |= PS_ENDCAP_FLAT;
-      break;
-    case CFX_GraphStateData::LineCapRound:
-      PenStyle |= PS_ENDCAP_ROUND;
-      break;
-    case CFX_GraphStateData::LineCapSquare:
-      PenStyle |= PS_ENDCAP_SQUARE;
-      break;
-  }
-  switch (pGraphState->m_LineJoin) {
-    case CFX_GraphStateData::LineJoinMiter:
-      PenStyle |= PS_JOIN_MITER;
-      break;
-    case CFX_GraphStateData::LineJoinRound:
-      PenStyle |= PS_JOIN_ROUND;
-      break;
-    case CFX_GraphStateData::LineJoinBevel:
-      PenStyle |= PS_JOIN_BEVEL;
-      break;
-  }
-
-  FX_COLORREF colorref = ArgbToColorRef(argb);
-  LOGBRUSH lb;
-  lb.lbColor = colorref;
-  lb.lbStyle = BS_SOLID;
-  lb.lbHatch = 0;
-  std::vector<uint32_t> dashes;
-  if (!pGraphState->m_DashArray.empty()) {
-    dashes.resize(pGraphState->m_DashArray.size());
-    for (size_t i = 0; i < pGraphState->m_DashArray.size(); i++) {
-      dashes[i] = FXSYS_roundf(
-          pMatrix ? pMatrix->TransformDistance(pGraphState->m_DashArray[i])
-                  : pGraphState->m_DashArray[i]);
-      dashes[i] = std::max(dashes[i], 1U);
-    }
-  }
-  return ExtCreatePen(PenStyle, (DWORD)ceil(width), &lb,
-                      pGraphState->m_DashArray.size(),
-                      reinterpret_cast<const DWORD*>(dashes.data()));
-}
-
-HBRUSH CreateBrush(uint32_t argb) {
-  return CreateSolidBrush(ArgbToColorRef(argb));
-}
-
-void SetPathToDC(HDC hDC,
-                 const CFX_PathData* pPathData,
-                 const CFX_Matrix* pMatrix) {
-  BeginPath(hDC);
-
-  pdfium::span<const FX_PATHPOINT> points = pPathData->GetPoints();
-  for (size_t i = 0; i < points.size(); ++i) {
-    CFX_PointF pos = points[i].m_Point;
-    if (pMatrix)
-      pos = pMatrix->Transform(pos);
-
-    CFX_Point screen(FXSYS_roundf(pos.x), FXSYS_roundf(pos.y));
-    FXPT_TYPE point_type = points[i].m_Type;
-    if (point_type == FXPT_TYPE::MoveTo) {
-      MoveToEx(hDC, screen.x, screen.y, nullptr);
-    } else if (point_type == FXPT_TYPE::LineTo) {
-      if (points[i].m_Point == points[i - 1].m_Point)
-        screen.x++;
-
-      LineTo(hDC, screen.x, screen.y);
-    } else if (point_type == FXPT_TYPE::BezierTo) {
-      POINT lppt[3];
-      lppt[0].x = screen.x;
-      lppt[0].y = screen.y;
-
-      pos = points[i + 1].m_Point;
-      if (pMatrix)
-        pos = pMatrix->Transform(pos);
-
-      lppt[1].x = FXSYS_roundf(pos.x);
-      lppt[1].y = FXSYS_roundf(pos.y);
-
-      pos = points[i + 2].m_Point;
-      if (pMatrix)
-        pos = pMatrix->Transform(pos);
-
-      lppt[2].x = FXSYS_roundf(pos.x);
-      lppt[2].y = FXSYS_roundf(pos.y);
-      PolyBezierTo(hDC, lppt, 3);
-      i += 2;
-    }
-    if (points[i].m_CloseFigure)
-      CloseFigure(hDC);
-  }
-  EndPath(hDC);
-}
-
-#if defined(_SKIA_SUPPORT_)
-// TODO(caryclark)  This antigrain function is duplicated here to permit
-// removing the last remaining dependency. Eventually, this will be elminiated
-// altogether and replace by Skia code.
-
-struct rect_base {
-  float x1;
-  float y1;
-  float x2;
-  float y2;
-};
-
-unsigned clip_liang_barsky(float x1,
-                           float y1,
-                           float x2,
-                           float y2,
-                           const rect_base& clip_box,
-                           float* x,
-                           float* y) {
-  const float nearzero = 1e-30f;
-  float deltax = x2 - x1;
-  float deltay = y2 - y1;
-  unsigned np = 0;
-  if (deltax == 0)
-    deltax = (x1 > clip_box.x1) ? -nearzero : nearzero;
-  float xin, xout;
-  if (deltax > 0) {
-    xin = clip_box.x1;
-    xout = clip_box.x2;
-  } else {
-    xin = clip_box.x2;
-    xout = clip_box.x1;
-  }
-  float tinx = (xin - x1) / deltax;
-  if (deltay == 0)
-    deltay = (y1 > clip_box.y1) ? -nearzero : nearzero;
-  float yin, yout;
-  if (deltay > 0) {
-    yin = clip_box.y1;
-    yout = clip_box.y2;
-  } else {
-    yin = clip_box.y2;
-    yout = clip_box.y1;
-  }
-  float tiny = (yin - y1) / deltay;
-  float tin1, tin2;
-  if (tinx < tiny) {
-    tin1 = tinx;
-    tin2 = tiny;
-  } else {
-    tin1 = tiny;
-    tin2 = tinx;
-  }
-  if (tin1 <= 1.0f) {
-    if (0 < tin1) {
-      *x++ = xin;
-      *y++ = yin;
-      ++np;
-    }
-    if (tin2 <= 1.0f) {
-      float toutx = (xout - x1) / deltax;
-      float touty = (yout - y1) / deltay;
-      float tout1 = (toutx < touty) ? toutx : touty;
-      if (tin2 > 0 || tout1 > 0) {
-        if (tin2 <= tout1) {
-          if (tin2 > 0) {
-            if (tinx > tiny) {
-              *x++ = xin;
-              *y++ = y1 + (deltay * tinx);
-            } else {
-              *x++ = x1 + (deltax * tiny);
-              *y++ = yin;
-            }
-            ++np;
-          }
-          if (tout1 < 1.0f) {
-            if (toutx < touty) {
-              *x++ = xout;
-              *y++ = y1 + (deltay * toutx);
-            } else {
-              *x++ = x1 + (deltax * touty);
-              *y++ = yout;
-            }
-          } else {
-            *x++ = x2;
-            *y++ = y2;
-          }
-          ++np;
-        } else {
-          if (tinx > tiny) {
-            *x++ = xin;
-            *y++ = yout;
-          } else {
-            *x++ = xout;
-            *y++ = yin;
-          }
-          ++np;
-        }
-      }
-    }
-  }
-  return np;
-}
-#endif  //  defined(_SKIA_SUPPORT_)
-
 class CFX_Win32FallbackFontInfo final : public CFX_FolderFontInfo {
  public:
   CFX_Win32FallbackFontInfo() = default;
@@ -721,444 +472,6 @@
   return std::make_unique<CWin32Platform>();
 }
 
-CGdiDeviceDriver::CGdiDeviceDriver(HDC hDC, DeviceType device_type)
-    : m_hDC(hDC), m_DeviceType(device_type) {
-  auto* pPlatform =
-      static_cast<CWin32Platform*>(CFX_GEModule::Get()->GetPlatform());
-  SetStretchBltMode(m_hDC, pPlatform->m_bHalfTone ? HALFTONE : COLORONCOLOR);
-  DWORD obj_type = GetObjectType(m_hDC);
-  m_bMetafileDCType = obj_type == OBJ_ENHMETADC || obj_type == OBJ_ENHMETAFILE;
-  if (obj_type == OBJ_MEMDC) {
-    HBITMAP hBitmap = CreateBitmap(1, 1, 1, 1, nullptr);
-    hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap);
-    BITMAP bitmap;
-    GetObject(hBitmap, sizeof bitmap, &bitmap);
-    m_nBitsPerPixel = bitmap.bmBitsPixel;
-    m_Width = bitmap.bmWidth;
-    m_Height = abs(bitmap.bmHeight);
-    hBitmap = (HBITMAP)SelectObject(m_hDC, hBitmap);
-    DeleteObject(hBitmap);
-  } else {
-    m_nBitsPerPixel = ::GetDeviceCaps(m_hDC, BITSPIXEL);
-    m_Width = ::GetDeviceCaps(m_hDC, HORZRES);
-    m_Height = ::GetDeviceCaps(m_hDC, VERTRES);
-  }
-  if (m_DeviceType != DeviceType::kDisplay) {
-    m_RenderCaps = FXRC_BIT_MASK;
-  } else {
-    m_RenderCaps = FXRC_GET_BITS | FXRC_BIT_MASK;
-  }
-}
-
-CGdiDeviceDriver::~CGdiDeviceDriver() = default;
-
-DeviceType CGdiDeviceDriver::GetDeviceType() const {
-  return m_DeviceType;
-}
-
-int CGdiDeviceDriver::GetDeviceCaps(int caps_id) const {
-  switch (caps_id) {
-    case FXDC_PIXEL_WIDTH:
-      return m_Width;
-    case FXDC_PIXEL_HEIGHT:
-      return m_Height;
-    case FXDC_BITS_PIXEL:
-      return m_nBitsPerPixel;
-    case FXDC_RENDER_CAPS:
-      return m_RenderCaps;
-    default:
-      NOTREACHED();
-      return 0;
-  }
-}
-
-void CGdiDeviceDriver::SaveState() {
-  SaveDC(m_hDC);
-}
-
-void CGdiDeviceDriver::RestoreState(bool bKeepSaved) {
-  RestoreDC(m_hDC, -1);
-  if (bKeepSaved)
-    SaveDC(m_hDC);
-}
-
-bool CGdiDeviceDriver::GDI_SetDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap1,
-                                     const FX_RECT& src_rect,
-                                     int left,
-                                     int top) {
-  if (m_DeviceType == DeviceType::kPrinter) {
-    RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1->FlipImage(false, true);
-    if (!pBitmap)
-      return false;
-
-    if (pBitmap->IsCmykImage() && !pBitmap->ConvertFormat(FXDIB_Rgb))
-      return false;
-
-    LPBYTE pBuffer = pBitmap->GetBuffer();
-    ByteString info = CFX_WindowsDIB::GetBitmapInfo(pBitmap);
-    ((BITMAPINFOHEADER*)info.c_str())->biHeight *= -1;
-    FX_RECT dst_rect(0, 0, src_rect.Width(), src_rect.Height());
-    dst_rect.Intersect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
-    int dst_width = dst_rect.Width();
-    int dst_height = dst_rect.Height();
-    ::StretchDIBits(m_hDC, left, top, dst_width, dst_height, 0, 0, dst_width,
-                    dst_height, pBuffer, (BITMAPINFO*)info.c_str(),
-                    DIB_RGB_COLORS, SRCCOPY);
-    return true;
-  }
-
-  RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1;
-  if (pBitmap->IsCmykImage()) {
-    pBitmap = pBitmap->CloneConvert(FXDIB_Rgb);
-    if (!pBitmap)
-      return false;
-  }
-  LPBYTE pBuffer = pBitmap->GetBuffer();
-  ByteString info = CFX_WindowsDIB::GetBitmapInfo(pBitmap);
-  ::SetDIBitsToDevice(m_hDC, left, top, src_rect.Width(), src_rect.Height(),
-                      src_rect.left, pBitmap->GetHeight() - src_rect.bottom, 0,
-                      pBitmap->GetHeight(), pBuffer, (BITMAPINFO*)info.c_str(),
-                      DIB_RGB_COLORS);
-  return true;
-}
-
-bool CGdiDeviceDriver::GDI_StretchDIBits(
-    const RetainPtr<CFX_DIBitmap>& pBitmap1,
-    int dest_left,
-    int dest_top,
-    int dest_width,
-    int dest_height,
-    const FXDIB_ResampleOptions& options) {
-  RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1;
-  if (!pBitmap || dest_width == 0 || dest_height == 0)
-    return false;
-
-  if (pBitmap->IsCmykImage() && !pBitmap->ConvertFormat(FXDIB_Rgb))
-    return false;
-
-  ByteString info = CFX_WindowsDIB::GetBitmapInfo(pBitmap);
-  if ((int64_t)abs(dest_width) * abs(dest_height) <
-          (int64_t)pBitmap1->GetWidth() * pBitmap1->GetHeight() * 4 ||
-      options.bInterpolateBilinear || options.bInterpolateBicubic) {
-    SetStretchBltMode(m_hDC, HALFTONE);
-  } else {
-    SetStretchBltMode(m_hDC, COLORONCOLOR);
-  }
-  RetainPtr<CFX_DIBitmap> pToStrechBitmap = pBitmap;
-  if (m_DeviceType == DeviceType::kPrinter &&
-      ((int64_t)pBitmap->GetWidth() * pBitmap->GetHeight() >
-       (int64_t)abs(dest_width) * abs(dest_height))) {
-    pToStrechBitmap = pBitmap->StretchTo(dest_width, dest_height,
-                                         FXDIB_ResampleOptions(), nullptr);
-  }
-  ByteString toStrechBitmapInfo =
-      CFX_WindowsDIB::GetBitmapInfo(pToStrechBitmap);
-  ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height, 0, 0,
-                  pToStrechBitmap->GetWidth(), pToStrechBitmap->GetHeight(),
-                  pToStrechBitmap->GetBuffer(),
-                  (BITMAPINFO*)toStrechBitmapInfo.c_str(), DIB_RGB_COLORS,
-                  SRCCOPY);
-  return true;
-}
-
-bool CGdiDeviceDriver::GDI_StretchBitMask(
-    const RetainPtr<CFX_DIBitmap>& pBitmap1,
-    int dest_left,
-    int dest_top,
-    int dest_width,
-    int dest_height,
-    uint32_t bitmap_color) {
-  RetainPtr<CFX_DIBitmap> pBitmap = pBitmap1;
-  if (!pBitmap || dest_width == 0 || dest_height == 0)
-    return false;
-
-  int width = pBitmap->GetWidth(), height = pBitmap->GetHeight();
-  struct {
-    BITMAPINFOHEADER bmiHeader;
-    uint32_t bmiColors[2];
-  } bmi;
-  memset(&bmi.bmiHeader, 0, sizeof(BITMAPINFOHEADER));
-  bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
-  bmi.bmiHeader.biBitCount = 1;
-  bmi.bmiHeader.biCompression = BI_RGB;
-  bmi.bmiHeader.biHeight = -height;
-  bmi.bmiHeader.biPlanes = 1;
-  bmi.bmiHeader.biWidth = width;
-  if (m_nBitsPerPixel != 1) {
-    SetStretchBltMode(m_hDC, HALFTONE);
-  }
-  bmi.bmiColors[0] = 0xffffff;
-  bmi.bmiColors[1] = 0;
-
-  HBRUSH hPattern = CreateBrush(bitmap_color);
-  HBRUSH hOld = (HBRUSH)SelectObject(m_hDC, hPattern);
-
-  // In PDF, when image mask is 1, use device bitmap; when mask is 0, use brush
-  // bitmap.
-  // A complete list of the boolen operations is as follows:
-
-  /* P(bitmap_color)    S(ImageMask)    D(DeviceBitmap)    Result
-   *        0                 0                0              0
-   *        0                 0                1              0
-   *        0                 1                0              0
-   *        0                 1                1              1
-   *        1                 0                0              1
-   *        1                 0                1              1
-   *        1                 1                0              0
-   *        1                 1                1              1
-   */
-  // The boolen codes is B8. Based on
-  // http://msdn.microsoft.com/en-us/library/aa932106.aspx, the ROP3 code is
-  // 0xB8074A
-
-  ::StretchDIBits(m_hDC, dest_left, dest_top, dest_width, dest_height, 0, 0,
-                  width, height, pBitmap->GetBuffer(), (BITMAPINFO*)&bmi,
-                  DIB_RGB_COLORS, 0xB8074A);
-
-  SelectObject(m_hDC, hOld);
-  DeleteObject(hPattern);
-
-  return true;
-}
-
-bool CGdiDeviceDriver::GetClipBox(FX_RECT* pRect) {
-  return !!(::GetClipBox(m_hDC, (RECT*)pRect));
-}
-
-void CGdiDeviceDriver::DrawLine(float x1, float y1, float x2, float y2) {
-  if (!m_bMetafileDCType) {  // EMF drawing is not bound to the DC.
-    int startOutOfBoundsFlag = (x1 < 0) | ((x1 > m_Width) << 1) |
-                               ((y1 < 0) << 2) | ((y1 > m_Height) << 3);
-    int endOutOfBoundsFlag = (x2 < 0) | ((x2 > m_Width) << 1) |
-                             ((y2 < 0) << 2) | ((y2 > m_Height) << 3);
-    if (startOutOfBoundsFlag & endOutOfBoundsFlag)
-      return;
-
-    if (startOutOfBoundsFlag || endOutOfBoundsFlag) {
-      float x[2];
-      float y[2];
-      int np;
-#if defined(_SKIA_SUPPORT_)
-      // TODO(caryclark) temporary replacement of antigrain in line function
-      // to permit removing antigrain altogether
-      rect_base rect = {0.0f, 0.0f, (float)(m_Width), (float)(m_Height)};
-      np = clip_liang_barsky(x1, y1, x2, y2, rect, x, y);
-#else
-      pdfium::agg::rect_base<float> rect(0.0f, 0.0f, (float)(m_Width),
-                                         (float)(m_Height));
-      np = pdfium::agg::clip_liang_barsky<float>(x1, y1, x2, y2, rect, x, y);
-#endif
-      if (np == 0)
-        return;
-
-      if (np == 1) {
-        x2 = x[0];
-        y2 = y[0];
-      } else {
-        ASSERT(np == 2);
-        x1 = x[0];
-        y1 = y[0];
-        x2 = x[1];
-        y2 = y[1];
-      }
-    }
-  }
-
-  MoveToEx(m_hDC, FXSYS_roundf(x1), FXSYS_roundf(y1), nullptr);
-  LineTo(m_hDC, FXSYS_roundf(x2), FXSYS_roundf(y2));
-}
-
-bool CGdiDeviceDriver::DrawPath(const CFX_PathData* pPathData,
-                                const CFX_Matrix* pMatrix,
-                                const CFX_GraphStateData* pGraphState,
-                                uint32_t fill_color,
-                                uint32_t stroke_color,
-                                const CFX_FillRenderOptions& fill_options,
-                                BlendMode blend_type) {
-  if (blend_type != BlendMode::kNormal)
-    return false;
-
-  auto* pPlatform =
-      static_cast<CWin32Platform*>(CFX_GEModule::Get()->GetPlatform());
-  if (!(pGraphState || stroke_color == 0) &&
-      !pPlatform->m_GdiplusExt.IsAvailable()) {
-    CFX_FloatRect bbox_f = pPathData->GetBoundingBox();
-    if (pMatrix)
-      bbox_f = pMatrix->TransformRect(bbox_f);
-
-    FX_RECT bbox = bbox_f.GetInnerRect();
-    if (bbox.Width() <= 0) {
-      return DrawCosmeticLine(CFX_PointF(bbox.left, bbox.top),
-                              CFX_PointF(bbox.left, bbox.bottom + 1),
-                              fill_color, BlendMode::kNormal);
-    }
-    if (bbox.Height() <= 0) {
-      return DrawCosmeticLine(CFX_PointF(bbox.left, bbox.top),
-                              CFX_PointF(bbox.right + 1, bbox.top), fill_color,
-                              BlendMode::kNormal);
-    }
-  }
-  int fill_alpha = FXARGB_A(fill_color);
-  int stroke_alpha = FXARGB_A(stroke_color);
-  bool bDrawAlpha = (fill_alpha > 0 && fill_alpha < 255) ||
-                    (stroke_alpha > 0 && stroke_alpha < 255 && pGraphState);
-  if (!pPlatform->m_GdiplusExt.IsAvailable() && bDrawAlpha)
-    return false;
-
-  if (pPlatform->m_GdiplusExt.IsAvailable()) {
-    if (bDrawAlpha ||
-        ((m_DeviceType != DeviceType::kPrinter && !fill_options.full_cover) ||
-         (pGraphState && !pGraphState->m_DashArray.empty()))) {
-      if (!((!pMatrix || !pMatrix->WillScale()) && pGraphState &&
-            pGraphState->m_LineWidth == 1.0f &&
-            (pPathData->GetPoints().size() == 5 ||
-             pPathData->GetPoints().size() == 4) &&
-            pPathData->IsRect())) {
-        if (pPlatform->m_GdiplusExt.DrawPath(m_hDC, pPathData, pMatrix,
-                                             pGraphState, fill_color,
-                                             stroke_color, fill_options)) {
-          return true;
-        }
-      }
-    }
-  }
-  const bool fill =
-      fill_options.fill_type != CFX_FillRenderOptions::FillType::kNoFill;
-  HPEN hPen = nullptr;
-  HBRUSH hBrush = nullptr;
-  if (pGraphState && stroke_alpha) {
-    SetMiterLimit(m_hDC, pGraphState->m_MiterLimit, nullptr);
-    hPen = CreateExtPen(pGraphState, pMatrix, stroke_color);
-    hPen = (HPEN)SelectObject(m_hDC, hPen);
-  }
-  if (fill && fill_alpha) {
-    SetPolyFillMode(m_hDC, FillTypeToGdiFillType(fill_options.fill_type));
-    hBrush = CreateBrush(fill_color);
-    hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
-  }
-  if (pPathData->GetPoints().size() == 2 && pGraphState &&
-      !pGraphState->m_DashArray.empty()) {
-    CFX_PointF pos1 = pPathData->GetPoint(0);
-    CFX_PointF pos2 = pPathData->GetPoint(1);
-    if (pMatrix) {
-      pos1 = pMatrix->Transform(pos1);
-      pos2 = pMatrix->Transform(pos2);
-    }
-    DrawLine(pos1.x, pos1.y, pos2.x, pos2.y);
-  } else {
-    SetPathToDC(m_hDC, pPathData, pMatrix);
-    if (pGraphState && stroke_alpha) {
-      if (fill && fill_alpha) {
-        if (fill_options.text_mode) {
-          StrokeAndFillPath(m_hDC);
-        } else {
-          FillPath(m_hDC);
-          SetPathToDC(m_hDC, pPathData, pMatrix);
-          StrokePath(m_hDC);
-        }
-      } else {
-        StrokePath(m_hDC);
-      }
-    } else if (fill && fill_alpha) {
-      FillPath(m_hDC);
-    }
-  }
-  if (hPen) {
-    hPen = (HPEN)SelectObject(m_hDC, hPen);
-    DeleteObject(hPen);
-  }
-  if (hBrush) {
-    hBrush = (HBRUSH)SelectObject(m_hDC, hBrush);
-    DeleteObject(hBrush);
-  }
-  return true;
-}
-
-bool CGdiDeviceDriver::FillRectWithBlend(const FX_RECT& rect,
-                                         uint32_t fill_color,
-                                         BlendMode blend_type) {
-  if (blend_type != BlendMode::kNormal)
-    return false;
-
-  int alpha;
-  FX_COLORREF colorref;
-  std::tie(alpha, colorref) = ArgbToAlphaAndColorRef(fill_color);
-  if (alpha == 0)
-    return true;
-
-  if (alpha < 255)
-    return false;
-
-  HBRUSH hBrush = CreateSolidBrush(colorref);
-  const RECT* pRect = reinterpret_cast<const RECT*>(&rect);
-  ::FillRect(m_hDC, pRect, hBrush);
-  DeleteObject(hBrush);
-  return true;
-}
-
-void CGdiDeviceDriver::SetBaseClip(const FX_RECT& rect) {
-  m_BaseClipBox = rect;
-}
-
-bool CGdiDeviceDriver::SetClip_PathFill(
-    const CFX_PathData* pPathData,
-    const CFX_Matrix* pMatrix,
-    const CFX_FillRenderOptions& fill_options) {
-  if (pPathData->GetPoints().size() == 5) {
-    Optional<CFX_FloatRect> maybe_rectf = pPathData->GetRect(pMatrix);
-    if (maybe_rectf.has_value()) {
-      FX_RECT rect = maybe_rectf.value().GetOuterRect();
-      // Can easily apply base clip to protect against wildly large rectangular
-      // clips. crbug.com/1019026
-      if (m_BaseClipBox.has_value())
-        rect.Intersect(m_BaseClipBox.value());
-      return IntersectClipRect(m_hDC, rect.left, rect.top, rect.right,
-                               rect.bottom) != ERROR;
-    }
-  }
-  SetPathToDC(m_hDC, pPathData, pMatrix);
-  SetPolyFillMode(m_hDC, FillTypeToGdiFillType(fill_options.fill_type));
-  SelectClipPath(m_hDC, RGN_AND);
-  return true;
-}
-
-bool CGdiDeviceDriver::SetClip_PathStroke(
-    const CFX_PathData* pPathData,
-    const CFX_Matrix* pMatrix,
-    const CFX_GraphStateData* pGraphState) {
-  HPEN hPen = CreateExtPen(pGraphState, pMatrix, 0xff000000);
-  hPen = (HPEN)SelectObject(m_hDC, hPen);
-  SetPathToDC(m_hDC, pPathData, pMatrix);
-  WidenPath(m_hDC);
-  SetPolyFillMode(m_hDC, WINDING);
-  bool ret = !!SelectClipPath(m_hDC, RGN_AND);
-  hPen = (HPEN)SelectObject(m_hDC, hPen);
-  DeleteObject(hPen);
-  return ret;
-}
-
-bool CGdiDeviceDriver::DrawCosmeticLine(const CFX_PointF& ptMoveTo,
-                                        const CFX_PointF& ptLineTo,
-                                        uint32_t color,
-                                        BlendMode blend_type) {
-  if (blend_type != BlendMode::kNormal)
-    return false;
-
-  int alpha;
-  FX_COLORREF colorref;
-  std::tie(alpha, colorref) = ArgbToAlphaAndColorRef(color);
-  if (alpha == 0)
-    return true;
-
-  HPEN hPen = CreatePen(PS_SOLID, 1, colorref);
-  hPen = (HPEN)SelectObject(m_hDC, hPen);
-  MoveToEx(m_hDC, FXSYS_roundf(ptMoveTo.x), FXSYS_roundf(ptMoveTo.y), nullptr);
-  LineTo(m_hDC, FXSYS_roundf(ptLineTo.x), FXSYS_roundf(ptLineTo.y));
-  hPen = (HPEN)SelectObject(m_hDC, hPen);
-  DeleteObject(hPen);
-  return true;
-}
-
 CFX_WindowsRenderDevice::CFX_WindowsRenderDevice(
     HDC hDC,
     const EncoderIface* pEncoderIface) {
diff --git a/core/fxge/win32/fx_win32_device_embeddertest.cpp b/core/fxge/win32/fx_win32_device_embeddertest.cpp
index 68e43ad..b0df665 100644
--- a/core/fxge/win32/fx_win32_device_embeddertest.cpp
+++ b/core/fxge/win32/fx_win32_device_embeddertest.cpp
@@ -2,13 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "core/fxge/win32/win32_int.h"
+#include "core/fxge/cfx_windowsrenderdevice.h"
 
 #include <windows.h>
 
 #include <memory>
 
 #include "core/fxge/cfx_fillrenderoptions.h"
+#include "core/fxge/cfx_pathdata.h"
 #include "testing/embedder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/core/fxge/win32/win32_int.h b/core/fxge/win32/win32_int.h
index fa925c2..7ca11ff 100644
--- a/core/fxge/win32/win32_int.h
+++ b/core/fxge/win32/win32_int.h
@@ -10,19 +10,10 @@
 #include <windows.h>
 
 #include <memory>
-#include <vector>
 
 #include "core/fxcrt/retain_ptr.h"
 #include "core/fxge/cfx_gemodule.h"
-#include "core/fxge/cfx_pathdata.h"
-#include "core/fxge/cfx_windowsrenderdevice.h"
-#include "core/fxge/renderdevicedriver_iface.h"
 #include "core/fxge/win32/cgdi_plus_ext.h"
-#include "third_party/base/optional.h"
-
-class CFX_ImageRenderer;
-class TextCharPos;
-struct CFX_FillRenderOptions;
 
 RetainPtr<CFX_DIBitmap> FX_WindowsDIB_LoadFromBuf(BITMAPINFO* pbmi,
                                                   LPVOID pData,
@@ -41,66 +32,4 @@
   CGdiplusExt m_GdiplusExt;
 };
 
-class CGdiDeviceDriver : public RenderDeviceDriverIface {
- protected:
-  CGdiDeviceDriver(HDC hDC, DeviceType device_type);
-  ~CGdiDeviceDriver() override;
-
-  // RenderDeviceDriverIface:
-  DeviceType GetDeviceType() const override;
-  int GetDeviceCaps(int caps_id) const override;
-  void SaveState() override;
-  void RestoreState(bool bKeepSaved) override;
-  void SetBaseClip(const FX_RECT& rect) override;
-  bool SetClip_PathFill(const CFX_PathData* pPathData,
-                        const CFX_Matrix* pObject2Device,
-                        const CFX_FillRenderOptions& fill_options) override;
-  bool SetClip_PathStroke(const CFX_PathData* pPathData,
-                          const CFX_Matrix* pObject2Device,
-                          const CFX_GraphStateData* pGraphState) override;
-  bool DrawPath(const CFX_PathData* pPathData,
-                const CFX_Matrix* pObject2Device,
-                const CFX_GraphStateData* pGraphState,
-                uint32_t fill_color,
-                uint32_t stroke_color,
-                const CFX_FillRenderOptions& fill_options,
-                BlendMode blend_type) override;
-  bool FillRectWithBlend(const FX_RECT& rect,
-                         uint32_t fill_color,
-                         BlendMode blend_type) override;
-  bool DrawCosmeticLine(const CFX_PointF& ptMoveTo,
-                        const CFX_PointF& ptLineTo,
-                        uint32_t color,
-                        BlendMode blend_type) override;
-  bool GetClipBox(FX_RECT* pRect) override;
-
-  void DrawLine(float x1, float y1, float x2, float y2);
-
-  bool GDI_SetDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap,
-                     const FX_RECT& src_rect,
-                     int left,
-                     int top);
-  bool GDI_StretchDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap,
-                         int dest_left,
-                         int dest_top,
-                         int dest_width,
-                         int dest_height,
-                         const FXDIB_ResampleOptions& options);
-  bool GDI_StretchBitMask(const RetainPtr<CFX_DIBitmap>& pBitmap,
-                          int dest_left,
-                          int dest_top,
-                          int dest_width,
-                          int dest_height,
-                          uint32_t bitmap_color);
-
-  const HDC m_hDC;
-  bool m_bMetafileDCType;
-  int m_Width;
-  int m_Height;
-  int m_nBitsPerPixel;
-  const DeviceType m_DeviceType;
-  int m_RenderCaps;
-  pdfium::Optional<FX_RECT> m_BaseClipBox;
-};
-
 #endif  // CORE_FXGE_WIN32_WIN32_INT_H_