1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
21 #include <osl/file.hxx>
22 #include <tools/debug.hxx>
23 #include <tools/urlobj.hxx>
24 #include <tools/poly.hxx>
25 #include <tools/diagnose_ex.h>
26 #include <unotools/resmgr.hxx>
27 #include <vcl/canvastools.hxx>
28 #include <vcl/mapmod.hxx>
29 #include <vcl/gdimtf.hxx>
30 #include <comphelper/sequence.hxx>
31 #include <comphelper/string.hxx>
32 #include <comphelper/storagehelper.hxx>
33 #include <basegfx/polygon/b2dpolygon.hxx>
34 #include <basegfx/polygon/b2dpolypolygon.hxx>
35 #include <basegfx/polygon/b2dpolygontools.hxx>
36 #include <toolkit/awt/vclxdevice.hxx>
37 #include <unotools/configmgr.hxx>
38 #include <cppuhelper/compbase.hxx>
39 #include <cppuhelper/basemutex.hxx>
40 
41 #include "pdfexport.hxx"
42 #include <strings.hrc>
43 
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/configuration/theDefaultProvider.hpp>
46 #include <com/sun/star/awt/XDevice.hpp>
47 #include <com/sun/star/frame/XModel.hpp>
48 #include <com/sun/star/frame/ModuleManager.hpp>
49 #include <com/sun/star/frame/XStorable.hpp>
50 #include <com/sun/star/document/XDocumentProperties.hpp>
51 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
52 #include <com/sun/star/container/XNameAccess.hpp>
53 #include <com/sun/star/view/XViewSettingsSupplier.hpp>
54 #include <com/sun/star/task/XInteractionRequest.hpp>
55 #include <com/sun/star/task/PDFExportException.hpp>
56 #include <com/sun/star/io/IOException.hpp>
57 #include <com/sun/star/io/XOutputStream.hpp>
58 #include <com/sun/star/lang/XServiceInfo.hpp>
59 #include <com/sun/star/drawing/XShapes.hpp>
60 #include <com/sun/star/security/XCertificate.hpp>
61 #include <com/sun/star/beans/XMaterialHolder.hpp>
62 
63 #include <memory>
64 
65 using namespace ::com::sun::star;
66 using namespace ::com::sun::star::io;
67 using namespace ::com::sun::star::uno;
68 using namespace ::com::sun::star::lang;
69 using namespace ::com::sun::star::beans;
70 using namespace ::com::sun::star::view;
71 using namespace ::com::sun::star::graphic;
72 
73 
PDFExport(const Reference<XComponent> & rxSrcDoc,const Reference<task::XStatusIndicator> & rxStatusIndicator,const Reference<task::XInteractionHandler> & rxIH,const Reference<XComponentContext> & xContext)74 PDFExport::PDFExport( const Reference< XComponent >& rxSrcDoc,
75                       const Reference< task::XStatusIndicator >& rxStatusIndicator,
76                       const Reference< task::XInteractionHandler >& rxIH,
77                       const Reference< XComponentContext >& xContext ) :
78     mxSrcDoc                    ( rxSrcDoc ),
79     mxContext                   ( xContext ),
80     mxStatusIndicator           ( rxStatusIndicator ),
81     mxIH                        ( rxIH ),
82     mbUseTaggedPDF              ( false ),
83     mnPDFTypeSelection          ( 0 ),
84     mbPDFUACompliance           ( false),
85     mbExportNotes               ( true ),
86     mbExportPlaceholders        ( false ),
87     mbUseReferenceXObject       ( false ),
88     mbExportNotesPages          ( false ),
89     mbExportOnlyNotesPages      ( false ),
90     mbUseTransitionEffects      ( true ),
91     mbExportBookmarks           ( true ),
92     mbExportHiddenSlides        ( false ),
93     mbSinglePageSheets          ( false ),
94     mnOpenBookmarkLevels        ( -1 ),
95     mbUseLosslessCompression    ( false ),
96     mbReduceImageResolution     ( true ),
97     mbSkipEmptyPages            ( true ),
98     mbAddStream                 ( false ),
99     mnMaxImageResolution        ( 300 ),
100     mnQuality                   ( 80 ),
101     mnFormsFormat               ( 0 ),
102     mbExportFormFields          ( true ),
103     mbAllowDuplicateFieldNames  ( false ),
104     mnProgressValue             ( 0 ),
105     mbRemoveTransparencies      ( false ),
106 
107     mbIsRedactMode              ( false ),
108 
109     mbHideViewerToolbar         ( false ),
110     mbHideViewerMenubar         ( false ),
111     mbHideViewerWindowControls  ( false ),
112     mbFitWindow                 ( false ),
113     mbCenterWindow              ( false ),
114     mbOpenInFullScreenMode      ( false ),
115     mbDisplayPDFDocumentTitle   ( true ),
116     mnPDFDocumentMode           ( 0 ),
117     mnPDFDocumentAction         ( 0 ),
118     mnZoom                      ( 100 ),
119     mnInitialPage               ( 1 ),
120     mnPDFPageLayout             ( 0 ),
121 
122     mbEncrypt                   ( false ),
123     mbRestrictPermissions       ( false ),
124     mnPrintAllowed              ( 2 ),
125     mnChangesAllowed            ( 4 ),
126     mbCanCopyOrExtract          ( true ),
127     mbCanExtractForAccessibility( true ),
128 
129     // #i56629
130     mbExportRelativeFsysLinks       ( false ),
131     mnDefaultLinkAction         ( 0 ),
132     mbConvertOOoTargetToPDFTarget( false ),
133     mbExportBmkToDest           ( false ),
134     mbSignPDF                   ( false )
135 {
136 }
137 
138 
~PDFExport()139 PDFExport::~PDFExport()
140 {
141 }
142 
143 
ExportSelection(vcl::PDFWriter & rPDFWriter,Reference<css::view::XRenderable> const & rRenderable,const Any & rSelection,const StringRangeEnumerator & rRangeEnum,Sequence<PropertyValue> & rRenderOptions,sal_Int32 nPageCount)144 bool PDFExport::ExportSelection( vcl::PDFWriter& rPDFWriter,
145     Reference< css::view::XRenderable > const & rRenderable,
146     const Any& rSelection,
147     const StringRangeEnumerator& rRangeEnum,
148     Sequence< PropertyValue >& rRenderOptions,
149     sal_Int32 nPageCount )
150 {
151     bool        bRet = false;
152     try
153     {
154         Any* pFirstPage = nullptr;
155         Any* pLastPage = nullptr;
156 
157         bool bExportNotesPages = false;
158 
159         for( sal_Int32 nData = 0, nDataCount = rRenderOptions.getLength(); nData < nDataCount; ++nData )
160         {
161             if ( rRenderOptions[ nData ].Name == "IsFirstPage" )
162                 pFirstPage = &rRenderOptions[ nData ].Value;
163             else if ( rRenderOptions[ nData ].Name == "IsLastPage" )
164                 pLastPage = &rRenderOptions[ nData ].Value;
165             else if ( rRenderOptions[ nData ].Name == "ExportNotesPages" )
166                 rRenderOptions[ nData ].Value >>= bExportNotesPages;
167         }
168 
169         OutputDevice* pOut = rPDFWriter.GetReferenceDevice();
170 
171         if( pOut )
172         {
173             if ( nPageCount )
174             {
175                 vcl::PDFExtOutDevData& rPDFExtOutDevData = dynamic_cast<vcl::PDFExtOutDevData&>(*pOut->GetExtOutDevData());
176                 rPDFExtOutDevData.SetIsExportNotesPages( bExportNotesPages );
177 
178                 sal_Int32 nCurrentPage(0);
179                 StringRangeEnumerator::Iterator aIter = rRangeEnum.begin();
180                 StringRangeEnumerator::Iterator aEnd  = rRangeEnum.end();
181                 while ( aIter != aEnd )
182                 {
183                     const Sequence< PropertyValue > aRenderer( rRenderable->getRenderer( *aIter, rSelection, rRenderOptions ) );
184                     awt::Size                   aPageSize;
185 
186                     for( const PropertyValue& rProp : aRenderer )
187                     {
188                         if ( rProp.Name == "PageSize" )
189                         {
190                             rProp.Value >>= aPageSize;
191                             break;
192                         }
193                     }
194 
195                     rPDFExtOutDevData.SetCurrentPageNumber( nCurrentPage );
196 
197                     GDIMetaFile                 aMtf;
198                     const MapMode               aMapMode( MapUnit::Map100thMM );
199                     const Size                  aMtfSize( aPageSize.Width, aPageSize.Height );
200 
201                     pOut->Push();
202                     pOut->EnableOutput( false );
203                     pOut->SetMapMode( aMapMode );
204 
205                     aMtf.SetPrefSize( aMtfSize );
206                     aMtf.SetPrefMapMode( aMapMode );
207                     aMtf.Record( pOut );
208 
209                     // #i35176#
210                     // IsLastPage property.
211                     const sal_Int32 nCurrentRenderer = *aIter;
212                     ++aIter;
213                     if ( pLastPage && aIter == aEnd )
214                         *pLastPage <<= true;
215 
216                     rRenderable->render( nCurrentRenderer, rSelection, rRenderOptions );
217 
218                     aMtf.Stop();
219                     aMtf.WindStart();
220 
221                     bool bEmptyPage = false;
222                     if( aMtf.GetActionSize() &&
223                              ( !mbSkipEmptyPages || aPageSize.Width || aPageSize.Height ) )
224                     {
225                         // We convert the whole metafile into a bitmap to get rid of the
226                         // text covered by redaction shapes
227                         if (mbIsRedactMode)
228                         {
229                             try
230                             {
231                                 Graphic aGraph(aMtf);
232                                 // use antialiasing to improve how graphic objects look
233                                 BitmapEx bmp = aGraph.GetBitmapEx(GraphicConversionParameters(Size(0, 0), false, true, false));
234                                 Graphic bgraph(bmp);
235                                 aMtf = bgraph.GetGDIMetaFile();
236                             }
237                             catch(const Exception&)
238                             {
239                                 TOOLS_WARN_EXCEPTION("filter.pdf", "Something went wrong while converting metafile to bitmap");
240                             }
241                         }
242 
243                         ImplExportPage(rPDFWriter, rPDFExtOutDevData, aMtf);
244                         bRet = true;
245                     }
246                     else
247                     {
248                         bEmptyPage = true;
249                     }
250 
251                     pOut->Pop();
252 
253                     if ( mxStatusIndicator.is() )
254                         mxStatusIndicator->setValue( mnProgressValue );
255                     if ( pFirstPage )
256                         *pFirstPage <<= false;
257 
258                     ++mnProgressValue;
259                     if (!bEmptyPage)
260                     {
261                         // Calculate the page number in the PDF output, which may be smaller than the page number in
262                         // case of hidden slides or a partial export.
263                         ++nCurrentPage;
264                     }
265                 }
266             }
267             else
268             {
269                 bRet = true;                            // #i18334# nPageCount == 0,
270                 rPDFWriter.NewPage( 10000, 10000 );     // creating dummy page
271                 rPDFWriter.SetMapMode(MapMode(MapUnit::Map100thMM));
272             }
273         }
274     }
275     catch(const RuntimeException &)
276     {
277     }
278     return bRet;
279 }
280 
281 namespace {
282 
283 class PDFExportStreamDoc : public vcl::PDFOutputStream
284 {
285 private:
286 
287     Reference< XComponent >             m_xSrcDoc;
288     Sequence< beans::NamedValue >       m_aPreparedPassword;
289 
290 public:
291 
PDFExportStreamDoc(const Reference<XComponent> & xDoc,const Sequence<beans::NamedValue> & rPwd)292     PDFExportStreamDoc( const Reference< XComponent >& xDoc, const Sequence<beans::NamedValue>& rPwd )
293     : m_xSrcDoc( xDoc ),
294       m_aPreparedPassword( rPwd )
295     {}
296 
297     virtual void write( const Reference< XOutputStream >& xStream ) override;
298 };
299 
300 }
301 
write(const Reference<XOutputStream> & xStream)302 void PDFExportStreamDoc::write( const Reference< XOutputStream >& xStream )
303 {
304     Reference< css::frame::XStorable > xStore( m_xSrcDoc, UNO_QUERY );
305     if( !xStore.is() )
306         return;
307 
308     Sequence< beans::PropertyValue > aArgs( 2 + (m_aPreparedPassword.hasElements() ? 1 : 0) );
309     aArgs.getArray()[0].Name = "FilterName";
310     aArgs.getArray()[1].Name = "OutputStream";
311     aArgs.getArray()[1].Value <<= xStream;
312     if( m_aPreparedPassword.hasElements() )
313     {
314         aArgs.getArray()[2].Name = "EncryptionData";
315         aArgs.getArray()[2].Value <<= m_aPreparedPassword;
316     }
317 
318     try
319     {
320         xStore->storeToURL( "private:stream", aArgs );
321     }
322     catch( const IOException& )
323     {
324     }
325 }
326 
327 
getMimetypeForDocument(const Reference<XComponentContext> & xContext,const Reference<XComponent> & xDoc)328 static OUString getMimetypeForDocument( const Reference< XComponentContext >& xContext,
329                                         const Reference< XComponent >& xDoc ) noexcept
330 {
331     OUString aDocMimetype;
332     try
333     {
334         // get document service name
335         Reference< css::frame::XStorable > xStore( xDoc, UNO_QUERY );
336         Reference< frame::XModuleManager2 > xModuleManager = frame::ModuleManager::create(xContext);
337         if( xStore.is() )
338         {
339             OUString aDocServiceName = xModuleManager->identify( Reference< XInterface >( xStore, uno::UNO_QUERY ) );
340             if ( !aDocServiceName.isEmpty() )
341             {
342                 // get the actual filter name
343                 Reference< lang::XMultiServiceFactory > xConfigProvider =
344                     configuration::theDefaultProvider::get( xContext );
345                 uno::Sequence< uno::Any > aArgs( 1 );
346                 beans::NamedValue aPathProp;
347                 aPathProp.Name = "nodepath";
348                 aPathProp.Value <<= OUString( "/org.openoffice.Setup/Office/Factories/" );
349                 aArgs[0] <<= aPathProp;
350 
351                 Reference< container::XNameAccess > xSOFConfig(
352                     xConfigProvider->createInstanceWithArguments(
353                         "com.sun.star.configuration.ConfigurationAccess", aArgs ),
354                     uno::UNO_QUERY );
355 
356                 Reference< container::XNameAccess > xApplConfig;
357                 xSOFConfig->getByName( aDocServiceName ) >>= xApplConfig;
358                 if ( xApplConfig.is() )
359                 {
360                     OUString aFilterName;
361                     xApplConfig->getByName( "ooSetupFactoryActualFilter" ) >>= aFilterName;
362                     if( !aFilterName.isEmpty() )
363                     {
364                         // find the related type name
365                         OUString aTypeName;
366                         Reference< container::XNameAccess > xFilterFactory(
367                             xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", xContext),
368                             uno::UNO_QUERY );
369 
370                         Sequence< beans::PropertyValue > aFilterData;
371                         xFilterFactory->getByName( aFilterName ) >>= aFilterData;
372                         for ( const beans::PropertyValue& rProp : std::as_const(aFilterData) )
373                             if ( rProp.Name == "Type" )
374                                 rProp.Value >>= aTypeName;
375 
376                         if ( !aTypeName.isEmpty() )
377                         {
378                             // find the mediatype
379                             Reference< container::XNameAccess > xTypeDetection(
380                                 xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", xContext),
381                                 UNO_QUERY );
382 
383                             Sequence< beans::PropertyValue > aTypeData;
384                             xTypeDetection->getByName( aTypeName ) >>= aTypeData;
385                             for ( const beans::PropertyValue& rProp : std::as_const(aTypeData) )
386                                 if ( rProp.Name == "MediaType" )
387                                     rProp.Value >>= aDocMimetype;
388                         }
389                     }
390                 }
391             }
392         }
393     }
394     catch (...)
395     {
396     }
397     return aDocMimetype;
398 }
399 
400 
Export(const OUString & rFile,const Sequence<PropertyValue> & rFilterData)401 bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& rFilterData )
402 {
403     INetURLObject   aURL( rFile );
404     bool        bRet = false;
405 
406     std::set< vcl::PDFWriter::ErrorCode > aErrors;
407 
408     if( aURL.GetProtocol() != INetProtocol::File )
409     {
410         OUString aTmp;
411 
412         if( osl::FileBase::getFileURLFromSystemPath( rFile, aTmp ) == osl::FileBase::E_None )
413             aURL = INetURLObject(aTmp);
414     }
415 
416     if( aURL.GetProtocol() == INetProtocol::File )
417     {
418         Reference< XRenderable > xRenderable( mxSrcDoc, UNO_QUERY );
419 
420         if( xRenderable.is() )
421         {
422             rtl::Reference<VCLXDevice>  xDevice(new VCLXDevice);
423             OUString                    aPageRange;
424             Any                         aSelection;
425             vcl::PDFWriter::PDFWriterContext aContext;
426             OUString aOpenPassword, aPermissionPassword;
427             Reference< beans::XMaterialHolder > xEnc;
428             Sequence< beans::NamedValue > aPreparedPermissionPassword;
429 
430 
431             // getting the string for the creator
432             OUString aCreator;
433             Reference< XServiceInfo > xInfo( mxSrcDoc, UNO_QUERY );
434             if ( xInfo.is() )
435             {
436                 if ( xInfo->supportsService( "com.sun.star.presentation.PresentationDocument" ) )
437                     aCreator += "Impress";
438                 else if ( xInfo->supportsService( "com.sun.star.drawing.DrawingDocument" ) )
439                     aCreator += "Draw";
440                 else if ( xInfo->supportsService( "com.sun.star.text.TextDocument" ) )
441                     aCreator += "Writer";
442                 else if ( xInfo->supportsService( "com.sun.star.sheet.SpreadsheetDocument" ) )
443                     aCreator += "Calc";
444                 else if ( xInfo->supportsService( "com.sun.star.formula.FormulaProperties"  ) )
445                     aCreator += "Math";
446             }
447 
448             Reference< document::XDocumentPropertiesSupplier > xDocumentPropsSupplier( mxSrcDoc, UNO_QUERY );
449             if ( xDocumentPropsSupplier.is() )
450             {
451                 Reference< document::XDocumentProperties > xDocumentProps( xDocumentPropsSupplier->getDocumentProperties() );
452                 if ( xDocumentProps.is() )
453                 {
454                     aContext.DocumentInfo.Title = xDocumentProps->getTitle();
455                     aContext.DocumentInfo.Author = xDocumentProps->getAuthor();
456                     aContext.DocumentInfo.Subject = xDocumentProps->getSubject();
457                     aContext.DocumentInfo.Keywords = ::comphelper::string::convertCommaSeparated(xDocumentProps->getKeywords());
458                 }
459             }
460             // getting the string for the producer
461             aContext.DocumentInfo.Producer =
462                 utl::ConfigManager::getProductName() +
463                 " " +
464                 utl::ConfigManager::getProductVersion();
465             aContext.DocumentInfo.Creator = aCreator;
466 
467             for ( const beans::PropertyValue& rProp : rFilterData )
468             {
469                 if ( rProp.Name == "PageRange" )
470                     rProp.Value >>= aPageRange;
471                 else if ( rProp.Name == "Selection" )
472                     aSelection = rProp.Value;
473                 else if ( rProp.Name == "UseLosslessCompression" )
474                     rProp.Value >>= mbUseLosslessCompression;
475                 else if ( rProp.Name == "Quality" )
476                     rProp.Value >>= mnQuality;
477                 else if ( rProp.Name == "ReduceImageResolution" )
478                     rProp.Value >>= mbReduceImageResolution;
479                 else if ( rProp.Name == "IsSkipEmptyPages" )
480                     rProp.Value >>= mbSkipEmptyPages;
481                 else if ( rProp.Name == "MaxImageResolution" )
482                     rProp.Value >>= mnMaxImageResolution;
483                 else if ( rProp.Name == "UseTaggedPDF" )
484                     rProp.Value >>= mbUseTaggedPDF;
485                 else if ( rProp.Name == "SelectPdfVersion" )
486                     rProp.Value >>= mnPDFTypeSelection;
487                 else if ( rProp.Name == "PDFUACompliance" )
488                     rProp.Value >>= mbPDFUACompliance;
489                 else if ( rProp.Name == "ExportNotes" )
490                     rProp.Value >>= mbExportNotes;
491                 else if ( rProp.Name == "ExportNotesPages" )
492                     rProp.Value >>= mbExportNotesPages;
493                 else if ( rProp.Name == "ExportOnlyNotesPages" )
494                     rProp.Value >>= mbExportOnlyNotesPages;
495                 else if ( rProp.Name == "UseTransitionEffects" )
496                     rProp.Value >>= mbUseTransitionEffects;
497                 else if ( rProp.Name == "ExportFormFields" )
498                     rProp.Value >>= mbExportFormFields;
499                 else if ( rProp.Name == "FormsType" )
500                     rProp.Value >>= mnFormsFormat;
501                 else if ( rProp.Name == "AllowDuplicateFieldNames" )
502                     rProp.Value >>= mbAllowDuplicateFieldNames;
503                 // viewer properties
504                 else if ( rProp.Name == "HideViewerToolbar" )
505                     rProp.Value >>= mbHideViewerToolbar;
506                 else if ( rProp.Name == "HideViewerMenubar" )
507                     rProp.Value >>= mbHideViewerMenubar;
508                 else if ( rProp.Name == "HideViewerWindowControls" )
509                     rProp.Value >>= mbHideViewerWindowControls;
510                 else if ( rProp.Name == "ResizeWindowToInitialPage" )
511                     rProp.Value >>= mbFitWindow;
512                 else if ( rProp.Name == "CenterWindow" )
513                     rProp.Value >>= mbCenterWindow;
514                 else if ( rProp.Name == "OpenInFullScreenMode" )
515                     rProp.Value >>= mbOpenInFullScreenMode;
516                 else if ( rProp.Name == "DisplayPDFDocumentTitle" )
517                     rProp.Value >>= mbDisplayPDFDocumentTitle;
518                 else if ( rProp.Name == "InitialView" )
519                     rProp.Value >>= mnPDFDocumentMode;
520                 else if ( rProp.Name == "Magnification" )
521                     rProp.Value >>= mnPDFDocumentAction;
522                 else if ( rProp.Name == "Zoom" )
523                     rProp.Value >>= mnZoom;
524                 else if ( rProp.Name == "InitialPage" )
525                     rProp.Value >>= mnInitialPage;
526                 else if ( rProp.Name == "PageLayout" )
527                     rProp.Value >>= mnPDFPageLayout;
528                 else if ( rProp.Name == "FirstPageOnLeft" )
529                     rProp.Value >>= aContext.FirstPageLeft;
530                 else if ( rProp.Name == "IsAddStream" )
531                     rProp.Value >>= mbAddStream;
532                 else if ( rProp.Name == "Watermark" )
533                     rProp.Value >>= msWatermark;
534                 else if ( rProp.Name == "TiledWatermark" )
535                     rProp.Value >>= msTiledWatermark;
536                 // now all the security related properties...
537                 else if ( rProp.Name == "EncryptFile" )
538                     rProp.Value >>= mbEncrypt;
539                 else if ( rProp.Name == "DocumentOpenPassword" )
540                     rProp.Value >>= aOpenPassword;
541                 else if ( rProp.Name == "RestrictPermissions" )
542                     rProp.Value >>= mbRestrictPermissions;
543                 else if ( rProp.Name == "PermissionPassword" )
544                     rProp.Value >>= aPermissionPassword;
545                 else if ( rProp.Name == "PreparedPasswords" )
546                     rProp.Value >>= xEnc;
547                 else if ( rProp.Name == "PreparedPermissionPassword" )
548                     rProp.Value >>= aPreparedPermissionPassword;
549                 else if ( rProp.Name == "Printing" )
550                     rProp.Value >>= mnPrintAllowed;
551                 else if ( rProp.Name == "Changes" )
552                     rProp.Value >>= mnChangesAllowed;
553                 else if ( rProp.Name == "EnableCopyingOfContent" )
554                     rProp.Value >>= mbCanCopyOrExtract;
555                 else if ( rProp.Name == "EnableTextAccessForAccessibilityTools" )
556                     rProp.Value >>= mbCanExtractForAccessibility;
557                 // i56629 links extra (relative links and other related stuff)
558                 else if ( rProp.Name == "ExportLinksRelativeFsys" )
559                     rProp.Value >>= mbExportRelativeFsysLinks;
560                 else if ( rProp.Name == "PDFViewSelection" )
561                     rProp.Value >>= mnDefaultLinkAction;
562                 else if ( rProp.Name == "ConvertOOoTargetToPDFTarget" )
563                     rProp.Value >>= mbConvertOOoTargetToPDFTarget;
564                 else if ( rProp.Name == "ExportBookmarksToPDFDestination" )
565                     rProp.Value >>= mbExportBmkToDest;
566                 else if ( rProp.Name == "ExportBookmarks" )
567                     rProp.Value >>= mbExportBookmarks;
568                 else if ( rProp.Name == "ExportHiddenSlides" )
569                     rProp.Value >>= mbExportHiddenSlides;
570                 else if ( rProp.Name == "SinglePageSheets" )
571                     rProp.Value >>= mbSinglePageSheets;
572                 else if ( rProp.Name == "OpenBookmarkLevels" )
573                     rProp.Value >>= mnOpenBookmarkLevels;
574                 else if ( rProp.Name == "SignPDF" )
575                     rProp.Value >>= mbSignPDF;
576                 else if ( rProp.Name == "SignatureLocation" )
577                     rProp.Value >>= msSignLocation;
578                 else if ( rProp.Name == "SignatureReason" )
579                     rProp.Value >>= msSignReason;
580                 else if ( rProp.Name == "SignatureContactInfo" )
581                     rProp.Value >>= msSignContact;
582                 else if ( rProp.Name == "SignaturePassword" )
583                     rProp.Value >>= msSignPassword;
584                 else if ( rProp.Name == "SignatureCertificate" )
585                     rProp.Value >>= maSignCertificate;
586                 else if ( rProp.Name == "SignatureTSA" )
587                     rProp.Value >>= msSignTSA;
588                 else if ( rProp.Name == "ExportPlaceholders" )
589                     rProp.Value >>= mbExportPlaceholders;
590                 else if ( rProp.Name == "UseReferenceXObject" )
591                     rProp.Value >>= mbUseReferenceXObject;
592                 // Redaction & bitmap related stuff
593                 else if ( rProp.Name == "IsRedactMode" )
594                     rProp.Value >>= mbIsRedactMode;
595             }
596 
597             aContext.URL        = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
598 
599             // set the correct version, depending on user request
600             switch( mnPDFTypeSelection )
601             {
602             default:
603             case 0:
604                 aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_6;
605                 break;
606             case 1:
607                 aContext.Version    = vcl::PDFWriter::PDFVersion::PDF_A_1;
608                 mbUseTaggedPDF = true;          // force the tagged PDF as well
609                 mbRemoveTransparencies = true;  // does not allow transparencies
610                 mbEncrypt = false;              // no encryption
611                 xEnc.clear();
612                 break;
613             case 2:
614                 aContext.Version    = vcl::PDFWriter::PDFVersion::PDF_A_2;
615                 mbUseTaggedPDF = true;          // force the tagged PDF as well
616                 mbRemoveTransparencies = false; // does allow transparencies
617                 mbEncrypt = false;              // no encryption
618                 xEnc.clear();
619                 break;
620             case 3:
621                 aContext.Version    = vcl::PDFWriter::PDFVersion::PDF_A_3;
622                 mbUseTaggedPDF = true;          // force the tagged PDF as well
623                 mbRemoveTransparencies = false; // does allow transparencies
624                 mbEncrypt = false;              // no encryption
625                 xEnc.clear();
626                 break;
627             case 15:
628                 aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_5;
629                 break;
630             case 16:
631                 aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_6;
632                 break;
633             }
634 
635             // PDF/UA support
636             aContext.UniversalAccessibilityCompliance = mbPDFUACompliance;
637             if (mbPDFUACompliance)
638             {
639                 mbUseTaggedPDF = true;
640             }
641 
642             // copy in context the values default in the constructor or set by the FilterData sequence of properties
643             aContext.Tagged     = mbUseTaggedPDF;
644 
645             // values used in viewer
646             aContext.HideViewerToolbar          = mbHideViewerToolbar;
647             aContext.HideViewerMenubar          = mbHideViewerMenubar;
648             aContext.HideViewerWindowControls   = mbHideViewerWindowControls;
649             aContext.FitWindow                  = mbFitWindow;
650             aContext.CenterWindow               = mbCenterWindow;
651             aContext.OpenInFullScreenMode       = mbOpenInFullScreenMode;
652             aContext.DisplayPDFDocumentTitle    = mbDisplayPDFDocumentTitle;
653             aContext.InitialPage                = mnInitialPage-1;
654             aContext.OpenBookmarkLevels         = mnOpenBookmarkLevels;
655 
656             switch( mnPDFDocumentMode )
657             {
658                 default:
659                 case 0:
660                     aContext.PDFDocumentMode = vcl::PDFWriter::ModeDefault;
661                     break;
662                 case 1:
663                     aContext.PDFDocumentMode = vcl::PDFWriter::UseOutlines;
664                     break;
665                 case 2:
666                     aContext.PDFDocumentMode = vcl::PDFWriter::UseThumbs;
667                     break;
668             }
669             switch( mnPDFDocumentAction )
670             {
671                 default:
672                 case 0:
673                     aContext.PDFDocumentAction = vcl::PDFWriter::ActionDefault;
674                     break;
675                 case 1:
676                     aContext.PDFDocumentAction = vcl::PDFWriter::FitInWindow;
677                     break;
678                 case 2:
679                     aContext.PDFDocumentAction = vcl::PDFWriter::FitWidth;
680                     break;
681                 case 3:
682                     aContext.PDFDocumentAction = vcl::PDFWriter::FitVisible;
683                     break;
684                 case 4:
685                     aContext.PDFDocumentAction = vcl::PDFWriter::ActionZoom;
686                     aContext.Zoom = mnZoom;
687                     break;
688             }
689 
690             switch( mnPDFPageLayout )
691             {
692                 default:
693                 case 0:
694                     aContext.PageLayout = vcl::PDFWriter::DefaultLayout;
695                     break;
696                 case 1:
697                     aContext.PageLayout = vcl::PDFWriter::SinglePage;
698                     break;
699                 case 2:
700                     aContext.PageLayout = vcl::PDFWriter::Continuous;
701                     break;
702                 case 3:
703                     aContext.PageLayout = vcl::PDFWriter::ContinuousFacing;
704                     break;
705             }
706 
707             aContext.FirstPageLeft = false;
708 
709             // check if PDF/A, which does not allow encryption
710             if( aContext.Version != vcl::PDFWriter::PDFVersion::PDF_A_1 )
711             {
712                 // set check for permission change password
713                 // if not enabled and no permission password, force permissions to default as if PDF where without encryption
714                 if( mbRestrictPermissions && (xEnc.is() || !aPermissionPassword.isEmpty()) )
715                 {
716                     mbEncrypt = true; // permission set as desired, done after
717                 }
718                 else
719                 {
720                     // force permission to default
721                     mnPrintAllowed                  = 2 ;
722                     mnChangesAllowed                = 4 ;
723                     mbCanCopyOrExtract              = true;
724                     mbCanExtractForAccessibility    = true ;
725                 }
726 
727                 switch( mnPrintAllowed )
728                 {
729                 case 0: // initialized when aContext is build, means no printing
730                     break;
731                 default:
732                 case 2:
733                     aContext.Encryption.CanPrintFull            = true;
734                     [[fallthrough]];
735                 case 1:
736                     aContext.Encryption.CanPrintTheDocument     = true;
737                     break;
738                 }
739 
740                 switch( mnChangesAllowed )
741                 {
742                 case 0: // already in struct PDFSecPermissions CTOR
743                     break;
744                 case 1:
745                     aContext.Encryption.CanAssemble             = true;
746                     break;
747                 case 2:
748                     aContext.Encryption.CanFillInteractive      = true;
749                     break;
750                 case 3:
751                     aContext.Encryption.CanAddOrModify          = true;
752                     break;
753                 default:
754                 case 4:
755                     aContext.Encryption.CanModifyTheContent     =
756                         aContext.Encryption.CanCopyOrExtract    =
757                         aContext.Encryption.CanAddOrModify      =
758                         aContext.Encryption.CanFillInteractive  = true;
759                     break;
760                 }
761 
762                 aContext.Encryption.CanCopyOrExtract                = mbCanCopyOrExtract;
763                 aContext.Encryption.CanExtractForAccessibility  = mbCanExtractForAccessibility;
764                 if( mbEncrypt && ! xEnc.is() )
765                     xEnc = vcl::PDFWriter::InitEncryption( aPermissionPassword, aOpenPassword );
766                 if( mbEncrypt && !aPermissionPassword.isEmpty() && ! aPreparedPermissionPassword.hasElements() )
767                     aPreparedPermissionPassword = comphelper::OStorageHelper::CreatePackageEncryptionData( aPermissionPassword );
768             }
769             // after this point we don't need the legacy clear passwords anymore
770             // however they are still inside the passed filter data sequence
771             // which is sadly out of our control
772             aPermissionPassword.clear();
773             aOpenPassword.clear();
774 
775             /*
776             * FIXME: the entries are only implicitly defined by the resource file. Should there
777             * ever be an additional form submit format this could get invalid.
778             */
779             switch( mnFormsFormat )
780             {
781                 case 1:
782                     aContext.SubmitFormat = vcl::PDFWriter::PDF;
783                     break;
784                 case 2:
785                     aContext.SubmitFormat = vcl::PDFWriter::HTML;
786                     break;
787                 case 3:
788                     aContext.SubmitFormat = vcl::PDFWriter::XML;
789                     break;
790                 default:
791                 case 0:
792                     aContext.SubmitFormat = vcl::PDFWriter::FDF;
793                     break;
794             }
795             aContext.AllowDuplicateFieldNames = mbAllowDuplicateFieldNames;
796 
797             // get model
798             Reference< frame::XModel > xModel( mxSrcDoc, UNO_QUERY );
799             {
800                 // #i56629: Relative link stuff
801                 // set the base URL of the file: then base URL
802                 aContext.BaseURL = xModel->getURL();
803                 // relative link option is private to PDF Export filter and limited to local filesystem only
804                 aContext.RelFsys = mbExportRelativeFsysLinks;
805                 // determine the default acton for PDF links
806                 switch( mnDefaultLinkAction )
807                 {
808                 default:
809                     // default: URI, without fragment conversion (the bookmark in PDF may not work)
810                 case 0:
811                     aContext.DefaultLinkAction = vcl::PDFWriter::URIAction;
812                     break;
813                 case 1:
814                     // view PDF through the reader application
815                     aContext.ForcePDFAction = true;
816                     aContext.DefaultLinkAction = vcl::PDFWriter::LaunchAction;
817                     break;
818                 case 2:
819                     // view PDF through an Internet browser
820                     aContext.DefaultLinkAction = vcl::PDFWriter::URIActionDestination;
821                     break;
822                 }
823                 aContext.ConvertOOoTargetToPDFTarget = mbConvertOOoTargetToPDFTarget;
824 
825                 // check for Link Launch action, not allowed on PDF/A-1
826                 // this code chunk checks when the filter is called from scripting
827                 if( aContext.Version == vcl::PDFWriter::PDFVersion::PDF_A_1 &&
828                     aContext.DefaultLinkAction == vcl::PDFWriter::LaunchAction )
829                 {
830                     // force the similar allowed URI action
831                     aContext.DefaultLinkAction = vcl::PDFWriter::URIActionDestination;
832                     // and remove the remote goto action forced on PDF file
833                     aContext.ForcePDFAction = false;
834                 }
835             }
836 
837             aContext.SignPDF = mbSignPDF;
838             aContext.SignLocation = msSignLocation;
839             aContext.SignContact = msSignContact;
840             aContext.SignReason = msSignReason;
841             aContext.SignPassword = msSignPassword;
842             aContext.SignCertificate = maSignCertificate;
843             aContext.SignTSA = msSignTSA;
844             aContext.UseReferenceXObject = mbUseReferenceXObject;
845 
846             // all context data set, time to create the printing device
847             vcl::PDFWriter aPDFWriter( aContext, xEnc );
848             OutputDevice*  pOut = aPDFWriter.GetReferenceDevice();
849 
850             DBG_ASSERT( pOut, "PDFExport::Export: no reference device" );
851             xDevice->SetOutputDevice(pOut);
852 
853             if( mbAddStream )
854             {
855                 // export stream
856                 // get mimetype
857                 OUString aSrcMimetype = getMimetypeForDocument( mxContext, mxSrcDoc );
858                 aPDFWriter.AddStream( aSrcMimetype,
859                                        new PDFExportStreamDoc( mxSrcDoc, aPreparedPermissionPassword )
860                                        );
861             }
862 
863             if ( pOut )
864             {
865                 DBG_ASSERT( pOut->GetExtOutDevData() == nullptr, "PDFExport: ExtOutDevData already set!!!" );
866                 vcl::PDFExtOutDevData aPDFExtOutDevData( *pOut );
867                 pOut->SetExtOutDevData( &aPDFExtOutDevData );
868                 aPDFExtOutDevData.SetIsExportNotes( mbExportNotes );
869                 aPDFExtOutDevData.SetIsExportTaggedPDF( mbUseTaggedPDF );
870                 aPDFExtOutDevData.SetIsExportTransitionEffects( mbUseTransitionEffects );
871                 aPDFExtOutDevData.SetIsExportFormFields( mbExportFormFields );
872                 aPDFExtOutDevData.SetIsExportBookmarks( mbExportBookmarks );
873                 aPDFExtOutDevData.SetIsExportHiddenSlides( mbExportHiddenSlides );
874                 aPDFExtOutDevData.SetIsSinglePageSheets( mbSinglePageSheets );
875                 aPDFExtOutDevData.SetIsLosslessCompression( mbUseLosslessCompression );
876                 aPDFExtOutDevData.SetCompressionQuality( mnQuality );
877                 aPDFExtOutDevData.SetIsReduceImageResolution( mbReduceImageResolution );
878                 aPDFExtOutDevData.SetIsExportNamedDestinations( mbExportBmkToDest );
879 
880                 Sequence< PropertyValue > aRenderOptions( 8 );
881                 aRenderOptions[ 0 ].Name = "RenderDevice";
882                 aRenderOptions[ 0 ].Value <<= uno::Reference<awt::XDevice>(xDevice);
883                 aRenderOptions[ 1 ].Name = "ExportNotesPages";
884                 aRenderOptions[ 1 ].Value <<= false;
885                 Any& rExportNotesValue = aRenderOptions[ 1 ].Value;
886                 aRenderOptions[ 2 ].Name = "IsFirstPage";
887                 aRenderOptions[ 2 ].Value <<= true;
888                 aRenderOptions[ 3 ].Name = "IsLastPage";
889                 aRenderOptions[ 3 ].Value <<= false;
890                 aRenderOptions[ 4 ].Name = "IsSkipEmptyPages";
891                 aRenderOptions[ 4 ].Value <<= mbSkipEmptyPages;
892                 aRenderOptions[ 5 ].Name = "PageRange";
893                 aRenderOptions[ 5 ].Value <<= aPageRange;
894                 aRenderOptions[ 6 ].Name = "ExportPlaceholders";
895                 aRenderOptions[ 6 ].Value <<= mbExportPlaceholders;
896                 aRenderOptions[ 7 ].Name = "SinglePageSheets";
897                 aRenderOptions[ 7 ].Value <<= mbSinglePageSheets;
898 
899                 if( !aPageRange.isEmpty() || !aSelection.hasValue() )
900                 {
901                     aSelection = Any();
902                     aSelection <<= mxSrcDoc;
903                 }
904                 bool bExportNotesPages = false;
905                 bool bReChangeToNormalView = false;
906                 static const OUStringLiteral sShowOnlineLayout( u"ShowOnlineLayout" );
907                 bool bReHideWhitespace = false;
908                 static const OUStringLiteral sHideWhitespace(u"HideWhitespace");
909                 uno::Reference< beans::XPropertySet > xViewProperties;
910 
911                 if ( aCreator == "Writer" )
912                 {
913                     // #i92835: if Writer is in web layout mode this has to be switched to normal view and back to web view in the end
914                     try
915                     {
916                         Reference< view::XViewSettingsSupplier > xVSettingsSupplier( xModel->getCurrentController(), uno::UNO_QUERY_THROW );
917                         xViewProperties = xVSettingsSupplier->getViewSettings();
918                         xViewProperties->getPropertyValue( sShowOnlineLayout ) >>= bReChangeToNormalView;
919                         if( bReChangeToNormalView )
920                         {
921                             xViewProperties->setPropertyValue( sShowOnlineLayout, uno::makeAny( false ) );
922                         }
923 
924                         // Also, disable hide-whitespace during export.
925                         xViewProperties->getPropertyValue(sHideWhitespace) >>= bReHideWhitespace;
926                         if (bReHideWhitespace)
927                         {
928                             xViewProperties->setPropertyValue(sHideWhitespace, uno::makeAny(false));
929                         }
930                     }
931                     catch( const uno::Exception& )
932                     {
933                     }
934 
935                 }
936 
937                 const sal_Int32 nPageCount = xRenderable->getRendererCount( aSelection, aRenderOptions );
938 
939                 if ( mbExportNotesPages && aCreator == "Impress" )
940                 {
941                     uno::Reference< drawing::XShapes > xShapes;     // do not allow to export notes when exporting a selection
942                     if ( ! ( aSelection >>= xShapes ) )
943                         bExportNotesPages = true;
944                 }
945                 const bool bExportPages = !bExportNotesPages || !mbExportOnlyNotesPages;
946 
947                 if( aPageRange.isEmpty() || mbSinglePageSheets)
948                 {
949                     aPageRange = OUString::number( 1 ) + "-" + OUString::number(nPageCount );
950                 }
951                 StringRangeEnumerator aRangeEnum( aPageRange, 0, nPageCount-1 );
952 
953                 if ( mxStatusIndicator.is() )
954                 {
955                     std::locale loc(Translate::Create("flt"));
956                     sal_Int32 nTotalPageCount = aRangeEnum.size();
957                     if ( bExportPages && bExportNotesPages )
958                         nTotalPageCount *= 2;
959                     mxStatusIndicator->start(Translate::get(PDF_PROGRESS_BAR, loc), nTotalPageCount);
960                 }
961 
962                 bRet = nPageCount > 0;
963 
964                 if ( bRet && bExportPages )
965                     bRet = ExportSelection( aPDFWriter, xRenderable, aSelection, aRangeEnum, aRenderOptions, nPageCount );
966 
967                 if ( bRet && bExportNotesPages )
968                 {
969                     rExportNotesValue <<= true;
970                     bRet = ExportSelection( aPDFWriter, xRenderable, aSelection, aRangeEnum, aRenderOptions, nPageCount );
971                 }
972                 if ( mxStatusIndicator.is() )
973                     mxStatusIndicator->end();
974 
975                 // if during the export the doc locale was set copy it to PDF writer
976                 const css::lang::Locale& rLoc( aPDFExtOutDevData.GetDocumentLocale() );
977                 if( !rLoc.Language.isEmpty() )
978                     aPDFWriter.SetDocumentLocale( rLoc );
979 
980                 if( bRet )
981                 {
982                     aPDFExtOutDevData.PlayGlobalActions( aPDFWriter );
983                     bRet = aPDFWriter.Emit();
984                     aErrors = aPDFWriter.GetErrors();
985                 }
986                 pOut->SetExtOutDevData( nullptr );
987                 if( bReChangeToNormalView )
988                 {
989                     try
990                     {
991                         xViewProperties->setPropertyValue( sShowOnlineLayout, uno::makeAny( true ) );
992                     }
993                     catch( const uno::Exception& )
994                     {
995                     }
996                 }
997                 if( bReHideWhitespace )
998                 {
999                     try
1000                     {
1001                         xViewProperties->setPropertyValue( sHideWhitespace, uno::makeAny( true ) );
1002                     }
1003                     catch( const uno::Exception& )
1004                     {
1005                     }
1006                 }
1007             }
1008         }
1009     }
1010 
1011     // show eventual errors during export
1012     showErrors( aErrors );
1013 
1014     return bRet;
1015 }
1016 
1017 
1018 namespace
1019 {
1020 
1021 typedef cppu::WeakComponentImplHelper< task::XInteractionRequest > PDFErrorRequestBase;
1022 
1023 class PDFErrorRequest : private cppu::BaseMutex,
1024                         public PDFErrorRequestBase
1025 {
1026     task::PDFExportException maExc;
1027 public:
1028     explicit PDFErrorRequest( const task::PDFExportException& i_rExc );
1029 
1030     // XInteractionRequest
1031     virtual uno::Any SAL_CALL getRequest() override;
1032     virtual uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL getContinuations() override;
1033 };
1034 
1035 
PDFErrorRequest(const task::PDFExportException & i_rExc)1036 PDFErrorRequest::PDFErrorRequest( const task::PDFExportException& i_rExc ) :
1037     PDFErrorRequestBase( m_aMutex ),
1038     maExc( i_rExc )
1039 {
1040 }
1041 
1042 
getRequest()1043 uno::Any SAL_CALL PDFErrorRequest::getRequest()
1044 {
1045     osl::MutexGuard const guard( m_aMutex );
1046 
1047     uno::Any aRet;
1048     aRet <<= maExc;
1049     return aRet;
1050 }
1051 
1052 
getContinuations()1053 uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL PDFErrorRequest::getContinuations()
1054 {
1055     return uno::Sequence< uno::Reference< task::XInteractionContinuation > >();
1056 }
1057 
1058 } // end anonymous namespace
1059 
1060 
showErrors(const std::set<vcl::PDFWriter::ErrorCode> & rErrors)1061 void PDFExport::showErrors( const std::set< vcl::PDFWriter::ErrorCode >& rErrors )
1062 {
1063     if( ! rErrors.empty() && mxIH.is() )
1064     {
1065         task::PDFExportException aExc;
1066         aExc.ErrorCodes = comphelper::containerToSequence<sal_Int32>( rErrors );
1067         Reference< task::XInteractionRequest > xReq( new PDFErrorRequest( aExc ) );
1068         mxIH->handle( xReq );
1069     }
1070 }
1071 
1072 
ImplExportPage(vcl::PDFWriter & rWriter,vcl::PDFExtOutDevData & rPDFExtOutDevData,const GDIMetaFile & rMtf)1073 void PDFExport::ImplExportPage( vcl::PDFWriter& rWriter, vcl::PDFExtOutDevData& rPDFExtOutDevData, const GDIMetaFile& rMtf )
1074 {
1075     //Rectangle(Point, Size) creates a rectangle off by 1, use Rectangle(long, long, long, long) instead
1076     basegfx::B2DPolygon aSize(tools::Polygon(tools::Rectangle(0, 0, rMtf.GetPrefSize().Width(), rMtf.GetPrefSize().Height())).getB2DPolygon());
1077     basegfx::B2DPolygon aSizePDF(OutputDevice::LogicToLogic(aSize, rMtf.GetPrefMapMode(), MapMode(MapUnit::MapPoint)));
1078     basegfx::B2DRange aRangePDF(aSizePDF.getB2DRange());
1079     tools::Rectangle       aPageRect( Point(), rMtf.GetPrefSize() );
1080 
1081     rWriter.NewPage( aRangePDF.getWidth(), aRangePDF.getHeight() );
1082     rWriter.SetMapMode( rMtf.GetPrefMapMode() );
1083 
1084     vcl::PDFWriter::PlayMetafileContext aCtx;
1085     GDIMetaFile aMtf;
1086     if( mbRemoveTransparencies )
1087     {
1088         aCtx.m_bTransparenciesWereRemoved = rWriter.GetReferenceDevice()->
1089             RemoveTransparenciesFromMetaFile( rMtf, aMtf, mnMaxImageResolution, mnMaxImageResolution,
1090                                               false, true, mbReduceImageResolution );
1091         // tdf#134736 if the metafile was replaced then rPDFExtOutDevData's PageSyncData mActions
1092         // all still point to MetaAction indexes in the original metafile that are now invalid.
1093         // Throw them all away in the absence of a way to reposition them to new positions of
1094         // their replacements.
1095         if (aCtx.m_bTransparenciesWereRemoved)
1096             rPDFExtOutDevData.ResetSyncData();
1097     }
1098     else
1099     {
1100         aMtf = rMtf;
1101     }
1102     aCtx.m_nMaxImageResolution      = mbReduceImageResolution ? mnMaxImageResolution : 0;
1103     aCtx.m_bOnlyLosslessCompression = mbUseLosslessCompression;
1104     aCtx.m_nJPEGQuality             = mnQuality;
1105 
1106 
1107     rWriter.SetClipRegion( basegfx::B2DPolyPolygon(
1108         basegfx::utils::createPolygonFromRect( vcl::unotools::b2DRectangleFromRectangle(aPageRect) ) ) );
1109 
1110     rWriter.PlayMetafile( aMtf, aCtx, &rPDFExtOutDevData );
1111 
1112     rPDFExtOutDevData.ResetSyncData();
1113 
1114     if (!msWatermark.isEmpty())
1115     {
1116         ImplWriteWatermark( rWriter, Size(aRangePDF.getWidth(), aRangePDF.getHeight()) );
1117     }
1118     else if (!msTiledWatermark.isEmpty())
1119     {
1120         ImplWriteTiledWatermark( rWriter, Size(aRangePDF.getWidth(), aRangePDF.getHeight()) );
1121     }
1122 }
1123 
1124 
ImplWriteWatermark(vcl::PDFWriter & rWriter,const Size & rPageSize)1125 void PDFExport::ImplWriteWatermark( vcl::PDFWriter& rWriter, const Size& rPageSize )
1126 {
1127     vcl::Font aFont( "Helvetica", Size( 0, 3*rPageSize.Height()/4 ) );
1128     aFont.SetItalic( ITALIC_NONE );
1129     aFont.SetWidthType( WIDTH_NORMAL );
1130     aFont.SetWeight( WEIGHT_NORMAL );
1131     aFont.SetAlignment( ALIGN_BOTTOM );
1132     tools::Long nTextWidth = rPageSize.Width();
1133     if( rPageSize.Width() < rPageSize.Height() )
1134     {
1135         nTextWidth = rPageSize.Height();
1136         aFont.SetOrientation( 2700_deg10 );
1137     }
1138 
1139     // adjust font height for text to fit
1140     OutputDevice* pDev = rWriter.GetReferenceDevice();
1141     pDev->Push();
1142     pDev->SetFont( aFont );
1143     pDev->SetMapMode( MapMode( MapUnit::MapPoint ) );
1144     int w = 0;
1145     while( ( w = pDev->GetTextWidth( msWatermark ) ) > nTextWidth )
1146     {
1147         if (w == 0)
1148             break;
1149         tools::Long nNewHeight = aFont.GetFontHeight() * nTextWidth / w;
1150         if( nNewHeight == aFont.GetFontHeight() )
1151         {
1152             nNewHeight--;
1153             if( nNewHeight <= 0 )
1154                 break;
1155         }
1156         aFont.SetFontHeight( nNewHeight );
1157         pDev->SetFont( aFont );
1158     }
1159     tools::Long nTextHeight = pDev->GetTextHeight();
1160     // leave some maneuvering room for rounding issues, also
1161     // some fonts go a little outside ascent/descent
1162     nTextHeight += nTextHeight/20;
1163     pDev->Pop();
1164 
1165     rWriter.Push();
1166     rWriter.SetMapMode( MapMode( MapUnit::MapPoint ) );
1167     rWriter.SetFont( aFont );
1168     rWriter.SetTextColor( COL_LIGHTGREEN );
1169     Point aTextPoint;
1170     tools::Rectangle aTextRect;
1171     if( rPageSize.Width() > rPageSize.Height() )
1172     {
1173         aTextPoint = Point( (rPageSize.Width()-w)/2,
1174                             rPageSize.Height()-(rPageSize.Height()-nTextHeight)/2 );
1175         aTextRect = tools::Rectangle( Point( (rPageSize.Width()-w)/2,
1176                                       (rPageSize.Height()-nTextHeight)/2 ),
1177                                Size( w, nTextHeight ) );
1178     }
1179     else
1180     {
1181         aTextPoint = Point( (rPageSize.Width()-nTextHeight)/2,
1182                             (rPageSize.Height()-w)/2 );
1183         aTextRect = tools::Rectangle( aTextPoint, Size( nTextHeight, w ) );
1184     }
1185     rWriter.SetClipRegion();
1186     rWriter.BeginTransparencyGroup();
1187     rWriter.DrawText( aTextPoint, msWatermark );
1188     rWriter.EndTransparencyGroup( aTextRect, 50 );
1189     rWriter.Pop();
1190 }
1191 
ImplWriteTiledWatermark(vcl::PDFWriter & rWriter,const Size & rPageSize)1192 void PDFExport::ImplWriteTiledWatermark( vcl::PDFWriter& rWriter, const Size& rPageSize )
1193 {
1194     OUString watermark = msTiledWatermark;
1195     // Maximum number of characters in one line.
1196     // it is set to 21 to make it look like tiled watermarks as online in secure view
1197     const int lineLength = 21;
1198     vcl::Font aFont( "Liberation Sans", Size( 0, 40 ) );
1199     aFont.SetItalic( ITALIC_NONE );
1200     aFont.SetWidthType( WIDTH_NORMAL );
1201     aFont.SetWeight( WEIGHT_NORMAL );
1202     aFont.SetAlignment( ALIGN_BOTTOM );
1203     aFont.SetFontHeight(40);
1204     aFont.SetOrientation(450_deg10);
1205 
1206     OutputDevice* pDev = rWriter.GetReferenceDevice();
1207     pDev->SetFont(aFont);
1208     pDev->Push();
1209     pDev->SetFont(aFont);
1210     pDev->SetMapMode( MapMode( MapUnit::MapPoint ) );
1211     int w = 0;
1212     int watermarkcount = ((rPageSize.Width()) / 200)+1;
1213     tools::Long nTextWidth = rPageSize.Width() / (watermarkcount*1.5);
1214     OUString oneLineText = watermark;
1215 
1216     if(watermark.getLength() > lineLength)
1217         oneLineText = watermark.copy(0, lineLength);
1218 
1219     while((w = pDev->GetTextWidth(oneLineText)) > nTextWidth)
1220     {
1221         if(w==0)
1222             break;
1223 
1224         tools::Long nNewHeight = aFont.GetFontHeight() * nTextWidth / w;
1225         aFont.SetFontHeight(nNewHeight);
1226         pDev->SetFont( aFont );
1227     }
1228     // maximum number of watermark count for the width
1229     if(watermarkcount > 8)
1230         watermarkcount = 8;
1231 
1232     pDev->Pop();
1233 
1234     rWriter.Push();
1235     rWriter.SetMapMode( MapMode( MapUnit::MapPoint ) );
1236     rWriter.SetFont(aFont);
1237     rWriter.SetTextColor( Color(19,20,22) );
1238     // center watermarks horizontally
1239     Point aTextPoint( (rPageSize.Width()/2) - (((nTextWidth*watermarkcount)+(watermarkcount-1)*nTextWidth)/2),
1240                       pDev->GetTextHeight());
1241 
1242     for( int i = 0; i < watermarkcount; i ++)
1243     {
1244         while(aTextPoint.getY()+pDev->GetTextHeight()*3 <= rPageSize.Height())
1245         {
1246             tools::Rectangle aTextRect(aTextPoint, Size(nTextWidth*2,pDev->GetTextHeight()*4));
1247 
1248             pDev->Push();
1249             rWriter.SetClipRegion();
1250             rWriter.BeginTransparencyGroup();
1251             rWriter.SetTextColor( Color(19,20,22) );
1252             rWriter.DrawText(aTextRect, watermark, DrawTextFlags::MultiLine|DrawTextFlags::Center|DrawTextFlags::VCenter|DrawTextFlags::WordBreak|DrawTextFlags::Bottom);
1253             rWriter.EndTransparencyGroup( aTextRect, 50 );
1254             pDev->Pop();
1255 
1256             pDev->Push();
1257             rWriter.SetClipRegion();
1258             rWriter.BeginTransparencyGroup();
1259             rWriter.SetTextColor( Color(236,235,233) );
1260             rWriter.DrawText(aTextRect, watermark, DrawTextFlags::MultiLine|DrawTextFlags::Center|DrawTextFlags::VCenter|DrawTextFlags::WordBreak|DrawTextFlags::Bottom);
1261             rWriter.EndTransparencyGroup( aTextRect, 50 );
1262             pDev->Pop();
1263 
1264             aTextPoint.Move(0, pDev->GetTextHeight()*3);
1265         }
1266         aTextPoint=Point( aTextPoint.getX(), pDev->GetTextHeight() );
1267         aTextPoint.Move( nTextWidth*1.5, 0 );
1268     }
1269 
1270     rWriter.Pop();
1271 }
1272 
1273 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1274