Support --md5 with pdfium_test --skp

Supports --md5 with pdfium_test's SKP output format by playing back the
SKP to an intermediate buffer.

Bug: pdfium:1929
Change-Id: I9f2b3bedb1a9c6cb1c16872e3df8bd8f444cc959
Cq-Do-Not-Cancel-Tryjobs: true
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/101474
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: K. Moon <kmoon@chromium.org>
diff --git a/samples/pdfium_test.cc b/samples/pdfium_test.cc
index 1e63000..42f33ec 100644
--- a/samples/pdfium_test.cc
+++ b/samples/pdfium_test.cc
@@ -56,6 +56,16 @@
 #include <valgrind/callgrind.h>
 #endif  // ENABLE_CALLGRIND
 
+#ifdef PDF_ENABLE_SKIA
+#include "third_party/skia/include/core/SkCanvas.h"           // nogncheck
+#include "third_party/skia/include/core/SkColor.h"            // nogncheck
+#include "third_party/skia/include/core/SkPicture.h"          // nogncheck
+#include "third_party/skia/include/core/SkPictureRecorder.h"  // nogncheck
+#include "third_party/skia/include/core/SkPixmap.h"           // nogncheck
+#include "third_party/skia/include/core/SkRefCnt.h"           // nogncheck
+#include "third_party/skia/include/core/SkSurface.h"          // nogncheck
+#endif
+
 #ifdef PDF_ENABLE_V8
 #include "testing/v8_initializer.h"
 #include "v8/include/libplatform/libplatform.h"
@@ -757,7 +767,7 @@
  public:
   virtual ~PageRenderer() = default;
 
-  // Returns `true` if the rendered output exists. Must call `Start()` first.
+  // Returns `true` if the rendered output exists. Must call `Finish()` first.
   virtual bool HasOutput() const = 0;
 
   // Starts rendering the page, returning `false` on failure.
@@ -808,7 +818,7 @@
     bool alpha = FPDFPage_HasTransparency(page());
     bitmap_.reset(FPDFBitmap_Create(/*width=*/width(), /*height=*/height(),
                                     /*alpha=*/alpha));
-    if (!HasOutput())
+    if (!bitmap_)
       return false;
 
     FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF;
@@ -958,37 +968,54 @@
                      /*height=*/height,
                      /*flags=*/flags) {}
 
-  bool HasOutput() const override { return !!recorder_; }
+  bool HasOutput() const override { return !!picture_; }
 
   bool Start() override {
     recorder_.reset(reinterpret_cast<SkPictureRecorder*>(
         FPDF_RenderPageSkp(page(), /*size_x=*/width(), /*size_y=*/height())));
-    return HasOutput();
+    return !!recorder_;
   }
 
   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);
+
+    picture_ = recorder_->finishRecordingAsPicture();
+    recorder_.reset();
   }
 
   bool Write(const std::string& name, int page_index, bool md5) override {
-    std::string image_file_name =
-        WriteSkp(name.c_str(), page_index, recorder_.get());
+    std::string image_file_name = WriteSkp(name.c_str(), page_index, *picture_);
     if (image_file_name.empty())
       return false;
 
     if (md5) {
-      // Supporting --md5 would require rasterization.
-      // TODO(crbug.com/pdfium/1929): It may be useful to compute the MD5 of the
-      // replayed SKP, in order to compare with direct rasterization.
-      return false;
+      // Play back the `SkPicture` so we can take a hash of the result.
+      sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(
+          /*width=*/width(), /*height=*/height());
+      if (!surface)
+        return false;
+
+      // Must clear to white before replay to match initial `CFX_DIBitmap`.
+      surface->getCanvas()->clear(SK_ColorWHITE);
+      surface->getCanvas()->drawPicture(picture_);
+
+      // Write the filename and the MD5 of the buffer to stdout.
+      SkPixmap pixmap;
+      if (!surface->peekPixels(&pixmap))
+        return false;
+
+      OutputMD5Hash(image_file_name.c_str(),
+                    {static_cast<const uint8_t*>(pixmap.addr()),
+                     pixmap.computeByteSize()});
     }
     return true;
   }
 
  private:
   std::unique_ptr<SkPictureRecorder> recorder_;
+  sk_sp<SkPicture> picture_;
 };
 #endif  // PDF_ENABLE_SKIA
 
diff --git a/samples/pdfium_test_write_helper.cc b/samples/pdfium_test_write_helper.cc
index 4111208..c3e170e 100644
--- a/samples/pdfium_test_write_helper.cc
+++ b/samples/pdfium_test_write_helper.cc
@@ -19,6 +19,11 @@
 #include "testing/image_diff/image_diff_png.h"
 #include "third_party/base/notreached.h"
 
+#ifdef PDF_ENABLE_SKIA
+#include "third_party/skia/include/core/SkPicture.h"  // nogncheck
+#include "third_party/skia/include/core/SkStream.h"   // nogncheck
+#endif
+
 namespace {
 
 bool CheckDimensions(int stride, int width, int height) {
@@ -513,9 +518,7 @@
 #endif  // _WIN32
 
 #ifdef PDF_ENABLE_SKIA
-std::string WriteSkp(const char* pdf_name,
-                     int num,
-                     SkPictureRecorder* recorder) {
+std::string WriteSkp(const char* pdf_name, int num, const SkPicture& picture) {
   char filename[256];
   int chars_formatted =
       snprintf(filename, sizeof(filename), "%s.%d.skp", pdf_name, num);
@@ -526,9 +529,8 @@
     return "";
   }
 
-  sk_sp<SkPicture> picture(recorder->finishRecordingAsPicture());
   SkFILEWStream wStream(filename);
-  picture->serialize(&wStream);
+  picture.serialize(&wStream);
   return std::string(filename);
 }
 #endif
diff --git a/samples/pdfium_test_write_helper.h b/samples/pdfium_test_write_helper.h
index 06f1e34..ffeba1f 100644
--- a/samples/pdfium_test_write_helper.h
+++ b/samples/pdfium_test_write_helper.h
@@ -10,8 +10,7 @@
 #include "public/fpdfview.h"
 
 #ifdef PDF_ENABLE_SKIA
-#include "third_party/skia/include/core/SkPictureRecorder.h"  // nogncheck
-#include "third_party/skia/include/core/SkStream.h"           // nogncheck
+class SkPicture;
 #endif
 
 std::string WritePpm(const char* pdf_name,
@@ -41,9 +40,7 @@
 #endif  // _WIN32
 
 #ifdef PDF_ENABLE_SKIA
-std::string WriteSkp(const char* pdf_name,
-                     int num,
-                     SkPictureRecorder* recorder);
+std::string WriteSkp(const char* pdf_name, int num, const SkPicture& picture);
 #endif  // PDF_ENABLE_SKIA
 
 void WriteAttachments(FPDF_DOCUMENT doc, const std::string& name);