diff options
Diffstat (limited to 'filter/source/pdf/pdfexport.cxx')
-rw-r--r-- | filter/source/pdf/pdfexport.cxx | 646 |
1 files changed, 423 insertions, 223 deletions
diff --git a/filter/source/pdf/pdfexport.cxx b/filter/source/pdf/pdfexport.cxx index 604326b4bdbf..03ecbf576c56 100644 --- a/filter/source/pdf/pdfexport.cxx +++ b/filter/source/pdf/pdfexport.cxx @@ -22,11 +22,12 @@ #include <tools/debug.hxx> #include <tools/urlobj.hxx> #include <tools/poly.hxx> -#include <tools/diagnose_ex.h> -#include <unotools/resmgr.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <utility> #include <vcl/canvastools.hxx> #include <vcl/mapmod.hxx> #include <vcl/gdimtf.hxx> +#include <rtl/ustring.hxx> #include <comphelper/propertyvalue.hxx> #include <comphelper/sequence.hxx> #include <comphelper/string.hxx> @@ -36,8 +37,8 @@ #include <basegfx/polygon/b2dpolygontools.hxx> #include <toolkit/awt/vclxdevice.hxx> #include <unotools/configmgr.hxx> -#include <cppuhelper/compbase.hxx> -#include <cppuhelper/basemutex.hxx> +#include <comphelper/compbase.hxx> +#include <officecfg/Office/Common.hxx> #include "pdfexport.hxx" #include <strings.hrc> @@ -48,7 +49,7 @@ #include <com/sun/star/frame/XModel.hpp> #include <com/sun/star/frame/ModuleManager.hpp> #include <com/sun/star/frame/XStorable.hpp> -#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/XDocumentProperties2.hpp> #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> #include <com/sun/star/container/XNameAccess.hpp> #include <com/sun/star/view/XViewSettingsSupplier.hpp> @@ -58,18 +59,22 @@ #include <com/sun/star/io/XOutputStream.hpp> #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/sheet/XSheetRange.hpp> #include <com/sun/star/security/XCertificate.hpp> #include <com/sun/star/beans/XMaterialHolder.hpp> +#include <com/sun/star/xml/crypto/SEInitializer.hpp> #include <memory> +#include <rtl/bootstrap.hxx> +#include <config_features.h> + using namespace ::com::sun::star; using namespace ::com::sun::star::io; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::view; -using namespace ::com::sun::star::graphic; PDFExport::PDFExport( const Reference< XComponent >& rxSrcDoc, @@ -80,59 +85,17 @@ PDFExport::PDFExport( const Reference< XComponent >& rxSrcDoc, mxContext ( xContext ), mxStatusIndicator ( rxStatusIndicator ), mxIH ( rxIH ), - mbUseTaggedPDF ( false ), - mnPDFTypeSelection ( 0 ), - mbPDFUACompliance ( false), - mbExportNotes ( true ), - mbExportPlaceholders ( false ), - mbUseReferenceXObject ( false ), - mbExportNotesPages ( false ), - mbExportOnlyNotesPages ( false ), - mbUseTransitionEffects ( true ), - mbExportBookmarks ( true ), - mbExportHiddenSlides ( false ), - mbSinglePageSheets ( false ), - mnOpenBookmarkLevels ( -1 ), mbUseLosslessCompression ( false ), mbReduceImageResolution ( true ), mbSkipEmptyPages ( true ), - mbAddStream ( false ), mnMaxImageResolution ( 300 ), mnQuality ( 80 ), - mnFormsFormat ( 0 ), - mbExportFormFields ( true ), - mbAllowDuplicateFieldNames ( false ), mnProgressValue ( 0 ), mbRemoveTransparencies ( false ), mbIsRedactMode ( false ), - - mbHideViewerToolbar ( false ), - mbHideViewerMenubar ( false ), - mbHideViewerWindowControls ( false ), - mbFitWindow ( false ), - mbCenterWindow ( false ), - mbOpenInFullScreenMode ( false ), - mbDisplayPDFDocumentTitle ( true ), - mnPDFDocumentMode ( 0 ), - mnPDFDocumentAction ( 0 ), - mnZoom ( 100 ), - mnInitialPage ( 1 ), - mnPDFPageLayout ( 0 ), - - mbEncrypt ( false ), - mbRestrictPermissions ( false ), - mnPrintAllowed ( 2 ), - mnChangesAllowed ( 4 ), - mbCanCopyOrExtract ( true ), - mbCanExtractForAccessibility( true ), - - // #i56629 - mbExportRelativeFsysLinks ( false ), - mnDefaultLinkAction ( 0 ), - mbConvertOOoTargetToPDFTarget( false ), - mbExportBmkToDest ( false ), - mbSignPDF ( false ) + maWatermarkColor ( COL_LIGHTGREEN ), + maWatermarkFontName ( "Helvetica" ) { } @@ -307,19 +270,16 @@ void PDFExportStreamDoc::write( const Reference< XOutputStream >& xStream ) if( !xStore.is() ) return; - Sequence< beans::PropertyValue > aArgs( 2 + (m_aPreparedPassword.hasElements() ? 1 : 0) ); - aArgs.getArray()[0].Name = "FilterName"; - aArgs.getArray()[1].Name = "OutputStream"; - aArgs.getArray()[1].Value <<= xStream; - if( m_aPreparedPassword.hasElements() ) - { - aArgs.getArray()[2].Name = "EncryptionData"; - aArgs.getArray()[2].Value <<= m_aPreparedPassword; - } + std::vector<beans::PropertyValue> aArgs { + comphelper::makePropertyValue("FilterName", OUString()), + comphelper::makePropertyValue("OutputStream", xStream), + }; + if (m_aPreparedPassword.hasElements()) + aArgs.push_back(comphelper::makePropertyValue("EncryptionData", m_aPreparedPassword)); try { - xStore->storeToURL( "private:stream", aArgs ); + xStore->storeToURL("private:stream", comphelper::containerToSequence(aArgs)); } catch( const IOException& ) { @@ -370,7 +330,7 @@ static OUString getMimetypeForDocument( const Reference< XComponentContext >& xC Sequence< beans::PropertyValue > aFilterData; xFilterFactory->getByName( aFilterName ) >>= aFilterData; - for ( const beans::PropertyValue& rProp : std::as_const(aFilterData) ) + for (const beans::PropertyValue& rProp : aFilterData) if ( rProp.Name == "Type" ) rProp.Value >>= aTypeName; @@ -383,7 +343,7 @@ static OUString getMimetypeForDocument( const Reference< XComponentContext >& xC Sequence< beans::PropertyValue > aTypeData; xTypeDetection->getByName( aTypeName ) >>= aTypeData; - for ( const beans::PropertyValue& rProp : std::as_const(aTypeData) ) + for (const beans::PropertyValue& rProp : aTypeData) if ( rProp.Name == "MediaType" ) rProp.Value >>= aDocMimetype; } @@ -398,6 +358,25 @@ static OUString getMimetypeForDocument( const Reference< XComponentContext >& xC return aDocMimetype; } +uno::Reference<security::XCertificate> +PDFExport::GetCertificateFromSubjectName(const std::u16string_view& rSubjectName) const +{ + uno::Reference<xml::crypto::XSEInitializer> xSEInitializer + = xml::crypto::SEInitializer::create(mxContext); + uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext + = xSEInitializer->createSecurityContext(OUString()); + uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment + = xSecurityContext->getSecurityEnvironment(); + for (const auto& xCertificate : xSecurityEnvironment->getPersonalCertificates()) + { + if (xCertificate->getSubjectName() == rSubjectName) + { + return xCertificate; + } + } + + return {}; +} bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& rFilterData ) { @@ -420,6 +399,53 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& if( xRenderable.is() ) { + // The defaults + bool bUseTaggedPDF = false; + sal_Int32 nPDFTypeSelection = 0; + bool bPDFUACompliance = false; + bool bExportNotes = true; + bool bExportNotesInMargin = false; + bool bExportNotesPages = false; + bool bExportOnlyNotesPages = false; + bool bUseTransitionEffects = true; + bool bExportFormFields = true; + sal_Int32 nFormsFormat = 0; + bool bAllowDuplicateFieldNames = false; + bool bHideViewerToolbar = false; + bool bHideViewerMenubar = false; + bool bHideViewerWindowControls = false; + bool bFitWindow = false; + bool bCenterWindow = false; + bool bOpenInFullScreenMode = false; + bool bDisplayPDFDocumentTitle = true; + sal_Int32 nPDFDocumentMode = 0; + sal_Int32 nPDFDocumentAction = 0; + sal_Int32 nZoom = 100; + sal_Int32 nInitialPage = 1; + sal_Int32 nPDFPageLayout = 0; + bool bAddStream = false; + bool bEncrypt = false; + bool bRestrictPermissions = false; + sal_Int32 nPrintAllowed = 2; + sal_Int32 nChangesAllowed = 4; + bool bCanCopyOrExtract = true; + bool bCanExtractForAccessibility = true; + // #i56629 + bool bExportRelativeFsysLinks = false; + sal_Int32 nDefaultLinkAction = 0; + bool bConvertOOoTargetToPDFTarget = false; + bool bExportBmkToDest = false; + bool bExportBookmarks = true; + bool bExportHiddenSlides = false; + bool bSinglePageSheets = false; + sal_Int32 nOpenBookmarkLevels = -1; + bool bSignPDF = false; + OUString sSignLocation, sSignReason, sSignContact, sSignPassword; + css::uno::Reference<css::security::XCertificate> aSignCertificate; + OUString sSignTSA; + bool bExportPlaceholders = false; + bool bUseReferenceXObject = false; + rtl::Reference<VCLXDevice> xDevice(new VCLXDevice); OUString aPageRange; Any aSelection; @@ -427,7 +453,11 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& OUString aOpenPassword, aPermissionPassword; Reference< beans::XMaterialHolder > xEnc; Sequence< beans::NamedValue > aPreparedPermissionPassword; - + std::optional<PropertyValue> oMathTitleRow; + std::optional<PropertyValue> oMathFormulaText; + std::optional<PropertyValue> oMathBorder; + std::optional<PropertyValue> oMathPrintFormat; + std::optional<PropertyValue> oMathPrintScale; // getting the string for the creator OUString aCreator; @@ -435,40 +465,74 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& if ( xInfo.is() ) { if ( xInfo->supportsService( "com.sun.star.presentation.PresentationDocument" ) ) - aCreator += "Impress"; + aCreator = u"Impress"_ustr; else if ( xInfo->supportsService( "com.sun.star.drawing.DrawingDocument" ) ) - aCreator += "Draw"; + aCreator = u"Draw"_ustr; else if ( xInfo->supportsService( "com.sun.star.text.TextDocument" ) ) - aCreator += "Writer"; + aCreator = u"Writer"_ustr; else if ( xInfo->supportsService( "com.sun.star.sheet.SpreadsheetDocument" ) ) - aCreator += "Calc"; + aCreator = u"Calc"_ustr; else if ( xInfo->supportsService( "com.sun.star.formula.FormulaProperties" ) ) - aCreator += "Math"; + aCreator = u"Math"_ustr; } Reference< document::XDocumentPropertiesSupplier > xDocumentPropsSupplier( mxSrcDoc, UNO_QUERY ); if ( xDocumentPropsSupplier.is() ) { - Reference< document::XDocumentProperties > xDocumentProps( xDocumentPropsSupplier->getDocumentProperties() ); + Reference< document::XDocumentProperties2 > xDocumentProps( xDocumentPropsSupplier->getDocumentProperties(), UNO_QUERY ); if ( xDocumentProps.is() ) { aContext.DocumentInfo.Title = xDocumentProps->getTitle(); aContext.DocumentInfo.Author = xDocumentProps->getAuthor(); aContext.DocumentInfo.Subject = xDocumentProps->getSubject(); aContext.DocumentInfo.Keywords = ::comphelper::string::convertCommaSeparated(xDocumentProps->getKeywords()); + aContext.DocumentInfo.ModificationDate + = xDocumentProps->getEditingCycles() < 1 + ? xDocumentProps->getCreationDate() + : xDocumentProps->getModificationDate(); + aContext.DocumentInfo.Contributor = xDocumentProps->getContributor(); + aContext.DocumentInfo.Coverage = xDocumentProps->getCoverage(); + aContext.DocumentInfo.Identifier = xDocumentProps->getIdentifier(); + aContext.DocumentInfo.Publisher = xDocumentProps->getPublisher(); + aContext.DocumentInfo.Relation = xDocumentProps->getRelation(); + aContext.DocumentInfo.Rights = xDocumentProps->getRights(); + aContext.DocumentInfo.Source = xDocumentProps->getSource(); + aContext.DocumentInfo.Type = xDocumentProps->getType(); } } - // getting the string for the producer - aContext.DocumentInfo.Producer = - utl::ConfigManager::getProductName() + - " " + - utl::ConfigManager::getProductVersion(); + + if (!comphelper::IsFuzzing()) + { + OUString arch; + auto const ok = rtl::Bootstrap::get("_ARCH", arch); + assert(ok); (void) ok; + // getting the string for the producer + OUString aProducerOverride = officecfg::Office::Common::Save::Document::GeneratorOverride::get(); + if (!aProducerOverride.isEmpty()) + aContext.DocumentInfo.Producer = aProducerOverride; + else + aContext.DocumentInfo.Producer = + utl::ConfigManager::getProductName() + + " " + + utl::ConfigManager::getAboutBoxProductVersion() + + " (" + arch + ") / LibreOffice Community"; + } + aContext.DocumentInfo.Creator = aCreator; + OUString aSignCertificateSubjectName; for ( const beans::PropertyValue& rProp : rFilterData ) { if ( rProp.Name == "PageRange" ) rProp.Value >>= aPageRange; + else if ( rProp.Name == "SheetRange" ) + { + Reference< frame::XController > xController( Reference< frame::XModel >( mxSrcDoc, UNO_QUERY_THROW )->getCurrentController() ); + Reference< sheet::XSheetRange > xView( xController, UNO_QUERY); + OUString aSheetRange; + rProp.Value >>= aSheetRange; + aSelection = xView->getSelectionFromString(aSheetRange); + } else if ( rProp.Name == "Selection" ) aSelection = rProp.Value; else if ( rProp.Name == "UseLosslessCompression" ) @@ -482,65 +546,99 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& else if ( rProp.Name == "MaxImageResolution" ) rProp.Value >>= mnMaxImageResolution; else if ( rProp.Name == "UseTaggedPDF" ) - rProp.Value >>= mbUseTaggedPDF; + rProp.Value >>= bUseTaggedPDF; else if ( rProp.Name == "SelectPdfVersion" ) - rProp.Value >>= mnPDFTypeSelection; + rProp.Value >>= nPDFTypeSelection; else if ( rProp.Name == "PDFUACompliance" ) - rProp.Value >>= mbPDFUACompliance; + rProp.Value >>= bPDFUACompliance; else if ( rProp.Name == "ExportNotes" ) - rProp.Value >>= mbExportNotes; + rProp.Value >>= bExportNotes; + else if ( rProp.Name == "ExportNotesInMargin" ) + rProp.Value >>= bExportNotesInMargin; else if ( rProp.Name == "ExportNotesPages" ) - rProp.Value >>= mbExportNotesPages; + rProp.Value >>= bExportNotesPages; else if ( rProp.Name == "ExportOnlyNotesPages" ) - rProp.Value >>= mbExportOnlyNotesPages; + rProp.Value >>= bExportOnlyNotesPages; else if ( rProp.Name == "UseTransitionEffects" ) - rProp.Value >>= mbUseTransitionEffects; + rProp.Value >>= bUseTransitionEffects; else if ( rProp.Name == "ExportFormFields" ) - rProp.Value >>= mbExportFormFields; + rProp.Value >>= bExportFormFields; else if ( rProp.Name == "FormsType" ) - rProp.Value >>= mnFormsFormat; + rProp.Value >>= nFormsFormat; else if ( rProp.Name == "AllowDuplicateFieldNames" ) - rProp.Value >>= mbAllowDuplicateFieldNames; + rProp.Value >>= bAllowDuplicateFieldNames; // viewer properties else if ( rProp.Name == "HideViewerToolbar" ) - rProp.Value >>= mbHideViewerToolbar; + rProp.Value >>= bHideViewerToolbar; else if ( rProp.Name == "HideViewerMenubar" ) - rProp.Value >>= mbHideViewerMenubar; + rProp.Value >>= bHideViewerMenubar; else if ( rProp.Name == "HideViewerWindowControls" ) - rProp.Value >>= mbHideViewerWindowControls; + rProp.Value >>= bHideViewerWindowControls; else if ( rProp.Name == "ResizeWindowToInitialPage" ) - rProp.Value >>= mbFitWindow; + rProp.Value >>= bFitWindow; else if ( rProp.Name == "CenterWindow" ) - rProp.Value >>= mbCenterWindow; + rProp.Value >>= bCenterWindow; else if ( rProp.Name == "OpenInFullScreenMode" ) - rProp.Value >>= mbOpenInFullScreenMode; + rProp.Value >>= bOpenInFullScreenMode; else if ( rProp.Name == "DisplayPDFDocumentTitle" ) - rProp.Value >>= mbDisplayPDFDocumentTitle; + rProp.Value >>= bDisplayPDFDocumentTitle; else if ( rProp.Name == "InitialView" ) - rProp.Value >>= mnPDFDocumentMode; + rProp.Value >>= nPDFDocumentMode; else if ( rProp.Name == "Magnification" ) - rProp.Value >>= mnPDFDocumentAction; + rProp.Value >>= nPDFDocumentAction; else if ( rProp.Name == "Zoom" ) - rProp.Value >>= mnZoom; + rProp.Value >>= nZoom; else if ( rProp.Name == "InitialPage" ) - rProp.Value >>= mnInitialPage; + rProp.Value >>= nInitialPage; else if ( rProp.Name == "PageLayout" ) - rProp.Value >>= mnPDFPageLayout; + rProp.Value >>= nPDFPageLayout; else if ( rProp.Name == "FirstPageOnLeft" ) rProp.Value >>= aContext.FirstPageLeft; else if ( rProp.Name == "IsAddStream" ) - rProp.Value >>= mbAddStream; + rProp.Value >>= bAddStream; else if ( rProp.Name == "Watermark" ) rProp.Value >>= msWatermark; + else if ( rProp.Name == "WatermarkColor" ) + { + sal_Int32 nColor{}; + if (rProp.Value >>= nColor) + { + maWatermarkColor = Color(ColorTransparency, nColor); + } + } + else if (rProp.Name == "WatermarkFontHeight") + { + sal_Int32 nFontHeight{}; + if (rProp.Value >>= nFontHeight) + { + moWatermarkFontHeight = nFontHeight; + } + } + else if (rProp.Name == "WatermarkRotateAngle") + { + sal_Int32 nRotateAngle{}; + if (rProp.Value >>= nRotateAngle) + { + moWatermarkRotateAngle = Degree10(nRotateAngle); + } + } + else if (rProp.Name == "WatermarkFontName") + { + OUString aFontName{}; + if (rProp.Value >>= aFontName) + { + maWatermarkFontName = aFontName; + } + } else if ( rProp.Name == "TiledWatermark" ) rProp.Value >>= msTiledWatermark; // now all the security related properties... else if ( rProp.Name == "EncryptFile" ) - rProp.Value >>= mbEncrypt; + rProp.Value >>= bEncrypt; else if ( rProp.Name == "DocumentOpenPassword" ) rProp.Value >>= aOpenPassword; else if ( rProp.Name == "RestrictPermissions" ) - rProp.Value >>= mbRestrictPermissions; + rProp.Value >>= bRestrictPermissions; else if ( rProp.Name == "PermissionPassword" ) rProp.Value >>= aPermissionPassword; else if ( rProp.Name == "PreparedPasswords" ) @@ -548,81 +646,99 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& else if ( rProp.Name == "PreparedPermissionPassword" ) rProp.Value >>= aPreparedPermissionPassword; else if ( rProp.Name == "Printing" ) - rProp.Value >>= mnPrintAllowed; + rProp.Value >>= nPrintAllowed; else if ( rProp.Name == "Changes" ) - rProp.Value >>= mnChangesAllowed; + rProp.Value >>= nChangesAllowed; else if ( rProp.Name == "EnableCopyingOfContent" ) - rProp.Value >>= mbCanCopyOrExtract; + rProp.Value >>= bCanCopyOrExtract; else if ( rProp.Name == "EnableTextAccessForAccessibilityTools" ) - rProp.Value >>= mbCanExtractForAccessibility; + rProp.Value >>= bCanExtractForAccessibility; // i56629 links extra (relative links and other related stuff) else if ( rProp.Name == "ExportLinksRelativeFsys" ) - rProp.Value >>= mbExportRelativeFsysLinks; + rProp.Value >>= bExportRelativeFsysLinks; else if ( rProp.Name == "PDFViewSelection" ) - rProp.Value >>= mnDefaultLinkAction; + rProp.Value >>= nDefaultLinkAction; else if ( rProp.Name == "ConvertOOoTargetToPDFTarget" ) - rProp.Value >>= mbConvertOOoTargetToPDFTarget; + rProp.Value >>= bConvertOOoTargetToPDFTarget; else if ( rProp.Name == "ExportBookmarksToPDFDestination" ) - rProp.Value >>= mbExportBmkToDest; + rProp.Value >>= bExportBmkToDest; else if ( rProp.Name == "ExportBookmarks" ) - rProp.Value >>= mbExportBookmarks; + rProp.Value >>= bExportBookmarks; else if ( rProp.Name == "ExportHiddenSlides" ) - rProp.Value >>= mbExportHiddenSlides; + rProp.Value >>= bExportHiddenSlides; else if ( rProp.Name == "SinglePageSheets" ) - rProp.Value >>= mbSinglePageSheets; + rProp.Value >>= bSinglePageSheets; else if ( rProp.Name == "OpenBookmarkLevels" ) - rProp.Value >>= mnOpenBookmarkLevels; + rProp.Value >>= nOpenBookmarkLevels; else if ( rProp.Name == "SignPDF" ) - rProp.Value >>= mbSignPDF; + rProp.Value >>= bSignPDF; else if ( rProp.Name == "SignatureLocation" ) - rProp.Value >>= msSignLocation; + rProp.Value >>= sSignLocation; else if ( rProp.Name == "SignatureReason" ) - rProp.Value >>= msSignReason; + rProp.Value >>= sSignReason; else if ( rProp.Name == "SignatureContactInfo" ) - rProp.Value >>= msSignContact; + rProp.Value >>= sSignContact; else if ( rProp.Name == "SignaturePassword" ) - rProp.Value >>= msSignPassword; + rProp.Value >>= sSignPassword; else if ( rProp.Name == "SignatureCertificate" ) - rProp.Value >>= maSignCertificate; + rProp.Value >>= aSignCertificate; + else if (rProp.Name == "SignCertificateSubjectName") + rProp.Value >>= aSignCertificateSubjectName; else if ( rProp.Name == "SignatureTSA" ) - rProp.Value >>= msSignTSA; + rProp.Value >>= sSignTSA; else if ( rProp.Name == "ExportPlaceholders" ) - rProp.Value >>= mbExportPlaceholders; + rProp.Value >>= bExportPlaceholders; else if ( rProp.Name == "UseReferenceXObject" ) - rProp.Value >>= mbUseReferenceXObject; + rProp.Value >>= bUseReferenceXObject; // Redaction & bitmap related stuff else if ( rProp.Name == "IsRedactMode" ) rProp.Value >>= mbIsRedactMode; + // Math-specific render options + else if (rProp.Name == "TitleRow") + oMathTitleRow = rProp; + else if (rProp.Name == "FormulaText") + oMathFormulaText = rProp; + else if (rProp.Name == "Border") + oMathBorder = rProp; + else if (rProp.Name == "PrintFormat") + oMathPrintFormat = rProp; + else if (rProp.Name == "PrintScale") + oMathPrintScale = rProp; + } + + if (!aSignCertificate.is() && !aSignCertificateSubjectName.isEmpty()) + { + aSignCertificate = GetCertificateFromSubjectName(aSignCertificateSubjectName); } aContext.URL = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri); // set the correct version, depending on user request - switch( mnPDFTypeSelection ) + switch( nPDFTypeSelection ) { default: case 0: - aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_6; + aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_7; break; case 1: aContext.Version = vcl::PDFWriter::PDFVersion::PDF_A_1; - mbUseTaggedPDF = true; // force the tagged PDF as well + bUseTaggedPDF = true; // force the tagged PDF as well mbRemoveTransparencies = true; // does not allow transparencies - mbEncrypt = false; // no encryption + bEncrypt = false; // no encryption xEnc.clear(); break; case 2: aContext.Version = vcl::PDFWriter::PDFVersion::PDF_A_2; - mbUseTaggedPDF = true; // force the tagged PDF as well + bUseTaggedPDF = true; // force the tagged PDF as well mbRemoveTransparencies = false; // does allow transparencies - mbEncrypt = false; // no encryption + bEncrypt = false; // no encryption xEnc.clear(); break; case 3: aContext.Version = vcl::PDFWriter::PDFVersion::PDF_A_3; - mbUseTaggedPDF = true; // force the tagged PDF as well + bUseTaggedPDF = true; // force the tagged PDF as well mbRemoveTransparencies = false; // does allow transparencies - mbEncrypt = false; // no encryption + bEncrypt = false; // no encryption xEnc.clear(); break; case 15: @@ -631,30 +747,38 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& case 16: aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_6; break; + case 17: + aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_7; + break; } // PDF/UA support - aContext.UniversalAccessibilityCompliance = mbPDFUACompliance; - if (mbPDFUACompliance) + aContext.UniversalAccessibilityCompliance = bPDFUACompliance; + if (bPDFUACompliance) { - mbUseTaggedPDF = true; + // ISO 14289-1:2014, Clause: 7.1 + bUseTaggedPDF = true; + // ISO 14289-1:2014, Clause: 7.16 + bCanExtractForAccessibility = true; + // ISO 14289-1:2014, Clause: 7.20 + bUseReferenceXObject = false; } // copy in context the values default in the constructor or set by the FilterData sequence of properties - aContext.Tagged = mbUseTaggedPDF; + aContext.Tagged = bUseTaggedPDF; // values used in viewer - aContext.HideViewerToolbar = mbHideViewerToolbar; - aContext.HideViewerMenubar = mbHideViewerMenubar; - aContext.HideViewerWindowControls = mbHideViewerWindowControls; - aContext.FitWindow = mbFitWindow; - aContext.CenterWindow = mbCenterWindow; - aContext.OpenInFullScreenMode = mbOpenInFullScreenMode; - aContext.DisplayPDFDocumentTitle = mbDisplayPDFDocumentTitle; - aContext.InitialPage = mnInitialPage-1; - aContext.OpenBookmarkLevels = mnOpenBookmarkLevels; - - switch( mnPDFDocumentMode ) + aContext.HideViewerToolbar = bHideViewerToolbar; + aContext.HideViewerMenubar = bHideViewerMenubar; + aContext.HideViewerWindowControls = bHideViewerWindowControls; + aContext.FitWindow = bFitWindow; + aContext.CenterWindow = bCenterWindow; + aContext.OpenInFullScreenMode = bOpenInFullScreenMode; + aContext.DisplayPDFDocumentTitle = bDisplayPDFDocumentTitle; + aContext.InitialPage = nInitialPage-1; + aContext.OpenBookmarkLevels = nOpenBookmarkLevels; + + switch( nPDFDocumentMode ) { default: case 0: @@ -667,7 +791,7 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& aContext.PDFDocumentMode = vcl::PDFWriter::UseThumbs; break; } - switch( mnPDFDocumentAction ) + switch( nPDFDocumentAction ) { default: case 0: @@ -684,11 +808,11 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& break; case 4: aContext.PDFDocumentAction = vcl::PDFWriter::ActionZoom; - aContext.Zoom = mnZoom; + aContext.Zoom = nZoom; break; } - switch( mnPDFPageLayout ) + switch( nPDFPageLayout ) { default: case 0: @@ -712,20 +836,20 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& { // set check for permission change password // if not enabled and no permission password, force permissions to default as if PDF where without encryption - if( mbRestrictPermissions && (xEnc.is() || !aPermissionPassword.isEmpty()) ) + if( bRestrictPermissions && (xEnc.is() || !aPermissionPassword.isEmpty()) ) { - mbEncrypt = true; // permission set as desired, done after + bEncrypt = true; // permission set as desired, done after } else { // force permission to default - mnPrintAllowed = 2 ; - mnChangesAllowed = 4 ; - mbCanCopyOrExtract = true; - mbCanExtractForAccessibility = true ; + nPrintAllowed = 2 ; + nChangesAllowed = 4 ; + bCanCopyOrExtract = true; + bCanExtractForAccessibility = true ; } - switch( mnPrintAllowed ) + switch( nPrintAllowed ) { case 0: // initialized when aContext is build, means no printing break; @@ -738,7 +862,7 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& break; } - switch( mnChangesAllowed ) + switch( nChangesAllowed ) { case 0: // already in struct PDFSecPermissions CTOR break; @@ -760,11 +884,11 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& break; } - aContext.Encryption.CanCopyOrExtract = mbCanCopyOrExtract; - aContext.Encryption.CanExtractForAccessibility = mbCanExtractForAccessibility; - if( mbEncrypt && ! xEnc.is() ) + aContext.Encryption.CanCopyOrExtract = bCanCopyOrExtract; + aContext.Encryption.CanExtractForAccessibility = bCanExtractForAccessibility; + if( bEncrypt && ! xEnc.is() ) xEnc = vcl::PDFWriter::InitEncryption( aPermissionPassword, aOpenPassword ); - if( mbEncrypt && !aPermissionPassword.isEmpty() && ! aPreparedPermissionPassword.hasElements() ) + if( bEncrypt && !aPermissionPassword.isEmpty() && ! aPreparedPermissionPassword.hasElements() ) aPreparedPermissionPassword = comphelper::OStorageHelper::CreatePackageEncryptionData( aPermissionPassword ); } // after this point we don't need the legacy clear passwords anymore @@ -777,7 +901,7 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& * FIXME: the entries are only implicitly defined by the resource file. Should there * ever be an additional form submit format this could get invalid. */ - switch( mnFormsFormat ) + switch( nFormsFormat ) { case 1: aContext.SubmitFormat = vcl::PDFWriter::PDF; @@ -793,7 +917,7 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& aContext.SubmitFormat = vcl::PDFWriter::FDF; break; } - aContext.AllowDuplicateFieldNames = mbAllowDuplicateFieldNames; + aContext.AllowDuplicateFieldNames = bAllowDuplicateFieldNames; // get model Reference< frame::XModel > xModel( mxSrcDoc, UNO_QUERY ); @@ -802,9 +926,9 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& // set the base URL of the file: then base URL aContext.BaseURL = xModel->getURL(); // relative link option is private to PDF Export filter and limited to local filesystem only - aContext.RelFsys = mbExportRelativeFsysLinks; - // determine the default acton for PDF links - switch( mnDefaultLinkAction ) + aContext.RelFsys = bExportRelativeFsysLinks; + // determine the default action for PDF links + switch( nDefaultLinkAction ) { default: // default: URI, without fragment conversion (the bookmark in PDF may not work) @@ -821,7 +945,7 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& aContext.DefaultLinkAction = vcl::PDFWriter::URIActionDestination; break; } - aContext.ConvertOOoTargetToPDFTarget = mbConvertOOoTargetToPDFTarget; + aContext.ConvertOOoTargetToPDFTarget = bConvertOOoTargetToPDFTarget; // check for Link Launch action, not allowed on PDF/A-1 // this code chunk checks when the filter is called from scripting @@ -835,14 +959,14 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& } } - aContext.SignPDF = mbSignPDF; - aContext.SignLocation = msSignLocation; - aContext.SignContact = msSignContact; - aContext.SignReason = msSignReason; - aContext.SignPassword = msSignPassword; - aContext.SignCertificate = maSignCertificate; - aContext.SignTSA = msSignTSA; - aContext.UseReferenceXObject = mbUseReferenceXObject; + aContext.SignPDF = bSignPDF; + aContext.SignLocation = sSignLocation; + aContext.SignContact = sSignContact; + aContext.SignReason = sSignReason; + aContext.SignPassword = sSignPassword; + aContext.SignCertificate = aSignCertificate; + aContext.SignTSA = sSignTSA; + aContext.UseReferenceXObject = bUseReferenceXObject; // all context data set, time to create the printing device vcl::PDFWriter aPDFWriter( aContext, xEnc ); @@ -851,14 +975,22 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& DBG_ASSERT( pOut, "PDFExport::Export: no reference device" ); xDevice->SetOutputDevice(pOut); - if( mbAddStream ) + if( bAddStream ) { // export stream // get mimetype OUString aSrcMimetype = getMimetypeForDocument( mxContext, mxSrcDoc ); - aPDFWriter.AddStream( aSrcMimetype, - new PDFExportStreamDoc( mxSrcDoc, aPreparedPermissionPassword ) - ); + OUString aExt; + if (aSrcMimetype == "application/vnd.oasis.opendocument.text") + aExt = ".odt"; + else if (aSrcMimetype == "application/vnd.oasis.opendocument.presentation") + aExt = ".odp"; + else if (aSrcMimetype == "application/vnd.oasis.opendocument.spreadsheet") + aExt = ".ods"; + else if (aSrcMimetype == "application/vnd.oasis.opendocument.graphics") + aExt = ".odg"; + std::unique_ptr<vcl::PDFOutputStream> pStream(new PDFExportStreamDoc(mxSrcDoc, aPreparedPermissionPassword)); + aPDFWriter.AddAttachedFile("Original" + aExt, aSrcMimetype, u"Embedded original document of this PDF file"_ustr, std::move(pStream)); } if ( pOut ) @@ -866,28 +998,41 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& DBG_ASSERT( pOut->GetExtOutDevData() == nullptr, "PDFExport: ExtOutDevData already set!!!" ); vcl::PDFExtOutDevData aPDFExtOutDevData( *pOut ); pOut->SetExtOutDevData( &aPDFExtOutDevData ); - aPDFExtOutDevData.SetIsExportNotes( mbExportNotes ); - aPDFExtOutDevData.SetIsExportTaggedPDF( mbUseTaggedPDF ); - aPDFExtOutDevData.SetIsExportTransitionEffects( mbUseTransitionEffects ); - aPDFExtOutDevData.SetIsExportFormFields( mbExportFormFields ); - aPDFExtOutDevData.SetIsExportBookmarks( mbExportBookmarks ); - aPDFExtOutDevData.SetIsExportHiddenSlides( mbExportHiddenSlides ); - aPDFExtOutDevData.SetIsSinglePageSheets( mbSinglePageSheets ); + aPDFExtOutDevData.SetIsExportNotes( bExportNotes ); + aPDFExtOutDevData.SetIsExportNotesInMargin( bExportNotesInMargin ); + aPDFExtOutDevData.SetIsExportTaggedPDF( bUseTaggedPDF ); + aPDFExtOutDevData.SetIsExportTransitionEffects( bUseTransitionEffects ); + aPDFExtOutDevData.SetIsExportFormFields( bExportFormFields ); + aPDFExtOutDevData.SetIsExportBookmarks( bExportBookmarks ); + aPDFExtOutDevData.SetIsExportHiddenSlides( bExportHiddenSlides ); + aPDFExtOutDevData.SetIsSinglePageSheets( bSinglePageSheets ); aPDFExtOutDevData.SetIsLosslessCompression( mbUseLosslessCompression ); aPDFExtOutDevData.SetCompressionQuality( mnQuality ); aPDFExtOutDevData.SetIsReduceImageResolution( mbReduceImageResolution ); - aPDFExtOutDevData.SetIsExportNamedDestinations( mbExportBmkToDest ); + aPDFExtOutDevData.SetIsExportNamedDestinations( bExportBmkToDest ); - Sequence< PropertyValue > aRenderOptions{ + std::vector<PropertyValue> aRenderOptionsVector{ comphelper::makePropertyValue("RenderDevice", uno::Reference<awt::XDevice>(xDevice)), comphelper::makePropertyValue("ExportNotesPages", false), comphelper::makePropertyValue("IsFirstPage", true), comphelper::makePropertyValue("IsLastPage", false), comphelper::makePropertyValue("IsSkipEmptyPages", mbSkipEmptyPages), comphelper::makePropertyValue("PageRange", aPageRange), - comphelper::makePropertyValue("ExportPlaceholders", mbExportPlaceholders), - comphelper::makePropertyValue("SinglePageSheets", mbSinglePageSheets) + comphelper::makePropertyValue("ExportPlaceholders", bExportPlaceholders), + comphelper::makePropertyValue("SinglePageSheets", bSinglePageSheets), + comphelper::makePropertyValue("ExportNotesInMargin", bExportNotesInMargin) }; + if (oMathTitleRow) + aRenderOptionsVector.push_back(*oMathTitleRow); + if (oMathFormulaText) + aRenderOptionsVector.push_back(*oMathFormulaText); + if (oMathBorder) + aRenderOptionsVector.push_back(*oMathBorder); + if (oMathPrintFormat) + aRenderOptionsVector.push_back(*oMathPrintFormat); + if (oMathPrintScale) + aRenderOptionsVector.push_back(*oMathPrintScale); + Sequence aRenderOptions = comphelper::containerToSequence(aRenderOptionsVector); Any& rExportNotesValue = aRenderOptions.getArray()[ 1 ].Value; if( !aPageRange.isEmpty() || !aSelection.hasValue() ) @@ -895,11 +1040,10 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& aSelection = Any(); aSelection <<= mxSrcDoc; } - bool bExportNotesPages = false; bool bReChangeToNormalView = false; - static const OUStringLiteral sShowOnlineLayout( u"ShowOnlineLayout" ); + static constexpr OUString sShowOnlineLayout( u"ShowOnlineLayout"_ustr ); bool bReHideWhitespace = false; - static const OUStringLiteral sHideWhitespace(u"HideWhitespace"); + static constexpr OUString sHideWhitespace(u"HideWhitespace"_ustr); uno::Reference< beans::XPropertySet > xViewProperties; if ( aCreator == "Writer" ) @@ -912,14 +1056,14 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& xViewProperties->getPropertyValue( sShowOnlineLayout ) >>= bReChangeToNormalView; if( bReChangeToNormalView ) { - xViewProperties->setPropertyValue( sShowOnlineLayout, uno::makeAny( false ) ); + xViewProperties->setPropertyValue( sShowOnlineLayout, uno::Any( false ) ); } // Also, disable hide-whitespace during export. xViewProperties->getPropertyValue(sHideWhitespace) >>= bReHideWhitespace; if (bReHideWhitespace) { - xViewProperties->setPropertyValue(sHideWhitespace, uno::makeAny(false)); + xViewProperties->setPropertyValue(sHideWhitespace, uno::Any(false)); } } catch( const uno::Exception& ) @@ -930,15 +1074,17 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& const sal_Int32 nPageCount = xRenderable->getRendererCount( aSelection, aRenderOptions ); - if ( mbExportNotesPages && aCreator == "Impress" ) + if ( bExportNotesPages && aCreator == "Impress" ) { uno::Reference< drawing::XShapes > xShapes; // do not allow to export notes when exporting a selection - if ( ! ( aSelection >>= xShapes ) ) - bExportNotesPages = true; + if ( aSelection >>= xShapes ) + bExportNotesPages = false; } - const bool bExportPages = !bExportNotesPages || !mbExportOnlyNotesPages; + else + bExportNotesPages = false; + const bool bExportPages = !bExportNotesPages || !bExportOnlyNotesPages; - if( aPageRange.isEmpty() || mbSinglePageSheets) + if( aPageRange.isEmpty() || bSinglePageSheets) { aPageRange = OUString::number( 1 ) + "-" + OUString::number(nPageCount ); } @@ -946,11 +1092,10 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& if ( mxStatusIndicator.is() ) { - std::locale loc(Translate::Create("flt")); sal_Int32 nTotalPageCount = aRangeEnum.size(); if ( bExportPages && bExportNotesPages ) nTotalPageCount *= 2; - mxStatusIndicator->start(Translate::get(PDF_PROGRESS_BAR, loc), nTotalPageCount); + mxStatusIndicator->start(FilterResId(PDF_PROGRESS_BAR), nTotalPageCount); } bRet = nPageCount > 0; @@ -982,7 +1127,7 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& { try { - xViewProperties->setPropertyValue( sShowOnlineLayout, uno::makeAny( true ) ); + xViewProperties->setPropertyValue( sShowOnlineLayout, uno::Any( true ) ); } catch( const uno::Exception& ) { @@ -992,7 +1137,7 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& { try { - xViewProperties->setPropertyValue( sHideWhitespace, uno::makeAny( true ) ); + xViewProperties->setPropertyValue( sHideWhitespace, uno::Any( true ) ); } catch( const uno::Exception& ) { @@ -1012,14 +1157,13 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& namespace { -typedef cppu::WeakComponentImplHelper< task::XInteractionRequest > PDFErrorRequestBase; +typedef comphelper::WeakComponentImplHelper< task::XInteractionRequest > PDFErrorRequestBase; -class PDFErrorRequest : private cppu::BaseMutex, - public PDFErrorRequestBase +class PDFErrorRequest : public PDFErrorRequestBase { task::PDFExportException maExc; public: - explicit PDFErrorRequest( const task::PDFExportException& i_rExc ); + explicit PDFErrorRequest( task::PDFExportException aExc ); // XInteractionRequest virtual uno::Any SAL_CALL getRequest() override; @@ -1027,16 +1171,15 @@ public: }; -PDFErrorRequest::PDFErrorRequest( const task::PDFExportException& i_rExc ) : - PDFErrorRequestBase( m_aMutex ), - maExc( i_rExc ) +PDFErrorRequest::PDFErrorRequest( task::PDFExportException aExc ) : + maExc(std::move( aExc )) { } uno::Any SAL_CALL PDFErrorRequest::getRequest() { - osl::MutexGuard const guard( m_aMutex ); + std::unique_lock guard( m_aMutex ); uno::Any aRet; aRet <<= maExc; @@ -1058,7 +1201,7 @@ void PDFExport::showErrors( const std::set< vcl::PDFWriter::ErrorCode >& rErrors { task::PDFExportException aExc; aExc.ErrorCodes = comphelper::containerToSequence<sal_Int32>( rErrors ); - Reference< task::XInteractionRequest > xReq( new PDFErrorRequest( aExc ) ); + Reference< task::XInteractionRequest > xReq( new PDFErrorRequest( std::move(aExc) ) ); mxIH->handle( xReq ); } } @@ -1087,7 +1230,7 @@ void PDFExport::ImplExportPage( vcl::PDFWriter& rWriter, vcl::PDFExtOutDevData& // Throw them all away in the absence of a way to reposition them to new positions of // their replacements. if (aCtx.m_bTransparenciesWereRemoved) - rPDFExtOutDevData.ResetSyncData(); + rPDFExtOutDevData.ResetSyncData(&rWriter); } else { @@ -1103,7 +1246,7 @@ void PDFExport::ImplExportPage( vcl::PDFWriter& rWriter, vcl::PDFExtOutDevData& rWriter.PlayMetafile( aMtf, aCtx, &rPDFExtOutDevData ); - rPDFExtOutDevData.ResetSyncData(); + rPDFExtOutDevData.ResetSyncData(nullptr); if (!msWatermark.isEmpty()) { @@ -1118,7 +1261,7 @@ void PDFExport::ImplExportPage( vcl::PDFWriter& rWriter, vcl::PDFExtOutDevData& void PDFExport::ImplWriteWatermark( vcl::PDFWriter& rWriter, const Size& rPageSize ) { - vcl::Font aFont( "Helvetica", Size( 0, 3*rPageSize.Height()/4 ) ); + vcl::Font aFont( maWatermarkFontName, Size( 0, moWatermarkFontHeight ? *moWatermarkFontHeight : 3*rPageSize.Height()/4 ) ); aFont.SetItalic( ITALIC_NONE ); aFont.SetWidthType( WIDTH_NORMAL ); aFont.SetWeight( WEIGHT_NORMAL ); @@ -1130,25 +1273,43 @@ void PDFExport::ImplWriteWatermark( vcl::PDFWriter& rWriter, const Size& rPageSi aFont.SetOrientation( 2700_deg10 ); } + if (moWatermarkRotateAngle) + { + aFont.SetOrientation(*moWatermarkRotateAngle); + if (rPageSize.Width() < rPageSize.Height()) + { + // Set text width based on the shorter side, so rotation can't push text outside the + // page boundaries. + nTextWidth = rPageSize.Width(); + } + } + // adjust font height for text to fit OutputDevice* pDev = rWriter.GetReferenceDevice(); pDev->Push(); pDev->SetFont( aFont ); pDev->SetMapMode( MapMode( MapUnit::MapPoint ) ); int w = 0; - while( ( w = pDev->GetTextWidth( msWatermark ) ) > nTextWidth ) + if (moWatermarkFontHeight) { - if (w == 0) - break; - tools::Long nNewHeight = aFont.GetFontHeight() * nTextWidth / w; - if( nNewHeight == aFont.GetFontHeight() ) + w = pDev->GetTextWidth(msWatermark); + } + else + { + while( ( w = pDev->GetTextWidth( msWatermark ) ) > nTextWidth ) { - nNewHeight--; - if( nNewHeight <= 0 ) + if (w == 0) break; + tools::Long nNewHeight = aFont.GetFontHeight() * nTextWidth / w; + if( nNewHeight == aFont.GetFontHeight() ) + { + nNewHeight--; + if( nNewHeight <= 0 ) + break; + } + aFont.SetFontHeight( nNewHeight ); + pDev->SetFont( aFont ); } - aFont.SetFontHeight( nNewHeight ); - pDev->SetFont( aFont ); } tools::Long nTextHeight = pDev->GetTextHeight(); // leave some maneuvering room for rounding issues, also @@ -1157,9 +1318,18 @@ void PDFExport::ImplWriteWatermark( vcl::PDFWriter& rWriter, const Size& rPageSi pDev->Pop(); rWriter.Push(); + // tdf#152235 tag around the reference to the XObject on the page + sal_Int32 const id = rWriter.EnsureStructureElement(); + rWriter.InitStructureElement(id, vcl::PDFWriter::NonStructElement, ::std::u16string_view()); + rWriter.BeginStructureElement(id); + rWriter.SetStructureAttribute(vcl::PDFWriter::Type, vcl::PDFWriter::Pagination); + rWriter.SetStructureAttribute(vcl::PDFWriter::Subtype, vcl::PDFWriter::Watermark); + // HACK: this should produce *nothing* itself but is necessary to output + // the Artifact tag here, not inside the XObject + rWriter.DrawPolyLine({}); rWriter.SetMapMode( MapMode( MapUnit::MapPoint ) ); rWriter.SetFont( aFont ); - rWriter.SetTextColor( COL_LIGHTGREEN ); + rWriter.SetTextColor(maWatermarkColor); Point aTextPoint; tools::Rectangle aTextRect; if( rPageSize.Width() > rPageSize.Height() ) @@ -1176,10 +1346,30 @@ void PDFExport::ImplWriteWatermark( vcl::PDFWriter& rWriter, const Size& rPageSi (rPageSize.Height()-w)/2 ); aTextRect = tools::Rectangle( aTextPoint, Size( nTextHeight, w ) ); } + + if (moWatermarkRotateAngle) + { + // First set the text's starting point to the center of the page. + tools::Rectangle aPageRectangle(Point(0, 0), rPageSize); + aTextPoint = aPageRectangle.Center(); + // Then adjust it so that the text remains centered, based on the rotation angle. + basegfx::B2DPolygon aTextPolygon + = basegfx::utils::createPolygonFromRect(basegfx::B2DRectangle(0, -nTextHeight, w, 0)); + basegfx::B2DHomMatrix aMatrix; + aMatrix.rotate(-1 * toRadians(*moWatermarkRotateAngle)); + aTextPolygon.transform(aMatrix); + basegfx::B2DPoint aPolygonCenter = aTextPolygon.getB2DRange().getCenter(); + aTextPoint.AdjustX(-aPolygonCenter.getX()); + aTextPoint.AdjustY(-aPolygonCenter.getY()); + + aTextRect = aPageRectangle; + } + rWriter.SetClipRegion(); rWriter.BeginTransparencyGroup(); rWriter.DrawText( aTextPoint, msWatermark ); rWriter.EndTransparencyGroup( aTextRect, 50 ); + rWriter.EndStructureElement(); rWriter.Pop(); } @@ -1226,6 +1416,15 @@ void PDFExport::ImplWriteTiledWatermark( vcl::PDFWriter& rWriter, const Size& rP pDev->Pop(); rWriter.Push(); + // tdf#152235 tag around the reference to the XObject on the page + sal_Int32 const id = rWriter.EnsureStructureElement(); + rWriter.InitStructureElement(id, vcl::PDFWriter::NonStructElement, ::std::u16string_view()); + rWriter.BeginStructureElement(id); + rWriter.SetStructureAttribute(vcl::PDFWriter::Type, vcl::PDFWriter::Pagination); + rWriter.SetStructureAttribute(vcl::PDFWriter::Subtype, vcl::PDFWriter::Watermark); + // HACK: this should produce *nothing* itself but is necessary to output + // the Artifact tag here, not inside the XObject + rWriter.DrawPolyLine({}); rWriter.SetMapMode( MapMode( MapUnit::MapPoint ) ); rWriter.SetFont(aFont); rWriter.SetTextColor( Color(19,20,22) ); @@ -1261,6 +1460,7 @@ void PDFExport::ImplWriteTiledWatermark( vcl::PDFWriter& rWriter, const Size& rP aTextPoint.Move( nTextWidth*1.5, 0 ); } + rWriter.EndStructureElement(); rWriter.Pop(); } |