Replace FPDF_RECORDER with FPDF_SKIA_CANVAS

Replaces FPDF_RECORDER (an opaque pointer to an SkPictureRecorder) with
FPDF_SKIA_CANVAS (an opaque pointer to an SkCanvas). An SkCanvas is
strictly more general than an SkPictureRecorder.

Since we no longer need the definition of SkPictureRecorder, we can use
forward declarations more aggressively, and reduce the //fpdfsdk
target's dependency on //skia.

This change also reorganizes FPDF_RenderPageSkia() to follow the
structure of the other FPDF_RenderPage*() APIs more consistently.

Bug: pdfium:2059
Change-Id: If4855d61a39acc1f96e4c5adb9373bb4d26e19fe
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/109210
Reviewed-by: Nigi <nigi@chromium.org>
Commit-Queue: K. Moon <kmoon@chromium.org>
Auto-Submit: K. Moon <kmoon@chromium.org>
diff --git a/fpdfsdk/BUILD.gn b/fpdfsdk/BUILD.gn
index b3dff66..c8aa54f 100644
--- a/fpdfsdk/BUILD.gn
+++ b/fpdfsdk/BUILD.gn
@@ -97,10 +97,6 @@
     ]
     allow_circular_includes_from += [ "fpdfxfa" ]
   }
-
-  if (pdf_use_skia) {
-    deps += [ "//skia" ]
-  }
 }
 
 pdfium_unittest_source_set("unittests") {
diff --git a/fpdfsdk/DEPS b/fpdfsdk/DEPS
index 7bcf89b..1e52515 100644
--- a/fpdfsdk/DEPS
+++ b/fpdfsdk/DEPS
@@ -10,7 +10,7 @@
 ]
 
 specific_include_rules = {
-  'fpdf_formfill\.cpp|fpdf_view(_embeddertest)?\.cpp': [
+  'fpdf_view_embeddertest\.cpp': [
     '+third_party/skia/include',
   ],
 }
diff --git a/fpdfsdk/fpdf_formfill.cpp b/fpdfsdk/fpdf_formfill.cpp
index f1f8ada..ee72562 100644
--- a/fpdfsdk/fpdf_formfill.cpp
+++ b/fpdfsdk/fpdf_formfill.cpp
@@ -29,14 +29,16 @@
 #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"
+#endif  // PDF_ENABLE_XFA
 
+#if defined(_SKIA_SUPPORT_)
+class SkCanvas;
+#endif  // defined(_SKIA_SUPPORT_)
+
+#ifdef PDF_ENABLE_XFA
 static_assert(static_cast<int>(AlertButton::kDefault) ==
                   JSPLATFORM_ALERT_BUTTON_DEFAULT,
               "Default alert button types must match");
@@ -176,7 +178,7 @@
 
 void FFLCommon(FPDF_FORMHANDLE hHandle,
                FPDF_BITMAP bitmap,
-               FPDF_RECORDER recorder,
+               FPDF_SKIA_CANVAS canvas,
                FPDF_PAGE fpdf_page,
                int start_x,
                int start_y,
@@ -199,9 +201,8 @@
 
   auto pDevice = std::make_unique<CFX_DefaultRenderDevice>();
 #if defined(_SKIA_SUPPORT_)
-  if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer() && recorder) {
-    pDevice->AttachCanvas(
-        static_cast<SkPictureRecorder*>(recorder)->getRecordingCanvas());
+  if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer() && canvas) {
+    pDevice->AttachCanvas(reinterpret_cast<SkCanvas*>(canvas));
   }
 #endif
 
@@ -689,16 +690,16 @@
 }
 
 #if defined(_SKIA_SUPPORT_)
-FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLRecord(FPDF_FORMHANDLE hHandle,
-                                              FPDF_RECORDER recorder,
-                                              FPDF_PAGE page,
-                                              int start_x,
-                                              int start_y,
-                                              int size_x,
-                                              int size_y,
-                                              int rotate,
-                                              int flags) {
-  FFLCommon(hHandle, nullptr, recorder, page, start_x, start_y, size_x, size_y,
+FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDrawSkia(FPDF_FORMHANDLE hHandle,
+                                                FPDF_SKIA_CANVAS canvas,
+                                                FPDF_PAGE page,
+                                                int start_x,
+                                                int start_y,
+                                                int size_x,
+                                                int size_y,
+                                                int rotate,
+                                                int flags) {
+  FFLCommon(hHandle, nullptr, canvas, page, start_x, start_y, size_x, size_y,
             rotate, flags);
 }
 #endif
diff --git a/fpdfsdk/fpdf_view.cpp b/fpdfsdk/fpdf_view.cpp
index 600e6fb..4f7a95d 100644
--- a/fpdfsdk/fpdf_view.cpp
+++ b/fpdfsdk/fpdf_view.cpp
@@ -53,11 +53,6 @@
 #include "third_party/base/ptr_util.h"
 #include "third_party/base/span.h"
 
-#if defined(_SKIA_SUPPORT_)
-#include "third_party/skia/include/core/SkPictureRecorder.h"  // nogncheck
-#include "third_party/skia/include/core/SkRect.h"             // nogncheck
-#endif  // defined(_SKIA_SUPPORT_)
-
 #ifdef PDF_ENABLE_V8
 #include "fxjs/cfx_v8_array_buffer_allocator.h"
 #include "third_party/base/no_destructor.h"
@@ -73,6 +68,10 @@
 #include "core/fpdfapi/render/cpdf_windowsrenderdevice.h"
 #include "public/fpdf_edit.h"
 
+#if defined(_SKIA_SUPPORT_)
+class SkCanvas;
+#endif  // defined(_SKIA_SUPPORT_)
+
 // These checks are here because core/ and public/ cannot depend on each other.
 static_assert(static_cast<int>(WindowsPrintMode::kEmf) == FPDF_PRINTMODE_EMF,
               "WindowsPrintMode::kEmf value mismatch");
@@ -728,37 +727,32 @@
 }
 
 #if defined(_SKIA_SUPPORT_)
-FPDF_EXPORT FPDF_RECORDER FPDF_CALLCONV FPDF_RenderPageSkp(FPDF_PAGE page,
-                                                           int size_x,
-                                                           int size_y) {
-  auto skDevice = std::make_unique<CFX_DefaultRenderDevice>();
-  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) {
-    // The equivalent bitmap APIs don't signal failure in this case, but defer
-    // the real work to a later call to `FPDF_FFLDraw()`. This is the case for
-    // XFA pages, for example.
-    //
-    // The caller still needs the `SkPictureRecorder` in order to call
-    // `FPDF_FFLRecord()` later.
-    return recorder.release();
+FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas,
+                                                   FPDF_PAGE page,
+                                                   int size_x,
+                                                   int size_y) {
+  if (!canvas) {
+    return;
   }
 
-  auto pOwnedContext = std::make_unique<CPDF_PageRenderContext>();
-  pOwnedContext->m_pDevice = std::move(skDevice);
+  CPDF_Page* cpdf_page = CPDFPageFromFPDFPage(page);
+  if (!cpdf_page) {
+    return;
+  }
 
-  CPDF_Page::RenderContextClearer clearer(pPage);
-  CPDF_PageRenderContext* pContext = pOwnedContext.get();
-  pPage->SetRenderContext(std::move(pOwnedContext));
+  auto owned_context = std::make_unique<CPDF_PageRenderContext>();
+  CPDF_PageRenderContext* context = owned_context.get();
+  CPDF_Page::RenderContextClearer clearer(cpdf_page);
+  cpdf_page->SetRenderContext(std::move(owned_context));
 
-  CPDFSDK_RenderPageWithContext(pContext, pPage, 0, 0, size_x, size_y, 0, 0,
+  auto owned_device = std::make_unique<CFX_DefaultRenderDevice>();
+  CFX_DefaultRenderDevice& device = *owned_device;
+  context->m_pDevice = std::move(owned_device);
+
+  device.AttachCanvas(reinterpret_cast<SkCanvas*>(canvas));
+  CPDFSDK_RenderPageWithContext(context, cpdf_page, 0, 0, size_x, size_y, 0, 0,
                                 /*color_scheme=*/nullptr,
                                 /*need_to_restore=*/true, /*pause=*/nullptr);
-
-  return recorder.release();
 }
 #endif  // defined(_SKIA_SUPPORT_)
 
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index b66fe62..5907a4e 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -312,7 +312,7 @@
     CHK(FPDFPage_HasFormFieldAtPoint);
     CHK(FPDF_FFLDraw);
 #if defined(_SKIA_SUPPORT_)
-    CHK(FPDF_FFLRecord);
+    CHK(FPDF_FFLDrawSkia);
 #endif
     CHK(FPDF_GetFormType);
     CHK(FPDF_LoadXFA);
@@ -518,7 +518,7 @@
     CHK(FPDF_RenderPageBitmap);
     CHK(FPDF_RenderPageBitmapWithMatrix);
 #if defined(_SKIA_SUPPORT_)
-    CHK(FPDF_RenderPageSkp);
+    CHK(FPDF_RenderPageSkia);
 #endif
 #if defined(_WIN32)
     CHK(FPDF_SetPrintMode);
diff --git a/fpdfsdk/fpdf_view_embeddertest.cpp b/fpdfsdk/fpdf_view_embeddertest.cpp
index a24240b..88477ad 100644
--- a/fpdfsdk/fpdf_view_embeddertest.cpp
+++ b/fpdfsdk/fpdf_view_embeddertest.cpp
@@ -232,13 +232,15 @@
     int width = static_cast<int>(FPDF_GetPageWidth(page));
     int height = static_cast<int>(FPDF_GetPageHeight(page));
 
-    FPDF_RECORDER opaque_recorder = FPDF_RenderPageSkp(page, width, height);
-    ASSERT_TRUE(opaque_recorder);
+    auto recorder = std::make_unique<SkPictureRecorder>();
+    recorder->beginRecording(width, height);
 
-    SkPictureRecorder* recorder =
-        reinterpret_cast<SkPictureRecorder*>(opaque_recorder);
+    FPDF_RenderPageSkia(
+        reinterpret_cast<FPDF_SKIA_CANVAS>(recorder->getRecordingCanvas()),
+        page, width, height);
+
     sk_sp<SkPicture> picture = recorder->finishRecordingAsPicture();
-    delete recorder;
+    recorder.reset();
     ASSERT_TRUE(picture);
 
     ScopedFPDFBitmap bitmap = SkPictureToPdfiumBitmap(
diff --git a/public/fpdf_formfill.h b/public/fpdf_formfill.h
index 2bcf7f7..a0769b7 100644
--- a/public/fpdf_formfill.h
+++ b/public/fpdf_formfill.h
@@ -8,7 +8,7 @@
 #define PUBLIC_FPDF_FORMFILL_H_
 
 // clang-format off
-// NOLINTNEXTLINE(build/include)
+// NOLINTNEXTLINE(build/include_directory)
 #include "fpdfview.h"
 
 // These values are return values for a public API, so should not be changed
@@ -1913,15 +1913,15 @@
                                             int flags);
 
 #if defined(_SKIA_SUPPORT_)
-FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLRecord(FPDF_FORMHANDLE hHandle,
-                                              FPDF_RECORDER recorder,
-                                              FPDF_PAGE page,
-                                              int start_x,
-                                              int start_y,
-                                              int size_x,
-                                              int size_y,
-                                              int rotate,
-                                              int flags);
+FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDrawSkia(FPDF_FORMHANDLE hHandle,
+                                                FPDF_SKIA_CANVAS canvas,
+                                                FPDF_PAGE page,
+                                                int start_x,
+                                                int start_y,
+                                                int size_x,
+                                                int size_y,
+                                                int rotate,
+                                                int flags);
 #endif
 
 /*
diff --git a/public/fpdfview.h b/public/fpdfview.h
index 1527090..0c901a7 100644
--- a/public/fpdfview.h
+++ b/public/fpdfview.h
@@ -79,9 +79,9 @@
 typedef struct fpdf_pageobjectmark_t__* FPDF_PAGEOBJECTMARK;
 typedef const struct fpdf_pagerange_t__* FPDF_PAGERANGE;
 typedef const struct fpdf_pathsegment_t* FPDF_PATHSEGMENT;
-typedef void* FPDF_RECORDER;  // Passed into Skia as a SkPictureRecorder.
 typedef struct fpdf_schhandle_t__* FPDF_SCHHANDLE;
 typedef const struct fpdf_signature_t__* FPDF_SIGNATURE;
+typedef void* FPDF_SKIA_CANVAS;  // Passed into Skia as an SkCanvas.
 typedef struct fpdf_structelement_t__* FPDF_STRUCTELEMENT;
 typedef const struct fpdf_structelement_attr_t__* FPDF_STRUCTELEMENT_ATTR;
 typedef struct fpdf_structtree_t__* FPDF_STRUCTTREE;
@@ -278,7 +278,6 @@
   // corresponding render library is not included in the build will similarly
   // fail with an immediate crash.
   FPDF_RENDERER_TYPE m_RendererType;
-
 } FPDF_LIBRARY_CONFIG;
 
 // Function: FPDF_InitLibraryWithConfig
@@ -926,18 +925,19 @@
 
 #if defined(_SKIA_SUPPORT_)
 // Experimental API.
-// Function: FPDF_RenderPageSkp
-//          Render contents of a page to a Skia SkPictureRecorder.
+// Function: FPDF_RenderPageSkia
+//          Render contents of a page to a Skia SkCanvas.
 // Parameters:
+//          canvas      -   SkCanvas to render to.
 //          page        -   Handle to the page.
 //          size_x      -   Horizontal size (in pixels) for displaying the page.
 //          size_y      -   Vertical size (in pixels) for displaying the page.
 // Return value:
-//          The SkPictureRecorder that holds the rendering of the page, or NULL
-//          on failure. Caller takes ownership of the returned result.
-FPDF_EXPORT FPDF_RECORDER FPDF_CALLCONV FPDF_RenderPageSkp(FPDF_PAGE page,
-                                                           int size_x,
-                                                           int size_y);
+//          None.
+FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageSkia(FPDF_SKIA_CANVAS canvas,
+                                                   FPDF_PAGE page,
+                                                   int size_x,
+                                                   int size_y);
 #endif
 
 // Function: FPDF_ClosePage
diff --git a/samples/pdfium_test.cc b/samples/pdfium_test.cc
index 99deae3..145029e 100644
--- a/samples/pdfium_test.cc
+++ b/samples/pdfium_test.cc
@@ -1155,15 +1155,21 @@
   bool HasOutput() const override { return !!picture_; }
 
   bool Start() override {
-    recorder_.reset(reinterpret_cast<SkPictureRecorder*>(
-        FPDF_RenderPageSkp(page(), /*size_x=*/width(), /*size_y=*/height())));
-    return !!recorder_;
+    recorder_ = std::make_unique<SkPictureRecorder>();
+    recorder_->beginRecording(width(), height());
+
+    FPDF_RenderPageSkia(
+        reinterpret_cast<FPDF_SKIA_CANVAS>(recorder_->getRecordingCanvas()),
+        page(), /*size_x=*/width(), /*size_y=*/height());
+    return true;
   }
 
   void Finish(FPDF_FORMHANDLE form) override {
-    FPDF_FFLRecord(form, reinterpret_cast<FPDF_RECORDER>(recorder_.get()),
-                   page(), /*start_x=*/0, /*start_y=*/0, /*size_x=*/width(),
-                   /*size_y=*/height(), /*rotate=*/0, /*flags=*/0);
+    FPDF_FFLDrawSkia(
+        form,
+        reinterpret_cast<FPDF_SKIA_CANVAS>(recorder_->getRecordingCanvas()),
+        page(), /*start_x=*/0, /*start_y=*/0, /*size_x=*/width(),
+        /*size_y=*/height(), /*rotate=*/0, /*flags=*/0);
 
     picture_ = recorder_->finishRecordingAsPicture();
     recorder_.reset();