5#include "core/fxge/skia/fx_skia_device.h"
11#include "core/fpdfapi/page/cpdf_page.h"
12#include "core/fpdfapi/render/cpdf_pagerendercontext.h"
13#include "core/fxcrt/fx_codepage.h"
14#include "core/fxge/cfx_defaultrenderdevice.h"
15#include "core/fxge/cfx_fillrenderoptions.h"
16#include "core/fxge/cfx_font.h"
17#include "core/fxge/cfx_graphstatedata.h"
18#include "core/fxge/cfx_path.h"
19#include "core/fxge/cfx_renderdevice.h"
20#include "core/fxge/cfx_textrenderoptions.h"
21#include "core/fxge/dib/cfx_dibitmap.h"
22#include "core/fxge/text_char_pos.h"
23#include "fpdfsdk/cpdfsdk_helpers.h"
24#include "fpdfsdk/cpdfsdk_renderpage.h"
25#include "public/cpp/fpdf_scopers.h"
26#include "public/fpdfview.h"
27#include "testing/embedder_test.h"
28#include "testing/gmock/include/gmock/gmock.h"
29#include "testing/gtest/include/gtest/gtest.h"
30#include "third_party/skia/include/core/SkCanvas.h"
31#include "third_party/skia/include/core/SkImage.h"
32#include "third_party/skia/include/core/SkSize.h"
33#include "third_party/skia/include/utils/SkNoDrawCanvas.h"
37using ::testing::NiceMock;
38using ::testing::SizeIs;
39using ::testing::WithArg;
42 enum class Change { kNo, kYes };
43 enum class Save { kNo, kYes };
44 enum class Clip { kNo, kSame, kDifferentPath, kDifferentMatrix };
45 enum class Graphic { kNone, kPath, kText };
54void EmptyTest(CFX_SkiaDeviceDriver* driver,
const State&) {
60void CommonTest(CFX_SkiaDeviceDriver* driver,
const State& state) {
62 charPos[0].m_Origin = CFX_PointF(0, 1);
89 if (state.m_save == State::Save::kYes)
91 if (state.m_clip != State::Clip::kNo)
93 if (state.m_graphic == State::Graphic::kPath) {
97 }
else if (state.m_graphic == State::Graphic::kText) {
101 if (state.m_save == State::Save::kYes)
105 if (state.m_change == State::Change::kYes) {
106 if (state.m_graphic == State::Graphic::kPath)
108 else if (state.m_graphic == State::Graphic::kText)
111 if (state.m_clip == State::Clip::kSame)
113 else if (state.m_clip == State::Clip::kDifferentPath)
115 else if (state.m_clip == State::Clip::kDifferentMatrix)
117 if (state.m_graphic == State::Graphic::kPath) {
121 }
else if (state.m_graphic == State::Graphic::kText) {
125 if (state.m_save == State::Save::kYes)
130void OutOfSequenceClipTest(CFX_SkiaDeviceDriver* driver,
const State&) {
151void Harness(
void (*Test)(CFX_SkiaDeviceDriver*,
const State&),
152 const State& state) {
153 constexpr int kWidth = 4;
154 constexpr int kHeight = 1;
155 ScopedFPDFBitmap bitmap(FPDFBitmap_Create(kWidth, kHeight, 1));
157 FPDFBitmap_FillRect(bitmap.get(), 0, 0, kWidth, kHeight, 0x00000000);
158 RetainPtr<CFX_DIBitmap> pBitmap(CFXDIBitmapFromFPDFBitmap(bitmap.get()));
159 auto driver = CFX_SkiaDeviceDriver::Create(pBitmap,
false,
nullptr,
false);
161 (*Test)(driver.get(), state);
162 uint32_t pixel = pBitmap->GetPixelForTesting(0, 0);
163 EXPECT_EQ(state.m_pixel, pixel);
166void RenderPageToSkCanvas(FPDF_PAGE page,
174 auto context =
std::make_unique<CPDF_PageRenderContext>();
175 CPDF_PageRenderContext* unowned_context = context.get();
178 cpdf_page->SetRenderContext(
std::move(context));
180 auto default_device =
std::make_unique<CFX_DefaultRenderDevice>();
181 default_device->AttachCanvas(canvas);
182 unowned_context->m_pDevice =
std::move(default_device);
185 size_x
, size_y
, 0
, 0
,
190class MockCanvas :
public SkNoDrawCanvas {
192 MockCanvas(
int width,
int height) : SkNoDrawCanvas(width, height) {}
199 const SkSamplingOptions&,
210 if (!CFX_DefaultRenderDevice::UseSkiaRenderer()) {
213 Harness(&EmptyTest, {});
217 if (!CFX_DefaultRenderDevice::UseSkiaRenderer()) {
220 Harness(&CommonTest, {State::Change::kNo, State::Save::kYes,
221 State::Clip::kSame, State::Graphic::kPath, 0xFF112233});
223 {State::Change::kNo, State::Save::kYes, State::Clip::kDifferentPath,
224 State::Graphic::kPath, 0xFF112233});
225 Harness(&CommonTest, {State::Change::kNo, State::Save::kYes, State::Clip::kNo,
226 State::Graphic::kPath, 0xFF112233});
227 Harness(&CommonTest, {State::Change::kYes, State::Save::kNo, State::Clip::kNo,
228 State::Graphic::kPath, 0xFF112233});
229 Harness(&CommonTest, {State::Change::kNo, State::Save::kNo, State::Clip::kNo,
230 State::Graphic::kPath, 0xFF112233});
234 if (!CFX_DefaultRenderDevice::UseSkiaRenderer()) {
239 {State::Change::kNo, State::Save::kYes, State::Clip::kDifferentMatrix,
240 State::Graphic::kText, 0xFF445566});
241 Harness(&CommonTest, {State::Change::kNo, State::Save::kYes,
242 State::Clip::kSame, State::Graphic::kText, 0xFF445566});
246 if (!CFX_DefaultRenderDevice::UseSkiaRenderer()) {
249 Harness(&OutOfSequenceClipTest, {});
253 static constexpr int kImageWidth = 5100;
254 static constexpr int kImageHeight = 6600;
258 static constexpr int kPageToImageFactor = 20;
259 static constexpr int kPageWidth = kImageWidth / kPageToImageFactor;
260 static constexpr int kPageHeight = kImageHeight / kPageToImageFactor;
263 GTEST_SKIP() <<
"Skia is not the default renderer";
266 ASSERT_TRUE(OpenDocument(
"bug_2034.pdf"));
267 FPDF_PAGE page = LoadPage(0);
270 std::set<
int> image_ids;
271 NiceMock<MockCanvas> canvas(kPageWidth, kPageHeight / 2);
272 EXPECT_CALL(canvas, onDrawImageRect2)
273 .WillRepeatedly(WithArg<0>([&image_ids](
const SkImage* image) {
275 image_ids.insert(image->uniqueID());
279 EXPECT_EQ(SkISize::Make(kImageWidth, kImageHeight), image->dimensions())
280 <<
"Actual image dimensions: " << image->width() <<
"x"
285 RenderPageToSkCanvas(page, 0, 0,
286 kPageWidth, kPageHeight, &canvas);
289 RenderPageToSkCanvas(page, 0, -kPageHeight / 2,
290 kPageWidth, kPageHeight, &canvas);
292 EXPECT_THAT(image_ids, SizeIs(1));
static bool UseSkiaRenderer()
void LoadSubst(const ByteString &face_name, bool bTrueType, uint32_t flags, int weight, int italic_angle, FX_CodePage code_page, bool bVertical)
CFX_Matrix(float a1, float b1, float c1, float d1, float e1, float f1)
void Translate(int32_t x, int32_t y)
void AppendRect(float left, float bottom, float right, float top)
bool DrawDeviceText(pdfium::span< const TextCharPos > pCharPos, CFX_Font *pFont, const CFX_Matrix &mtObject2Device, float font_size, uint32_t color, const CFX_TextRenderOptions &options) override
void SaveState() override
bool SetClip_PathFill(const CFX_Path &path, const CFX_Matrix *pObject2Device, const CFX_FillRenderOptions &fill_options) override
void RestoreState(bool bKeepSaved) override
bool DrawPath(const CFX_Path &path, const CFX_Matrix *pObject2Device, const CFX_GraphStateData *pGraphState, uint32_t fill_color, uint32_t stroke_color, const CFX_FillRenderOptions &fill_options, BlendMode blend_type) override
RenderContextClearer(CPDF_Page *pPage)
CPDF_Page * CPDFPageFromFPDFPage(FPDF_PAGE page)
void CPDFSDK_RenderPageWithContext(CPDF_PageRenderContext *pContext, CPDF_Page *pPage, int start_x, int start_y, int size_x, int size_y, int rotate, int flags, const FPDF_COLORSCHEME *color_scheme, bool need_to_restore, CPDFSDK_PauseAdapter *pause)
TEST_F(FPDFParserDecodeEmbedderTest, Bug552046)
TEST(FXCRYPT, CryptToBase16)
constexpr CFX_FillRenderOptions()
static constexpr CFX_FillRenderOptions WindingOptions()
constexpr CFX_TextRenderOptions(AliasingType type)