// Copyright 2016 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "core/fpdfapi/page/cpdf_form.h" #include "core/fpdfapi/page/cpdf_formobject.h" #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_name.h" #include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/cpdf_string.h" #include "core/fxge/cfx_defaultrenderdevice.h" #include "fpdfsdk/cpdfsdk_helpers.h" #include "public/cpp/fpdf_scopers.h" #include "public/fpdf_edit.h" #include "public/fpdf_ppo.h" #include "public/fpdf_save.h" #include "public/fpdfview.h" #include "testing/embedder_test.h" #include "testing/embedder_test_constants.h" #include "testing/gtest/include/gtest/gtest.h" namespace { class FPDFPPOEmbedderTest : public EmbedderTest {}; int FakeBlockWriter(FPDF_FILEWRITE* pThis, const void* pData, unsigned long size) { return 1; // Always succeeds. } constexpr int kRectanglesMultiPagesPageCount = 2; const char* RectanglesMultiPagesExpectedChecksum(int page_index) { if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) { static constexpr const char* kChecksums[kRectanglesMultiPagesPageCount] = { "07606a12487bd0c28a88f23fa00fc313", "94ea6e1eef220833a3ec14d6a1c612b0"}; return kChecksums[page_index]; } static constexpr const char* kChecksums[kRectanglesMultiPagesPageCount] = { "72d0d7a19a2f40e010ca6a1133b33e1e", "fb18142190d770cfbc329d2b071aee4d"}; return kChecksums[page_index]; } const char* Bug750568PageHash(int page_index) { constexpr int kBug750568PageCount = 4; if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) { static constexpr const char* kChecksums[kBug750568PageCount] = { "eaa139e944eafb43d31e8742a0e158de", "226485e9d4fa6a67dfe0a88723f12060", "c5601a3492ae5dcc5dd25140fc463bfe", "1f60055b54de4fac8a59c65e90da156e"}; return kChecksums[page_index]; } static constexpr const char* kChecksums[kBug750568PageCount] = { "64ad08132a1c5a166768298c8a578f57", "83b83e2f6bc80707d0a917c7634140b9", "913cd3723a451e4e46fbc2c05702d1ee", "81fb7cfd4860f855eb468f73dfeb6d60"}; return kChecksums[page_index]; } } // namespace TEST_F(FPDFPPOEmbedderTest, NoViewerPreferences) { ASSERT_TRUE(OpenDocument("hello_world.pdf")); FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument(); EXPECT_TRUE(output_doc); EXPECT_FALSE(FPDF_CopyViewerPreferences(output_doc, document())); FPDF_CloseDocument(output_doc); } TEST_F(FPDFPPOEmbedderTest, ViewerPreferences) { ASSERT_TRUE(OpenDocument("viewer_ref.pdf")); FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument(); EXPECT_TRUE(output_doc); EXPECT_TRUE(FPDF_CopyViewerPreferences(output_doc, document())); FPDF_CloseDocument(output_doc); } TEST_F(FPDFPPOEmbedderTest, ImportPagesByIndex) { ASSERT_TRUE(OpenDocument("viewer_ref.pdf")); FPDF_PAGE page = LoadPage(0); EXPECT_TRUE(page); ScopedFPDFDocument output_doc(FPDF_CreateNewDocument()); ASSERT_TRUE(output_doc); EXPECT_TRUE(FPDF_CopyViewerPreferences(output_doc.get(), document())); static constexpr int kPageIndices[] = {1}; EXPECT_TRUE(FPDF_ImportPagesByIndex( output_doc.get(), document(), kPageIndices, std::size(kPageIndices), 0)); EXPECT_EQ(1, FPDF_GetPageCount(output_doc.get())); UnloadPage(page); } TEST_F(FPDFPPOEmbedderTest, ImportPages) { ASSERT_TRUE(OpenDocument("viewer_ref.pdf")); FPDF_PAGE page = LoadPage(0); EXPECT_TRUE(page); FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument(); ASSERT_TRUE(output_doc); EXPECT_TRUE(FPDF_CopyViewerPreferences(output_doc, document())); EXPECT_TRUE(FPDF_ImportPages(output_doc, document(), "1", 0)); EXPECT_EQ(1, FPDF_GetPageCount(output_doc)); FPDF_CloseDocument(output_doc); UnloadPage(page); } TEST_F(FPDFPPOEmbedderTest, ImportNPages) { ASSERT_TRUE(OpenDocument("rectangles_multi_pages.pdf")); ScopedFPDFDocument output_doc_2up( FPDF_ImportNPagesToOne(document(), 612, 792, 2, 1)); ASSERT_TRUE(output_doc_2up); EXPECT_EQ(3, FPDF_GetPageCount(output_doc_2up.get())); ScopedFPDFDocument output_doc_5up( FPDF_ImportNPagesToOne(document(), 612, 792, 5, 1)); ASSERT_TRUE(output_doc_5up); EXPECT_EQ(1, FPDF_GetPageCount(output_doc_5up.get())); ScopedFPDFDocument output_doc_8up( FPDF_ImportNPagesToOne(document(), 792, 612, 8, 1)); ASSERT_TRUE(output_doc_8up); EXPECT_EQ(1, FPDF_GetPageCount(output_doc_8up.get())); ScopedFPDFDocument output_doc_128up( FPDF_ImportNPagesToOne(document(), 792, 612, 128, 1)); ASSERT_TRUE(output_doc_128up); EXPECT_EQ(1, FPDF_GetPageCount(output_doc_128up.get())); } TEST_F(FPDFPPOEmbedderTest, BadNupParams) { ASSERT_TRUE(OpenDocument("rectangles_multi_pages.pdf")); FPDF_DOCUMENT output_doc_zero_row = FPDF_ImportNPagesToOne(document(), 612, 792, 0, 3); ASSERT_FALSE(output_doc_zero_row); FPDF_DOCUMENT output_doc_zero_col = FPDF_ImportNPagesToOne(document(), 612, 792, 2, 0); ASSERT_FALSE(output_doc_zero_col); FPDF_DOCUMENT output_doc_zero_width = FPDF_ImportNPagesToOne(document(), 0, 792, 2, 1); ASSERT_FALSE(output_doc_zero_width); FPDF_DOCUMENT output_doc_zero_height = FPDF_ImportNPagesToOne(document(), 612, 0, 7, 1); ASSERT_FALSE(output_doc_zero_height); } // TODO(Xlou): Add more tests to check output doc content of // FPDF_ImportNPagesToOne() TEST_F(FPDFPPOEmbedderTest, NupRenderImage) { ASSERT_TRUE(OpenDocument("rectangles_multi_pages.pdf")); ScopedFPDFDocument output_doc_3up( FPDF_ImportNPagesToOne(document(), 792, 612, 3, 1)); ASSERT_TRUE(output_doc_3up); ASSERT_EQ(kRectanglesMultiPagesPageCount, FPDF_GetPageCount(output_doc_3up.get())); for (int i = 0; i < kRectanglesMultiPagesPageCount; ++i) { ScopedFPDFPage page(FPDF_LoadPage(output_doc_3up.get(), i)); ASSERT_TRUE(page); ScopedFPDFBitmap bitmap = RenderPage(page.get()); EXPECT_EQ(792, FPDFBitmap_GetWidth(bitmap.get())); EXPECT_EQ(612, FPDFBitmap_GetHeight(bitmap.get())); EXPECT_EQ(RectanglesMultiPagesExpectedChecksum(i), HashBitmap(bitmap.get())); } } TEST_F(FPDFPPOEmbedderTest, ImportPageToXObject) { const char* checksum = []() { if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) return "d6ebc0a8afc22fe0137f54ce54e1a19c"; return "2d88d180af7109eb346439f7c855bb29"; }(); ASSERT_TRUE(OpenDocument("rectangles.pdf")); { ScopedFPDFDocument output_doc(FPDF_CreateNewDocument()); ASSERT_TRUE(output_doc); FPDF_XOBJECT xobject = FPDF_NewXObjectFromPage(output_doc.get(), document(), 0); ASSERT_TRUE(xobject); for (int i = 0; i < 2; ++i) { ScopedFPDFPage page(FPDFPage_New(output_doc.get(), 0, 612, 792)); ASSERT_TRUE(page); FPDF_PAGEOBJECT page_object = FPDF_NewFormObjectFromXObject(xobject); ASSERT_TRUE(page_object); EXPECT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(page_object)); FPDFPage_InsertObject(page.get(), page_object); EXPECT_TRUE(FPDFPage_GenerateContent(page.get())); ScopedFPDFBitmap page_bitmap = RenderPage(page.get()); CompareBitmap(page_bitmap.get(), 612, 792, checksum); float left; float bottom; float right; float top; ASSERT_TRUE( FPDFPageObj_GetBounds(page_object, &left, &bottom, &right, &top)); EXPECT_FLOAT_EQ(-1.0f, left); EXPECT_FLOAT_EQ(-1.0f, bottom); EXPECT_FLOAT_EQ(201.0f, right); EXPECT_FLOAT_EQ(301.0f, top); } EXPECT_TRUE(FPDF_SaveAsCopy(output_doc.get(), this, 0)); FPDF_CloseXObject(xobject); } constexpr int kExpectedPageCount = 2; ASSERT_TRUE(OpenSavedDocument()); FPDF_PAGE saved_pages[kExpectedPageCount]; FPDF_PAGEOBJECT xobjects[kExpectedPageCount]; for (int i = 0; i < kExpectedPageCount; ++i) { saved_pages[i] = LoadSavedPage(i); ASSERT_TRUE(saved_pages[i]); EXPECT_EQ(1, FPDFPage_CountObjects(saved_pages[i])); xobjects[i] = FPDFPage_GetObject(saved_pages[i], 0); ASSERT_TRUE(xobjects[i]); ASSERT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(xobjects[i])); EXPECT_EQ(8, FPDFFormObj_CountObjects(xobjects[i])); { ScopedFPDFBitmap page_bitmap = RenderPage(saved_pages[i]); CompareBitmap(page_bitmap.get(), 612, 792, checksum); } } for (int i = 0; i < kExpectedPageCount; ++i) { float left; float bottom; float right; float top; ASSERT_TRUE( FPDFPageObj_GetBounds(xobjects[i], &left, &bottom, &right, &top)); EXPECT_FLOAT_EQ(-1.0f, left); EXPECT_FLOAT_EQ(-1.0f, bottom); EXPECT_FLOAT_EQ(201.0f, right); EXPECT_FLOAT_EQ(301.0f, top); } // Peek at object internals to make sure the two XObjects use the same stream. EXPECT_NE(xobjects[0], xobjects[1]); CPDF_PageObject* obj1 = CPDFPageObjectFromFPDFPageObject(xobjects[0]); ASSERT_TRUE(obj1->AsForm()); ASSERT_TRUE(obj1->AsForm()->form()); ASSERT_TRUE(obj1->AsForm()->form()->GetStream()); CPDF_PageObject* obj2 = CPDFPageObjectFromFPDFPageObject(xobjects[1]); ASSERT_TRUE(obj2->AsForm()); ASSERT_TRUE(obj2->AsForm()->form()); ASSERT_TRUE(obj2->AsForm()->form()->GetStream()); EXPECT_EQ(obj1->AsForm()->form()->GetStream(), obj2->AsForm()->form()->GetStream()); for (FPDF_PAGE saved_page : saved_pages) CloseSavedPage(saved_page); CloseSavedDocument(); } TEST_F(FPDFPPOEmbedderTest, ImportPageToXObjectWithSameDoc) { const char* checksum = []() { if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) return "8e7d672f49f9ca98fb9157824cefc204"; return "4d5ca14827b7707f8283e639b33c121a"; }(); ASSERT_TRUE(OpenDocument("rectangles.pdf")); FPDF_XOBJECT xobject = FPDF_NewXObjectFromPage(document(), document(), 0); ASSERT_TRUE(xobject); FPDF_PAGE page = LoadPage(0); ASSERT_TRUE(page); { ScopedFPDFBitmap bitmap = RenderLoadedPage(page); CompareBitmap(bitmap.get(), 200, 300, pdfium::RectanglesChecksum()); } FPDF_PAGEOBJECT page_object = FPDF_NewFormObjectFromXObject(xobject); ASSERT_TRUE(page_object); ASSERT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(page_object)); static constexpr FS_MATRIX kMatrix = {0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f}; EXPECT_TRUE(FPDFPageObj_SetMatrix(page_object, &kMatrix)); FPDFPage_InsertObject(page, page_object); EXPECT_TRUE(FPDFPage_GenerateContent(page)); { ScopedFPDFBitmap bitmap = RenderLoadedPage(page); CompareBitmap(bitmap.get(), 200, 300, checksum); } FPDF_CloseXObject(xobject); EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0)); VerifySavedDocument(200, 300, checksum); UnloadPage(page); } TEST_F(FPDFPPOEmbedderTest, XObjectNullParams) { ASSERT_TRUE(OpenDocument("rectangles.pdf")); ASSERT_EQ(1, FPDF_GetPageCount(document())); EXPECT_FALSE(FPDF_NewXObjectFromPage(nullptr, nullptr, -1)); EXPECT_FALSE(FPDF_NewXObjectFromPage(nullptr, nullptr, 0)); EXPECT_FALSE(FPDF_NewXObjectFromPage(nullptr, nullptr, 1)); EXPECT_FALSE(FPDF_NewXObjectFromPage(document(), nullptr, -1)); EXPECT_FALSE(FPDF_NewXObjectFromPage(document(), nullptr, 0)); EXPECT_FALSE(FPDF_NewXObjectFromPage(document(), nullptr, 1)); EXPECT_FALSE(FPDF_NewXObjectFromPage(nullptr, document(), -1)); EXPECT_FALSE(FPDF_NewXObjectFromPage(nullptr, document(), 0)); EXPECT_FALSE(FPDF_NewXObjectFromPage(nullptr, document(), 1)); { ScopedFPDFDocument output_doc(FPDF_CreateNewDocument()); ASSERT_TRUE(output_doc); EXPECT_FALSE(FPDF_NewXObjectFromPage(output_doc.get(), document(), -1)); EXPECT_FALSE(FPDF_NewXObjectFromPage(output_doc.get(), document(), 1)); } // Should be a no-op. FPDF_CloseXObject(nullptr); EXPECT_FALSE(FPDF_NewFormObjectFromXObject(nullptr)); } TEST_F(FPDFPPOEmbedderTest, BUG_925981) { ASSERT_TRUE(OpenDocument("bug_925981.pdf")); ScopedFPDFDocument output_doc_2up( FPDF_ImportNPagesToOne(document(), 612, 792, 2, 1)); EXPECT_EQ(1, FPDF_GetPageCount(output_doc_2up.get())); } TEST_F(FPDFPPOEmbedderTest, BUG_1229106) { static constexpr int kPageCount = 4; static constexpr int kTwoUpPageCount = 2; static const char kRectsChecksum[] = "140d629b3c96a07ced2e3e408ea85a1d"; static const char kTwoUpChecksum[] = "fa4501562301b2e75da354bd067495ec"; ASSERT_TRUE(OpenDocument("bug_1229106.pdf")); // Show all pages render the same. ASSERT_EQ(kPageCount, FPDF_GetPageCount(document())); for (int i = 0; i < kPageCount; ++i) { FPDF_PAGE page = LoadPage(0); ScopedFPDFBitmap bitmap = RenderLoadedPage(page); CompareBitmap(bitmap.get(), 792, 612, kRectsChecksum); UnloadPage(page); } // Create a 2-up PDF. ScopedFPDFDocument output_doc_2up( FPDF_ImportNPagesToOne(document(), 612, 792, 1, 2)); ASSERT_EQ(kTwoUpPageCount, FPDF_GetPageCount(output_doc_2up.get())); for (int i = 0; i < kTwoUpPageCount; ++i) { ScopedFPDFPage page(FPDF_LoadPage(output_doc_2up.get(), i)); ScopedFPDFBitmap bitmap = RenderPage(page.get()); CompareBitmap(bitmap.get(), 612, 792, kTwoUpChecksum); } } TEST_F(FPDFPPOEmbedderTest, BadRepeatViewerPref) { ASSERT_TRUE(OpenDocument("repeat_viewer_ref.pdf")); FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument(); EXPECT_TRUE(output_doc); EXPECT_TRUE(FPDF_CopyViewerPreferences(output_doc, document())); FPDF_FILEWRITE writer; writer.version = 1; writer.WriteBlock = FakeBlockWriter; EXPECT_TRUE(FPDF_SaveAsCopy(output_doc, &writer, 0)); FPDF_CloseDocument(output_doc); } TEST_F(FPDFPPOEmbedderTest, BadCircularViewerPref) { ASSERT_TRUE(OpenDocument("circular_viewer_ref.pdf")); FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument(); EXPECT_TRUE(output_doc); EXPECT_TRUE(FPDF_CopyViewerPreferences(output_doc, document())); FPDF_FILEWRITE writer; writer.version = 1; writer.WriteBlock = FakeBlockWriter; EXPECT_TRUE(FPDF_SaveAsCopy(output_doc, &writer, 0)); FPDF_CloseDocument(output_doc); } TEST_F(FPDFPPOEmbedderTest, CopyViewerPrefTypes) { ASSERT_TRUE(OpenDocument("viewer_pref_types.pdf")); ScopedFPDFDocument output_doc(FPDF_CreateNewDocument()); ASSERT_TRUE(output_doc); EXPECT_TRUE(FPDF_CopyViewerPreferences(output_doc.get(), document())); // Peek under the hook to check the result. const CPDF_Document* output_doc_impl = CPDFDocumentFromFPDFDocument(output_doc.get()); RetainPtr prefs = output_doc_impl->GetRoot()->GetDictFor("ViewerPreferences"); ASSERT_TRUE(prefs); EXPECT_EQ(6u, prefs->size()); RetainPtr bool_obj = prefs->GetObjectFor("Bool"); ASSERT_TRUE(bool_obj); EXPECT_TRUE(bool_obj->IsBoolean()); RetainPtr num_obj = prefs->GetNumberFor("Num"); ASSERT_TRUE(num_obj); EXPECT_TRUE(num_obj->IsInteger()); EXPECT_EQ(1, num_obj->GetInteger()); RetainPtr str_obj = prefs->GetStringFor("Str"); ASSERT_TRUE(str_obj); EXPECT_EQ("str", str_obj->GetString()); EXPECT_EQ("name", prefs->GetNameFor("Name")); RetainPtr empty_array_obj = prefs->GetArrayFor("EmptyArray"); ASSERT_TRUE(empty_array_obj); EXPECT_TRUE(empty_array_obj->IsEmpty()); RetainPtr good_array_obj = prefs->GetArrayFor("GoodArray"); ASSERT_TRUE(good_array_obj); EXPECT_EQ(4u, good_array_obj->size()); } TEST_F(FPDFPPOEmbedderTest, BadIndices) { ASSERT_TRUE(OpenDocument("hello_world.pdf")); FPDF_PAGE page = LoadPage(0); EXPECT_TRUE(page); ScopedFPDFDocument output_doc(FPDF_CreateNewDocument()); EXPECT_TRUE(output_doc); static constexpr int kBadIndices1[] = {-1}; EXPECT_FALSE(FPDF_ImportPagesByIndex( output_doc.get(), document(), kBadIndices1, std::size(kBadIndices1), 0)); static constexpr int kBadIndices2[] = {1}; EXPECT_FALSE(FPDF_ImportPagesByIndex( output_doc.get(), document(), kBadIndices2, std::size(kBadIndices2), 0)); static constexpr int kBadIndices3[] = {-1, 0, 1}; EXPECT_FALSE(FPDF_ImportPagesByIndex( output_doc.get(), document(), kBadIndices3, std::size(kBadIndices3), 0)); static constexpr int kBadIndices4[] = {42}; EXPECT_FALSE(FPDF_ImportPagesByIndex( output_doc.get(), document(), kBadIndices4, std::size(kBadIndices4), 0)); UnloadPage(page); } TEST_F(FPDFPPOEmbedderTest, GoodIndices) { ASSERT_TRUE(OpenDocument("viewer_ref.pdf")); FPDF_PAGE page = LoadPage(0); EXPECT_TRUE(page); ScopedFPDFDocument output_doc(FPDF_CreateNewDocument()); EXPECT_TRUE(output_doc); static constexpr int kGoodIndices1[] = {0, 0, 0, 0}; EXPECT_TRUE(FPDF_ImportPagesByIndex(output_doc.get(), document(), kGoodIndices1, std::size(kGoodIndices1), 0)); EXPECT_EQ(4, FPDF_GetPageCount(output_doc.get())); static constexpr int kGoodIndices2[] = {0}; EXPECT_TRUE(FPDF_ImportPagesByIndex(output_doc.get(), document(), kGoodIndices2, std::size(kGoodIndices2), 0)); EXPECT_EQ(5, FPDF_GetPageCount(output_doc.get())); static constexpr int kGoodIndices3[] = {4}; EXPECT_TRUE(FPDF_ImportPagesByIndex(output_doc.get(), document(), kGoodIndices3, std::size(kGoodIndices3), 0)); EXPECT_EQ(6, FPDF_GetPageCount(output_doc.get())); static constexpr int kGoodIndices4[] = {1, 2, 3}; EXPECT_TRUE(FPDF_ImportPagesByIndex(output_doc.get(), document(), kGoodIndices4, std::size(kGoodIndices4), 0)); EXPECT_EQ(9, FPDF_GetPageCount(output_doc.get())); // Passing in a nullptr should import all the pages. EXPECT_TRUE( FPDF_ImportPagesByIndex(output_doc.get(), document(), nullptr, 0, 0)); EXPECT_EQ(14, FPDF_GetPageCount(output_doc.get())); UnloadPage(page); } TEST_F(FPDFPPOEmbedderTest, BadRanges) { ASSERT_TRUE(OpenDocument("hello_world.pdf")); FPDF_PAGE page = LoadPage(0); EXPECT_TRUE(page); FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument(); EXPECT_TRUE(output_doc); EXPECT_FALSE(FPDF_ImportPages(output_doc, document(), "clams", 0)); EXPECT_FALSE(FPDF_ImportPages(output_doc, document(), "0", 0)); EXPECT_FALSE(FPDF_ImportPages(output_doc, document(), "42", 0)); EXPECT_FALSE(FPDF_ImportPages(output_doc, document(), "1,2", 0)); EXPECT_FALSE(FPDF_ImportPages(output_doc, document(), "1-2", 0)); EXPECT_FALSE(FPDF_ImportPages(output_doc, document(), ",1", 0)); EXPECT_FALSE(FPDF_ImportPages(output_doc, document(), "1,", 0)); EXPECT_FALSE(FPDF_ImportPages(output_doc, document(), "1-", 0)); EXPECT_FALSE(FPDF_ImportPages(output_doc, document(), "-1", 0)); EXPECT_FALSE(FPDF_ImportPages(output_doc, document(), "-,0,,,1-", 0)); FPDF_CloseDocument(output_doc); UnloadPage(page); } TEST_F(FPDFPPOEmbedderTest, GoodRanges) { ASSERT_TRUE(OpenDocument("viewer_ref.pdf")); FPDF_PAGE page = LoadPage(0); EXPECT_TRUE(page); FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument(); EXPECT_TRUE(output_doc); EXPECT_TRUE(FPDF_CopyViewerPreferences(output_doc, document())); EXPECT_TRUE(FPDF_ImportPages(output_doc, document(), "1,1,1,1", 0)); EXPECT_EQ(4, FPDF_GetPageCount(output_doc)); EXPECT_TRUE(FPDF_ImportPages(output_doc, document(), "1-1", 0)); EXPECT_EQ(5, FPDF_GetPageCount(output_doc)); EXPECT_TRUE(FPDF_ImportPages(output_doc, document(), "5-5", 0)); EXPECT_EQ(6, FPDF_GetPageCount(output_doc)); EXPECT_TRUE(FPDF_ImportPages(output_doc, document(), "2-4", 0)); EXPECT_EQ(9, FPDF_GetPageCount(output_doc)); FPDF_CloseDocument(output_doc); UnloadPage(page); } TEST_F(FPDFPPOEmbedderTest, BUG_664284) { ASSERT_TRUE(OpenDocument("bug_664284.pdf")); FPDF_PAGE page = LoadPage(0); ASSERT_NE(nullptr, page); FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument(); EXPECT_TRUE(output_doc); static constexpr int kIndices[] = {0}; EXPECT_TRUE(FPDF_ImportPagesByIndex(output_doc, document(), kIndices, std::size(kIndices), 0)); FPDF_CloseDocument(output_doc); UnloadPage(page); } TEST_F(FPDFPPOEmbedderTest, BUG_750568) { ASSERT_TRUE(OpenDocument("bug_750568.pdf")); ASSERT_EQ(4, FPDF_GetPageCount(document())); for (size_t i = 0; i < 4; ++i) { FPDF_PAGE page = LoadPage(i); ASSERT_TRUE(page); ScopedFPDFBitmap bitmap = RenderLoadedPage(page); CompareBitmap(bitmap.get(), 200, 200, Bug750568PageHash(i)); UnloadPage(page); } FPDF_DOCUMENT output_doc = FPDF_CreateNewDocument(); ASSERT_TRUE(output_doc); static constexpr int kIndices[] = {0, 1, 2, 3}; EXPECT_TRUE(FPDF_ImportPagesByIndex(output_doc, document(), kIndices, std::size(kIndices), 0)); ASSERT_EQ(4, FPDF_GetPageCount(output_doc)); for (size_t i = 0; i < 4; ++i) { FPDF_PAGE page = FPDF_LoadPage(output_doc, i); ASSERT_TRUE(page); ScopedFPDFBitmap bitmap = RenderPage(page); CompareBitmap(bitmap.get(), 200, 200, Bug750568PageHash(i)); FPDF_ClosePage(page); } FPDF_CloseDocument(output_doc); } TEST_F(FPDFPPOEmbedderTest, ImportWithZeroLengthStream) { ASSERT_TRUE(OpenDocument("zero_length_stream.pdf")); FPDF_PAGE page = LoadPage(0); ASSERT_TRUE(page); ScopedFPDFBitmap bitmap = RenderLoadedPage(page); CompareBitmap(bitmap.get(), 200, 200, pdfium::HelloWorldChecksum()); UnloadPage(page); ScopedFPDFDocument new_doc(FPDF_CreateNewDocument()); ASSERT_TRUE(new_doc); static constexpr int kIndices[] = {0}; EXPECT_TRUE(FPDF_ImportPagesByIndex(new_doc.get(), document(), kIndices, std::size(kIndices), 0)); EXPECT_EQ(1, FPDF_GetPageCount(new_doc.get())); ScopedFPDFPage new_page(FPDF_LoadPage(new_doc.get(), 0)); ASSERT_TRUE(new_page); ScopedFPDFBitmap new_bitmap = RenderPage(new_page.get()); CompareBitmap(new_bitmap.get(), 200, 200, pdfium::HelloWorldChecksum()); }