chromium/third_party/pdfium/testing/pdfium_test.cc

// Copyright 2010 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <locale.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <algorithm>
#include <functional>
#include <iterator>
#include <map>
#include <memory>
#include <optional>
#include <sstream>
#include <string>
#include <vector>

#if defined(PDF_ENABLE_SKIA) && !defined(PDF_USE_SKIA)
#define PDF_USE_SKIA
#endif

#include "core/fxcrt/check_op.h"
#include "core/fxcrt/compiler_specific.h"
#include "core/fxcrt/span.h"
#include "public/cpp/fpdf_scopers.h"
#include "public/fpdf_annot.h"
#include "public/fpdf_attachment.h"
#include "public/fpdf_dataavail.h"
#include "public/fpdf_edit.h"
#include "public/fpdf_ext.h"
#include "public/fpdf_formfill.h"
#include "public/fpdf_progressive.h"
#include "public/fpdf_structtree.h"
#include "public/fpdf_text.h"
#include "public/fpdfview.h"
#include "testing/command_line_helpers.h"
#include "testing/font_renamer.h"
#include "testing/fx_string_testhelpers.h"
#include "testing/helpers/dump.h"
#include "testing/helpers/event.h"
#include "testing/helpers/page_renderer.h"
#include "testing/helpers/write.h"
#include "testing/test_loader.h"
#include "testing/utils/file_util.h"
#include "testing/utils/hash.h"
#include "testing/utils/path_service.h"

#ifdef _WIN32
#include <crtdbg.h>
#include <errhandlingapi.h>
#include <io.h>
#include <wingdi.h>

#include "testing/helpers/win32/com_factory.h"
#else
#include <unistd.h>
#endif  // _WIN32

#ifdef ENABLE_CALLGRIND
#include <valgrind/callgrind.h>
#endif  // ENABLE_CALLGRIND

#if defined(PDF_USE_PARTITION_ALLOC)
#include "testing/allocator_shim_config.h"
#endif

#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/SkDocument.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/SkStream.h"           // nogncheck
#include "third_party/skia/include/core/SkSurface.h"          // nogncheck

#ifdef _WIN32
#include "third_party/skia/include/docs/SkXPSDocument.h"  // nogncheck
#endif

#ifdef BUILD_WITH_CHROMIUM
#include "testing/chromium_support/discardable_memory_allocator.h"  // nogncheck
#endif
#endif  // PDF_ENABLE_SKIA

#ifdef PDF_ENABLE_V8
#include "testing/v8_initializer.h"
#include "v8/include/libplatform/libplatform.h"
#include "v8/include/v8-array-buffer.h"
#include "v8/include/v8-isolate.h"
#include "v8/include/v8-platform.h"
#include "v8/include/v8-snapshot.h"
#endif  // PDF_ENABLE_V8

#ifdef _WIN32
#define access
#define snprintf
#define R_OK
#endif

// wordexp is a POSIX function that is only available on macOS and non-Android
// Linux platforms.
#if defined(__APPLE__) || (defined(__linux__) && !defined(__ANDROID__))
#define WORDEXP_AVAILABLE
#endif

#ifdef WORDEXP_AVAILABLE
#include <wordexp.h>
#endif  // WORDEXP_AVAILABLE

namespace {

enum class RendererType {};

enum class OutputFormat {};

struct Options {};

int PageRenderFlagsFromOptions(const Options& options) {}

std::optional<std::string> ExpandDirectoryPath(const std::string& path) {}

std::optional<const char*> GetCustomFontPath(const Options& options) {}

struct FPDF_FORMFILLINFO_PDFiumTest final : public FPDF_FORMFILLINFO {};

FPDF_FORMFILLINFO_PDFiumTest* ToPDFiumTestFormFillInfo(
    FPDF_FORMFILLINFO* form_fill_info) {}

void OutputMD5Hash(const char* file_name, pdfium::span<const uint8_t> output) {}

#ifdef PDF_ENABLE_V8

struct V8IsolateDeleter {};

// These example JS platform callback handlers are entirely optional,
// and exist here to show the flow of information from a document back
// to the embedder.
int ExampleAppAlert(IPDF_JSPLATFORM*,
                    FPDF_WIDESTRING msg,
                    FPDF_WIDESTRING title,
                    int type,
                    int icon) {}

void ExampleAppBeep(IPDF_JSPLATFORM*, int type) {}

int ExampleAppResponse(IPDF_JSPLATFORM*,
                       FPDF_WIDESTRING question,
                       FPDF_WIDESTRING title,
                       FPDF_WIDESTRING default_value,
                       FPDF_WIDESTRING label,
                       FPDF_BOOL is_password,
                       void* response,
                       int length) {}

int ExampleDocGetFilePath(IPDF_JSPLATFORM*, void* file_path, int length) {}

void ExampleDocMail(IPDF_JSPLATFORM*,
                    void* mailData,
                    int length,
                    FPDF_BOOL UI,
                    FPDF_WIDESTRING To,
                    FPDF_WIDESTRING Subject,
                    FPDF_WIDESTRING CC,
                    FPDF_WIDESTRING BCC,
                    FPDF_WIDESTRING Msg) {}

void ExampleDocPrint(IPDF_JSPLATFORM*,
                     FPDF_BOOL bUI,
                     int nStart,
                     int nEnd,
                     FPDF_BOOL bSilent,
                     FPDF_BOOL bShrinkToFit,
                     FPDF_BOOL bPrintAsImage,
                     FPDF_BOOL bReverse,
                     FPDF_BOOL bAnnotations) {}

void ExampleDocSubmitForm(IPDF_JSPLATFORM*,
                          void* formData,
                          int length,
                          FPDF_WIDESTRING url) {}

void ExampleDocGotoPage(IPDF_JSPLATFORM*, int page_number) {}

int ExampleFieldBrowse(IPDF_JSPLATFORM*, void* file_path, int length) {}
#endif  // PDF_ENABLE_V8

#ifdef PDF_ENABLE_XFA
FPDF_BOOL ExamplePopupMenu(FPDF_FORMFILLINFO* pInfo,
                           FPDF_PAGE page,
                           FPDF_WIDGET always_null,
                           int flags,
                           float x,
                           float y) {}
#endif  // PDF_ENABLE_XFA

void ExampleNamedAction(FPDF_FORMFILLINFO* pInfo, FPDF_BYTESTRING name) {}

void ExampleUnsupportedHandler(UNSUPPORT_INFO*, int type) {}

bool ParseCommandLine(const std::vector<std::string>& args,
                      Options* options,
                      std::vector<std::string>* files) {}

void PrintLastError() {}

FPDF_BOOL Is_Data_Avail(FX_FILEAVAIL* avail, size_t offset, size_t size) {}

void Add_Segment(FX_DOWNLOADHINTS* hints, size_t offset, size_t size) {}

FPDF_PAGE GetPageForIndex(FPDF_FORMFILLINFO* param,
                          FPDF_DOCUMENT doc,
                          int index) {}

// Note, for a client using progressive rendering you'd want to determine if you
// need the rendering to pause instead of always saying |true|. This is for
// testing to force the renderer to break whenever possible.
FPDF_BOOL NeedToPauseNow(IFSDK_PAUSE* p) {}

class Processor final {};

class PdfProcessor final {};

// Page renderer with bitmap output.
class BitmapPageRenderer : public PageRenderer {};

// Bitmap page renderer completing in a single operation.
class OneShotBitmapPageRenderer : public BitmapPageRenderer {};

// Bitmap page renderer completing over multiple operations.
class ProgressiveBitmapPageRenderer : public BitmapPageRenderer {};

#ifdef _WIN32
class ScopedGdiDc final {
 public:
  ~ScopedGdiDc() { Reset(nullptr); }

  void Reset(HDC dc) {
    if (dc_) {
      [[maybe_unused]] BOOL success = DeleteDC(dc_);
      DCHECK(success);
    }
    dc_ = dc;
  }

  HDC Get() const { return dc_; }

 private:
  HDC dc_ = nullptr;
};

class ScopedGdiObject final {
 public:
  ~ScopedGdiObject() { Reset(nullptr); }

  void Reset(HGDIOBJ object) {
    if (object_) {
      [[maybe_unused]] BOOL success = DeleteObject(object_);
      DCHECK(success);
    }
    object_ = object;
  }

  HGDIOBJ Get() const { return object_; }

 private:
  HGDIOBJ object_ = nullptr;
};

class GdiDisplayPageRenderer : public BitmapPageRenderer {
 public:
  GdiDisplayPageRenderer(FPDF_PAGE page,
                         int width,
                         int height,
                         int flags,
                         const std::function<void()>& idler,
                         PageWriter writer)
      : BitmapPageRenderer(page,
                           /*width=*/width,
                           /*height=*/height,
                           /*flags=*/flags,
                           idler,
                           std::move(writer)) {}

  ~GdiDisplayPageRenderer() override {
    // Need to free `bitmap()` first, in case it points at `dib_` memory.
    ResetBitmap();
  }

  bool Start() override {
    // Create an in-memory DC compatible with the display.
    dc_.Reset(CreateCompatibleDC(/*hdc=*/nullptr));
    if (!dc_.Get()) {
      return false;
    }

    // Create a BGRA DIB and select it into the in-memory DC.
    BITMAPINFO dib_info;
    memset(&dib_info, 0, sizeof(BITMAPINFO));
    dib_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    dib_info.bmiHeader.biWidth = width();
    dib_info.bmiHeader.biHeight = -height();  // top-down
    dib_info.bmiHeader.biPlanes = 1;
    dib_info.bmiHeader.biBitCount = 32;
    dib_info.bmiHeader.biCompression = BI_RGB;

    VOID* dib_pixels;
    dib_.Reset(CreateDIBSection(dc_.Get(), &dib_info, DIB_RGB_COLORS,
                                &dib_pixels, /*hSection=*/nullptr,
                                /*offset=*/0));
    if (!dib_.Get() || !InitializeBitmap(dib_pixels)) {
      return false;
    }

    HGDIOBJ old_obj = SelectObject(dc_.Get(), dib_.Get());
    CHECK(old_obj);
    CHECK_NE(old_obj, HGDI_ERROR);

    // Render into the in-memory DC.
    FPDF_RenderPage(dc_.Get(), page(), /*start_x=*/0, /*start_y=*/0,
                    /*size_x=*/width(), /*size_y=*/height(), /*rotate=*/0,
                    /*flags=*/flags());

    bool result = !!GdiFlush();
    HGDIOBJ dib_obj = SelectObject(dc_.Get(), old_obj);
    CHECK((GetObjectType(old_obj) != OBJ_REGION && dib_obj) ||
          (GetObjectType(old_obj) == OBJ_REGION && dib_obj != HGDI_ERROR));
    return result;
  }

  void Finish(FPDF_FORMHANDLE /*form*/) override {
    // Note that `fpdf_formfill.h` does not support GDI.

    // The GDI backend doesn't support alpha and clears the alpha component to
    // transparent, so clear the alpha component back to opaque.
    const int stride = FPDFBitmap_GetStride(bitmap());
    DCHECK_EQ(width() * sizeof(uint32_t), static_cast<size_t>(stride));
    const int pixel_stride = stride / sizeof(uint32_t);

    uint32_t* scanline =
        reinterpret_cast<uint32_t*>(FPDFBitmap_GetBuffer(bitmap()));
    for (int row = 0; row < height(); ++row) {
      for (int column = 0; column < width(); ++column) {
        scanline[column] |= 0xFF000000;
      }
      scanline += pixel_stride;
    }
  }

 private:
  ScopedGdiDc dc_;
  ScopedGdiObject dib_;
};
#endif  // _WIN32

#ifdef PDF_ENABLE_SKIA
class SkCanvasPageRenderer : public PageRenderer {};

class SkPicturePageRenderer final : public SkCanvasPageRenderer {};

class SkDocumentPageRenderer final : public SkCanvasPageRenderer {};
#endif  // PDF_ENABLE_SKIA

bool PdfProcessor::ProcessPage(const int page_index) {}

void Processor::ProcessPdf(const std::string& name,
                           pdfium::span<const uint8_t> data,
                           const std::string& events) {}

void ShowConfig() {}

constexpr char kUsageString[] =;

void SetUpErrorHandling() {}

}  // namespace

int main(int argc, const char* argv[]) {}