#include "pdf/pdfium/pdfium_engine_exports.h"
#include <algorithm>
#include <optional>
#include <utility>
#include "base/functional/bind.h"
#include "base/memory/raw_span.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/numerics/checked_math.h"
#include "build/build_config.h"
#include "pdf/document_metadata.h"
#include "pdf/loader/document_loader.h"
#include "pdf/loader/url_loader_wrapper.h"
#include "pdf/pdfium/pdfium_api_string_buffer_adapter.h"
#include "pdf/pdfium/pdfium_document.h"
#include "pdf/pdfium/pdfium_document_metadata.h"
#include "pdf/pdfium/pdfium_mem_buffer_file_write.h"
#include "pdf/pdfium/pdfium_print.h"
#include "pdf/pdfium/pdfium_unsupported_features.h"
#include "printing/nup_parameters.h"
#include "printing/units.h"
#include "services/screen_ai/buildflags/buildflags.h"
#include "third_party/pdfium/public/cpp/fpdf_scopers.h"
#include "third_party/pdfium/public/fpdf_attachment.h"
#include "third_party/pdfium/public/fpdf_catalog.h"
#include "third_party/pdfium/public/fpdf_doc.h"
#include "third_party/pdfium/public/fpdf_ppo.h"
#include "third_party/pdfium/public/fpdf_structtree.h"
#include "third_party/pdfium/public/fpdfview.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/geometry/vector2d.h"
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
#include <memory>
#include "base/functional/callback.h"
#include "pdf/pdf_progressive_searchifier.h"
#include "pdf/pdfium/pdfium_searchify.h"
#include "services/screen_ai/public/mojom/screen_ai_service.mojom.h"
#include "third_party/skia/include/core/SkBitmap.h"
#endif
ConvertUnitFloat;
kPointsPerInch;
namespace chrome_pdf {
namespace {
class DataDocumentLoader : public DocumentLoader { … };
int CalculatePosition(FPDF_PAGE page,
const PDFiumEngineExports::RenderingSettings& settings,
gfx::Rect* dest) { … }
ScopedFPDFDocument LoadPdfData(base::span<const uint8_t> pdf_buffer) { … }
ScopedFPDFDocument CreatePdfDoc(
std::vector<base::span<const uint8_t>> input_buffers) { … }
bool IsValidPrintableArea(const gfx::Size& page_size,
const gfx::Rect& printable_area) { … }
int GetRenderFlagsFromSettings(
const PDFiumEngineExports::RenderingSettings& settings) { … }
base::Value RecursiveGetStructTree(FPDF_STRUCTELEMENT struct_elem) { … }
}
PDFiumEngineExports::RenderingSettings::RenderingSettings(
const gfx::Size& dpi,
const gfx::Rect& bounds,
bool fit_to_bounds,
bool stretch_to_bounds,
bool keep_aspect_ratio,
bool center_in_bounds,
bool autorotate,
bool use_color,
bool render_for_printing)
: … { … }
PDFiumEngineExports::RenderingSettings::RenderingSettings(
const RenderingSettings& that) = default;
PDFiumEngineExports* PDFiumEngineExports::Get() { … }
PDFiumEngineExports::PDFiumEngineExports() = default;
PDFiumEngineExports::~PDFiumEngineExports() = default;
#if BUILDFLAG(IS_CHROMEOS)
std::optional<FlattenPdfResult> PDFiumEngineExports::CreateFlattenedPdf(
base::span<const uint8_t> input_buffer) {
ScopedUnsupportedFeature scoped_unsupported_feature(
ScopedUnsupportedFeature::kNoEngine);
ScopedFPDFDocument doc = LoadPdfData(input_buffer);
return doc ? PDFiumPrint::CreateFlattenedPdf(std::move(doc)) : std::nullopt;
}
#endif
#if BUILDFLAG(IS_WIN)
bool PDFiumEngineExports::RenderPDFPageToDC(
base::span<const uint8_t> pdf_buffer,
int page_index,
const RenderingSettings& settings,
HDC dc) {
ScopedUnsupportedFeature scoped_unsupported_feature(
ScopedUnsupportedFeature::kNoEngine);
ScopedFPDFDocument doc = LoadPdfData(pdf_buffer);
if (!doc)
return false;
ScopedFPDFPage page(FPDF_LoadPage(doc.get(), page_index));
if (!page)
return false;
RenderingSettings new_settings = settings;
if (new_settings.dpi.width() == -1)
new_settings.dpi.set_width(GetDeviceCaps(dc, LOGPIXELSX));
if (new_settings.dpi.height() == -1)
new_settings.dpi.set_height(GetDeviceCaps(dc, LOGPIXELSY));
gfx::Rect dest;
int rotate = CalculatePosition(page.get(), new_settings, &dest);
int save_state = SaveDC(dc);
IntersectClipRect(dc, settings.bounds.x(), settings.bounds.y(),
settings.bounds.x() + settings.bounds.width(),
settings.bounds.y() + settings.bounds.height());
int flags = GetRenderFlagsFromSettings(settings);
int device_type = GetDeviceCaps(dc, TECHNOLOGY);
if (device_type == DT_RASPRINTER || device_type == DT_PLOTTER) {
ScopedFPDFBitmap bitmap(
FPDFBitmap_Create(dest.width(), dest.height(), FPDFBitmap_BGRx));
FPDFBitmap_FillRect(bitmap.get(), 0, 0, dest.width(), dest.height(),
0xFFFFFFFF);
FPDF_RenderPageBitmap(bitmap.get(), page.get(), 0, 0, dest.width(),
dest.height(), rotate, flags);
int stride = FPDFBitmap_GetStride(bitmap.get());
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = dest.width();
bmi.bmiHeader.biHeight = -dest.height();
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = stride * dest.height();
StretchDIBits(dc, dest.x(), dest.y(), dest.width(), dest.height(), 0, 0,
dest.width(), dest.height(),
FPDFBitmap_GetBuffer(bitmap.get()), &bmi, DIB_RGB_COLORS,
SRCCOPY);
} else {
FPDF_RenderPage(dc, page.get(), dest.x(), dest.y(), dest.width(),
dest.height(), rotate, flags);
}
RestoreDC(dc, save_state);
return true;
}
void PDFiumEngineExports::SetPDFUsePrintMode(int mode) {
FPDF_SetPrintMode(mode);
}
#endif
bool PDFiumEngineExports::RenderPDFPageToBitmap(
base::span<const uint8_t> pdf_buffer,
int page_index,
const RenderingSettings& settings,
void* bitmap_buffer) { … }
std::vector<uint8_t> PDFiumEngineExports::ConvertPdfPagesToNupPdf(
std::vector<base::span<const uint8_t>> input_buffers,
size_t pages_per_sheet,
const gfx::Size& page_size,
const gfx::Rect& printable_area) { … }
std::vector<uint8_t> PDFiumEngineExports::ConvertPdfDocumentToNupPdf(
base::span<const uint8_t> input_buffer,
size_t pages_per_sheet,
const gfx::Size& page_size,
const gfx::Rect& printable_area) { … }
bool PDFiumEngineExports::GetPDFDocInfo(base::span<const uint8_t> pdf_buffer,
int* page_count,
float* max_page_width) { … }
std::optional<DocumentMetadata> PDFiumEngineExports::GetPDFDocMetadata(
base::span<const uint8_t> pdf_buffer) { … }
std::optional<bool> PDFiumEngineExports::IsPDFDocTagged(
base::span<const uint8_t> pdf_buffer) { … }
base::Value PDFiumEngineExports::GetPDFStructTreeForPage(
base::span<const uint8_t> pdf_buffer,
int page_index) { … }
std::optional<bool> PDFiumEngineExports::PDFDocHasOutline(
base::span<const uint8_t> pdf_buffer) { … }
std::optional<gfx::SizeF> PDFiumEngineExports::GetPDFPageSizeByIndex(
base::span<const uint8_t> pdf_buffer,
int page_index) { … }
#if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
std::vector<uint8_t> PDFiumEngineExports::Searchify(
base::span<const uint8_t> pdf_buffer,
base::RepeatingCallback<screen_ai::mojom::VisualAnnotationPtr(
const SkBitmap& bitmap)> perform_ocr_callback) { … }
std::unique_ptr<PdfProgressiveSearchifier>
PDFiumEngineExports::CreateProgressiveSearchifier() { … }
#endif
}