1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <test/bootstrapfixture.hxx>
11 #include <unotest/macros_test.hxx>
15 #include <config_features.h>
17 #include <comphelper/scopeguard.hxx>
18 #include <comphelper/processfactory.hxx>
19 #include <comphelper/propertysequence.hxx>
21 #include <unotools/tempfile.hxx>
22 #include <unotools/mediadescriptor.hxx>
23 #include <tools/stream.hxx>
24 #include <svx/svdograf.hxx>
25 #include <editeng/outlobj.hxx>
26 #include <editeng/editobj.hxx>
28 #include <DrawDocShell.hxx>
29 #include <DrawController.hxx>
30 #include <ViewShell.hxx>
31 #include <drawdoc.hxx>
33 #include <unomodel.hxx>
35 #include <com/sun/star/frame/Desktop.hpp>
39 class SdrPdfImportTest
: public test::BootstrapFixture
, public unotest::MacrosTest
42 uno::Reference
<lang::XComponent
> mxComponent
;
45 virtual void setUp() override
;
46 virtual void tearDown() override
;
49 void SdrPdfImportTest::setUp()
51 test::BootstrapFixture::setUp();
53 mxDesktop
.set(frame::Desktop::create(mxComponentContext
));
56 void SdrPdfImportTest::tearDown()
59 mxComponent
->dispose();
61 test::BootstrapFixture::tearDown();
64 // Load the PDF in Draw, which will load the PDF as an Graphic, then
65 // mark the graphic object and trigger "break" function. This should
66 // convert the PDF content into objects/shapes.
67 CPPUNIT_TEST_FIXTURE(SdrPdfImportTest
, testImportSimpleText
)
69 #if HAVE_FEATURE_PDFIUM && !defined(_WIN32)
70 // We need to enable PDFium import (and make sure to disable after the test)
71 bool bResetEnvVar
= false;
72 if (getenv("LO_IMPORT_USE_PDFIUM") == nullptr)
75 setenv("LO_IMPORT_USE_PDFIUM", "1", false);
77 comphelper::ScopeGuard
aPDFiumEnvVarGuard([&]() {
79 unsetenv("LO_IMPORT_USE_PDFIUM");
82 mxComponent
= loadFromDesktop(m_directories
.getURLFromSrc("sd/qa/unit/data/SimplePDF.pdf"));
83 auto pImpressDocument
= dynamic_cast<SdXImpressDocument
*>(mxComponent
.get());
84 sd::ViewShell
* pViewShell
= pImpressDocument
->GetDocShell()->GetViewShell();
85 CPPUNIT_ASSERT(pViewShell
);
87 // Get the first page - there should be only one.
88 SdPage
* pPage
= pViewShell
->GetActualPage();
89 CPPUNIT_ASSERT(pPage
);
91 // Check there is one object on the page only
92 CPPUNIT_ASSERT_EQUAL(size_t(1), pPage
->GetObjCount());
94 // Get the first object - there should be only one.
95 SdrObject
* pObject
= pPage
->GetObj(0);
96 CPPUNIT_ASSERT(pObject
);
98 // Check the object is a graphic object
99 SdrGrafObj
* pGraphicObject
= dynamic_cast<SdrGrafObj
*>(pObject
);
100 CPPUNIT_ASSERT(pGraphicObject
);
101 // Check the graphic is a vector graphic and that it is PDF
102 Graphic aGraphic
= pGraphicObject
->GetGraphic();
103 auto const& pVectorGraphicData
= aGraphic
.getVectorGraphicData();
104 CPPUNIT_ASSERT(pVectorGraphicData
);
105 CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf
,
106 pVectorGraphicData
->getVectorGraphicDataType());
109 SdrView
* pView
= pViewShell
->GetView();
110 pView
->MarkObj(pObject
, pView
->GetSdrPageView());
112 // Execute the break operation - to turn the PDF into shapes/objects
113 pViewShell
->GetDrawView()->DoImportMarkedMtf();
115 // Check there is one object on the page only
116 CPPUNIT_ASSERT_EQUAL(size_t(1), pPage
->GetObjCount());
119 SdrObject
* pImportedObject
= pPage
->GetObj(0);
120 CPPUNIT_ASSERT(pImportedObject
);
122 // Check the object position
123 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(2011, 2098), Size(2106 + 1, 302 + 1)),
124 pImportedObject
->GetLogicRect());
126 // Object should be a text object containing one paragraph with
127 // content "This is PDF!"
129 SdrTextObj
* pTextObject
= dynamic_cast<SdrTextObj
*>(pImportedObject
);
130 CPPUNIT_ASSERT(pTextObject
);
131 OutlinerParaObject
* pOutlinerParagraphObject
= pTextObject
->GetOutlinerParaObject();
132 const EditTextObject
& aEdit
= pOutlinerParagraphObject
->GetTextObject();
133 OUString sText
= aEdit
.GetText(0);
134 CPPUNIT_ASSERT_EQUAL(OUString("This is PDF!"), sText
);
136 #endif // HAVE_FEATURE_PDFIUM
139 CPPUNIT_TEST_FIXTURE(SdrPdfImportTest
, testAnnotationsImportExport
)
141 #if HAVE_FEATURE_PDFIUM && !defined(_WIN32)
142 // We need to enable PDFium import (and make sure to disable after the test)
143 bool bResetEnvVar
= false;
144 if (getenv("LO_IMPORT_USE_PDFIUM") == nullptr)
147 setenv("LO_IMPORT_USE_PDFIUM", "1", false);
149 comphelper::ScopeGuard
aPDFiumEnvVarGuard([&]() {
151 unsetenv("LO_IMPORT_USE_PDFIUM");
154 bool bPDFCompressorResetEnvVar
= false;
155 if (getenv("VCL_DEBUG_DISABLE_PDFCOMPRESSION") == nullptr)
157 bPDFCompressorResetEnvVar
= true;
158 setenv("VCL_DEBUG_DISABLE_PDFCOMPRESSION", "1", false);
160 comphelper::ScopeGuard
aPDFCompressorEnvVarGuard([&]() {
161 if (bPDFCompressorResetEnvVar
)
162 unsetenv("VCL_DEBUG_DISABLE_PDFCOMPRESSION");
165 auto pPdfiumLibrary
= vcl::pdf::PDFiumLibrary::get();
168 = loadFromDesktop(m_directories
.getURLFromSrc("sd/qa/unit/data/PdfWithAnnotation.pdf"));
169 auto pImpressDocument
= dynamic_cast<SdXImpressDocument
*>(mxComponent
.get());
170 sd::ViewShell
* pViewShell
= pImpressDocument
->GetDocShell()->GetViewShell();
171 CPPUNIT_ASSERT(pViewShell
);
173 const void* pData
= nullptr;
177 // Get the first page - there should be only one.
178 SdPage
* pPage
= pViewShell
->GetActualPage();
179 CPPUNIT_ASSERT(pPage
);
181 // Check the number of annotations
182 CPPUNIT_ASSERT_EQUAL(size_t(1), pPage
->getAnnotations().size());
184 // Get the first object - there should be only one.
185 SdrObject
* pObject
= pPage
->GetObj(0);
186 CPPUNIT_ASSERT(pObject
);
188 // Check the object is a graphic object
189 SdrGrafObj
* pGraphicObject
= dynamic_cast<SdrGrafObj
*>(pObject
);
190 CPPUNIT_ASSERT(pGraphicObject
);
192 // Check the graphic is a vector graphic and that it is PDF
193 Graphic aGraphic
= pGraphicObject
->GetGraphic();
194 auto const& pVectorGraphicData
= aGraphic
.getVectorGraphicData();
195 CPPUNIT_ASSERT(pVectorGraphicData
);
196 CPPUNIT_ASSERT_EQUAL(VectorGraphicDataType::Pdf
,
197 pVectorGraphicData
->getVectorGraphicDataType());
200 pData
= pVectorGraphicData
->getVectorGraphicDataArray().getConstArray();
201 nLength
= pVectorGraphicData
->getVectorGraphicDataArrayLength();
204 { // check graphic PDF has annotations
206 auto pPDFDocument
= pPdfiumLibrary
->openDocument(pData
, nLength
);
207 auto pPDFPage
= pPDFDocument
->openPage(0);
209 CPPUNIT_ASSERT_EQUAL(2, pPDFPage
->getAnnotationCount());
211 auto pPDFAnnotation1
= pPDFPage
->getAnnotation(0);
212 CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Text
,
213 pPDFAnnotation1
->getSubType()); // Text annotation
215 auto pPDFAnnotation2
= pPDFPage
->getAnnotation(1);
216 CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Popup
,
217 pPDFAnnotation2
->getSubType()); // Pop-up annotation
220 { // save as PDF and check annotations
221 utl::TempFile aTempFile
;
222 aTempFile
.EnableKillingFile();
224 uno::Reference
<frame::XStorable
> xStorable(mxComponent
, uno::UNO_QUERY
);
225 utl::MediaDescriptor aMediaDescriptor
;
226 aMediaDescriptor
["FilterName"] <<= OUString("writer_pdf_Export");
227 uno::Sequence
<beans::PropertyValue
> aFilterData(
228 comphelper::InitPropertySequence({ { "ExportBookmarks", uno::Any(true) } }));
229 aMediaDescriptor
["FilterData"] <<= aFilterData
;
230 xStorable
->storeToURL(aTempFile
.GetURL(), aMediaDescriptor
.getAsConstPropertyValueList());
231 mxComponent
->dispose();
233 SvFileStream
aFile(aTempFile
.GetURL(), StreamMode::READ
);
234 SvMemoryStream aMemory
;
235 aMemory
.WriteStream(aFile
);
237 // Check PDF for annotations
238 auto pPDFDocument
= pPdfiumLibrary
->openDocument(aMemory
.GetData(), aMemory
.GetSize());
239 CPPUNIT_ASSERT(pPDFDocument
);
240 CPPUNIT_ASSERT_EQUAL(1, pPDFDocument
->getPageCount());
242 auto pPDFPage
= pPDFDocument
->openPage(0);
243 CPPUNIT_ASSERT(pPDFPage
);
245 CPPUNIT_ASSERT_EQUAL(2, pPDFPage
->getAnnotationCount());
247 auto pPDFAnnotation1
= pPDFPage
->getAnnotation(0);
248 CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Text
,
249 pPDFAnnotation1
->getSubType()); // Text annotation
251 auto pPDFAnnotation2
= pPDFPage
->getAnnotation(1);
252 CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Popup
,
253 pPDFAnnotation2
->getSubType()); // Pop-up annotation
255 // Load document again
256 mxComponent
= loadFromDesktop(aTempFile
.GetURL());
257 auto pNewImpressDocument
= dynamic_cast<SdXImpressDocument
*>(mxComponent
.get());
258 sd::ViewShell
* pNewViewShell
= pNewImpressDocument
->GetDocShell()->GetViewShell();
259 CPPUNIT_ASSERT(pNewViewShell
);
261 SdPage
* pPage
= pNewViewShell
->GetActualPage();
262 CPPUNIT_ASSERT(pPage
);
264 // We expect only 1 annotation in the document because the PDF
265 // annotations are dependent on each-other:
266 // parent annotation "Text" and the child annotation "Pop-up"
268 CPPUNIT_ASSERT_EQUAL(size_t(1), pPage
->getAnnotations().size());
271 auto xAnnotation
= pPage
->getAnnotations().at(0);
273 CPPUNIT_ASSERT_DOUBLES_EQUAL(90.33, xAnnotation
->getPosition().X
, 1E-3);
274 CPPUNIT_ASSERT_DOUBLES_EQUAL(12.07, xAnnotation
->getPosition().Y
, 1E-3);
276 CPPUNIT_ASSERT_EQUAL(OUString("TheAuthor"), xAnnotation
->getAuthor());
277 CPPUNIT_ASSERT_EQUAL(OUString(), xAnnotation
->getInitials());
279 auto xText
= xAnnotation
->getTextRange();
281 CPPUNIT_ASSERT_EQUAL(OUString("This is the annotation text!"), xText
->getString());
283 auto aDateTime
= xAnnotation
->getDateTime();
284 CPPUNIT_ASSERT_EQUAL(sal_Int16(2020), aDateTime
.Year
);
285 CPPUNIT_ASSERT_EQUAL(sal_uInt16(6), aDateTime
.Month
);
286 CPPUNIT_ASSERT_EQUAL(sal_uInt16(18), aDateTime
.Day
);
287 CPPUNIT_ASSERT_EQUAL(sal_uInt16(12), aDateTime
.Hours
);
288 CPPUNIT_ASSERT_EQUAL(sal_uInt16(11), aDateTime
.Minutes
);
289 CPPUNIT_ASSERT_EQUAL(sal_uInt16(53), aDateTime
.Seconds
);
290 CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), aDateTime
.NanoSeconds
);
291 CPPUNIT_ASSERT_EQUAL(false, bool(aDateTime
.IsUTC
));
294 #endif // HAVE_FEATURE_PDFIUM
297 CPPUNIT_PLUGIN_IMPLEMENT();
299 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */