/* -*- 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: */