| // Copyright 2026 The PDFium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "fpdfsdk/display_list_renderer.h" |
| |
| #include <utility> |
| |
| #include "core/fpdfapi/page/cpdf_occontext.h" |
| #include "core/fpdfapi/page/cpdf_page.h" |
| #include "core/fpdfapi/parser/cpdf_document.h" |
| #include "core/fpdfapi/render/cpdf_pagerendercontext.h" |
| #include "core/fpdfapi/render/cpdf_renderoptions.h" |
| #include "core/fxcrt/bytestring.h" |
| #include "core/fxcrt/fx_coordinates.h" |
| #include "core/fxcrt/retain_ptr.h" |
| #include "core/fxge/cfx_renderdevice.h" |
| #include "core/fxge/display_list_device_driver.h" |
| #include "fpdfsdk/cpdfsdk_formfillenvironment.h" |
| #include "fpdfsdk/cpdfsdk_helpers.h" |
| #include "fpdfsdk/cpdfsdk_pageview.h" |
| #include "fpdfsdk/cpdfsdk_renderpage.h" |
| #include "public/fpdfview.h" |
| |
| // static |
| std::string DisplayListRenderer::RenderPage(FPDF_PAGE page, |
| FPDF_FORMHANDLE form, |
| int flags) { |
| int width = static_cast<int>(FPDF_GetPageWidthF(page)); |
| int height = static_cast<int>(FPDF_GetPageHeightF(page)); |
| DisplayListRenderer renderer(page, width, height, flags); |
| if (!renderer.Start()) { |
| return std::string(); |
| } |
| renderer.Finish(form); |
| return renderer.GetDisplayList(); |
| } |
| |
| DisplayListRenderer::DisplayListRenderer(FPDF_PAGE page, |
| int width, |
| int height, |
| int flags) |
| : page_(page), width_(width), height_(height), flags_(flags) { |
| auto driver = std::make_unique<DisplayListDeviceDriver>(width, height); |
| driver_ = driver.get(); |
| device_ = CFX_RenderDevice::CreateWithDriver(std::move(driver)); |
| } |
| |
| DisplayListRenderer::~DisplayListRenderer() = default; |
| |
| bool DisplayListRenderer::Start() { |
| if (!device_) { |
| return false; |
| } |
| CPDF_Page* cpdf_page = CPDFPageFromFPDFPage(page_); |
| if (!cpdf_page) { |
| return false; |
| } |
| context_ = std::make_unique<CPDF_PageRenderContext>(); |
| context_->device_ = std::move(device_); |
| CPDFSDK_RenderPageWithContext(context_.get(), cpdf_page, /*start_x=*/0, |
| /*start_y=*/0, /*size_x=*/width_, |
| /*size_y=*/height_, /*rotate=*/0, |
| /*flags=*/flags_, nullptr, |
| /*need_to_restore=*/true, nullptr); |
| return true; |
| } |
| |
| void DisplayListRenderer::Finish(FPDF_FORMHANDLE form) { |
| if (form && context_ && context_->device_) { |
| CPDFSDK_FormFillEnvironment* form_fill_env = |
| CPDFSDKFormFillEnvironmentFromFPDFFormHandle(form); |
| IPDF_Page* ipdf_page = IPDFPageFromFPDFPage(page_); |
| if (form_fill_env && ipdf_page) { |
| CPDFSDK_PageView* page_view = |
| form_fill_env->GetOrCreatePageView(ipdf_page); |
| if (page_view) { |
| CPDF_Page* cpdf_page = CPDFPageFromFPDFPage(page_); |
| const FX_RECT rect(0, 0, width_, height_); |
| CFX_Matrix matrix = cpdf_page->GetDisplayMatrixForRect(rect, 0); |
| CPDF_RenderOptions options; |
| options.GetOptions().bClearType = !!(flags_ & FPDF_LCD_TEXT); |
| if (flags_ & FPDF_GRAYSCALE) { |
| options.SetColorMode(CPDF_RenderOptions::kGray); |
| } |
| options.SetDrawAnnots(flags_ & FPDF_ANNOT); |
| options.SetOCContext(pdfium::MakeRetain<CPDF_OCContext>( |
| cpdf_page->GetDocument(), CPDF_OCContext::kView)); |
| page_view->PageView_OnDraw(context_->device_.get(), matrix, &options, |
| rect); |
| } |
| } |
| } |
| } |
| |
| std::string DisplayListRenderer::GetDisplayList() const { |
| return std::string(driver_->display_list().c_str()); |
| } |