Break remaining dependency from fxge to fxcodec.

Pass a struct of function pointers down to CFX_PSRenderer, so it can
access encoding functions without directly calling them.

Change-Id: I7fd1ddc75496f47d3a3ff32bb13a486b0db0da29
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/55154
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxcodec/BUILD.gn b/core/fxcodec/BUILD.gn
index 8f4d7b8..3543360 100644
--- a/core/fxcodec/BUILD.gn
+++ b/core/fxcodec/BUILD.gn
@@ -78,7 +78,6 @@
     "../fxge",
     "//third_party:jpeg",
   ]
-  allow_circular_includes_from = []
 
   if (pdf_enable_xfa) {
     sources += [
@@ -125,10 +124,6 @@
     }
   }
 
-  if (is_win) {
-    allow_circular_includes_from += [ "../fxge" ]
-  }
-
   visibility = [ "../../*" ]
 }
 
diff --git a/core/fxge/cfx_windowsrenderdevice.h b/core/fxge/cfx_windowsrenderdevice.h
index ef4dc39..d2ca8a0 100644
--- a/core/fxge/cfx_windowsrenderdevice.h
+++ b/core/fxge/cfx_windowsrenderdevice.h
@@ -21,6 +21,7 @@
 };
 
 class RenderDeviceDriverIface;
+struct EncoderIface;
 
 #if defined(PDFIUM_PRINT_TEXT_WITH_GDI)
 typedef void (*PDFiumEnsureTypefaceCharactersAccessible)(const LOGFONT* font,
@@ -35,11 +36,13 @@
 
 class CFX_WindowsRenderDevice final : public CFX_RenderDevice {
  public:
-  explicit CFX_WindowsRenderDevice(HDC hDC);
+  CFX_WindowsRenderDevice(HDC hDC, const EncoderIface* pEncoderIface);
   ~CFX_WindowsRenderDevice() override;
 
  private:
-  static RenderDeviceDriverIface* CreateDriver(HDC hDC);
+  static RenderDeviceDriverIface* CreateDriver(
+      HDC hDC,
+      const EncoderIface* pEncoderIface);
 };
 
 #endif  // CORE_FXGE_CFX_WINDOWSRENDERDEVICE_H_
diff --git a/core/fxge/win32/cfx_psrenderer.cpp b/core/fxge/win32/cfx_psrenderer.cpp
index 15efa25..3ae1df6 100644
--- a/core/fxge/win32/cfx_psrenderer.cpp
+++ b/core/fxge/win32/cfx_psrenderer.cpp
@@ -11,10 +11,6 @@
 #include <sstream>
 #include <utility>
 
-#include "core/fxcodec/codec/ccodec_basicmodule.h"
-#include "core/fxcodec/codec/ccodec_faxmodule.h"
-#include "core/fxcodec/codec/ccodec_flatemodule.h"
-#include "core/fxcodec/codec/ccodec_jpegmodule.h"
 #include "core/fxcrt/maybe_owned.h"
 #include "core/fxge/cfx_fontcache.h"
 #include "core/fxge/cfx_gemodule.h"
@@ -27,64 +23,6 @@
 #include "core/fxge/win32/cpsoutput.h"
 #include "third_party/base/ptr_util.h"
 
-namespace {
-
-bool FaxCompressData(std::unique_ptr<uint8_t, FxFreeDeleter> src_buf,
-                     int width,
-                     int height,
-                     std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
-                     uint32_t* dest_size) {
-  if (width * height <= 128) {
-    *dest_buf = std::move(src_buf);
-    *dest_size = (width + 7) / 8 * height;
-    return false;
-  }
-
-  CCodec_FaxModule::FaxEncode(src_buf.get(), width, height, (width + 7) / 8,
-                              dest_buf, dest_size);
-  return true;
-}
-
-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;
-
-  uint8_t* dest_buf = nullptr;
-  uint32_t dest_size = src_size;
-  if (PSLevel >= 3) {
-    std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf_unique;
-    if (CCodec_FlateModule::Encode(src_buf, src_size, &dest_buf_unique,
-                                   &dest_size)) {
-      dest_buf = dest_buf_unique.release();
-      *filter = "/FlateDecode filter ";
-    }
-  } else {
-    std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf_unique;
-    if (CCodec_BasicModule::RunLengthEncode({src_buf, src_size},
-                                            &dest_buf_unique, &dest_size)) {
-      dest_buf = dest_buf_unique.release();
-      *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 {
   UnownedPtr<CFX_Font> m_pFont;
   uint32_t m_GlyphIndex;
@@ -98,7 +36,8 @@
   PSGlyph m_Glyphs[256];
 };
 
-CFX_PSRenderer::CFX_PSRenderer() = default;
+CFX_PSRenderer::CFX_PSRenderer(const EncoderIface* pEncoderIface)
+    : m_pEncoderIface(pEncoderIface) {}
 
 CFX_PSRenderer::~CFX_PSRenderer() = default;
 
@@ -454,7 +393,8 @@
     size_t output_size = 0;
     const char* filter = nullptr;
     if ((m_PSLevel == 2 || options.bLossy) &&
-        CCodec_JpegModule::JpegEncode(pConverted, &output_buf, &output_size)) {
+        m_pEncoderIface->pJpegEncodeFunc(pConverted, &output_buf,
+                                         &output_size)) {
       filter = "/DCTDecode filter ";
     }
     if (!filter) {
@@ -477,8 +417,8 @@
       }
       uint8_t* compressed_buf;
       uint32_t compressed_size;
-      PSCompressData(m_PSLevel, output_buf, output_size, &compressed_buf,
-                     &compressed_size, &filter);
+      PSCompressData(output_buf, output_size, &compressed_buf, &compressed_size,
+                     &filter);
       if (output_buf != compressed_buf)
         FX_Free(output_buf);
 
@@ -680,11 +620,65 @@
   return true;
 }
 
+bool CFX_PSRenderer::FaxCompressData(
+    std::unique_ptr<uint8_t, FxFreeDeleter> src_buf,
+    int width,
+    int height,
+    std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
+    uint32_t* dest_size) const {
+  if (width * height <= 128) {
+    *dest_buf = std::move(src_buf);
+    *dest_size = (width + 7) / 8 * height;
+    return false;
+  }
+
+  m_pEncoderIface->pFaxEncodeFunc(src_buf.get(), width, height, (width + 7) / 8,
+                                  dest_buf, dest_size);
+  return true;
+}
+
+void CFX_PSRenderer::PSCompressData(uint8_t* src_buf,
+                                    uint32_t src_size,
+                                    uint8_t** output_buf,
+                                    uint32_t* output_size,
+                                    const char** filter) const {
+  *output_buf = src_buf;
+  *output_size = src_size;
+  *filter = "";
+  if (src_size < 1024)
+    return;
+
+  uint8_t* dest_buf = nullptr;
+  uint32_t dest_size = src_size;
+  if (m_PSLevel >= 3) {
+    std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf_unique;
+    if (m_pEncoderIface->pFlateEncodeFunc(src_buf, src_size, &dest_buf_unique,
+                                          &dest_size)) {
+      dest_buf = dest_buf_unique.release();
+      *filter = "/FlateDecode filter ";
+    }
+  } else {
+    std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf_unique;
+    if (m_pEncoderIface->pRunLengthEncodeFunc({src_buf, src_size},
+                                              &dest_buf_unique, &dest_size)) {
+      dest_buf = dest_buf_unique.release();
+      *filter = "/RunLengthDecode filter ";
+    }
+  }
+  if (dest_size < src_size) {
+    *output_buf = dest_buf;
+    *output_size = dest_size;
+  } else {
+    *filter = nullptr;
+    FX_Free(dest_buf);
+  }
+}
+
 void CFX_PSRenderer::WritePSBinary(const uint8_t* data, int len) {
   std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
   uint32_t dest_size;
-  if (CCodec_BasicModule::A85Encode({data, static_cast<size_t>(len)}, &dest_buf,
-                                    &dest_size)) {
+  if (m_pEncoderIface->pA85EncodeFunc({data, static_cast<size_t>(len)},
+                                      &dest_buf, &dest_size)) {
     m_pStream->WriteBlock(dest_buf.get(), dest_size);
   } else {
     m_pStream->WriteBlock(data, len);
diff --git a/core/fxge/win32/cfx_psrenderer.h b/core/fxge/win32/cfx_psrenderer.h
index a9b9f10..55dad2f 100644
--- a/core/fxge/win32/cfx_psrenderer.h
+++ b/core/fxge/win32/cfx_psrenderer.h
@@ -24,9 +24,32 @@
 class TextCharPos;
 struct FXDIB_ResampleOptions;
 
+struct EncoderIface {
+  bool (*pA85EncodeFunc)(pdfium::span<const uint8_t> src_buf,
+                         std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
+                         uint32_t* dest_size);
+  void (*pFaxEncodeFunc)(const uint8_t* src_buf,
+                         int width,
+                         int height,
+                         int pitch,
+                         std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
+                         uint32_t* dest_size);
+  bool (*pFlateEncodeFunc)(const uint8_t* src_buf,
+                           uint32_t src_size,
+                           std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
+                           uint32_t* dest_size);
+  bool (*pJpegEncodeFunc)(const RetainPtr<CFX_DIBBase>& pSource,
+                          uint8_t** dest_buf,
+                          size_t* dest_size);
+  bool (*pRunLengthEncodeFunc)(
+      pdfium::span<const uint8_t> src_buf,
+      std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
+      uint32_t* dest_size);
+};
+
 class CFX_PSRenderer {
  public:
-  CFX_PSRenderer();
+  explicit CFX_PSRenderer(const EncoderIface* pEncoderIface);
   ~CFX_PSRenderer();
 
   void Init(const RetainPtr<IFX_RetainableWriteStream>& stream,
@@ -83,6 +106,16 @@
                        const TextCharPos& charpos,
                        int* ps_fontnum,
                        int* ps_glyphindex);
+  bool FaxCompressData(std::unique_ptr<uint8_t, FxFreeDeleter> src_buf,
+                       int width,
+                       int height,
+                       std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
+                       uint32_t* dest_size) const;
+  void PSCompressData(uint8_t* src_buf,
+                      uint32_t src_size,
+                      uint8_t** output_buf,
+                      uint32_t* output_size,
+                      const char** filter) const;
   void WritePSBinary(const uint8_t* data, int len);
   void WriteToStream(std::ostringstream* stringStream);
 
@@ -94,6 +127,7 @@
   uint32_t m_LastColor = 0;
   FX_RECT m_ClipBox;
   CFX_GraphStateData m_CurGraphState;
+  const EncoderIface* const m_pEncoderIface;
   RetainPtr<IFX_RetainableWriteStream> m_pStream;
   std::vector<std::unique_ptr<CPSFont>> m_PSFontList;
   std::vector<FX_RECT> m_ClipBoxStack;
diff --git a/core/fxge/win32/fx_win32_device.cpp b/core/fxge/win32/fx_win32_device.cpp
index 2b53b61..9744857 100644
--- a/core/fxge/win32/fx_win32_device.cpp
+++ b/core/fxge/win32/fx_win32_device.cpp
@@ -1337,15 +1337,18 @@
   return false;
 }
 
-CFX_WindowsRenderDevice::CFX_WindowsRenderDevice(HDC hDC) {
-  SetDeviceDriver(pdfium::WrapUnique(CreateDriver(hDC)));
+CFX_WindowsRenderDevice::CFX_WindowsRenderDevice(
+    HDC hDC,
+    const EncoderIface* pEncoderIface) {
+  SetDeviceDriver(pdfium::WrapUnique(CreateDriver(hDC, pEncoderIface)));
 }
 
 CFX_WindowsRenderDevice::~CFX_WindowsRenderDevice() = default;
 
 // static
 RenderDeviceDriverIface* CFX_WindowsRenderDevice::CreateDriver(
-    HDC hDC) {
+    HDC hDC,
+    const EncoderIface* pEncoderIface) {
   int device_type = ::GetDeviceCaps(hDC, TECHNOLOGY);
   int obj_type = ::GetObjectType(hDC);
   bool use_printer = device_type == DT_RASPRINTER ||
@@ -1361,5 +1364,5 @@
   if (g_pdfium_print_mode == WindowsPrintMode::kModeTextOnly)
     return new CTextOnlyPrinterDriver(hDC);
 
-  return new CPSPrinterDriver(hDC, g_pdfium_print_mode, false);
+  return new CPSPrinterDriver(hDC, g_pdfium_print_mode, false, pEncoderIface);
 }
diff --git a/core/fxge/win32/fx_win32_print.cpp b/core/fxge/win32/fx_win32_print.cpp
index b6dd416..8ebcec1 100644
--- a/core/fxge/win32/fx_win32_print.cpp
+++ b/core/fxge/win32/fx_win32_print.cpp
@@ -332,8 +332,9 @@
 
 CPSPrinterDriver::CPSPrinterDriver(HDC hDC,
                                    WindowsPrintMode mode,
-                                   bool bCmykOutput)
-    : m_hDC(hDC), m_bCmykOutput(bCmykOutput) {
+                                   bool bCmykOutput,
+                                   const EncoderIface* pEncoderIface)
+    : m_hDC(hDC), m_bCmykOutput(bCmykOutput), m_PSRenderer(pEncoderIface) {
   // |mode| should be PostScript.
   ASSERT(mode == WindowsPrintMode::kModePostScript2 ||
          mode == WindowsPrintMode::kModePostScript3 ||
diff --git a/core/fxge/win32/win32_int.h b/core/fxge/win32/win32_int.h
index 444c1dd..a021677 100644
--- a/core/fxge/win32/win32_int.h
+++ b/core/fxge/win32/win32_int.h
@@ -213,7 +213,10 @@
 
 class CPSPrinterDriver final : public RenderDeviceDriverIface {
  public:
-  CPSPrinterDriver(HDC hDC, WindowsPrintMode mode, bool bCmykOutput);
+  CPSPrinterDriver(HDC hDC,
+                   WindowsPrintMode mode,
+                   bool bCmykOutput,
+                   const EncoderIface* pEncoderIface);
   ~CPSPrinterDriver() override;
 
  private:
diff --git a/fpdfsdk/BUILD.gn b/fpdfsdk/BUILD.gn
index 0194ee5..786cc8f 100644
--- a/fpdfsdk/BUILD.gn
+++ b/fpdfsdk/BUILD.gn
@@ -83,6 +83,7 @@
     "../core/fpdfapi/render",
     "../core/fpdfdoc",
     "../core/fpdftext",
+    "../core/fxcodec",
     "../core/fxcrt",
     "../core/fxge",
     "../fxjs",
diff --git a/fpdfsdk/fpdf_view.cpp b/fpdfsdk/fpdf_view.cpp
index 3186779..82fdcd3 100644
--- a/fpdfsdk/fpdf_view.cpp
+++ b/fpdfsdk/fpdf_view.cpp
@@ -51,7 +51,12 @@
 #endif  // PDF_ENABLE_XFA
 
 #if defined(OS_WIN)
+#include "core/fxcodec/codec/ccodec_basicmodule.h"
+#include "core/fxcodec/codec/ccodec_faxmodule.h"
+#include "core/fxcodec/codec/ccodec_flatemodule.h"
+#include "core/fxcodec/codec/ccodec_jpegmodule.h"
 #include "core/fxge/cfx_windowsrenderdevice.h"
+#include "core/fxge/win32/cfx_psrenderer.h"
 #include "public/fpdf_edit.h"
 
 // These checks are here because core/ and public/ cannot depend on each other.
@@ -75,6 +80,13 @@
 
 bool g_bLibraryInitialized = false;
 
+#if defined(OS_WIN)
+constexpr EncoderIface kEncoderIface = {
+    CCodec_BasicModule::A85Encode, CCodec_FaxModule::FaxEncode,
+    CCodec_FlateModule::Encode, CCodec_JpegModule::JpegEncode,
+    CCodec_BasicModule::RunLengthEncode};
+#endif  // defined(OS_WIN)
+
 void RenderPageImpl(CPDF_PageRenderContext* pContext,
                     CPDF_Page* pPage,
                     const CFX_Matrix& matrix,
@@ -545,7 +557,8 @@
       pContext->m_pOptions->GetOptions().bBreakForMasks = true;
     }
   } else {
-    pContext->m_pDevice = pdfium::MakeUnique<CFX_WindowsRenderDevice>(dc);
+    pContext->m_pDevice =
+        pdfium::MakeUnique<CFX_WindowsRenderDevice>(dc, &kEncoderIface);
   }
 
   RenderPageWithContext(pContext, page, start_x, start_y, size_x, size_y,
@@ -572,7 +585,8 @@
     // pause after each image mask.
     pPage->SetRenderContext(pdfium::MakeUnique<CPDF_PageRenderContext>());
     pContext = pPage->GetRenderContext();
-    pContext->m_pDevice = pdfium::MakeUnique<CFX_WindowsRenderDevice>(dc);
+    pContext->m_pDevice =
+        pdfium::MakeUnique<CFX_WindowsRenderDevice>(dc, &kEncoderIface);
     pContext->m_pOptions = pdfium::MakeUnique<CPDF_RenderOptions>();
     pContext->m_pOptions->GetOptions().bBreakForMasks = true;
 
@@ -589,7 +603,7 @@
       pContext->m_pRenderer->Continue(nullptr);
     }
   } else if (bNewBitmap) {
-    CFX_WindowsRenderDevice WinDC(dc);
+    CFX_WindowsRenderDevice WinDC(dc, &kEncoderIface);
     bool bitsStretched = false;
     if (WinDC.GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) {
       auto pDst = pdfium::MakeRetain<CFX_DIBitmap>();