Add CFX_SkiaDeviceDriver(SkCanvas*) constructor

Adds a new CFX_SkiaDeviceDriver constructor that accepts an (unowned)
SkCanvas. This allows CFX_SkiaDeviceDriver to use any SkCanvas
implementation, rather than just one backed by SkBitmap or
SkPictureRecorder.

Removes internal APIs that use SkPictureRecorder, as all APIs other than
FPDF_RenderPageSkp() only need an SkCanvas.

For the constructor accepting a CFX_DIBitmap, replaces the (owned)
SkCanvas wrapping an SkBitmap with the (unowned) SkCanvas associated
with a raster SkSurface. This makes the SkCanvas uniformly unowned,
eliminating a special case in the destructor.

Bug: pdfium:2034
Change-Id: I2fb4420807fd3a763b59bde889758d4fa52ab3e3
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/108071
Reviewed-by: Nigi <nigi@chromium.org>
Commit-Queue: Nigi <nigi@chromium.org>
Auto-Submit: K. Moon <kmoon@chromium.org>
diff --git a/core/fxge/cfx_defaultrenderdevice.h b/core/fxge/cfx_defaultrenderdevice.h
index f9c20fe..112c4c7 100644
--- a/core/fxge/cfx_defaultrenderdevice.h
+++ b/core/fxge/cfx_defaultrenderdevice.h
@@ -13,8 +13,7 @@
 #include "core/fxge/cfx_renderdevice.h"
 #include "core/fxge/dib/fx_dib.h"
 
-class SkPictureRecorder;
-struct SkRect;
+class SkCanvas;
 
 class CFX_DefaultRenderDevice final : public CFX_RenderDevice {
  public:
@@ -34,9 +33,8 @@
               RetainPtr<CFX_DIBitmap> pBackdropBitmap);
 
 #if defined(_SKIA_SUPPORT_)
-  bool AttachRecorder(SkPictureRecorder* recorder);
+  bool AttachCanvas(SkCanvas* canvas);
   void Clear(uint32_t color);
-  std::unique_ptr<SkPictureRecorder> CreateRecorder(const SkRect& bounds);
   bool SetBitsWithMask(const RetainPtr<CFX_DIBBase>& pBitmap,
                        const RetainPtr<CFX_DIBBase>& pMask,
                        int left,
diff --git a/core/fxge/skia/fx_skia_device.cpp b/core/fxge/skia/fx_skia_device.cpp
index a8d22eb..c600e3f 100644
--- a/core/fxge/skia/fx_skia_device.cpp
+++ b/core/fxge/skia/fx_skia_device.cpp
@@ -64,13 +64,13 @@
 #include "third_party/skia/include/core/SkPath.h"
 #include "third_party/skia/include/core/SkPathEffect.h"
 #include "third_party/skia/include/core/SkPathUtils.h"
-#include "third_party/skia/include/core/SkPictureRecorder.h"
 #include "third_party/skia/include/core/SkRSXform.h"
 #include "third_party/skia/include/core/SkRect.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "third_party/skia/include/core/SkSamplingOptions.h"
 #include "third_party/skia/include/core/SkShader.h"
 #include "third_party/skia/include/core/SkStream.h"
+#include "third_party/skia/include/core/SkSurface.h"
 #include "third_party/skia/include/core/SkTextBlob.h"
 #include "third_party/skia/include/core/SkTypeface.h"
 #include "third_party/skia/include/effects/SkDashPathEffect.h"
@@ -832,10 +832,8 @@
     bool bGroupKnockout)
     : m_pBitmap(std::move(pBitmap)),
       m_pBackdropBitmap(pBackdropBitmap),
-      m_pRecorder(nullptr),
       m_bRgbByteOrder(bRgbByteOrder),
       m_bGroupKnockout(bGroupKnockout) {
-  SkBitmap skBitmap;
   SkColorType color_type;
   const int bpp = m_pBitmap->GetBPP();
   if (bpp == 8) {
@@ -865,14 +863,13 @@
   SkImageInfo imageInfo =
       SkImageInfo::Make(m_pBitmap->GetWidth(), m_pBitmap->GetHeight(),
                         color_type, kPremul_SkAlphaType);
-  skBitmap.installPixels(imageInfo, m_pBitmap->GetBuffer().data(),
-                         m_pBitmap->GetPitch());
-  m_pCanvas = new SkCanvas(skBitmap);
+  surface_ = SkSurfaces::WrapPixels(imageInfo, m_pBitmap->GetBuffer().data(),
+                                    m_pBitmap->GetPitch());
+  m_pCanvas = surface_->getCanvas();
 }
 
-CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(SkPictureRecorder* recorder)
-    : m_pRecorder(recorder), m_bGroupKnockout(false) {
-  m_pCanvas = m_pRecorder->getRecordingCanvas();
+CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(SkCanvas* canvas)
+    : m_pCanvas(canvas), m_bGroupKnockout(false) {
   int width = m_pCanvas->imageInfo().width();
   int height = m_pCanvas->imageInfo().height();
   DCHECK_EQ(kUnknown_SkColorType, m_pCanvas->imageInfo().colorType());
@@ -896,10 +893,6 @@
                                       height, m_pBitmap, /*src_left=*/0,
                                       /*src_top=*/0);
   }
-
-  if (!m_pRecorder) {
-    delete m_pCanvas.ExtractAsDangling();
-  }
 }
 
 bool CFX_SkiaDeviceDriver::DrawDeviceText(
@@ -1809,15 +1802,6 @@
   static_cast<CFX_SkiaDeviceDriver*>(GetDeviceDriver())->Clear(color);
 }
 
-std::unique_ptr<SkPictureRecorder> CFX_DefaultRenderDevice::CreateRecorder(
-    const SkRect& bounds) {
-  auto recorder = std::make_unique<SkPictureRecorder>();
-  recorder->beginRecording(bounds);
-
-  SetDeviceDriver(std::make_unique<CFX_SkiaDeviceDriver>(recorder.get()));
-  return recorder;
-}
-
 bool CFX_DefaultRenderDevice::AttachSkiaImpl(
     RetainPtr<CFX_DIBitmap> pBitmap,
     bool bRgbByteOrder,
@@ -1836,10 +1820,11 @@
   return true;
 }
 
-bool CFX_DefaultRenderDevice::AttachRecorder(SkPictureRecorder* recorder) {
-  if (!recorder)
+bool CFX_DefaultRenderDevice::AttachCanvas(SkCanvas* canvas) {
+  if (!canvas) {
     return false;
-  SetDeviceDriver(std::make_unique<CFX_SkiaDeviceDriver>(recorder));
+  }
+  SetDeviceDriver(std::make_unique<CFX_SkiaDeviceDriver>(canvas));
   return true;
 }
 
diff --git a/core/fxge/skia/fx_skia_device.h b/core/fxge/skia/fx_skia_device.h
index e6b2529..1051526 100644
--- a/core/fxge/skia/fx_skia_device.h
+++ b/core/fxge/skia/fx_skia_device.h
@@ -20,11 +20,12 @@
 #include "third_party/base/span.h"
 #include "third_party/skia/include/core/SkPoint.h"
 #include "third_party/skia/include/core/SkRSXform.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
 
 class CFX_Font;
 class CFX_Matrix;
 class SkCanvas;
-class SkPictureRecorder;
+class SkSurface;
 class TextCharPos;
 struct CFX_TextRenderOptions;
 
@@ -40,7 +41,7 @@
       RetainPtr<CFX_DIBitmap> pBackdropBitmap,
       bool bGroupKnockout);
 
-  explicit CFX_SkiaDeviceDriver(SkPictureRecorder* recorder);
+  explicit CFX_SkiaDeviceDriver(SkCanvas* canvas);
   ~CFX_SkiaDeviceDriver() override;
 
   /** Options */
@@ -218,8 +219,8 @@
   // bitmap is 24 bpp and cannot be directly used as the back of a SkCanvas.
   RetainPtr<CFX_DIBitmap> m_pOriginalBitmap;
 
+  sk_sp<SkSurface> surface_;
   UnownedPtr<SkCanvas> m_pCanvas;
-  UnownedPtr<SkPictureRecorder> const m_pRecorder;
   CFX_FillRenderOptions m_FillOptions;
   bool m_bRgbByteOrder;
   bool m_bGroupKnockout;
diff --git a/fpdfsdk/fpdf_formfill.cpp b/fpdfsdk/fpdf_formfill.cpp
index 8c1a083..0a6ae85 100644
--- a/fpdfsdk/fpdf_formfill.cpp
+++ b/fpdfsdk/fpdf_formfill.cpp
@@ -28,6 +28,10 @@
 #include "fpdfsdk/cpdfsdk_pageview.h"
 #include "public/fpdfview.h"
 
+#if defined(_SKIA_SUPPORT_)
+#include "third_party/skia/include/core/SkPictureRecorder.h"  // nogncheck
+#endif  // defined(_SKIA_SUPPORT_)
+
 #ifdef PDF_ENABLE_XFA
 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
@@ -194,8 +198,10 @@
 
   auto pDevice = std::make_unique<CFX_DefaultRenderDevice>();
 #if defined(_SKIA_SUPPORT_)
-  if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
-    pDevice->AttachRecorder(static_cast<SkPictureRecorder*>(recorder));
+  if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer() && recorder) {
+    pDevice->AttachCanvas(
+        static_cast<SkPictureRecorder*>(recorder)->getRecordingCanvas());
+  }
 #endif
 
   RetainPtr<CFX_DIBitmap> holder(CFXDIBitmapFromFPDFBitmap(bitmap));
diff --git a/fpdfsdk/fpdf_view.cpp b/fpdfsdk/fpdf_view.cpp
index d65579d..430b660 100644
--- a/fpdfsdk/fpdf_view.cpp
+++ b/fpdfsdk/fpdf_view.cpp
@@ -731,8 +731,9 @@
                                                            int size_x,
                                                            int size_y) {
   auto skDevice = std::make_unique<CFX_DefaultRenderDevice>();
-  std::unique_ptr<SkPictureRecorder> recorder =
-      skDevice->CreateRecorder(SkRect::MakeWH(size_x, size_y));
+  auto recorder = std::make_unique<SkPictureRecorder>();
+  recorder->beginRecording(SkRect::MakeWH(size_x, size_y));
+  skDevice->AttachCanvas(recorder->getRecordingCanvas());
 
   CPDF_Page* pPage = CPDFPageFromFPDFPage(page);
   if (!pPage) {