From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- filter/qa/pdf.cxx | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 filter/qa/pdf.cxx (limited to 'filter/qa/pdf.cxx') diff --git a/filter/qa/pdf.cxx b/filter/qa/pdf.cxx new file mode 100644 index 000000000..ec5460b9f --- /dev/null +++ b/filter/qa/pdf.cxx @@ -0,0 +1,347 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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/. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace +{ +/// Covers filter/source/pdf/ fixes. +class Test : public test::BootstrapFixture, public unotest::MacrosTest +{ +private: + uno::Reference mxComponent; + +public: + void setUp() override; + void tearDown() override; + uno::Reference& getComponent() { return mxComponent; } +}; + +void Test::setUp() +{ + test::BootstrapFixture::setUp(); + MacrosTest::setUpNssGpg(m_directories, "filter_pdf"); + + mxDesktop.set(frame::Desktop::create(mxComponentContext)); +} + +void Test::tearDown() +{ + if (mxComponent.is()) + mxComponent->dispose(); + + test::BootstrapFixture::tearDown(); +} + +constexpr OUStringLiteral DATA_DIRECTORY = u"/filter/qa/data/"; + +CPPUNIT_TEST_FIXTURE(Test, testSignCertificateSubjectName) +{ + std::shared_ptr pPDFium = vcl::pdf::PDFiumLibrary::get(); + if (!pPDFium) + return; + + uno::Reference xSEInitializer + = xml::crypto::SEInitializer::create(mxComponentContext); + uno::Reference xSecurityContext + = xSEInitializer->createSecurityContext(OUString()); + uno::Reference xSecurityEnvironment + = xSecurityContext->getSecurityEnvironment(); + uno::Sequence aFilterData{ + comphelper::makePropertyValue("SignPDF", true), + comphelper::makePropertyValue( + "SignCertificateSubjectName", + OUString( + "CN=Xmlsecurity RSA Test example Alice,O=Xmlsecurity RSA Test,ST=England,C=UK")), + }; + if (!GetValidCertificate(xSecurityEnvironment->getPersonalCertificates(), aFilterData)) + { + return; + } + + // Given an empty document: + getComponent().set( + loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument")); + + // When exporting to PDF, and referring to a certificate using a subject name: + uno::Reference xFactory = getMultiServiceFactory(); + uno::Reference xFilter( + xFactory->createInstance("com.sun.star.document.PDFFilter"), uno::UNO_QUERY); + uno::Reference xExporter(xFilter, uno::UNO_QUERY); + xExporter->setSourceDocument(getComponent()); + SvMemoryStream aStream; + uno::Reference xOutputStream(new utl::OStreamWrapper(aStream)); + + uno::Sequence aDescriptor{ + comphelper::makePropertyValue("FilterName", OUString("writer_pdf_Export")), + comphelper::makePropertyValue("FilterData", aFilterData), + comphelper::makePropertyValue("OutputStream", xOutputStream), + }; + xFilter->filter(aDescriptor); + + // Then make sure the resulting PDF has a signature: + std::unique_ptr pPdfDocument + = pPDFium->openDocument(aStream.GetData(), aStream.GetSize(), OString()); + // Without the accompanying fix in place, this test would have failed, as signing was enabled + // without configuring a certificate, so the whole export failed. + CPPUNIT_ASSERT(pPdfDocument); + CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getSignatureCount()); +} + +CPPUNIT_TEST_FIXTURE(Test, testPdfDecompositionSize) +{ + std::shared_ptr pPDFium = vcl::pdf::PDFiumLibrary::get(); + if (!pPDFium) + return; + + // Given an empty Writer document: + getComponent().set( + loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument")); + + // When inserting a 267 points wide PDF image into the document: + uno::Sequence aArgs = { + comphelper::makePropertyValue("FileName", + m_directories.getURLFromSrc(DATA_DIRECTORY) + "picture.pdf"), + }; + dispatchCommand(getComponent(), ".uno:InsertGraphic", aArgs); + + // Then make sure that its size is correct: + uno::Reference xDrawPageSupplier(getComponent(), uno::UNO_QUERY); + uno::Reference xDrawPage = xDrawPageSupplier->getDrawPage(); + uno::Reference xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + auto xGraphic = xShape->getPropertyValue("Graphic").get>(); + CPPUNIT_ASSERT(xGraphic.is()); + Graphic aGraphic(xGraphic); + basegfx::B2DRange aRange = aGraphic.getVectorGraphicData()->getRange(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 9437 + // - Actual : 34176 + // i.e. the width was too large, it used all width of the body frame. + // 9437 mm100 is 267.507 points from the file. +#if defined MACOSX + // TODO the bitmap size is larger (75486) on macOS, but that should not affect the logic size. + (void)aRange; +#else + // Unfortunately, this test is DPI-dependent. + // Use some allowance (~1/2 pt) to let it pass on non-default DPI. + CPPUNIT_ASSERT_DOUBLES_EQUAL(9437, aRange.getWidth(), 20.0); +#endif +} + +CPPUNIT_TEST_FIXTURE(Test, testWatermarkColor) +{ + // Given an empty Writer document: + std::shared_ptr pPDFium = vcl::pdf::PDFiumLibrary::get(); + if (!pPDFium) + return; + getComponent().set( + loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument")); + + // When exporting that as PDF with a red watermark: + uno::Reference xFactory = getMultiServiceFactory(); + uno::Reference xFilter( + xFactory->createInstance("com.sun.star.document.PDFFilter"), uno::UNO_QUERY); + uno::Reference xExporter(xFilter, uno::UNO_QUERY); + xExporter->setSourceDocument(getComponent()); + SvMemoryStream aStream; + uno::Reference xOutputStream(new utl::OStreamWrapper(aStream)); + uno::Sequence aFilterData{ + comphelper::makePropertyValue("Watermark", OUString("X")), + comphelper::makePropertyValue("WatermarkColor", static_cast(0xff0000)), + }; + uno::Sequence aDescriptor{ + comphelper::makePropertyValue("FilterName", OUString("writer_pdf_Export")), + comphelper::makePropertyValue("FilterData", aFilterData), + comphelper::makePropertyValue("OutputStream", xOutputStream), + }; + xFilter->filter(aDescriptor); + + // Then make sure that the watermark color is correct: + std::unique_ptr pPdfDocument + = pPDFium->openDocument(aStream.GetData(), aStream.GetSize(), OString()); + CPPUNIT_ASSERT(pPdfDocument); + std::unique_ptr pPage = pPdfDocument->openPage(0); + CPPUNIT_ASSERT_EQUAL(1, pPage->getObjectCount()); + std::unique_ptr pPageObject = pPage->getObject(0); + CPPUNIT_ASSERT_EQUAL(1, pPageObject->getFormObjectCount()); + std::unique_ptr pFormObject = pPageObject->getFormObject(0); + Color aFillColor = pFormObject->getFillColor(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: rgba[ff0000ff] + // - Actual : rgba[00ff00ff] + // i.e. the color was the (default) green, not red. + CPPUNIT_ASSERT_EQUAL(Color(ColorTransparency, 0xff0000), aFillColor); +} + +CPPUNIT_TEST_FIXTURE(Test, testWatermarkFontHeight) +{ + // Given an empty Writer document: + std::shared_ptr pPDFium = vcl::pdf::PDFiumLibrary::get(); + if (!pPDFium) + return; + getComponent().set( + loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument")); + + // When exporting that as PDF with a 100pt-sized watermark: + uno::Reference xFactory = getMultiServiceFactory(); + uno::Reference xFilter( + xFactory->createInstance("com.sun.star.document.PDFFilter"), uno::UNO_QUERY); + uno::Reference xExporter(xFilter, uno::UNO_QUERY); + xExporter->setSourceDocument(getComponent()); + SvMemoryStream aStream; + uno::Reference xOutputStream(new utl::OStreamWrapper(aStream)); + sal_Int32 nExpectedFontSize = 100; + uno::Sequence aFilterData{ + comphelper::makePropertyValue("Watermark", OUString("X")), + comphelper::makePropertyValue("WatermarkFontHeight", nExpectedFontSize), + }; + uno::Sequence aDescriptor{ + comphelper::makePropertyValue("FilterName", OUString("writer_pdf_Export")), + comphelper::makePropertyValue("FilterData", aFilterData), + comphelper::makePropertyValue("OutputStream", xOutputStream), + }; + xFilter->filter(aDescriptor); + + // Then make sure that the watermark font size is correct: + std::unique_ptr pPdfDocument + = pPDFium->openDocument(aStream.GetData(), aStream.GetSize(), OString()); + CPPUNIT_ASSERT(pPdfDocument); + std::unique_ptr pPage = pPdfDocument->openPage(0); + CPPUNIT_ASSERT_EQUAL(1, pPage->getObjectCount()); + std::unique_ptr pPageObject = pPage->getObject(0); + CPPUNIT_ASSERT_EQUAL(1, pPageObject->getFormObjectCount()); + std::unique_ptr pFormObject = pPageObject->getFormObject(0); + sal_Int32 nFontSize = pFormObject->getFontSize(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 100 + // - Actual : 594 + // i.e. the font size was automatic, could not specify an explicit size. + CPPUNIT_ASSERT_EQUAL(nExpectedFontSize, nFontSize); +} + +CPPUNIT_TEST_FIXTURE(Test, testWatermarkFontName) +{ + // Given an empty Writer document: + std::shared_ptr pPDFium = vcl::pdf::PDFiumLibrary::get(); + if (!pPDFium) + return; + getComponent().set( + loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument")); + + // When exporting that as PDF with a serif watermark: + uno::Reference xFactory = getMultiServiceFactory(); + uno::Reference xFilter( + xFactory->createInstance("com.sun.star.document.PDFFilter"), uno::UNO_QUERY); + uno::Reference xExporter(xFilter, uno::UNO_QUERY); + xExporter->setSourceDocument(getComponent()); + SvMemoryStream aStream; + uno::Reference xOutputStream(new utl::OStreamWrapper(aStream)); + OUString aExpectedFontName("Liberation Serif"); + uno::Sequence aFilterData{ + comphelper::makePropertyValue("Watermark", OUString("X")), + comphelper::makePropertyValue("WatermarkFontName", aExpectedFontName), + }; + uno::Sequence aDescriptor{ + comphelper::makePropertyValue("FilterName", OUString("writer_pdf_Export")), + comphelper::makePropertyValue("FilterData", aFilterData), + comphelper::makePropertyValue("OutputStream", xOutputStream), + }; + xFilter->filter(aDescriptor); + + // Then make sure that the watermark font name is correct: + std::unique_ptr pPdfDocument + = pPDFium->openDocument(aStream.GetData(), aStream.GetSize(), OString()); + CPPUNIT_ASSERT(pPdfDocument); + std::unique_ptr pPage = pPdfDocument->openPage(0); + CPPUNIT_ASSERT_EQUAL(1, pPage->getObjectCount()); + std::unique_ptr pPageObject = pPage->getObject(0); + CPPUNIT_ASSERT_EQUAL(1, pPageObject->getFormObjectCount()); + std::unique_ptr pFormObject = pPageObject->getFormObject(0); + OUString aFontName = pFormObject->getFontName(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: Liberation Serif + // - Actual : Helvetica + // i.e. the font name was sans, could not specify an explicit name. + CPPUNIT_ASSERT_EQUAL(aExpectedFontName, aFontName); +} + +CPPUNIT_TEST_FIXTURE(Test, testWatermarkRotateAngle) +{ + // Given an empty Writer document: + std::shared_ptr pPDFium = vcl::pdf::PDFiumLibrary::get(); + if (!pPDFium) + return; + getComponent().set( + loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument")); + + // When exporting that as PDF with a rotated watermark: + uno::Reference xFactory = getMultiServiceFactory(); + uno::Reference xFilter( + xFactory->createInstance("com.sun.star.document.PDFFilter"), uno::UNO_QUERY); + uno::Reference xExporter(xFilter, uno::UNO_QUERY); + xExporter->setSourceDocument(getComponent()); + SvMemoryStream aStream; + uno::Reference xOutputStream(new utl::OStreamWrapper(aStream)); + // 45.0 degrees, counter-clockwise. + sal_Int32 nExpectedRotateAngle = 45; + uno::Sequence aFilterData{ + comphelper::makePropertyValue("Watermark", OUString("X")), + comphelper::makePropertyValue("WatermarkRotateAngle", nExpectedRotateAngle * 10), + }; + uno::Sequence aDescriptor{ + comphelper::makePropertyValue("FilterName", OUString("writer_pdf_Export")), + comphelper::makePropertyValue("FilterData", aFilterData), + comphelper::makePropertyValue("OutputStream", xOutputStream), + }; + xFilter->filter(aDescriptor); + + // Then make sure that the watermark rotation angle is correct: + std::unique_ptr pPdfDocument + = pPDFium->openDocument(aStream.GetData(), aStream.GetSize(), OString()); + CPPUNIT_ASSERT(pPdfDocument); + std::unique_ptr pPage = pPdfDocument->openPage(0); + CPPUNIT_ASSERT_EQUAL(1, pPage->getObjectCount()); + std::unique_ptr pPageObject = pPage->getObject(0); + CPPUNIT_ASSERT_EQUAL(1, pPageObject->getFormObjectCount()); + std::unique_ptr pFormObject = pPageObject->getFormObject(0); + basegfx::B2DHomMatrix aMatrix = pFormObject->getMatrix(); + basegfx::B2DTuple aScale; + basegfx::B2DTuple aTranslate; + double fRotate{}; + double fShearX{}; + aMatrix.decompose(aScale, aTranslate, fRotate, fShearX); + sal_Int32 nActualRotateAngle = NormAngle360(basegfx::rad2deg<1>(fRotate)); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 45 + // - Actual : 270 + // i.e. the rotation angle was 270 for an A4 page, not the requested 45 degrees. + CPPUNIT_ASSERT_EQUAL(nExpectedRotateAngle, nActualRotateAngle); +} +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3