vcl/CppunitTest_vcl_pdfexport2.mk | 52 vcl/Module_vcl.mk | 1 vcl/qa/cppunit/pdfexport/pdfexport.cxx | 4732 ------------------------------- vcl/qa/cppunit/pdfexport/pdfexport2.cxx | 4802 ++++++++++++++++++++++++++++++++ 4 files changed, 4856 insertions(+), 4731 deletions(-)
New commits: commit a04fc307ba2706bb9e5b8441aaf4380797b5f397 Author: Xisco Fauli <xiscofa...@libreoffice.org> AuthorDate: Mon Oct 30 16:09:34 2023 +0100 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Tue Oct 31 08:42:56 2023 +0100 CppunitTest_vcl_pdfexport: split into two It already has 109 tests Change-Id: Ic16c5ee68f020c2ee1662354786fb82aada62e0b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158667 Tested-by: Jenkins Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/vcl/CppunitTest_vcl_pdfexport2.mk b/vcl/CppunitTest_vcl_pdfexport2.mk new file mode 100644 index 000000000000..5574f515a7b0 --- /dev/null +++ b/vcl/CppunitTest_vcl_pdfexport2.mk @@ -0,0 +1,52 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_pdfexport2)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_pdfexport2, \ + vcl/qa/cppunit/pdfexport/pdfexport2 \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_pdfexport2)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_pdfexport2, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + subsequenttest \ + test \ + unotest \ + utl \ + tl \ + vcl \ + xmlsecurity \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_pdfexport2, \ + boost_headers \ + $(if $(filter PDFIUM,$(BUILD_TYPE)),pdfium) \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_pdfexport2)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_pdfexport2)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_pdfexport2)) + +$(eval $(call gb_CppunitTest_use_rdb,vcl_pdfexport2,services)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_pdfexport2)) + +# assert if font/glyph fallback occurs +$(eval $(call gb_CppunitTest_set_non_application_font_use,vcl_pdfexport2,abort)) + +$(eval $(call gb_CppunitTest_use_more_fonts,vcl_pdfexport2)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Module_vcl.mk b/vcl/Module_vcl.mk index dd66a86dbf73..19ab27106ad0 100644 --- a/vcl/Module_vcl.mk +++ b/vcl/Module_vcl.mk @@ -286,6 +286,7 @@ endif ifneq (,$(filter PDFIUM,$(BUILD_TYPE))) $(eval $(call gb_Module_add_slowcheck_targets,vcl,\ CppunitTest_vcl_pdfexport \ + CppunitTest_vcl_pdfexport2 \ CppunitTest_vcl_filter_ipdf \ )) endif diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx index 89e2f4990973..fdcc1730b6a8 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx @@ -11,41 +11,21 @@ #include <memory> #include <string_view> -#include <type_traits> -#include <config_features.h> #include <config_fonts.h> -#include <osl/process.h> -#include <com/sun/star/frame/Desktop.hpp> #include <com/sun/star/frame/XStorable.hpp> #include <com/sun/star/view/XPrintable.hpp> -#include <com/sun/star/text/XDocumentIndexesSupplier.hpp> -#include <com/sun/star/util/XRefreshable.hpp> -#include <com/sun/star/beans/XPropertySet.hpp> -#include <com/sun/star/drawing/XShape.hpp> -#include <com/sun/star/text/XTextDocument.hpp> -#include <com/sun/star/document/XFilter.hpp> -#include <com/sun/star/document/XExporter.hpp> -#include <com/sun/star/io/XOutputStream.hpp> - -#include <comphelper/scopeguard.hxx> -#include <comphelper/processfactory.hxx> + #include <comphelper/propertysequence.hxx> #include <test/unoapi_test.hxx> #include <unotools/mediadescriptor.hxx> #include <unotools/tempfile.hxx> #include <vcl/filter/pdfdocument.hxx> #include <tools/zcodec.hxx> -#include <tools/XmlWalker.hxx> -#include <vcl/graphicfilter.hxx> -#include <basegfx/matrix/b2dhommatrix.hxx> -#include <unotools/streamwrap.hxx> -#include <rtl/math.hxx> #include <o3tl/string_view.hxx> #include <vcl/filter/PDFiumLibrary.hxx> -#include <comphelper/propertyvalue.hxx> using namespace ::com::sun::star; @@ -2009,4716 +1989,6 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf115967) CPPUNIT_ASSERT_EQUAL(OUString("m=750abc"), sText); } -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf124272) -{ - // Import the bugdoc and export as PDF. - vcl::filter::PDFDocument aDocument; - load(u"tdf124272.odt", aDocument); - - // The document has one page. - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); - - // The page has a stream. - vcl::filter::PDFObjectElement* pContents = aPages[0]->LookupObject("Contents"); - CPPUNIT_ASSERT(pContents); - vcl::filter::PDFStreamElement* pStream = pContents->GetStream(); - CPPUNIT_ASSERT(pStream); - SvMemoryStream& rObjectStream = pStream->GetMemory(); - // Uncompress it. - SvMemoryStream aUncompressed; - ZCodec aZCodec; - aZCodec.BeginCompression(); - rObjectStream.Seek(0); - aZCodec.Decompress(rObjectStream, aUncompressed); - CPPUNIT_ASSERT(aZCodec.EndCompression()); - - OString aBitmap("Q q 299.899 782.189 m\n" - "55.2 435.889 l 299.899 435.889 l 299.899 782.189 l\n" - "h"); - - auto pStart = static_cast<const char*>(aUncompressed.GetData()); - const char* pEnd = pStart + aUncompressed.GetSize(); - auto it = std::search(pStart, pEnd, aBitmap.getStr(), aBitmap.getStr() + aBitmap.getLength()); - CPPUNIT_ASSERT(it != pEnd); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf121615) -{ - vcl::filter::PDFDocument aDocument; - load(u"tdf121615.odt", aDocument); - - // The document has one page. - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); - - // Get access to the only image on the only page. - vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); - CPPUNIT_ASSERT(pResources); - auto pXObjects - = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject")); - CPPUNIT_ASSERT(pXObjects); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size()); - vcl::filter::PDFObjectElement* pXObject - = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); - CPPUNIT_ASSERT(pXObject); - vcl::filter::PDFStreamElement* pStream = pXObject->GetStream(); - CPPUNIT_ASSERT(pStream); - SvMemoryStream& rObjectStream = pStream->GetMemory(); - - // Load the embedded image. - rObjectStream.Seek(0); - GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); - Graphic aGraphic; - sal_uInt16 format; - ErrCode bResult = rFilter.ImportGraphic(aGraphic, u"import", rObjectStream, - GRFILTER_FORMAT_DONTKNOW, &format); - CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); - - // The image should be grayscale 8bit JPEG. - sal_uInt16 jpegFormat = rFilter.GetImportFormatNumberForShortName(JPG_SHORTNAME); - CPPUNIT_ASSERT(jpegFormat != GRFILTER_FORMAT_NOTFOUND); - CPPUNIT_ASSERT_EQUAL(jpegFormat, format); - BitmapEx aBitmap = aGraphic.GetBitmapEx(); - CPPUNIT_ASSERT_EQUAL(tools::Long(200), aBitmap.GetSizePixel().Width()); - CPPUNIT_ASSERT_EQUAL(tools::Long(300), aBitmap.GetSizePixel().Height()); - CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N8_BPP, aBitmap.getPixelFormat()); - // tdf#121615 was caused by broken handling of data width with 8bit color, - // so the test image has some black in the bottomright corner, check it's there - CPPUNIT_ASSERT_EQUAL(COL_WHITE, aBitmap.GetPixelColor(0, 0)); - CPPUNIT_ASSERT_EQUAL(COL_WHITE, aBitmap.GetPixelColor(0, 299)); - CPPUNIT_ASSERT_EQUAL(COL_WHITE, aBitmap.GetPixelColor(199, 0)); - CPPUNIT_ASSERT_EQUAL(COL_BLACK, aBitmap.GetPixelColor(199, 299)); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf141171) -{ - vcl::filter::PDFDocument aDocument; - load(u"tdf141171.odt", aDocument); - - // The document has one page. - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); - - // Get access to the only image on the only page. - vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); - CPPUNIT_ASSERT(pResources); - auto pXObjects - = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject")); - CPPUNIT_ASSERT(pXObjects); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size()); - vcl::filter::PDFObjectElement* pXObject - = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); - CPPUNIT_ASSERT(pXObject); - vcl::filter::PDFStreamElement* pStream = pXObject->GetStream(); - CPPUNIT_ASSERT(pStream); - SvMemoryStream& rObjectStream = pStream->GetMemory(); - - // Load the embedded image. - rObjectStream.Seek(0); - GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); - Graphic aGraphic; - sal_uInt16 format; - ErrCode bResult = rFilter.ImportGraphic(aGraphic, u"import", rObjectStream, - GRFILTER_FORMAT_DONTKNOW, &format); - CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); - - // The image should be grayscale 8bit JPEG. - sal_uInt16 jpegFormat = rFilter.GetImportFormatNumberForShortName(JPG_SHORTNAME); - CPPUNIT_ASSERT(jpegFormat != GRFILTER_FORMAT_NOTFOUND); - CPPUNIT_ASSERT_EQUAL(jpegFormat, format); - BitmapEx aBitmap = aGraphic.GetBitmapEx(); - Size aSize = aBitmap.GetSizePixel(); - CPPUNIT_ASSERT_EQUAL(tools::Long(878), aSize.Width()); - CPPUNIT_ASSERT_EQUAL(tools::Long(127), aSize.Height()); - CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N8_BPP, aBitmap.getPixelFormat()); - - for (tools::Long nX = 0; nX < aSize.Width(); ++nX) - { - for (tools::Long nY = 0; nY < aSize.Height(); ++nY) - { - // Check all pixels in the image are white - // Without the fix in place, this test would have failed with - // - Expected: Color: R:255 G:255 B:255 A:0 - // - Actual : Color: R:0 G:0 B:0 A:0 - CPPUNIT_ASSERT_EQUAL(COL_WHITE, aBitmap.GetPixelColor(nX, nY)); - } - } -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf129085) -{ - vcl::filter::PDFDocument aDocument; - load(u"tdf129085.docx", aDocument); - - // The document has one page. - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); - - // Get access to the only image on the only page. - vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); - CPPUNIT_ASSERT(pResources); - auto pXObjects - = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject")); - - // Without the fix in place, this test would have failed here - CPPUNIT_ASSERT(pXObjects); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pXObjects->GetItems().size()); - vcl::filter::PDFObjectElement* pXObject - = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); - CPPUNIT_ASSERT(pXObject); - vcl::filter::PDFStreamElement* pStream = pXObject->GetStream(); - CPPUNIT_ASSERT(pStream); - SvMemoryStream& rObjectStream = pStream->GetMemory(); - - // Load the embedded image. - rObjectStream.Seek(0); - GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); - Graphic aGraphic; - sal_uInt16 format; - ErrCode bResult = rFilter.ImportGraphic(aGraphic, u"import", rObjectStream, - GRFILTER_FORMAT_DONTKNOW, &format); - CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); - - sal_uInt16 jpegFormat = rFilter.GetImportFormatNumberForShortName(JPG_SHORTNAME); - CPPUNIT_ASSERT(jpegFormat != GRFILTER_FORMAT_NOTFOUND); - CPPUNIT_ASSERT_EQUAL(jpegFormat, format); - BitmapEx aBitmap = aGraphic.GetBitmapEx(); - CPPUNIT_ASSERT_EQUAL(tools::Long(884), aBitmap.GetSizePixel().Width()); - CPPUNIT_ASSERT_EQUAL(tools::Long(925), aBitmap.GetSizePixel().Height()); - CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N24_BPP, aBitmap.getPixelFormat()); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTocLink) -{ - // Load the Writer document. - loadFromURL(u"toc-link.fodt"); - - // Update the ToC. - uno::Reference<text::XDocumentIndexesSupplier> xDocumentIndexesSupplier(mxComponent, - uno::UNO_QUERY); - CPPUNIT_ASSERT(xDocumentIndexesSupplier.is()); - - uno::Reference<util::XRefreshable> xToc( - xDocumentIndexesSupplier->getDocumentIndexes()->getByIndex(0), uno::UNO_QUERY); - CPPUNIT_ASSERT(xToc.is()); - - xToc->refresh(); - - // Save as PDF. - save("writer_pdf_Export"); - - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount()); - - std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0); - CPPUNIT_ASSERT(pPdfPage); - - // Ensure there is a link on the first page (in the ToC). - // Without the accompanying fix in place, this test would have failed, as the page contained no - // links. - CPPUNIT_ASSERT(pPdfPage->hasLinks()); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testReduceSmallImage) -{ - // Load the Writer document. - aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); - saveAsPDF(u"reduce-small-image.fodt"); - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount()); - std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0); - CPPUNIT_ASSERT(pPdfPage); - CPPUNIT_ASSERT_EQUAL(1, pPdfPage->getObjectCount()); - std::unique_ptr<vcl::pdf::PDFiumPageObject> pPageObject = pPdfPage->getObject(0); - CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFPageObjectType::Image, pPageObject->getType()); - - // Make sure we don't scale down a tiny bitmap. - std::unique_ptr<vcl::pdf::PDFiumBitmap> pBitmap = pPageObject->getImageBitmap(); - CPPUNIT_ASSERT(pBitmap); - int nWidth = pBitmap->getWidth(); - int nHeight = pBitmap->getHeight(); - // Without the accompanying fix in place, this test would have failed with: - // - Expected: 16 - // - Actual : 6 - // i.e. the image was scaled down to 300 DPI, even if it had tiny size. - CPPUNIT_ASSERT_EQUAL(16, nWidth); - CPPUNIT_ASSERT_EQUAL(16, nHeight); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf114256) -{ - aMediaDescriptor["FilterName"] <<= OUString("calc_pdf_Export"); - saveAsPDF(u"tdf114256.ods"); - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount()); - std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0); - CPPUNIT_ASSERT(pPdfPage); - - // Without the fix in place, this test would have failed with - // - Expected: 13 - // - Actual : 0 - CPPUNIT_ASSERT_EQUAL(13, pPdfPage->getObjectCount()); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf150931) -{ - aMediaDescriptor["FilterName"] <<= OUString("calc_pdf_Export"); - saveAsPDF(u"tdf150931.ods"); - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount()); - std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0); - CPPUNIT_ASSERT(pPdfPage); - - int nPageObjectCount = pPdfPage->getObjectCount(); - // Without the fix in place, this test would have failed with - // - Expected: 15 - // - Actual : 16 - CPPUNIT_ASSERT_EQUAL(16, nPageObjectCount); - - int nYellowPathCount = 0; - int nBlackPathCount = 0; - int nGrayPathCount = 0; - int nRedPathCount = 0; - for (int i = 0; i < nPageObjectCount; ++i) - { - std::unique_ptr<vcl::pdf::PDFiumPageObject> pPdfPageObject = pPdfPage->getObject(i); - if (pPdfPageObject->getType() != vcl::pdf::PDFPageObjectType::Path) - continue; - - int nSegments = pPdfPageObject->getPathSegmentCount(); - CPPUNIT_ASSERT_EQUAL(5, nSegments); - - if (pPdfPageObject->getFillColor() == COL_YELLOW) - ++nYellowPathCount; - else if (pPdfPageObject->getFillColor() == COL_BLACK) - ++nBlackPathCount; - else if (pPdfPageObject->getFillColor() == COL_GRAY) - ++nGrayPathCount; - else if (pPdfPageObject->getFillColor() == COL_LIGHTRED) - ++nRedPathCount; - } - - CPPUNIT_ASSERT_EQUAL(3, nYellowPathCount); - CPPUNIT_ASSERT_EQUAL(3, nRedPathCount); - CPPUNIT_ASSERT_EQUAL(3, nGrayPathCount); - CPPUNIT_ASSERT_EQUAL(3, nBlackPathCount); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf147027) -{ - // FIXME: the DPI check should be removed when either (1) the test is fixed to work with - // non-default DPI; or (2) unit tests on Windows are made to use svp VCL plugin. - if (!IsDefaultDPI()) - return; - - // Load the Calc document. - aMediaDescriptor["FilterName"] <<= OUString("calc_pdf_Export"); - saveAsPDF(u"tdf147027.ods"); - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount()); - std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0); - CPPUNIT_ASSERT(pPdfPage); - - // Without the fix in place, this test would have failed with - // - Expected: 778 - // - Actual : 40 - CPPUNIT_ASSERT_EQUAL(778, pPdfPage->getObjectCount()); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf135346) -{ - // Load the Calc document. - aMediaDescriptor["FilterName"] <<= OUString("calc_pdf_Export"); - saveAsPDF(u"tdf135346.ods"); - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount()); - std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0); - CPPUNIT_ASSERT(pPdfPage); - - // Without the fix in place, this test would have failed with - // - Expected: 56 - // - Actual : 0 - CPPUNIT_ASSERT_EQUAL(56, pPdfPage->getObjectCount()); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf147164) -{ - aMediaDescriptor["FilterName"] <<= OUString("impress_pdf_Export"); - saveAsPDF(u"tdf147164.odp"); - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - CPPUNIT_ASSERT_EQUAL(2, pPdfDocument->getPageCount()); - std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/1); - CPPUNIT_ASSERT(pPdfPage); - - // Without the fix in place, this test would have failed with - // - Expected: 22 - // - Actual : 16 - CPPUNIT_ASSERT_EQUAL(22, pPdfPage->getObjectCount()); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testReduceImage) -{ - // Load the Writer document. - loadFromURL(u"reduce-image.fodt"); - - // Save as PDF. - uno::Reference<css::lang::XMultiServiceFactory> xFactory = getMultiServiceFactory(); - uno::Reference<document::XFilter> xFilter( - xFactory->createInstance("com.sun.star.document.PDFFilter"), uno::UNO_QUERY); - uno::Reference<document::XExporter> xExporter(xFilter, uno::UNO_QUERY); - xExporter->setSourceDocument(mxComponent); - - SvFileStream aOutputStream(maTempFile.GetURL(), StreamMode::WRITE); - uno::Reference<io::XOutputStream> xOutputStream(new utl::OStreamWrapper(aOutputStream)); - - uno::Sequence<beans::PropertyValue> aFilterData( - comphelper::InitPropertySequence({ { "ReduceImageResolution", uno::Any(false) } })); - - // This is intentionally in an "unlucky" order, output stream comes before filter data. - uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence({ - { "FilterName", uno::Any(OUString("writer_pdf_Export")) }, - { "OutputStream", uno::Any(xOutputStream) }, - { "FilterData", uno::Any(aFilterData) }, - })); - xFilter->filter(aDescriptor); - aOutputStream.Close(); - - // Parse the PDF: get the image. - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount()); - std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0); - CPPUNIT_ASSERT(pPdfPage); - CPPUNIT_ASSERT_EQUAL(1, pPdfPage->getObjectCount()); - std::unique_ptr<vcl::pdf::PDFiumPageObject> pPageObject = pPdfPage->getObject(0); - CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFPageObjectType::Image, pPageObject->getType()); - - // Make sure we don't scale down a bitmap. - std::unique_ptr<vcl::pdf::PDFiumBitmap> pBitmap = pPageObject->getImageBitmap(); - CPPUNIT_ASSERT(pBitmap); - int nWidth = pBitmap->getWidth(); - int nHeight = pBitmap->getHeight(); - // Without the accompanying fix in place, this test would have failed with: - // - Expected: 160 - // - Actual : 6 - // i.e. the image was scaled down even with ReduceImageResolution=false. - CPPUNIT_ASSERT_EQUAL(160, nWidth); - CPPUNIT_ASSERT_EQUAL(160, nHeight); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testLinkWrongPage) -{ - // Import the bugdoc and export as PDF. - aMediaDescriptor["FilterName"] <<= OUString("impress_pdf_Export"); - saveAsPDF(u"link-wrong-page.odp"); - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - - // The document has 2 pages. - CPPUNIT_ASSERT_EQUAL(2, pPdfDocument->getPageCount()); - - // First page should have 1 link (2nd slide, 1st was hidden). - std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0); - CPPUNIT_ASSERT(pPdfPage); - - // Without the accompanying fix in place, this test would have failed, as the link of the first - // page went to the second page due to the hidden first slide. - CPPUNIT_ASSERT(pPdfPage->hasLinks()); - - // Second page should have no links (3rd slide). - std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage2 = pPdfDocument->openPage(/*nIndex=*/1); - CPPUNIT_ASSERT(pPdfPage2); - CPPUNIT_ASSERT(!pPdfPage2->hasLinks()); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testLinkWrongPagePartial) -{ - // Given a Draw document with 3 pages, a link on the 2nd page: - // When exporting that the 2nd and 3rd page to pdf: - uno::Sequence<beans::PropertyValue> aFilterData = { - comphelper::makePropertyValue("PageRange", OUString("2-3")), - }; - aMediaDescriptor["FilterName"] <<= OUString("draw_pdf_Export"); - aMediaDescriptor["FilterData"] <<= aFilterData; - saveAsPDF(u"link-wrong-page-partial.odg"); - - // Then make sure the we have a link on the 1st page, but not on the 2nd one: - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - CPPUNIT_ASSERT_EQUAL(2, pPdfDocument->getPageCount()); - std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0); - CPPUNIT_ASSERT(pPdfPage); - // Without the accompanying fix in place, this test would have failed, as the link was on the - // 2nd page instead. - CPPUNIT_ASSERT(pPdfPage->hasLinks()); - std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage2 = pPdfDocument->openPage(/*nIndex=*/1); - CPPUNIT_ASSERT(pPdfPage2); - CPPUNIT_ASSERT(!pPdfPage2->hasLinks()); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testPageRange) -{ - // Given a document with 3 pages: - // When exporting that document to PDF, skipping the first page: - aMediaDescriptor["FilterName"] <<= OUString("draw_pdf_Export"); - aMediaDescriptor["FilterOptions"] - <<= OUString("{\"PageRange\":{\"type\":\"string\",\"value\":\"2-\"}}"); - saveAsPDF(u"link-wrong-page-partial.odg"); - - // Then make sure the resulting PDF has 2 pages: - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - // Without the accompanying fix in place, this test would have failed with: - // - Expected: 2 - // - Actual : 3 - // i.e. FilterOptions was ignored. - CPPUNIT_ASSERT_EQUAL(2, pPdfDocument->getPageCount()); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testLargePage) -{ - // Import the bugdoc and export as PDF. - aMediaDescriptor["FilterName"] <<= OUString("draw_pdf_Export"); - saveAsPDF(u"6m-wide.odg"); - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - - // The document has 1 page. - CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount()); - // Check the value (not the unit) of the page size. - basegfx::B2DSize aSize = pPdfDocument->getPageSize(0); - // Without the accompanying fix in place, this test would have failed with: - // - Expected: 8503.94 - // - Actual : 17007.875 - // i.e. the value for 600 cm was larger than the 14 400 limit set in the spec. - CPPUNIT_ASSERT_DOUBLES_EQUAL(8503.94, aSize.getWidth(), 0.01); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testPdfImageResourceInlineXObjectRef) -{ - // Create an empty document. - mxComponent = loadFromDesktop("private:factory/swriter"); - uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); - uno::Reference<text::XText> xText = xTextDocument->getText(); - uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor(); - - // Insert the PDF image. - uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY); - uno::Reference<beans::XPropertySet> xGraphicObject( - xFactory->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY); - OUString aURL = createFileURL(u"pdf-image-resource-inline-xobject-ref.pdf"); - xGraphicObject->setPropertyValue("GraphicURL", uno::Any(aURL)); - uno::Reference<drawing::XShape> xShape(xGraphicObject, uno::UNO_QUERY); - xShape->setSize(awt::Size(1000, 1000)); - uno::Reference<text::XTextContent> xTextContent(xGraphicObject, uno::UNO_QUERY); - xText->insertTextContent(xCursor->getStart(), xTextContent, /*bAbsorb=*/false); - - // Save as PDF. - uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); - aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); - xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); - - // Parse the export result. - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount()); - - // Make sure that the page -> form -> form has a child image. - std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0); - CPPUNIT_ASSERT(pPdfPage); - CPPUNIT_ASSERT_EQUAL(1, pPdfPage->getObjectCount()); - std::unique_ptr<vcl::pdf::PDFiumPageObject> pPageObject = pPdfPage->getObject(0); - CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFPageObjectType::Form, pPageObject->getType()); - // 2: white background and the actual object. - CPPUNIT_ASSERT_EQUAL(2, pPageObject->getFormObjectCount()); - std::unique_ptr<vcl::pdf::PDFiumPageObject> pFormObject = pPageObject->getFormObject(1); - CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFPageObjectType::Form, pFormObject->getType()); - // Without the accompanying fix in place, this test would have failed with: - // - Expected: 1 - // - Actual : 0 - // i.e. the sub-form was missing its image. - CPPUNIT_ASSERT_EQUAL(1, pFormObject->getFormObjectCount()); - - // Check if the inner form object (original page object in the pdf image) has the correct - // rotation. - std::unique_ptr<vcl::pdf::PDFiumPageObject> pInnerFormObject = pFormObject->getFormObject(0); - CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFPageObjectType::Form, pInnerFormObject->getType()); - CPPUNIT_ASSERT_EQUAL(1, pInnerFormObject->getFormObjectCount()); - std::unique_ptr<vcl::pdf::PDFiumPageObject> pImage = pInnerFormObject->getFormObject(0); - CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFPageObjectType::Image, pImage->getType()); - basegfx::B2DHomMatrix aMat = pInnerFormObject->getMatrix(); - basegfx::B2DTuple aScale; - basegfx::B2DTuple aTranslate; - double fRotate = 0; - double fShearX = 0; - aMat.decompose(aScale, aTranslate, fRotate, fShearX); - int nRotateDeg = basegfx::rad2deg(fRotate); - // Without the accompanying fix in place, this test would have failed with: - // - Expected: -90 - // - Actual : 0 - // i.e. rotation was lost on pdf export. - CPPUNIT_ASSERT_EQUAL(-90, nRotateDeg); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testDefaultVersion) -{ - // Create an empty document. - mxComponent = loadFromDesktop("private:factory/swriter"); - - // Save as PDF. - uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); - aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); - xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); - - // Parse the export result. - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - int nFileVersion = pPdfDocument->getFileVersion(); - CPPUNIT_ASSERT_EQUAL(17, nFileVersion); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testVersion15) -{ - // Create an empty document. - mxComponent = loadFromDesktop("private:factory/swriter"); - - // Save as PDF. - uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); - uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence( - { { "SelectPdfVersion", uno::Any(static_cast<sal_Int32>(15)) } })); - aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); - aMediaDescriptor["FilterData"] <<= aFilterData; - xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); - - // Parse the export result. - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - int nFileVersion = pPdfDocument->getFileVersion(); - CPPUNIT_ASSERT_EQUAL(15, nFileVersion); -} - -// Check round-trip of importing and exporting the PDF with PDFium filter, -// which imports the PDF document as multiple PDFs as graphic object. -// Each page in the document has one PDF graphic object which content is -// the corresponding page in the PDF. When such a document is exported, -// the PDF graphic gets embedded into the exported PDF document (as a -// Form XObject). -CPPUNIT_TEST_FIXTURE(PdfExportTest, testMultiPagePDF) -{ -// setenv only works on unix based systems -#ifndef _WIN32 - // We need to enable PDFium import (and make sure to disable after the test) - bool bResetEnvVar = false; - if (getenv("LO_IMPORT_USE_PDFIUM") == nullptr) - { - bResetEnvVar = true; - setenv("LO_IMPORT_USE_PDFIUM", "1", false); - } - comphelper::ScopeGuard aPDFiumEnvVarGuard([&]() { - if (bResetEnvVar) - unsetenv("LO_IMPORT_USE_PDFIUM"); - }); - - // Load the PDF and save as PDF - vcl::filter::PDFDocument aDocument; - load(u"SimpleMultiPagePDF.pdf", aDocument); - - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aPages.size()); - - vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); - CPPUNIT_ASSERT(pResources); - - auto pXObjects - = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject")); - CPPUNIT_ASSERT(pXObjects); - - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), - pXObjects->GetItems().size()); // 3 PDFs as Form XObjects - - std::vector<OString> rIDs; - for (auto const& rPair : pXObjects->GetItems()) - { - rIDs.push_back(rPair.first); - } - - // Let's check the embedded PDF pages - just make sure the size differs, - // which should indicate we don't have 3 times the same page. - - { // embedded PDF page 1 - vcl::filter::PDFObjectElement* pXObject1 = pXObjects->LookupObject(rIDs[0]); - CPPUNIT_ASSERT(pXObject1); - CPPUNIT_ASSERT_EQUAL(OString("Im21"), rIDs[0]); - - auto pSubtype1 = dynamic_cast<vcl::filter::PDFNameElement*>(pXObject1->Lookup("Subtype")); - CPPUNIT_ASSERT(pSubtype1); - CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype1->GetValue()); - - auto pXObjectResources - = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject1->Lookup("Resources")); - CPPUNIT_ASSERT(pXObjectResources); - auto pXObjectForms = dynamic_cast<vcl::filter::PDFDictionaryElement*>( - pXObjectResources->LookupElement("XObject")); - CPPUNIT_ASSERT(pXObjectForms); - vcl::filter::PDFObjectElement* pForm - = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first); - CPPUNIT_ASSERT(pForm); - - vcl::filter::PDFStreamElement* pStream = pForm->GetStream(); - CPPUNIT_ASSERT(pStream); - SvMemoryStream& rObjectStream = pStream->GetMemory(); - rObjectStream.Seek(STREAM_SEEK_TO_BEGIN); - - // Just check that the size of the page stream is what is expected. - CPPUNIT_ASSERT_EQUAL(sal_uInt64(230), rObjectStream.remainingSize()); - } - - { // embedded PDF page 2 - vcl::filter::PDFObjectElement* pXObject2 = pXObjects->LookupObject(rIDs[1]); - CPPUNIT_ASSERT(pXObject2); - CPPUNIT_ASSERT_EQUAL(OString("Im27"), rIDs[1]); - - auto pSubtype2 = dynamic_cast<vcl::filter::PDFNameElement*>(pXObject2->Lookup("Subtype")); - CPPUNIT_ASSERT(pSubtype2); - CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype2->GetValue()); - - auto pXObjectResources - = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject2->Lookup("Resources")); - CPPUNIT_ASSERT(pXObjectResources); - auto pXObjectForms = dynamic_cast<vcl::filter::PDFDictionaryElement*>( - pXObjectResources->LookupElement("XObject")); - CPPUNIT_ASSERT(pXObjectForms); - vcl::filter::PDFObjectElement* pForm - = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first); - CPPUNIT_ASSERT(pForm); - - vcl::filter::PDFStreamElement* pStream = pForm->GetStream(); - CPPUNIT_ASSERT(pStream); - SvMemoryStream& rObjectStream = pStream->GetMemory(); - rObjectStream.Seek(STREAM_SEEK_TO_BEGIN); - - // Just check that the size of the page stream is what is expected - CPPUNIT_ASSERT_EQUAL(sal_uInt64(309), rObjectStream.remainingSize()); - } - - { // embedded PDF page 3 - vcl::filter::PDFObjectElement* pXObject3 = pXObjects->LookupObject(rIDs[2]); - CPPUNIT_ASSERT(pXObject3); - CPPUNIT_ASSERT_EQUAL(OString("Im5"), rIDs[2]); - - auto pSubtype3 = dynamic_cast<vcl::filter::PDFNameElement*>(pXObject3->Lookup("Subtype")); - CPPUNIT_ASSERT(pSubtype3); - CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype3->GetValue()); - - auto pXObjectResources - = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject3->Lookup("Resources")); - CPPUNIT_ASSERT(pXObjectResources); - auto pXObjectForms = dynamic_cast<vcl::filter::PDFDictionaryElement*>( - pXObjectResources->LookupElement("XObject")); - CPPUNIT_ASSERT(pXObjectForms); - vcl::filter::PDFObjectElement* pForm - = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first); - CPPUNIT_ASSERT(pForm); - - vcl::filter::PDFStreamElement* pStream = pForm->GetStream(); - CPPUNIT_ASSERT(pStream); - SvMemoryStream& rObjectStream = pStream->GetMemory(); - rObjectStream.Seek(STREAM_SEEK_TO_BEGIN); - - // Just check that the size of the page stream is what is expected - CPPUNIT_ASSERT_EQUAL(sal_uInt64(193), rObjectStream.remainingSize()); - } -#endif -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testFormFontName) -{ - // Import the bugdoc and export as PDF. - aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); - saveAsPDF(u"form-font-name.odt"); - - // Parse the export result with pdfium. - std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = parsePDFExport(); - - // The document has one page. - CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount()); - std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0); - CPPUNIT_ASSERT(pPdfPage); - - // The page has one annotation. - CPPUNIT_ASSERT_EQUAL(1, pPdfPage->getAnnotationCount()); - std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnot = pPdfPage->getAnnotation(0); - - // Examine the default appearance. - CPPUNIT_ASSERT(pAnnot->hasKey("DA")); - CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFObjectType::String, pAnnot->getValueType("DA")); - OUString aDA = pAnnot->getString("DA"); - - // Without the accompanying fix in place, this test would have failed with: - // - Expected: 0 0 0 rg /TiRo 12 Tf - // - Actual : 0 0 0 rg /F2 12 Tf - // i.e. Liberation Serif was exposed as a form font as-is, without picking the closest built-in - // font. - CPPUNIT_ASSERT_EQUAL(OUString("0 0 0 rg /TiRo 12 Tf"), aDA); -} - -// Check we don't have duplicated objects when we reexport the PDF multiple -// times or the size will exponentially increase over time. -CPPUNIT_TEST_FIXTURE(PdfExportTest, testReexportPDF) -{ -// setenv only works on unix based systems -#ifndef _WIN32 - // We need to enable PDFium import (and make sure to disable after the test) - bool bResetEnvVar = false; - if (getenv("LO_IMPORT_USE_PDFIUM") == nullptr) - { - bResetEnvVar = true; - setenv("LO_IMPORT_USE_PDFIUM", "1", false); - } - comphelper::ScopeGuard aPDFiumEnvVarGuard([&]() { - if (bResetEnvVar) - unsetenv("LO_IMPORT_USE_PDFIUM"); - }); - - // Load the PDF and save as PDF - vcl::filter::PDFDocument aDocument; - load(u"PDFWithImages.pdf", aDocument); - - // Assert that the XObject in the page resources dictionary is a reference XObject. - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - - // The document has 2 pages. - CPPUNIT_ASSERT_EQUAL(size_t(2), aPages.size()); - - // PAGE 1 - { - vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); - CPPUNIT_ASSERT(pResources); - - auto pXObjects - = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject")); - CPPUNIT_ASSERT(pXObjects); - - std::vector<OString> rIDs; - for (auto const& rPair : pXObjects->GetItems()) - rIDs.push_back(rPair.first); - - CPPUNIT_ASSERT_EQUAL(size_t(2), rIDs.size()); - - std::vector<int> aBitmapRefs1; - std::vector<int> aBitmapRefs2; - - { - // FORM object 1 - OString aID = rIDs[0]; - CPPUNIT_ASSERT_EQUAL(OString("Im14"), aID); - vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(aID); - CPPUNIT_ASSERT(pXObject); - - auto pSubtype = dynamic_cast<vcl::filter::PDFNameElement*>(pXObject->Lookup("Subtype")); - CPPUNIT_ASSERT(pSubtype); - CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype->GetValue()); - - auto pInnerResources - = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject->Lookup("Resources")); - CPPUNIT_ASSERT(pInnerResources); - auto pInnerXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>( - pInnerResources->LookupElement("XObject")); - CPPUNIT_ASSERT(pInnerXObjects); - CPPUNIT_ASSERT_EQUAL(size_t(1), pInnerXObjects->GetItems().size()); - OString aInnerObjectID = pInnerXObjects->GetItems().begin()->first; - CPPUNIT_ASSERT_EQUAL(OString("Im15"), aInnerObjectID); - - vcl::filter::PDFObjectElement* pInnerXObject - = pInnerXObjects->LookupObject(aInnerObjectID); - CPPUNIT_ASSERT(pInnerXObject); - - auto pInnerSubtype - = dynamic_cast<vcl::filter::PDFNameElement*>(pInnerXObject->Lookup("Subtype")); - CPPUNIT_ASSERT(pInnerSubtype); - CPPUNIT_ASSERT_EQUAL(OString("Form"), pInnerSubtype->GetValue()); - - auto pInnerInnerResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>( - pInnerXObject->Lookup("Resources")); - CPPUNIT_ASSERT(pInnerInnerResources); - auto pInnerInnerXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>( - pInnerInnerResources->LookupElement("XObject")); - CPPUNIT_ASSERT(pInnerInnerXObjects); - CPPUNIT_ASSERT_EQUAL(size_t(2), pInnerInnerXObjects->GetItems().size()); - - std::vector<OString> aBitmapIDs1; - for (auto const& rPair : pInnerInnerXObjects->GetItems()) - aBitmapIDs1.push_back(rPair.first); - - { - CPPUNIT_ASSERT_EQUAL(OString("Im11"), aBitmapIDs1[0]); - auto pRef = dynamic_cast<vcl::filter::PDFReferenceElement*>( - pInnerInnerXObjects->LookupElement(aBitmapIDs1[0])); - CPPUNIT_ASSERT(pRef); - aBitmapRefs1.push_back(pRef->GetObjectValue()); - CPPUNIT_ASSERT_EQUAL(0, pRef->GetGenerationValue()); - - vcl::filter::PDFObjectElement* pBitmap - = pInnerInnerXObjects->LookupObject(aBitmapIDs1[0]); - CPPUNIT_ASSERT(pBitmap); - auto pBitmapSubtype - = dynamic_cast<vcl::filter::PDFNameElement*>(pBitmap->Lookup("Subtype")); - CPPUNIT_ASSERT(pBitmapSubtype); - CPPUNIT_ASSERT_EQUAL(OString("Image"), pBitmapSubtype->GetValue()); - } - { - CPPUNIT_ASSERT_EQUAL(OString("Im5"), aBitmapIDs1[1]); - auto pRef = dynamic_cast<vcl::filter::PDFReferenceElement*>( - pInnerInnerXObjects->LookupElement(aBitmapIDs1[1])); - CPPUNIT_ASSERT(pRef); - aBitmapRefs1.push_back(pRef->GetObjectValue()); - CPPUNIT_ASSERT_EQUAL(0, pRef->GetGenerationValue()); - - vcl::filter::PDFObjectElement* pBitmap - = pInnerInnerXObjects->LookupObject(aBitmapIDs1[1]); - CPPUNIT_ASSERT(pBitmap); - auto pBitmapSubtype - = dynamic_cast<vcl::filter::PDFNameElement*>(pBitmap->Lookup("Subtype")); - CPPUNIT_ASSERT(pBitmapSubtype); - CPPUNIT_ASSERT_EQUAL(OString("Image"), pBitmapSubtype->GetValue()); - } - } - - { - // FORM object 2 - OString aID = rIDs[1]; - CPPUNIT_ASSERT_EQUAL(OString("Im5"), aID); - vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(aID); - CPPUNIT_ASSERT(pXObject); - - auto pSubtype = dynamic_cast<vcl::filter::PDFNameElement*>(pXObject->Lookup("Subtype")); - CPPUNIT_ASSERT(pSubtype); - CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype->GetValue()); - - auto pInnerResources - = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject->Lookup("Resources")); - CPPUNIT_ASSERT(pInnerResources); - auto pInnerXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>( - pInnerResources->LookupElement("XObject")); - CPPUNIT_ASSERT(pInnerXObjects); - CPPUNIT_ASSERT_EQUAL(size_t(1), pInnerXObjects->GetItems().size()); - OString aInnerObjectID = pInnerXObjects->GetItems().begin()->first; - CPPUNIT_ASSERT_EQUAL(OString("Im6"), aInnerObjectID); - - vcl::filter::PDFObjectElement* pInnerXObject - = pInnerXObjects->LookupObject(aInnerObjectID); - CPPUNIT_ASSERT(pInnerXObject); - - auto pInnerSubtype - = dynamic_cast<vcl::filter::PDFNameElement*>(pInnerXObject->Lookup("Subtype")); - CPPUNIT_ASSERT(pInnerSubtype); - CPPUNIT_ASSERT_EQUAL(OString("Form"), pInnerSubtype->GetValue()); - - auto pInnerInnerResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>( - pInnerXObject->Lookup("Resources")); - CPPUNIT_ASSERT(pInnerInnerResources); - auto pInnerInnerXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>( - pInnerInnerResources->LookupElement("XObject")); - CPPUNIT_ASSERT(pInnerInnerXObjects); - CPPUNIT_ASSERT_EQUAL(size_t(2), pInnerInnerXObjects->GetItems().size()); - - std::vector<OString> aBitmapIDs2; - for (auto const& rPair : pInnerInnerXObjects->GetItems()) - aBitmapIDs2.push_back(rPair.first); - - { - CPPUNIT_ASSERT_EQUAL(OString("Im11"), aBitmapIDs2[0]); - auto pRef = dynamic_cast<vcl::filter::PDFReferenceElement*>( - pInnerInnerXObjects->LookupElement(aBitmapIDs2[0])); - CPPUNIT_ASSERT(pRef); - aBitmapRefs2.push_back(pRef->GetObjectValue()); - CPPUNIT_ASSERT_EQUAL(0, pRef->GetGenerationValue()); - - vcl::filter::PDFObjectElement* pBitmap - = pInnerInnerXObjects->LookupObject(aBitmapIDs2[0]); - CPPUNIT_ASSERT(pBitmap); - auto pBitmapSubtype - = dynamic_cast<vcl::filter::PDFNameElement*>(pBitmap->Lookup("Subtype")); - CPPUNIT_ASSERT(pBitmapSubtype); - CPPUNIT_ASSERT_EQUAL(OString("Image"), pBitmapSubtype->GetValue()); - } - { - CPPUNIT_ASSERT_EQUAL(OString("Im5"), aBitmapIDs2[1]); - auto pRef = dynamic_cast<vcl::filter::PDFReferenceElement*>( - pInnerInnerXObjects->LookupElement(aBitmapIDs2[1])); - CPPUNIT_ASSERT(pRef); - aBitmapRefs2.push_back(pRef->GetObjectValue()); - CPPUNIT_ASSERT_EQUAL(0, pRef->GetGenerationValue()); - - vcl::filter::PDFObjectElement* pBitmap - = pInnerInnerXObjects->LookupObject(aBitmapIDs2[1]); - CPPUNIT_ASSERT(pBitmap); - auto pBitmapSubtype - = dynamic_cast<vcl::filter::PDFNameElement*>(pBitmap->Lookup("Subtype")); - CPPUNIT_ASSERT(pBitmapSubtype); - CPPUNIT_ASSERT_EQUAL(OString("Image"), pBitmapSubtype->GetValue()); - } - } - // Ref should point to the same bitmap - CPPUNIT_ASSERT_EQUAL(aBitmapRefs1[0], aBitmapRefs2[0]); - CPPUNIT_ASSERT_EQUAL(aBitmapRefs1[1], aBitmapRefs2[1]); - } - -#endif -} - -// Check we correctly copy more complex resources (Fonts describing -// glyphs in recursive arrays) to the target PDF -CPPUNIT_TEST_FIXTURE(PdfExportTest, testReexportDocumentWithComplexResources) -{ -// setenv only works on unix based systems -#ifndef _WIN32 - // We need to enable PDFium import (and make sure to disable after the test) - bool bResetEnvVar = false; - if (getenv("LO_IMPORT_USE_PDFIUM") == nullptr) - { - bResetEnvVar = true; - setenv("LO_IMPORT_USE_PDFIUM", "1", false); - } - comphelper::ScopeGuard aPDFiumEnvVarGuard([&]() { - if (bResetEnvVar) - unsetenv("LO_IMPORT_USE_PDFIUM"); - }); - - // Load the PDF and save as PDF - vcl::filter::PDFDocument aDocument; - load(u"ComplexContentDictionary.pdf", aDocument); - - // Assert that the XObject in the page resources dictionary is a reference XObject. - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - CPPUNIT_ASSERT_EQUAL(size_t(1), aPages.size()); - - // Go directly to the Font object (24 0) (number could change if we change how PDF export works) - auto pFont = aDocument.LookupObject(24); - CPPUNIT_ASSERT(pFont); - - // Check it is the Font object (Type = Font) - auto pName - = dynamic_cast<vcl::filter::PDFNameElement*>(pFont->GetDictionary()->LookupElement("Type")); - CPPUNIT_ASSERT(pName); - CPPUNIT_ASSERT_EQUAL(OString("Font"), pName->GetValue()); - - // Check BaseFont is what we expect - auto pBaseFont = dynamic_cast<vcl::filter::PDFNameElement*>( - pFont->GetDictionary()->LookupElement("BaseFont")); - CPPUNIT_ASSERT(pBaseFont); - CPPUNIT_ASSERT_EQUAL(OString("HOTOMR+Calibri,Italic"), pBaseFont->GetValue()); - - // Check and get the W array - auto pWArray - = dynamic_cast<vcl::filter::PDFArrayElement*>(pFont->GetDictionary()->LookupElement("W")); - CPPUNIT_ASSERT(pWArray); - CPPUNIT_ASSERT_EQUAL(size_t(26), pWArray->GetElements().size()); - - // Check the content of W array - // ObjectCopier didn't copy this array correctly and the document - // had glyphs at the wrong places - { - // first 2 elements - auto pNumberAtIndex0 = dynamic_cast<vcl::filter::PDFNumberElement*>(pWArray->GetElement(0)); - CPPUNIT_ASSERT(pNumberAtIndex0); - CPPUNIT_ASSERT_EQUAL(3.0, pNumberAtIndex0->GetValue()); - - auto pArrayAtIndex1 = dynamic_cast<vcl::filter::PDFArrayElement*>(pWArray->GetElement(1)); - CPPUNIT_ASSERT(pArrayAtIndex1); - CPPUNIT_ASSERT_EQUAL(size_t(1), pArrayAtIndex1->GetElements().size()); - - { - auto pNumber - = dynamic_cast<vcl::filter::PDFNumberElement*>(pArrayAtIndex1->GetElement(0)); - CPPUNIT_ASSERT(pNumber); - CPPUNIT_ASSERT_EQUAL(226.0, pNumber->GetValue()); - } - - // last 2 elements - auto pNumberAtIndex24 - = dynamic_cast<vcl::filter::PDFNumberElement*>(pWArray->GetElement(24)); - CPPUNIT_ASSERT(pNumberAtIndex24); - CPPUNIT_ASSERT_EQUAL(894.0, pNumberAtIndex24->GetValue()); - - auto pArrayAtIndex25 = dynamic_cast<vcl::filter::PDFArrayElement*>(pWArray->GetElement(25)); - CPPUNIT_ASSERT(pArrayAtIndex25); - CPPUNIT_ASSERT_EQUAL(size_t(2), pArrayAtIndex25->GetElements().size()); - - { - auto pNumber1 - = dynamic_cast<vcl::filter::PDFNumberElement*>(pArrayAtIndex25->GetElement(0)); - CPPUNIT_ASSERT(pNumber1); - CPPUNIT_ASSERT_EQUAL(303.0, pNumber1->GetValue()); - - auto pNumber2 - = dynamic_cast<vcl::filter::PDFNumberElement*>(pArrayAtIndex25->GetElement(1)); - CPPUNIT_ASSERT(pNumber2); - CPPUNIT_ASSERT_EQUAL(303.0, pNumber2->GetValue()); - } - } -#endif -} - -// Tests that at export the PDF has the PDF/UA metadata properly set -// when we enable PDF/UA support. -CPPUNIT_TEST_FIXTURE(PdfExportTest, testPdfUaMetadata) -{ - // Import a basic document (document doesn't really matter) - aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); - - // Enable PDF/UA - uno::Sequence<beans::PropertyValue> aFilterData( - comphelper::InitPropertySequence({ { "PDFUACompliance", uno::Any(true) } })); - aMediaDescriptor["FilterData"] <<= aFilterData; - saveAsPDF(u"BrownFoxLazyDog.odt"); - - // Parse the export result. - vcl::filter::PDFDocument aDocument; - SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); - CPPUNIT_ASSERT(aDocument.Read(aStream)); - - auto* pCatalog = aDocument.GetCatalog(); - CPPUNIT_ASSERT(pCatalog); - auto* pCatalogDictionary = pCatalog->GetDictionary(); - CPPUNIT_ASSERT(pCatalogDictionary); - auto* pMetadataObject = pCatalogDictionary->LookupObject("Metadata"); - CPPUNIT_ASSERT(pMetadataObject); - auto* pMetadataDictionary = pMetadataObject->GetDictionary(); - auto* pType - = dynamic_cast<vcl::filter::PDFNameElement*>(pMetadataDictionary->LookupElement("Type")); - CPPUNIT_ASSERT(pType); - CPPUNIT_ASSERT_EQUAL(OString("Metadata"), pType->GetValue()); - - auto* pStreamObject = pMetadataObject->GetStream(); - CPPUNIT_ASSERT(pStreamObject); - auto& rStream = pStreamObject->GetMemory(); - rStream.Seek(0); - - // Search for the PDF/UA marker in the metadata - - tools::XmlWalker aWalker; - CPPUNIT_ASSERT(aWalker.open(&rStream)); - CPPUNIT_ASSERT_EQUAL(OString("xmpmeta"), aWalker.name()); - - bool bPdfUaMarkerFound = false; - OString aPdfUaPart; - - aWalker.children(); - while (aWalker.isValid()) - { - if (aWalker.name() == "RDF" - && aWalker.namespaceHref() == "http://www.w3.org/1999/02/22-rdf-syntax-ns#") - { - aWalker.children(); - while (aWalker.isValid()) - { - if (aWalker.name() == "Description" - && aWalker.namespaceHref() == "http://www.w3.org/1999/02/22-rdf-syntax-ns#") - { - aWalker.children(); - while (aWalker.isValid()) - { - if (aWalker.name() == "part" - && aWalker.namespaceHref() == "http://www.aiim.org/pdfua/ns/id/") - { - aPdfUaPart = aWalker.content(); - bPdfUaMarkerFound = true; - } - aWalker.next(); - } - aWalker.parent(); - } - aWalker.next(); - } - aWalker.parent(); - } - aWalker.next(); - } - aWalker.parent(); - - CPPUNIT_ASSERT(bPdfUaMarkerFound); - CPPUNIT_ASSERT_EQUAL(OString("1"), aPdfUaPart); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf139736) -{ - aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); - - // Enable PDF/UA - uno::Sequence<beans::PropertyValue> aFilterData( - comphelper::InitPropertySequence({ { "PDFUACompliance", uno::Any(true) }, - { "SelectPdfVersion", uno::Any(sal_Int32(17)) } })); - aMediaDescriptor["FilterData"] <<= aFilterData; - saveAsPDF(u"tdf139736-1.odt"); - - vcl::filter::PDFDocument aDocument; - SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); - CPPUNIT_ASSERT(aDocument.Read(aStream)); - - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); - - vcl::filter::PDFObjectElement* pContents = aPages[0]->LookupObject("Contents"); - CPPUNIT_ASSERT(pContents); - vcl::filter::PDFStreamElement* pStream = pContents->GetStream(); - CPPUNIT_ASSERT(pStream); - SvMemoryStream& rObjectStream = pStream->GetMemory(); - // Uncompress it. - SvMemoryStream aUncompressed; - ZCodec aZCodec; - aZCodec.BeginCompression(); - rObjectStream.Seek(0); - aZCodec.Decompress(rObjectStream, aUncompressed); - CPPUNIT_ASSERT(aZCodec.EndCompression()); - - auto pStart = static_cast<const char*>(aUncompressed.GetData()); - const char* const pEnd = pStart + aUncompressed.GetSize(); - - enum - { - Default, - Artifact, - ArtifactProps1, - ArtifactProps2, - Tagged - } state - = Default; - - auto nLine(0); - auto nTagged(0); - auto nArtifacts(0); - while (true) - { - ++nLine; - auto const pLine = ::std::find(pStart, pEnd, '\n'); - if (pLine == pEnd) - { - break; - } - std::string_view const line(pStart, pLine - pStart); - pStart = pLine + 1; - if (!line.empty() && line[0] != '%') - { - ::std::cerr << nLine << ": " << line << "\n"; - if (line == "/Artifact BMC") - { - CPPUNIT_ASSERT_EQUAL_MESSAGE("unexpected nesting", Default, state); - state = Artifact; - ++nArtifacts; - } - else if (o3tl::starts_with(line, "/Artifact <<")) - { - CPPUNIT_ASSERT_EQUAL_MESSAGE("unexpected nesting", Default, state); - // check header/footer properties - CPPUNIT_ASSERT_EQUAL(std::string_view("/Type/Pagination"), line.substr(12)); - state = ArtifactProps1; - ++nArtifacts; - } - else if (state == ArtifactProps1) - { - CPPUNIT_ASSERT_EQUAL(std::string_view("/Subtype/Header"), line); - state = ArtifactProps2; - } - else if (state == ArtifactProps2 && line == ">> BDC") - { - state = Artifact; - } - else if (line == "/Standard<</MCID 0>>BDC") - { - CPPUNIT_ASSERT_EQUAL_MESSAGE("unexpected nesting", Default, state); - state = Tagged; - ++nTagged; - } - else if (line == "EMC") - { - CPPUNIT_ASSERT_MESSAGE("unexpected end", state != Default); - state = Default; - } - else if (nLine > 1) // first line is expected "0.1 w" - { - CPPUNIT_ASSERT_MESSAGE("unexpected content outside MCS", state != Default); - } - } - } - CPPUNIT_ASSERT_EQUAL_MESSAGE("unclosed MCS", Default, state); - CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nTagged)>(1), nTagged); // text in body - // 1 image and 1 frame and 1 header text; arbitrary number of aux stuff like borders - CPPUNIT_ASSERT(nArtifacts >= 3); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf152231) -{ - aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); - - // Enable PDF/UA - uno::Sequence<beans::PropertyValue> aFilterData( - comphelper::InitPropertySequence({ { "PDFUACompliance", uno::Any(true) }, - { "ExportNotesInMargin", uno::Any(true) }, - { "SelectPdfVersion", uno::Any(sal_Int32(17)) } })); - aMediaDescriptor["FilterData"] <<= aFilterData; - saveAsPDF(u"tdf152231.fodt"); - - vcl::filter::PDFDocument aDocument; - SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); - CPPUNIT_ASSERT(aDocument.Read(aStream)); - - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); - - vcl::filter::PDFObjectElement* pContents = aPages[0]->LookupObject("Contents"); - CPPUNIT_ASSERT(pContents); - vcl::filter::PDFStreamElement* pStream = pContents->GetStream(); - CPPUNIT_ASSERT(pStream); - SvMemoryStream& rObjectStream = pStream->GetMemory(); - // Uncompress it. - SvMemoryStream aUncompressed; - ZCodec aZCodec; - aZCodec.BeginCompression(); - rObjectStream.Seek(0); - aZCodec.Decompress(rObjectStream, aUncompressed); - CPPUNIT_ASSERT(aZCodec.EndCompression()); - - auto pStart = static_cast<const char*>(aUncompressed.GetData()); - const char* const pEnd = pStart + aUncompressed.GetSize(); - - enum - { - Default, - Artifact, - Tagged - } state - = Default; - - auto nLine(0); - auto nTagged(0); - auto nArtifacts(0); - while (true) - { - ++nLine; - auto const pLine = ::std::find(pStart, pEnd, '\n'); - if (pLine == pEnd) - { - break; - } - std::string_view const line(pStart, pLine - pStart); - pStart = pLine + 1; - if (!line.empty() && line[0] != '%') - { - ::std::cerr << nLine << ": " << line << "\n"; - if (line == "/Artifact BMC") - { - CPPUNIT_ASSERT_EQUAL_MESSAGE("unexpected nesting", Default, state); - state = Artifact; - ++nArtifacts; - } - else if (o3tl::starts_with(line, "/Standard<</MCID ")) - { - CPPUNIT_ASSERT_EQUAL_MESSAGE("unexpected nesting", Default, state); - state = Tagged; - ++nTagged; - } - else if (line == "EMC") - { - CPPUNIT_ASSERT_MESSAGE("unexpected end", state != Default); - state = Default; - } - else if (nLine > 1) // first line is expected "0.1 w" - { - CPPUNIT_ASSERT_MESSAGE("unexpected content outside MCS", state != Default); - } - } - } - CPPUNIT_ASSERT_EQUAL_MESSAGE("unclosed MCS", Default, state); - CPPUNIT_ASSERT(nTagged >= 12); // text in body - // 1 annotation - CPPUNIT_ASSERT(nArtifacts >= 1); - - auto nPara(0); - for (const auto& rDocElement : aDocument.GetElements()) - { - auto pObject = dynamic_cast<vcl::filter::PDFObjectElement*>(rDocElement.get()); - if (!pObject) - continue; - auto pType = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("Type")); - if (pType && pType->GetValue() == "StructElem") - { - auto pS = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("S")); - if (pS && pS->GetValue() == "Standard") - { - ++nPara; - auto pKids = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject->Lookup("K")); - CPPUNIT_ASSERT(pKids); - // one problem was that some StructElem were missing kids - CPPUNIT_ASSERT(!pKids->GetElements().empty()); - } - } - } - CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nPara)>(12), nPara); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf152235) -{ - aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); - // Enable PDF/UA - uno::Sequence<beans::PropertyValue> aFilterData(comphelper::InitPropertySequence( - { { "PDFUACompliance", uno::Any(true) }, - { "Watermark", uno::Any(OUString("kendy")) }, - // need to set a font to avoid assertions about missing "Helvetica" - { "WatermarkFontName", uno::Any(OUString("Liberation Sans")) }, - { "SelectPdfVersion", uno::Any(sal_Int32(17)) } })); - aMediaDescriptor["FilterData"] <<= aFilterData; - mxComponent = loadFromDesktop("private:factory/swriter"); - uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); - xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); - - vcl::filter::PDFDocument aDocument; - SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); - CPPUNIT_ASSERT(aDocument.Read(aStream)); - - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); - - vcl::filter::PDFObjectElement* pContents = aPages[0]->LookupObject("Contents"); - CPPUNIT_ASSERT(pContents); - vcl::filter::PDFStreamElement* pStream = pContents->GetStream(); - CPPUNIT_ASSERT(pStream); - SvMemoryStream& rObjectStream = pStream->GetMemory(); - // Uncompress it. - SvMemoryStream aUncompressed; - ZCodec aZCodec; - aZCodec.BeginCompression(); - rObjectStream.Seek(0); - aZCodec.Decompress(rObjectStream, aUncompressed); - CPPUNIT_ASSERT(aZCodec.EndCompression()); - - auto pStart = static_cast<const char*>(aUncompressed.GetData()); - const char* const pEnd = pStart + aUncompressed.GetSize(); - - enum - { - Default, - Artifact, - Tagged - } state - = Default; - - auto nLine(0); - auto nTagged(0); - auto nArtifacts(0); - while (true) - { - ++nLine; - auto const pLine = ::std::find(pStart, pEnd, '\n'); - if (pLine == pEnd) - { - break; - } - std::string_view const line(pStart, pLine - pStart); - pStart = pLine + 1; - if (!line.empty() && line[0] != '%') - { - ::std::cerr << nLine << ": " << line << "\n"; - if (o3tl::starts_with(line, "/Artifact ")) - { - CPPUNIT_ASSERT_EQUAL_MESSAGE("unexpected nesting", Default, state); - state = Artifact; - ++nArtifacts; - } - else if (o3tl::starts_with(line, "/Standard<</MCID ")) - { - CPPUNIT_ASSERT_EQUAL_MESSAGE("unexpected nesting", Default, state); - state = Tagged; - ++nTagged; - } - else if (line == "EMC") - { - CPPUNIT_ASSERT_MESSAGE("unexpected end", state != Default); - state = Default; - } - else if (nLine > 1) // first line is expected "0.1 w" - { - CPPUNIT_ASSERT_MESSAGE("unexpected content outside MCS", state != Default); - } - } - } - CPPUNIT_ASSERT_EQUAL_MESSAGE("unclosed MCS", Default, state); - CPPUNIT_ASSERT(nTagged >= 0); // text in body - CPPUNIT_ASSERT(nArtifacts >= 2); // 1 watermark + 1 other thing -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf149140) -{ - aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); - - // Enable PDF/UA - uno::Sequence<beans::PropertyValue> aFilterData( - comphelper::InitPropertySequence({ { "PDFUACompliance", uno::Any(true) } })); - aMediaDescriptor["FilterData"] <<= aFilterData; - saveAsPDF(u"TableTH_test_LibreOfficeWriter7.3.3_HeaderRow-HeadersInTopRow.fodt"); - - vcl::filter::PDFDocument aDocument; - SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); - CPPUNIT_ASSERT(aDocument.Read(aStream)); - - // The document has one page. - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); - - int nTH(0); - for (const auto& rDocElement : aDocument.GetElements()) - { - auto pObject = dynamic_cast<vcl::filter::PDFObjectElement*>(rDocElement.get()); - if (!pObject) - continue; - auto pType = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("Type")); - if (pType && pType->GetValue() == "StructElem") - { - auto pS = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("S")); - if (pS && pS->GetValue() == "TH") - { - int nTable(0); - auto pAttrs = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject->Lookup("A")); - CPPUNIT_ASSERT(pAttrs != nullptr); - for (const auto& rAttrRef : pAttrs->GetElements()) - { - auto pAttrDict = dynamic_cast<vcl::filter::PDFDictionaryElement*>(rAttrRef); - CPPUNIT_ASSERT(pAttrDict != nullptr); - auto pOwner - = dynamic_cast<vcl::filter::PDFNameElement*>(pAttrDict->LookupElement("O")); - CPPUNIT_ASSERT(pOwner != nullptr); - if (pOwner->GetValue() == "Table") - { - auto pScope = dynamic_cast<vcl::filter::PDFNameElement*>( - pAttrDict->LookupElement("Scope")); - CPPUNIT_ASSERT(pScope != nullptr); - CPPUNIT_ASSERT_EQUAL(OString("Column"), pScope->GetValue()); - ++nTable; - } - } - CPPUNIT_ASSERT_EQUAL(int(1), nTable); - ++nTH; - } - } - } - CPPUNIT_ASSERT_EQUAL(int(6), nTH); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testNestedSection) -{ - aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); - - // Enable PDF/UA - uno::Sequence<beans::PropertyValue> aFilterData( - comphelper::InitPropertySequence({ { "PDFUACompliance", uno::Any(true) } })); - aMediaDescriptor["FilterData"] <<= aFilterData; - saveAsPDF(u"nestedsection.fodt"); - - vcl::filter::PDFDocument aDocument; - SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); - CPPUNIT_ASSERT(aDocument.Read(aStream)); - - // the assert needs 2 follows to reproduce => 3 pages - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aPages.size()); - - auto nDoc(0); - for (const auto& rDocElement : aDocument.GetElements()) - { - auto pObject1 = dynamic_cast<vcl::filter::PDFObjectElement*>(rDocElement.get()); - if (!pObject1) - continue; - auto pType1 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1->Lookup("Type")); - if (pType1 && pType1->GetValue() == "StructElem") - { - auto pS1 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1->Lookup("S")); - if (pS1 && pS1->GetValue() == "Document") - { - auto pKids1 = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject1->Lookup("K")); - CPPUNIT_ASSERT(pKids1); - // assume there are no MCID ref at this level - auto pKids1v = pKids1->GetElements(); - auto pRefKid10 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids1v[0]); - CPPUNIT_ASSERT(pRefKid10); - auto pObject10 = pRefKid10->LookupObject(); - CPPUNIT_ASSERT(pObject10); - auto pType10 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject10->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType10->GetValue()); - auto pS10 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject10->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Sect"), pS10->GetValue()); - - auto pKids10 = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject10->Lookup("K")); - CPPUNIT_ASSERT(pKids10); - // assume there are no MCID ref at this level - auto pKids10v = pKids10->GetElements(); - - auto pRefKid100 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids10v[0]); - CPPUNIT_ASSERT(pRefKid100); - auto pObject100 = pRefKid100->LookupObject(); - CPPUNIT_ASSERT(pObject100); - auto pType100 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject100->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType100->GetValue()); - auto pS100 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject100->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Standard"), pS100->GetValue()); - - auto pRefKid101 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids10v[1]); - CPPUNIT_ASSERT(pRefKid101); - auto pObject101 = pRefKid101->LookupObject(); - CPPUNIT_ASSERT(pObject101); - auto pType101 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject101->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType101->GetValue()); - auto pS101 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject101->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Standard"), pS101->GetValue()); - - auto pRefKid102 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids10v[2]); - CPPUNIT_ASSERT(pRefKid102); - auto pObject102 = pRefKid102->LookupObject(); - CPPUNIT_ASSERT(pObject102); - auto pType102 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject102->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType102->GetValue()); - auto pS102 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject102->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Sect"), pS102->GetValue()); - - auto pKids102 - = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject102->Lookup("K")); - CPPUNIT_ASSERT(pKids102); - // assume there are no MCID ref at this level - auto pKids102v = pKids102->GetElements(); - - auto pRefKid1020 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids102v[0]); - CPPUNIT_ASSERT(pRefKid1020); - auto pObject1020 = pRefKid1020->LookupObject(); - CPPUNIT_ASSERT(pObject1020); - auto pType1020 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1020->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType1020->GetValue()); - auto pS1020 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1020->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Standard"), pS1020->GetValue()); - - CPPUNIT_ASSERT_EQUAL(size_t(1), pKids102v.size()); - - auto pRefKid103 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids10v[3]); - CPPUNIT_ASSERT(pRefKid103); - auto pObject103 = pRefKid103->LookupObject(); - CPPUNIT_ASSERT(pObject103); - auto pType103 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject103->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType103->GetValue()); - auto pS103 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject103->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Standard"), pS103->GetValue()); - - auto pRefKid104 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids10v[4]); - CPPUNIT_ASSERT(pRefKid104); - auto pObject104 = pRefKid104->LookupObject(); - CPPUNIT_ASSERT(pObject104); - auto pType104 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject104->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType104->GetValue()); - auto pS104 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject104->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Standard"), pS104->GetValue()); - - CPPUNIT_ASSERT_EQUAL(size_t(5), pKids10v.size()); - - auto pRefKid11 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKids1v[1]); - CPPUNIT_ASSERT(pRefKid11); - auto pObject11 = pRefKid11->LookupObject(); - CPPUNIT_ASSERT(pObject11); - auto pType11 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject11->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType11->GetValue()); - auto pS11 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject11->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Standard"), pS11->GetValue()); - - CPPUNIT_ASSERT_EQUAL(size_t(2), pKids1v.size()); - ++nDoc; - } - } - } - CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nDoc)>(1), nDoc); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf157817) -{ - aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); - - // Enable PDF/UA - uno::Sequence<beans::PropertyValue> aFilterData( - comphelper::InitPropertySequence({ { "PDFUACompliance", uno::Any(true) } })); - aMediaDescriptor["FilterData"] <<= aFilterData; - saveAsPDF(u"SimpleTOC.fodt"); - - vcl::filter::PDFDocument aDocument; - SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); - CPPUNIT_ASSERT(aDocument.Read(aStream)); - - // The document has one page. - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), aPages.size()); - - vcl::filter::PDFObjectElement* pTOC(nullptr); - for (const auto& rDocElement : aDocument.GetElements()) - { - auto pObject1 = dynamic_cast<vcl::filter::PDFObjectElement*>(rDocElement.get()); - if (!pObject1) - continue; - auto pType1 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1->Lookup("Type")); - if (pType1 && pType1->GetValue() == "StructElem") - { - auto pS1 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1->Lookup("S")); - if (pS1 && pS1->GetValue() == "TOC") - { - pTOC = pObject1; - } - } - } - CPPUNIT_ASSERT(pTOC); - - auto pKidsT = dynamic_cast<vcl::filter::PDFArrayElement*>(pTOC->Lookup("K")); - CPPUNIT_ASSERT(pKidsT); - // assume there are no MCID ref at this level - auto pKidsTv = pKidsT->GetElements(); - auto pRefKidT0 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsTv[0]); - CPPUNIT_ASSERT(pRefKidT0); - auto pObjectT0 = pRefKidT0->LookupObject(); - CPPUNIT_ASSERT(pObjectT0); - auto pTypeT0 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT0->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeT0->GetValue()); - auto pST0 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT0->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Caption"), pST0->GetValue()); - - auto pKidsT0 = dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectT0->Lookup("K")); - CPPUNIT_ASSERT(pKidsT0); - auto pKidsT0v = pKidsT0->GetElements(); - auto pRefKidT00 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsT0v[0]); - CPPUNIT_ASSERT(pRefKidT00); - auto pObjectT00 = pRefKidT00->LookupObject(); - CPPUNIT_ASSERT(pObjectT00); - auto pTypeT00 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT00->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeT00->GetValue()); - auto pST00 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT00->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Contents#20Heading"), pST00->GetValue()); - - auto pRefKidT1 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsTv[1]); - CPPUNIT_ASSERT(pRefKidT1); - auto pObjectT1 = pRefKidT1->LookupObject(); - CPPUNIT_ASSERT(pObjectT1); - auto pTypeT1 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT1->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeT1->GetValue()); - auto pST1 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT1->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("TOCI"), pST1->GetValue()); - - auto pKidsT1 = dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectT1->Lookup("K")); - CPPUNIT_ASSERT(pKidsT1); - auto pKidsT1v = pKidsT1->GetElements(); - - auto pRefKidT10 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsT1v[0]); - CPPUNIT_ASSERT(pRefKidT10); - auto pObjectT10 = pRefKidT10->LookupObject(); - CPPUNIT_ASSERT(pObjectT10); - auto pTypeT10 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT10->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeT10->GetValue()); - auto pST10 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT10->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Contents#201"), pST10->GetValue()); - - auto pKidsT10 = dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectT10->Lookup("K")); - CPPUNIT_ASSERT(pKidsT10); - auto pKidsT10v = pKidsT10->GetElements(); - CPPUNIT_ASSERT_EQUAL(size_t(1), pKidsT10v.size()); - - // there is one and only one Link - auto pRefKidT100 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsT10v[0]); - CPPUNIT_ASSERT(pRefKidT100); - auto pObjectT100 = pRefKidT100->LookupObject(); - CPPUNIT_ASSERT(pObjectT100); - auto pTypeT100 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT100->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeT100->GetValue()); - auto pST100 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT100->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Link"), pST100->GetValue()); - - auto pRefKidT2 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsTv[1]); - CPPUNIT_ASSERT(pRefKidT2); - auto pObjectT2 = pRefKidT2->LookupObject(); - CPPUNIT_ASSERT(pObjectT2); - auto pTypeT2 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT2->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeT2->GetValue()); - auto pST2 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT2->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("TOCI"), pST2->GetValue()); - - auto pKidsT2 = dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectT2->Lookup("K")); - CPPUNIT_ASSERT(pKidsT2); - auto pKidsT2v = pKidsT2->GetElements(); - - auto pRefKidT20 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsT2v[0]); - CPPUNIT_ASSERT(pRefKidT20); - auto pObjectT20 = pRefKidT20->LookupObject(); - CPPUNIT_ASSERT(pObjectT20); - auto pTypeT20 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT20->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeT20->GetValue()); - auto pST20 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT20->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Contents#201"), pST20->GetValue()); - - auto pKidsT20 = dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectT20->Lookup("K")); - CPPUNIT_ASSERT(pKidsT20); - auto pKidsT20v = pKidsT20->GetElements(); - CPPUNIT_ASSERT_EQUAL(size_t(1), pKidsT20v.size()); - - // there is one and only one Link - auto pRefKidT200 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsT20v[0]); - CPPUNIT_ASSERT(pRefKidT200); - auto pObjectT200 = pRefKidT200->LookupObject(); - CPPUNIT_ASSERT(pObjectT200); - auto pTypeT200 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT200->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeT200->GetValue()); - auto pST200 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT200->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Link"), pST200->GetValue()); - - auto pRefKidT3 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsTv[1]); - CPPUNIT_ASSERT(pRefKidT3); - auto pObjectT3 = pRefKidT3->LookupObject(); - CPPUNIT_ASSERT(pObjectT3); - auto pTypeT3 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT3->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeT3->GetValue()); - auto pST3 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT3->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("TOCI"), pST3->GetValue()); - - auto pKidsT3 = dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectT3->Lookup("K")); - CPPUNIT_ASSERT(pKidsT3); - auto pKidsT3v = pKidsT3->GetElements(); - - auto pRefKidT30 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsT3v[0]); - CPPUNIT_ASSERT(pRefKidT30); - auto pObjectT30 = pRefKidT30->LookupObject(); - CPPUNIT_ASSERT(pObjectT30); - auto pTypeT30 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT30->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeT30->GetValue()); - auto pST30 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT30->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Contents#201"), pST30->GetValue()); - - auto pKidsT30 = dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectT30->Lookup("K")); - CPPUNIT_ASSERT(pKidsT30); - auto pKidsT30v = pKidsT30->GetElements(); - CPPUNIT_ASSERT_EQUAL(size_t(1), pKidsT30v.size()); - - // there is one and only one Link - auto pRefKidT300 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsT30v[0]); - CPPUNIT_ASSERT(pRefKidT300); - auto pObjectT300 = pRefKidT300->LookupObject(); - CPPUNIT_ASSERT(pObjectT300); - auto pTypeT300 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT300->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeT300->GetValue()); - auto pST300 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectT300->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Link"), pST300->GetValue()); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf135638) -{ - aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); - - // Enable PDF/UA - uno::Sequence<beans::PropertyValue> aFilterData( - comphelper::InitPropertySequence({ { "PDFUACompliance", uno::Any(true) } })); - aMediaDescriptor["FilterData"] <<= aFilterData; - saveAsPDF(u"image-shape.fodt"); - - vcl::filter::PDFDocument aDocument; - SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); - CPPUNIT_ASSERT(aDocument.Read(aStream)); - - // The document has one page. - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); - - int nFigure(0); - for (const auto& rDocElement : aDocument.GetElements()) - { - auto pObject = dynamic_cast<vcl::filter::PDFObjectElement*>(rDocElement.get()); - if (!pObject) - continue; - auto pType = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("Type")); - if (pType && pType->GetValue() == "StructElem") - { - auto pS = dynamic_cast<vcl::filter::PDFNameElement*>(pObject->Lookup("S")); - if (pS && pS->GetValue() == "Figure") - { - auto pAttrDict - = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pObject->Lookup("A")); - CPPUNIT_ASSERT(pAttrDict != nullptr); - auto pOwner - = dynamic_cast<vcl::filter::PDFNameElement*>(pAttrDict->LookupElement("O")); - CPPUNIT_ASSERT(pOwner != nullptr); - CPPUNIT_ASSERT_EQUAL(OString("Layout"), pOwner->GetValue()); - auto pBBox - = dynamic_cast<vcl::filter::PDFArrayElement*>(pAttrDict->LookupElement("BBox")); - CPPUNIT_ASSERT(pBBox != nullptr); - if (nFigure == 0) - { - CPPUNIT_ASSERT_DOUBLES_EQUAL( - 139.5, - dynamic_cast<vcl::filter::PDFNumberElement*>(pBBox->GetElements()[0]) - ->GetValue(), - 0.01); - CPPUNIT_ASSERT_DOUBLES_EQUAL( - 480.3, - dynamic_cast<vcl::filter::PDFNumberElement*>(pBBox->GetElements()[1]) - ->GetValue(), - 0.01); - CPPUNIT_ASSERT_DOUBLES_EQUAL( - 472.5, - dynamic_cast<vcl::filter::PDFNumberElement*>(pBBox->GetElements()[2]) - ->GetValue(), - 0.01); - CPPUNIT_ASSERT_DOUBLES_EQUAL( - 735.3, - dynamic_cast<vcl::filter::PDFNumberElement*>(pBBox->GetElements()[3]) - ->GetValue(), - 0.01); - } - else - { - CPPUNIT_ASSERT_DOUBLES_EQUAL( - 178.45, - dynamic_cast<vcl::filter::PDFNumberElement*>(pBBox->GetElements()[0]) - ->GetValue(), - 0.01); - CPPUNIT_ASSERT_DOUBLES_EQUAL( - 318.65, - dynamic_cast<vcl::filter::PDFNumberElement*>(pBBox->GetElements()[1]) - ->GetValue(), - 0.01); - CPPUNIT_ASSERT_DOUBLES_EQUAL( - 326.35, - dynamic_cast<vcl::filter::PDFNumberElement*>(pBBox->GetElements()[2]) - ->GetValue(), - 0.01); - CPPUNIT_ASSERT_DOUBLES_EQUAL( - 382.55, - dynamic_cast<vcl::filter::PDFNumberElement*>(pBBox->GetElements()[3]) - ->GetValue(), - 0.01); - } - ++nFigure; - } - } - } - // the first one is a Writer image, 2nd one SdrRectObj - CPPUNIT_ASSERT_EQUAL(int(2), nFigure); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testTdf157703) -{ - aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); - - // Enable PDF/UA - uno::Sequence<beans::PropertyValue> aFilterData( - comphelper::InitPropertySequence({ { "PDFUACompliance", uno::Any(true) } })); - aMediaDescriptor["FilterData"] <<= aFilterData; - saveAsPDF(u"LO_Lbl_Lbody_bug_report.fodt"); - - vcl::filter::PDFDocument aDocument; - SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); - CPPUNIT_ASSERT(aDocument.Read(aStream)); - - // The document has one page. - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages.size()); - - vcl::filter::PDFObjectElement* pDocument(nullptr); - for (const auto& rDocElement : aDocument.GetElements()) - { - auto pObject1 = dynamic_cast<vcl::filter::PDFObjectElement*>(rDocElement.get()); - if (!pObject1) - continue; - auto pType1 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1->Lookup("Type")); - if (pType1 && pType1->GetValue() == "StructElem") - { - auto pS1 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1->Lookup("S")); - if (pS1 && pS1->GetValue() == "Document") - { - pDocument = pObject1; - } - } - } - CPPUNIT_ASSERT(pDocument); - - auto pKidsD = dynamic_cast<vcl::filter::PDFArrayElement*>(pDocument->Lookup("K")); - CPPUNIT_ASSERT(pKidsD); - // assume there are no MCID ref at this level - auto pKidsDv = pKidsD->GetElements(); - auto pRefKidD0 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsDv[0]); - CPPUNIT_ASSERT(pRefKidD0); - auto pObjectD0 = pRefKidD0->LookupObject(); - CPPUNIT_ASSERT(pObjectD0); - auto pTypeD0 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD0->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeD0->GetValue()); - auto pSD0 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD0->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("H1"), pSD0->GetValue()); - - auto pKidsD0 = dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectD0->Lookup("K")); - CPPUNIT_ASSERT(pKidsD0); - auto pKidsD0v = pKidsD0->GetElements(); - auto pRefKidD00 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsD0v[0]); - // MCID for label - CPPUNIT_ASSERT(!pRefKidD00); - - // MCID for text - auto pRefKidD01 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsD0v[1]); - CPPUNIT_ASSERT(!pRefKidD01); - - auto pRefKidD1 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsDv[1]); - CPPUNIT_ASSERT(pRefKidD1); - auto pObjectD1 = pRefKidD1->LookupObject(); - CPPUNIT_ASSERT(pObjectD1); - auto pTypeD1 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD1->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pTypeD1->GetValue()); - auto pSD1 = dynamic_cast<vcl::filter::PDFNameElement*>(pObjectD1->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("H2"), pSD1->GetValue()); - - auto pKidsD1 = dynamic_cast<vcl::filter::PDFArrayElement*>(pObjectD1->Lookup("K")); - CPPUNIT_ASSERT(pKidsD1); - auto pKidsD1v = pKidsD1->GetElements(); - - // MCID for text - auto pRefKidD11 = dynamic_cast<vcl::filter::PDFReferenceElement*>(pKidsD1v[0]); - CPPUNIT_ASSERT(!pRefKidD11); -} - -CPPUNIT_TEST_FIXTURE(PdfExportTest, testSpans) -{ - aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); - - // Enable PDF/UA - uno::Sequence<beans::PropertyValue> aFilterData( - comphelper::InitPropertySequence({ { "PDFUACompliance", uno::Any(true) } })); - aMediaDescriptor["FilterData"] <<= aFilterData; - saveAsPDF(u"spanlist.fodt"); - - vcl::filter::PDFDocument aDocument; - SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); - CPPUNIT_ASSERT(aDocument.Read(aStream)); - - // The document has one page. - std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), aPages.size()); - - auto nDoc(0); - for (const auto& rDocElement : aDocument.GetElements()) - { - auto pObject1 = dynamic_cast<vcl::filter::PDFObjectElement*>(rDocElement.get()); - if (!pObject1) - continue; - auto pType1 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1->Lookup("Type")); - if (pType1 && pType1->GetValue() == "StructElem") - { - auto pS1 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1->Lookup("S")); - if (pS1 && pS1->GetValue() == "Document") - { - auto pKids1 = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject1->Lookup("K")); - CPPUNIT_ASSERT(pKids1); - // assume there are no MCID ref at this level - auto vKids1 = pKids1->GetElements(); - CPPUNIT_ASSERT_EQUAL(size_t(2), vKids1.size()); - auto pRefKid10 = dynamic_cast<vcl::filter::PDFReferenceElement*>(vKids1[0]); - CPPUNIT_ASSERT(pRefKid10); - auto pObject10 = pRefKid10->LookupObject(); - CPPUNIT_ASSERT(pObject10); - auto pType10 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject10->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType10->GetValue()); - auto pS10 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject10->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("L"), pS10->GetValue()); - - auto pKids10 = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject10->Lookup("K")); - CPPUNIT_ASSERT(pKids10); - // assume there are no MCID ref at this level - auto vKids10 = pKids10->GetElements(); - CPPUNIT_ASSERT_EQUAL(size_t(4), vKids10.size()); - - auto pRefKid100 = dynamic_cast<vcl::filter::PDFReferenceElement*>(vKids10[0]); - CPPUNIT_ASSERT(pRefKid100); - auto pObject100 = pRefKid100->LookupObject(); - CPPUNIT_ASSERT(pObject100); - auto pType100 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject100->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType100->GetValue()); - auto pS100 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject100->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("LI"), pS100->GetValue()); - - auto pKids100 - = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject100->Lookup("K")); - CPPUNIT_ASSERT(pKids100); - // assume there are no MCID ref at this level - auto vKids100 = pKids100->GetElements(); - CPPUNIT_ASSERT_EQUAL(size_t(2), vKids100.size()); - - auto pRefKid1000 = dynamic_cast<vcl::filter::PDFReferenceElement*>(vKids100[0]); - CPPUNIT_ASSERT(pRefKid1000); - auto pObject1000 = pRefKid1000->LookupObject(); - CPPUNIT_ASSERT(pObject1000); - auto pType1000 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1000->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType1000->GetValue()); - auto pS1000 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1000->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Lbl"), pS1000->GetValue()); - - auto pRefKid1001 = dynamic_cast<vcl::filter::PDFReferenceElement*>(vKids100[1]); - CPPUNIT_ASSERT(pRefKid1001); - auto pObject1001 = pRefKid1001->LookupObject(); - CPPUNIT_ASSERT(pObject1001); - auto pType1001 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1001->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType1001->GetValue()); - auto pS1001 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject1001->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("LBody"), pS1001->GetValue()); - auto pKids1001 - = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject1001->Lookup("K")); - CPPUNIT_ASSERT(pKids1001); - // assume there are no MCID ref at this level - auto vKids1001 = pKids1001->GetElements(); - CPPUNIT_ASSERT_EQUAL(size_t(1), vKids1001.size()); - - auto pRefKid10010 = dynamic_cast<vcl::filter::PDFReferenceElement*>(vKids1001[0]); - CPPUNIT_ASSERT(pRefKid10010); - auto pObject10010 = pRefKid10010->LookupObject(); - CPPUNIT_ASSERT(pObject10010); - auto pType10010 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject10010->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType10010->GetValue()); - auto pS10010 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject10010->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Standard"), pS10010->GetValue()); - auto pKids10010 - = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject10010->Lookup("K")); - CPPUNIT_ASSERT(pKids10010); - // assume there are no MCID ref at this level - auto vKids10010 = pKids10010->GetElements(); - // only one span - CPPUNIT_ASSERT_EQUAL(size_t(1), vKids10010.size()); - - auto pRefKid100100 = dynamic_cast<vcl::filter::PDFReferenceElement*>(vKids10010[0]); - CPPUNIT_ASSERT(pRefKid100100); - auto pObject100100 = pRefKid100100->LookupObject(); - CPPUNIT_ASSERT(pObject100100); - auto pType100100 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject100100->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType100100->GetValue()); - auto pS100100 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject100100->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("Span"), pS100100->GetValue()); - // this span exists because of lang - auto pLang100100 = dynamic_cast<vcl::filter::PDFLiteralStringElement*>( - pObject100100->Lookup("Lang")); - CPPUNIT_ASSERT_EQUAL(OString("en-GB"), pLang100100->GetValue()); - - auto pRefKid101 = dynamic_cast<vcl::filter::PDFReferenceElement*>(vKids10[1]); - CPPUNIT_ASSERT(pRefKid101); - auto pObject101 = pRefKid101->LookupObject(); - CPPUNIT_ASSERT(pObject101); - auto pType101 - = dynamic_cast<vcl::filter::PDFNameElement*>(pObject101->Lookup("Type")); - CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType101->GetValue()); - auto pS101 = dynamic_cast<vcl::filter::PDFNameElement*>(pObject101->Lookup("S")); - CPPUNIT_ASSERT_EQUAL(OString("LI"), pS101->GetValue()); - - auto pKids101 - = dynamic_cast<vcl::filter::PDFArrayElement*>(pObject101->Lookup("K")); - CPPUNIT_ASSERT(pKids101); - // assume there are no MCID ref at this level - auto vKids101 = pKids101->GetElements(); ... etc. - the rest is truncated