Use PageRenderer::Write() for all output formats

Consistently uses PageRenderer::Write() for all output formats, rather
than making separate calls to WriteAnnot(), WriteEmf(), WritePS(), and
WriteText().

Bug: pdfium:2054
Change-Id: I39ba54148d44b11da2f8e44de1f96e6bba405b0f
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/108891
Commit-Queue: K. Moon <kmoon@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/samples/pdfium_test.cc b/samples/pdfium_test.cc
index a720859..c979db3 100644
--- a/samples/pdfium_test.cc
+++ b/samples/pdfium_test.cc
@@ -801,16 +801,73 @@
 // Page renderer with bitmap output.
 class BitmapPageRenderer : public PageRenderer {
  public:
-  // Function type that writes a bitmap to an image file. The function returns
-  // the name of the image file on success, or an empty name on failure.
+  // Function type that writes rendered output to a file, returning `false` on
+  // failure.
   //
-  // Intended for use with some of the `pdfium_test_write_helper.h` functions.
-  using BitmapWriter = std::string (*)(const char* pdf_name,
-                                       int num,
-                                       void* buffer,
-                                       int stride,
-                                       int width,
-                                       int height);
+  // Intended to wrap functions from `pdfium_test_write_helper.h`.
+  using PageWriter = std::function<bool(BitmapPageRenderer& renderer,
+                                        const std::string& name,
+                                        int page_index,
+                                        bool md5)>;
+
+  // Wraps a `PageWriter` around a function pointer that writes the text page.
+  static PageWriter WrapPageWriter(
+      void (*text_page_writer)(FPDF_TEXTPAGE text_page,
+                               const char* pdf_name,
+                               int num)) {
+    return [text_page_writer](BitmapPageRenderer& renderer,
+                              const std::string& name, int page_index,
+                              bool /*md5*/) {
+      ScopedFPDFTextPage text_page(FPDFText_LoadPage(renderer.page()));
+      if (!text_page) {
+        return false;
+      }
+
+      text_page_writer(text_page.get(), name.c_str(), page_index);
+      return true;
+    };
+  }
+
+  // Wraps a `PageWriter` around a function pointer that writes the page.
+  static PageWriter WrapPageWriter(void (*page_writer)(FPDF_PAGE page,
+                                                       const char* pdf_name,
+                                                       int num)) {
+    return [page_writer](BitmapPageRenderer& renderer, const std::string& name,
+                         int page_index, bool /*md5*/) {
+      page_writer(renderer.page(), name.c_str(), page_index);
+      return true;
+    };
+  }
+
+  // Wraps a `PageWriter` around a function pointer that writes the rasterized
+  // bitmap to an image file.
+  static PageWriter WrapPageWriter(
+      std::string (*bitmap_writer)(const char* pdf_name,
+                                   int num,
+                                   void* buffer,
+                                   int stride,
+                                   int width,
+                                   int height)) {
+    return [bitmap_writer](BitmapPageRenderer& renderer,
+                           const std::string& name, int page_index, bool md5) {
+      int stride = FPDFBitmap_GetStride(renderer.bitmap());
+      void* buffer = FPDFBitmap_GetBuffer(renderer.bitmap());
+      std::string image_file_name = bitmap_writer(
+          name.c_str(), page_index, buffer, /*stride=*/stride,
+          /*width=*/renderer.width(), /*height=*/renderer.height());
+      if (image_file_name.empty()) {
+        return false;
+      }
+
+      if (md5) {
+        // Write the filename and the MD5 of the buffer to stdout.
+        OutputMD5Hash(image_file_name.c_str(),
+                      {static_cast<const uint8_t*>(buffer),
+                       static_cast<size_t>(stride) * renderer.height()});
+      }
+      return true;
+    };
+  }
 
   bool HasOutput() const override { return !!bitmap_; }
 
@@ -835,24 +892,7 @@
   }
 
   bool Write(const std::string& name, int page_index, bool md5) override {
-    if (!writer_)
-      return false;
-
-    int stride = FPDFBitmap_GetStride(bitmap());
-    void* buffer = FPDFBitmap_GetBuffer(bitmap());
-    std::string image_file_name =
-        writer_(name.c_str(), /*num=*/page_index, buffer, /*stride=*/stride,
-                /*width=*/width(), /*height=*/height());
-    if (image_file_name.empty())
-      return false;
-
-    if (md5) {
-      // Write the filename and the MD5 of the buffer to stdout.
-      OutputMD5Hash(image_file_name.c_str(),
-                    {static_cast<const uint8_t*>(buffer),
-                     static_cast<size_t>(stride) * height()});
-    }
-    return true;
+    return writer_ && writer_(*this, name, page_index, md5);
   }
 
  protected:
@@ -861,17 +901,17 @@
                      int height,
                      int flags,
                      const std::function<void()>& idler,
-                     BitmapWriter writer)
+                     PageWriter writer)
       : PageRenderer(page, /*width=*/width, /*height=*/height, /*flags=*/flags),
         idler_(idler),
-        writer_(writer) {}
+        writer_(std::move(writer)) {}
 
   void Idle() const { idler_(); }
   FPDF_BITMAP bitmap() { return bitmap_.get(); }
 
  private:
   const std::function<void()>& idler_;
-  BitmapWriter writer_;
+  PageWriter writer_;
   ScopedFPDFBitmap bitmap_;
 };
 
@@ -883,13 +923,13 @@
                             int height,
                             int flags,
                             const std::function<void()>& idler,
-                            BitmapWriter writer)
+                            PageWriter writer)
       : BitmapPageRenderer(page,
                            /*width=*/width,
                            /*height=*/height,
                            /*flags=*/flags,
                            idler,
-                           writer) {}
+                           std::move(writer)) {}
 
   bool Start() override {
     if (!BitmapPageRenderer::Start())
@@ -913,14 +953,14 @@
                                 int height,
                                 int flags,
                                 const std::function<void()>& idler,
-                                BitmapWriter writer,
+                                PageWriter writer,
                                 const FPDF_COLORSCHEME* color_scheme)
       : BitmapPageRenderer(page,
                            /*width=*/width,
                            /*height=*/height,
                            /*flags=*/flags,
                            idler,
-                           writer),
+                           std::move(writer)),
         color_scheme_(color_scheme) {
     pause_.version = 1;
     pause_.NeedToPauseNow = &NeedToPauseNow;
@@ -1061,40 +1101,59 @@
   int flags = PageRenderFlagsFromOptions(options);
 
   std::unique_ptr<PageRenderer> renderer;
-#ifdef PDF_ENABLE_SKIA
-  if (options.output_format == OutputFormat::kSkp) {
-    renderer = std::make_unique<SkPicturePageRenderer>(
-        page, /*width=*/width, /*height=*/height, /*flags=*/flags);
-  } else {
-#else
-  {
-#endif  // PDF_ENABLE_SKIA
-    BitmapPageRenderer::BitmapWriter writer;
-    switch (options.output_format) {
+  BitmapPageRenderer::PageWriter writer;
+  switch (options.output_format) {
+    case OutputFormat::kText:
+      writer = BitmapPageRenderer::WrapPageWriter(WriteText);
+      break;
+
+    case OutputFormat::kAnnot:
+      writer = BitmapPageRenderer::WrapPageWriter(WriteAnnot);
+      break;
+
+    case OutputFormat::kPpm:
+      writer = BitmapPageRenderer::WrapPageWriter(WritePpm);
+      break;
+
+    case OutputFormat::kPng:
+      writer = BitmapPageRenderer::WrapPageWriter(WritePng);
+      break;
+
 #ifdef _WIN32
-      case OutputFormat::kBmp:
-        writer = WriteBmp;
-        break;
+    case OutputFormat::kBmp:
+      writer = BitmapPageRenderer::WrapPageWriter(WriteBmp);
+      break;
+
+    case OutputFormat::kEmf:
+      // TODO(crbug.com/pdfium/2054): Render directly to DC.
+      writer = BitmapPageRenderer::WrapPageWriter(WriteEmf);
+      break;
+
+    case OutputFormat::kPs2:
+    case OutputFormat::kPs3:
+      // TODO(crbug.com/pdfium/2054): Render directly to DC.
+      writer = BitmapPageRenderer::WrapPageWriter(WritePS);
+      break;
 #endif  // _WIN32
 
-      case OutputFormat::kPng:
-        writer = WritePng;
-        break;
+#ifdef PDF_ENABLE_SKIA
+    case OutputFormat::kSkp:
+      renderer = std::make_unique<SkPicturePageRenderer>(
+          page, /*width=*/width, /*height=*/height, /*flags=*/flags);
+      break;
+#endif  // PDF_ENABLE_SKIA
 
-      case OutputFormat::kPpm:
-        writer = WritePpm;
-        break;
+    default:
+      // Other formats won't write the output to a file, but still rasterize.
+      break;
+  }
 
-      default:
-        // Other formats won't write the output to a file, but still rasterize.
-        writer = nullptr;
-        break;
-    }
-
+  if (!renderer) {
+    // Use a rasterizing page renderer by default.
     if (options.render_oneshot) {
       renderer = std::make_unique<OneShotBitmapPageRenderer>(
           page, /*width=*/width, /*height=*/height, /*flags=*/flags, idler,
-          writer);
+          std::move(writer));
     } else {
       // Client programs will be setting these values when rendering.
       // This is a sample color scheme with distinct colors.
@@ -1107,7 +1166,7 @@
 
       renderer = std::make_unique<ProgressiveBitmapPageRenderer>(
           page, /*width=*/width, /*height=*/height, /*flags=*/flags, idler,
-          writer, options.forced_color ? &color_scheme : nullptr);
+          std::move(writer), options.forced_color ? &color_scheme : nullptr);
     }
   }
 
@@ -1115,31 +1174,7 @@
     while (renderer->Continue())
       continue;
     renderer->Finish(form);
-
-    switch (options.output_format) {
-#ifdef _WIN32
-      case OutputFormat::kEmf:
-        WriteEmf(page, name.c_str(), page_index);
-        break;
-
-      case OutputFormat::kPs2:
-      case OutputFormat::kPs3:
-        WritePS(page, name.c_str(), page_index);
-        break;
-#endif  // _WIN32
-
-      case OutputFormat::kText:
-        WriteText(text_page.get(), name.c_str(), page_index);
-        break;
-
-      case OutputFormat::kAnnot:
-        WriteAnnot(page, name.c_str(), page_index);
-        break;
-
-      default:
-        renderer->Write(name, page_index, /*md5=*/options.md5);
-        break;
-    }
+    renderer->Write(name, page_index, /*md5=*/options.md5);
   } else {
     fprintf(stderr, "Page was too large to be rendered.\n");
   }