#include "precompiled_filter.hxx"

#include "pdfexport.hxx"
#include "impdialog.hxx"

#include "pdf.hrc"
#include "tools/urlobj.hxx"
#include "tools/fract.hxx"
#include "tools/poly.hxx"
#include "vcl/mapmod.hxx"
#include "vcl/virdev.hxx"
#include "vcl/metaact.hxx"
#include "vcl/gdimtf.hxx"
#include "vcl/jobset.hxx"
#include "vcl/salbtype.hxx"
#include "vcl/bmpacc.hxx"
#include "vcl/svapp.hxx"
#include "toolkit/awt/vclxdevice.hxx"
#include "unotools/localfilehelper.hxx"
#include "unotools/processfactory.hxx"
#include "svtools/FilterConfigItem.hxx"
#include "svtools/filter.hxx"
#include "svl/solar.hrc"
#include "comphelper/string.hxx"
#include "comphelper/storagehelper.hxx"
#include "unotools/streamwrap.hxx"
#include "com/sun/star/io/XSeekable.hpp"

#include "basegfx/polygon/b2dpolygon.hxx"
#include "basegfx/polygon/b2dpolypolygon.hxx"
#include "basegfx/polygon/b2dpolygontools.hxx"

#include "unotools/saveopt.hxx" 

#include "vcl/graphictools.hxx"
#include "com/sun/star/beans/XPropertySet.hpp"
#include "com/sun/star/awt/Rectangle.hpp"
#include "com/sun/star/awt/XDevice.hpp"
#include "com/sun/star/util/MeasureUnit.hpp"
#include "com/sun/star/frame/XModel.hpp"
#include "com/sun/star/frame/XModuleManager.hpp"
#include "com/sun/star/frame/XStorable.hpp"
#include "com/sun/star/frame/XController.hpp"
#include "com/sun/star/document/XDocumentProperties.hpp"
#include "com/sun/star/document/XDocumentPropertiesSupplier.hpp"
#include "com/sun/star/container/XNameAccess.hpp"
#include "com/sun/star/view/XViewSettingsSupplier.hpp"
#include "com/sun/star/task/XInteractionRequest.hpp"
#include "com/sun/star/task/PDFExportException.hpp"

#include "unotools/configmgr.hxx"
#include "cppuhelper/exc_hlp.hxx"
#include "cppuhelper/compbase1.hxx"
#include "cppuhelper/basemutex.hxx"

#include "com/sun/star/lang/XServiceInfo.hpp"
#include "com/sun/star/drawing/XShapes.hpp"
#include "com/sun/star/graphic/XGraphicProvider.hpp"

using namespace ::rtl;
using namespace ::vcl;
using namespace ::com::sun::star;
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,
                      const Reference< task::XStatusIndicator >& rxStatusIndicator,
                      const Reference< task::XInteractionHandler >& rxIH,
                      const Reference< lang::XMultiServiceFactory >& xFactory ) :
    mxSrcDoc				    ( rxSrcDoc ),
    mxMSF                       ( xFactory ),
	mxStatusIndicator		    ( rxStatusIndicator ),
	mxIH                        ( rxIH ),
	mbUseTaggedPDF			    ( sal_False ),
    mnPDFTypeSelection          ( 0 ),
	mbExportNotes			    ( sal_True ),
	mbExportNotesPages		    ( sal_False ),
	mbEmbedStandardFonts        ( sal_False ),

	mbUseTransitionEffects	    ( sal_True ),
    mbExportBookmarks           ( sal_True ),
    mnOpenBookmarkLevels        ( -1 ),
	mbUseLosslessCompression    ( sal_False ),
	mbReduceImageResolution	    ( sal_False ),
    mbSkipEmptyPages            ( sal_True ),
    mbAddStream                 ( sal_False ),
	mnMaxImageResolution	    ( 300 ),
	mnQuality				    ( 90 ),
	mnFormsFormat			    ( 0 ),
    mbExportFormFields          ( sal_True ),
    mbAllowDuplicateFieldNames  ( sal_False ),
	mnProgressValue			    ( 0 ),
    mbRemoveTransparencies      ( sal_False ),
    mbWatermark                 ( sal_False ),

    mbHideViewerToolbar			( sal_False ),
    mbHideViewerMenubar			( sal_False ),
    mbHideViewerWindowControls	( sal_False ),
    mbFitWindow					( sal_False ),
    mbCenterWindow				( sal_False ),
    mbOpenInFullScreenMode		( sal_False ),
    mbDisplayPDFDocumentTitle	( sal_True ),
    mnPDFDocumentMode       	( 0 ),
    mnPDFDocumentAction     	( 0 ),
    mnZoom                      ( 100 ),
    mnInitialPage               ( 1 ),
    mnPDFPageLayout         	( 0 ),
    mbFirstPageLeft				( sal_False ),

    mbEncrypt               	( sal_False ),
	mbRestrictPermissions		( sal_False ),
    mnPrintAllowed				( 2 ),
    mnChangesAllowed			( 4 ),
    mbCanCopyOrExtract			( sal_True ),
    mbCanExtractForAccessibility( sal_True ),

    mnCachePatternId            ( -1 ),

    mbExportRelativeFsysLinks	    ( sal_False ),
    mnDefaultLinkAction         ( 0 ),
    mbConvertOOoTargetToPDFTarget( sal_False ),
    mbExportBmkToDest			( sal_False )

{
}

PDFExport::~PDFExport()
{
}

sal_Bool PDFExport::ExportSelection( vcl::PDFWriter& rPDFWriter, Reference< com::sun::star::view::XRenderable >& rRenderable, Any& rSelection,
    MultiSelection aMultiSelection, Sequence< PropertyValue >& rRenderOptions, sal_Int32 nPageCount )
{
    sal_Bool        bRet = sal_False;
    try
    {
		Any* pFirstPage = NULL;
        Any* pLastPage = NULL;

		sal_Bool bExportNotesPages = sal_False;

		for( sal_Int32 nData = 0, nDataCount = rRenderOptions.getLength(); nData < nDataCount; ++nData )
        {
            if( rRenderOptions[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFirstPage" ) ) )
				pFirstPage = &rRenderOptions[ nData ].Value;
            else if( rRenderOptions[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "IsLastPage" ) ) )
                pLastPage = &rRenderOptions[ nData ].Value;
			else if( rRenderOptions[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportNotesPages" ) ) )
				rRenderOptions[ nData ].Value >>= bExportNotesPages;
        }

		OutputDevice* pOut = rPDFWriter.GetReferenceDevice();

        if( pOut )
        {
			vcl::PDFExtOutDevData* pPDFExtOutDevData = PTR_CAST( vcl::PDFExtOutDevData, pOut->GetExtOutDevData() );
			if ( nPageCount )
			{
				pPDFExtOutDevData->SetIsExportNotesPages( bExportNotesPages );

                sal_Int32 nSel = aMultiSelection.FirstSelected();
                sal_Int32 nIncreasingPageNumber(0);

                while ( nSel != sal_Int32(SFX_ENDOFSELECTION) )
                {
					Sequence< PropertyValue >   aRenderer( rRenderable->getRenderer( nSel - 1, rSelection, rRenderOptions ) );
					awt::Size                   aPageSize;

            		for( sal_Int32 nProperty = 0, nPropertyCount = aRenderer.getLength(); nProperty < nPropertyCount; ++nProperty )
					{
						if( aRenderer[ nProperty ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) )
							aRenderer[ nProperty].Value >>= aPageSize;
					}

                    pPDFExtOutDevData->SetCurrentPageNumber(nIncreasingPageNumber++ );

					GDIMetaFile	                aMtf;
					const MapMode               aMapMode( MAP_100TH_MM );
					const Size                  aMtfSize( aPageSize.Width, aPageSize.Height );

					pOut->Push();
					pOut->EnableOutput( sal_False );
					pOut->SetMapMode( aMapMode );

    				aMtf.SetPrefSize( aMtfSize );
					aMtf.SetPrefMapMode( aMapMode );
					aMtf.Record( pOut );

                    const sal_Int32 nCurrentRenderer = nSel - 1;
                    nSel = aMultiSelection.NextSelected();
                    if ( pLastPage && sal_Int32(SFX_ENDOFSELECTION) == nSel )
                        *pLastPage <<= sal_True;

                    rRenderable->render( nCurrentRenderer, rSelection, rRenderOptions );

					aMtf.Stop();
					aMtf.WindStart();

                    if( aMtf.GetActionCount() &&
                             ( !mbSkipEmptyPages || aPageSize.Width || aPageSize.Height ) )
                        bRet = ImplExportPage( rPDFWriter, *pPDFExtOutDevData, aMtf ) || bRet;

					pOut->Pop();

					if ( mxStatusIndicator.is() )
						mxStatusIndicator->setValue( mnProgressValue );
					if ( pFirstPage )
						*pFirstPage <<= sal_False;

                    ++mnProgressValue;
                }
			}
			else
			{
				bRet = sal_True;						
				rPDFWriter.NewPage( 10000, 10000 );		
				rPDFWriter.SetMapMode( MAP_100TH_MM );	
			}
        }
    }
    catch( RuntimeException )
    {
    }
	return bRet;
}

class PDFExportStreamDoc : public vcl::PDFOutputStream
{
    Reference< XComponent >             m_xSrcDoc;
    Sequence< beans::NamedValue >       m_aPreparedPassword;
    public:
        PDFExportStreamDoc( const Reference< XComponent >& xDoc, const Sequence<beans::NamedValue>& rPwd )
    : m_xSrcDoc( xDoc ),
      m_aPreparedPassword( rPwd )
    {}
    virtual ~PDFExportStreamDoc();

    virtual void write( const Reference< XOutputStream >& xStream );
};

PDFExportStreamDoc::~PDFExportStreamDoc()
{
}

void PDFExportStreamDoc::write( const Reference< XOutputStream >& xStream )
{
    Reference< com::sun::star::frame::XStorable > xStore( m_xSrcDoc, UNO_QUERY );
    if( xStore.is() )
    {
        Sequence< beans::PropertyValue > aArgs( 2 + ((m_aPreparedPassword.getLength() > 0) ? 1 : 0) );
        aArgs.getArray()[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" ) );
        aArgs.getArray()[1].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "OutputStream" ) );
        aArgs.getArray()[1].Value <<= xStream;
        if( m_aPreparedPassword.getLength() )
        {
            aArgs.getArray()[2].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "EncryptionData" ) );
            aArgs.getArray()[2].Value <<= m_aPreparedPassword;
        }

        try
        {
            xStore->storeToURL( OUString( RTL_CONSTASCII_USTRINGPARAM( "private:stream" ) ),
                                aArgs );
        }
        catch( IOException& )
        {
        }
    }
}

static OUString getMimetypeForDocument( const Reference< XMultiServiceFactory >& xFactory,
                                        const Reference< XComponent >& xDoc ) throw()
{
    OUString aDocMimetype;

    Reference< com::sun::star::frame::XStorable > xStore( xDoc, UNO_QUERY );
    Reference< frame::XModuleManager > xModuleManager(
        xFactory->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.ModuleManager" ) ) ),
                               uno::UNO_QUERY );
    if( xModuleManager.is() && xStore.is() )
    {
        OUString aDocServiceName = xModuleManager->identify( Reference< XInterface >( xStore, uno::UNO_QUERY ) );
        if ( aDocServiceName.getLength() )
        {

            OUString aFilterName;
            Reference< lang::XMultiServiceFactory > xConfigProvider(
                xFactory->createInstance(
                        OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationProvider" ) ) ),
                        uno::UNO_QUERY );
            if( xConfigProvider.is() )
            {
                uno::Sequence< uno::Any > aArgs( 1 );
                beans::PropertyValue aPathProp;
                aPathProp.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) );
                aPathProp.Value <<= OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Setup/Office/Factories/" ) );
                aArgs[0] <<= aPathProp;

                Reference< container::XNameAccess > xSOFConfig(
                    xConfigProvider->createInstanceWithArguments(
                        OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationAccess" ) ),
                        aArgs ),
                        uno::UNO_QUERY );

                Reference< container::XNameAccess > xApplConfig;
                xSOFConfig->getByName( aDocServiceName ) >>= xApplConfig;
                if ( xApplConfig.is() )
                {
                    xApplConfig->getByName( OUString( RTL_CONSTASCII_USTRINGPARAM( "ooSetupFactoryActualFilter" ) ) ) >>= aFilterName;
                    if( aFilterName.getLength() )
                    {

                        OUString aTypeName;
                        Reference< container::XNameAccess > xFilterFactory(
                            xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ),
                            uno::UNO_QUERY );

                        Sequence< beans::PropertyValue > aFilterData;
                        xFilterFactory->getByName( aFilterName ) >>= aFilterData;
                        for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ )
                            if ( aFilterData[nInd].Name.equalsAscii( "Type" ) )
                                aFilterData[nInd].Value >>= aTypeName;

                        if ( aTypeName.getLength() )
                        {

                            Reference< container::XNameAccess > xTypeDetection(
                                xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.TypeDetection" ) ),
                                UNO_QUERY );

                            Sequence< beans::PropertyValue > aTypeData;
                            xTypeDetection->getByName( aTypeName ) >>= aTypeData;
                            for ( sal_Int32 nInd = 0; nInd < aTypeData.getLength(); nInd++ )
                                if ( aTypeData[nInd].Name.equalsAscii( "MediaType" ) )
                                    aTypeData[nInd].Value >>= aDocMimetype;
                        }
                    }
                }
            }
        }
    }
    return aDocMimetype;
}

sal_Bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& rFilterData )
{
    INetURLObject   aURL( rFile );
    OUString        aFile;
    sal_Bool        bRet = sal_False;

    std::set< PDFWriter::ErrorCode > aErrors;

    if( aURL.GetProtocol() != INET_PROT_FILE )
    {
        String aTmp;

        if( ::utl::LocalFileHelper::ConvertPhysicalNameToURL( rFile, aTmp ) )
			aURL = INetURLObject(aTmp);
    }

    if( aURL.GetProtocol() == INET_PROT_FILE )
    {
        Reference< XRenderable > xRenderable( mxSrcDoc, UNO_QUERY );

        if( xRenderable.is() )
        {
            VCLXDevice*                 pXDevice = new VCLXDevice;
            OUString                    aPageRange;
            Any                         aSelection;
            PDFWriter::PDFWriterContext aContext;
            rtl::OUString aOpenPassword, aPermissionPassword;
            Reference< beans::XMaterialHolder > xEnc;
            Sequence< beans::NamedValue > aPreparedPermissionPassword;

			String aCreator;
			Reference< XServiceInfo > xInfo( mxSrcDoc, UNO_QUERY );
			if ( xInfo.is() )
			{
				if ( xInfo->supportsService( rtl::OUString::createFromAscii( "com.sun.star.presentation.PresentationDocument" ) ) )
					aCreator.AppendAscii( "Impress" );
				else if ( xInfo->supportsService( rtl::OUString::createFromAscii( "com.sun.star.drawing.DrawingDocument" ) ) )
					aCreator.AppendAscii( "Draw" );
				else if ( xInfo->supportsService( rtl::OUString::createFromAscii( "com.sun.star.text.TextDocument" ) ) )
					aCreator.AppendAscii( "Writer" );
				else if ( xInfo->supportsService( rtl::OUString::createFromAscii( "com.sun.star.sheet.SpreadsheetDocument" ) ) )
					aCreator.AppendAscii( "Calc" );
				else if ( xInfo->supportsService( rtl::OUString::createFromAscii( "com.sun.star.formula.FormulaProperties" ) ) )
					aCreator.AppendAscii( "Math" );
			}

			Reference< document::XDocumentPropertiesSupplier > xDocumentPropsSupplier( mxSrcDoc, UNO_QUERY );
			if ( xDocumentPropsSupplier.is() )
			{
				Reference< document::XDocumentProperties > xDocumentProps( xDocumentPropsSupplier->getDocumentProperties() );
				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());
				}
			}

			String aProducer;
			::utl::ConfigManager* pMgr = ::utl::ConfigManager::GetConfigManager();
			if ( pMgr )
			{
				Any aProductName = pMgr->GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTNAME );
				::rtl::OUString sProductName;
				aProductName >>= sProductName;
				aProducer = sProductName;
				aProductName = pMgr->GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTVERSION );
				aProductName >>= sProductName;
				aProducer.AppendAscii(" ");
				aProducer += String( sProductName );
			}
			aContext.DocumentInfo.Producer = aProducer;
			aContext.DocumentInfo.Creator = aCreator;

            for( sal_Int32 nData = 0, nDataCount = rFilterData.getLength(); nData < nDataCount; ++nData )
            {
				if( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "PageRange" ) ) )
				    rFilterData[ nData ].Value >>= aPageRange;
				else if( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "Selection" ) ) )
				    rFilterData[ nData ].Value >>= aSelection;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "UseLosslessCompression" ) ) )
					rFilterData[ nData ].Value >>= mbUseLosslessCompression;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "Quality" ) ) )
					rFilterData[ nData ].Value >>= mnQuality;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ReduceImageResolution" ) ) )
					rFilterData[ nData ].Value >>= mbReduceImageResolution;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "IsSkipEmptyPages" ) ) )
                    rFilterData[ nData ].Value >>= mbSkipEmptyPages;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "MaxImageResolution" ) ) )
					rFilterData[ nData ].Value >>= mnMaxImageResolution;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "UseTaggedPDF" ) ) )
					rFilterData[ nData ].Value >>= mbUseTaggedPDF;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "SelectPdfVersion" ) ) )
					rFilterData[ nData ].Value >>= mnPDFTypeSelection;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportNotes" ) ) )
					rFilterData[ nData ].Value >>= mbExportNotes;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportNotesPages" ) ) )
					rFilterData[ nData ].Value >>= mbExportNotesPages;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "EmbedStandardFonts" ) ) )
					rFilterData[ nData ].Value >>= mbEmbedStandardFonts;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "UseTransitionEffects" ) ) )
					rFilterData[ nData ].Value >>= mbUseTransitionEffects;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportFormFields" ) ) )
					rFilterData[ nData ].Value >>= mbExportFormFields;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "FormsType" ) ) )
					rFilterData[ nData ].Value >>= mnFormsFormat;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "AllowDuplicateFieldNames" ) ) )
					rFilterData[ nData ].Value >>= mbAllowDuplicateFieldNames;

                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "HideViewerToolbar" ) ) )
                    rFilterData[ nData ].Value >>= mbHideViewerToolbar;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "HideViewerMenubar" ) ) )
                    rFilterData[ nData ].Value >>= mbHideViewerMenubar;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "HideViewerWindowControls" ) ) )
                    rFilterData[ nData ].Value >>= mbHideViewerWindowControls;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ResizeWindowToInitialPage" ) ) )
                    rFilterData[ nData ].Value >>= mbFitWindow;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "CenterWindow" ) ) )
                    rFilterData[ nData ].Value >>= mbCenterWindow;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "OpenInFullScreenMode" ) ) )
                    rFilterData[ nData ].Value >>= mbOpenInFullScreenMode;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "DisplayPDFDocumentTitle" ) ) )
                    rFilterData[ nData ].Value >>= mbDisplayPDFDocumentTitle;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "InitialView" ) ) )
                    rFilterData[ nData ].Value >>= mnPDFDocumentMode;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "Magnification" ) ) )
                    rFilterData[ nData ].Value >>= mnPDFDocumentAction;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "Zoom" ) ) )
                    rFilterData[ nData ].Value >>= mnZoom;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "InitialPage" ) ) )
                    rFilterData[ nData ].Value >>= mnInitialPage;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "PageLayout" ) ) )
                    rFilterData[ nData ].Value >>= mnPDFPageLayout;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "FirstPageOnLeft" ) ) )
                    rFilterData[ nData ].Value >>= aContext.FirstPageLeft;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "IsAddStream" ) ) )
                    rFilterData[ nData ].Value >>= mbAddStream;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "Watermark" ) ) )
                {
                    maWatermark = rFilterData[ nData ].Value;
                    mbWatermark = sal_True;
                }

				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "EncryptFile" ) ) )
					rFilterData[ nData ].Value >>= mbEncrypt;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "DocumentOpenPassword" ) ) )
					rFilterData[ nData ].Value >>= aOpenPassword;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "RestrictPermissions" ) ) )
					rFilterData[ nData ].Value >>= mbRestrictPermissions;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "PermissionPassword" ) ) )
					rFilterData[ nData ].Value >>= aPermissionPassword;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "PreparedPasswords" ) ) )
					rFilterData[ nData ].Value >>= xEnc;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "PreparedPermissionPassword" ) ) )
					rFilterData[ nData ].Value >>= aPreparedPermissionPassword;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "Printing" ) ) )
					rFilterData[ nData ].Value >>= mnPrintAllowed;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "Changes" ) ) )
					rFilterData[ nData ].Value >>= mnChangesAllowed;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "EnableCopyingOfContent" ) ) )
					rFilterData[ nData ].Value >>= mbCanCopyOrExtract;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "EnableTextAccessForAccessibilityTools" ) ) )
					rFilterData[ nData ].Value >>= mbCanExtractForAccessibility;

 				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportLinksRelativeFsys" ) ) )
 					rFilterData[ nData ].Value >>= mbExportRelativeFsysLinks;
 				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "PDFViewSelection" ) ) )
 					rFilterData[ nData ].Value >>= mnDefaultLinkAction;
 				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ConvertOOoTargetToPDFTarget" ) ) )
 					rFilterData[ nData ].Value >>= mbConvertOOoTargetToPDFTarget;
  				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportBookmarksToPDFDestination" ) ) )
  					rFilterData[ nData ].Value >>= mbExportBmkToDest;

				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportBookmarks" ) ) )
					rFilterData[ nData ].Value >>= mbExportBookmarks;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "OpenBookmarkLevels" ) ) )
					rFilterData[ nData ].Value >>= mnOpenBookmarkLevels;
            }
            aContext.URL		= aURL.GetMainURL(INetURLObject::DECODE_TO_IURI);

            switch( mnPDFTypeSelection )
            {
            default:
            case 0:
                aContext.Version	= PDFWriter::PDF_1_4;
                break;
            case 1:
                aContext.Version	= PDFWriter::PDF_A_1;

                mbUseTaggedPDF = sal_True;

                mbEmbedStandardFonts = sal_True;

                mbExportFormFields = sal_False;

                mbRemoveTransparencies = sal_True;

                mbEncrypt = sal_False;
                xEnc.clear();
                break;
            }

			aContext.Tagged		= mbUseTaggedPDF;

            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;
            aContext.EmbedStandardFonts         = mbEmbedStandardFonts;

            switch( mnPDFDocumentMode )
            {
                default:
                case 0:
                    aContext.PDFDocumentMode = PDFWriter::ModeDefault;
                    break;
                case 1:
                    aContext.PDFDocumentMode = PDFWriter::UseOutlines;
                    break;
                case 2:
                    aContext.PDFDocumentMode = PDFWriter::UseThumbs;
                    break;
            }
            switch( mnPDFDocumentAction )
            {
                default:
                case 0:
                    aContext.PDFDocumentAction = PDFWriter::ActionDefault;
                    break;
                case 1:
                    aContext.PDFDocumentAction = PDFWriter::FitInWindow;
                    break;
                case 2:
                    aContext.PDFDocumentAction = PDFWriter::FitWidth;
                    break;
                case 3:
                    aContext.PDFDocumentAction = PDFWriter::FitVisible;
                    break;
                case 4:
                    aContext.PDFDocumentAction = PDFWriter::ActionZoom;
                    aContext.Zoom = mnZoom;
                    break;
            }

            switch( mnPDFPageLayout )
            {
                default:
                case 0:
                    aContext.PageLayout = PDFWriter::DefaultLayout;
                    break;
                case 1:
                    aContext.PageLayout = PDFWriter::SinglePage;
                    break;
                case 2:
                    aContext.PageLayout = PDFWriter::Continuous;
                    break;
                case 3:
                    aContext.PageLayout = PDFWriter::ContinuousFacing;
                    break;
            }

            aContext.FirstPageLeft = mbFirstPageLeft;

            if( aContext.Version != PDFWriter::PDF_A_1 )
            {

                aContext.Encryption.Security128bit = sal_True;

                if( mbRestrictPermissions && (xEnc.is() || aPermissionPassword.getLength() > 0) )
                {
                    mbEncrypt = sal_True;

                }
                else
                {

                    mnPrintAllowed					= 2 ;
                    mnChangesAllowed				= 4 ;
                    mbCanCopyOrExtract				= sal_True;
                    mbCanExtractForAccessibility 	= sal_True ;
                }

                switch( mnPrintAllowed )
                {
                case 0: 
                    break;
                default:
                case 2:
                    aContext.Encryption.CanPrintFull			= sal_True;
                case 1:
                    aContext.Encryption.CanPrintTheDocument	    = sal_True;
                    break;
                }

                switch( mnChangesAllowed )
                {
                case 0: 
                    break;
                case 1:
                    aContext.Encryption.CanAssemble				= sal_True;
                    break;
                case 2:
                    aContext.Encryption.CanFillInteractive		= sal_True;
                    break;
                case 3:
                    aContext.Encryption.CanAddOrModify			= sal_True;
                    break;
                default:
                case 4:
                    aContext.Encryption.CanModifyTheContent		=
                        aContext.Encryption.CanCopyOrExtract	=
                        aContext.Encryption.CanAddOrModify		=
                        aContext.Encryption.CanFillInteractive	= sal_True;
                    break;
                }

                aContext.Encryption.CanCopyOrExtract				= mbCanCopyOrExtract;
                aContext.Encryption.CanExtractForAccessibility	= mbCanExtractForAccessibility;
                if( mbEncrypt && ! xEnc.is() )
                    xEnc = PDFWriter::InitEncryption( aPermissionPassword, aOpenPassword, aContext.Encryption.Security128bit );
                if( mbEncrypt && aPermissionPassword.getLength() && ! aPreparedPermissionPassword.getLength() )
                    aPreparedPermissionPassword = comphelper::OStorageHelper::CreatePackageEncryptionData( aPermissionPassword );
            }

            aPermissionPassword = rtl::OUString();
            aOpenPassword = rtl::OUString();

            switch( mnFormsFormat )
            {
                case 1:
                    aContext.SubmitFormat = PDFWriter::PDF;
                    break;
                case 2:
                    aContext.SubmitFormat = PDFWriter::HTML;
                    break;
                case 3:
                    aContext.SubmitFormat = PDFWriter::XML;
                    break;
                default:
                case 0:
                    aContext.SubmitFormat = PDFWriter::FDF;
                    break;
            }
            aContext.AllowDuplicateFieldNames = mbAllowDuplicateFieldNames;

            Reference< frame::XModel > xModel( mxSrcDoc, UNO_QUERY );
			{

				aContext.BaseURL = xModel->getURL();

				aContext.RelFsys = mbExportRelativeFsysLinks;

                switch( mnDefaultLinkAction )
                {
                default:

                case 0:
                    aContext.DefaultLinkAction = PDFWriter::URIAction;
                    break;

                case 1:
                    aContext.ForcePDFAction = sal_True;
                    aContext.DefaultLinkAction = PDFWriter::LaunchAction;
                    break;

                case 2:
                    aContext.DefaultLinkAction = PDFWriter::URIActionDestination;
                    break;
                }
                aContext.ConvertOOoTargetToPDFTarget = mbConvertOOoTargetToPDFTarget;

                if( aContext.Version == PDFWriter::PDF_A_1 &&
                    aContext.DefaultLinkAction == PDFWriter::LaunchAction )
                {   
                    aContext.DefaultLinkAction = PDFWriter::URIActionDestination;

                    aContext.ForcePDFAction = sal_False;
                }

			}

            PDFWriter*			pPDFWriter = new PDFWriter( aContext, xEnc );
            OutputDevice*		pOut = pPDFWriter->GetReferenceDevice();
			vcl::PDFExtOutDevData* pPDFExtOutDevData = NULL;

            DBG_ASSERT( pOut, "PDFExport::Export: no reference device" );
            pXDevice->SetOutputDevice( pOut );

            if( mbAddStream )
            {

                OUString aSrcMimetype = getMimetypeForDocument( mxMSF, mxSrcDoc );
                pPDFWriter->AddStream( aSrcMimetype,
                                       new PDFExportStreamDoc( mxSrcDoc, aPreparedPermissionPassword ),
                                       false
                                       );
            }

			if ( pOut )
			{
				DBG_ASSERT( pOut->GetExtOutDevData() == NULL, "PDFExport: ExtOutDevData already set!!!" );
				pPDFExtOutDevData = new vcl::PDFExtOutDevData( *pOut );
				pOut->SetExtOutDevData( pPDFExtOutDevData );
				pPDFExtOutDevData->SetIsExportNotes( mbExportNotes );
				pPDFExtOutDevData->SetIsExportTaggedPDF( mbUseTaggedPDF );
				pPDFExtOutDevData->SetIsExportTransitionEffects( mbUseTransitionEffects );
				pPDFExtOutDevData->SetFormsFormat( mnFormsFormat );
                pPDFExtOutDevData->SetIsExportFormFields( mbExportFormFields );
                pPDFExtOutDevData->SetIsExportBookmarks( mbExportBookmarks );
				pPDFExtOutDevData->SetIsLosslessCompression( mbUseLosslessCompression );
				pPDFExtOutDevData->SetIsReduceImageResolution( mbReduceImageResolution );
                pPDFExtOutDevData->SetIsExportNamedDestinations( mbExportBmkToDest );

                Sequence< PropertyValue > aRenderOptions( 6 );
				aRenderOptions[ 0 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "RenderDevice" ) );
				aRenderOptions[ 0 ].Value <<= Reference< awt::XDevice >( pXDevice );
				aRenderOptions[ 1 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportNotesPages" ) );
				aRenderOptions[ 1 ].Value <<= sal_False;
				Any& rExportNotesValue = aRenderOptions[ 1 ].Value;
                aRenderOptions[ 2 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFirstPage" ) );
				aRenderOptions[ 2 ].Value <<= sal_True;
                aRenderOptions[ 3 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "IsLastPage" ) );
                aRenderOptions[ 3 ].Value <<= sal_False;
                aRenderOptions[ 4 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "IsSkipEmptyPages" ) );
                aRenderOptions[ 4 ].Value <<= mbSkipEmptyPages;
                aRenderOptions[ 5 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "PageRange" ) );
                aRenderOptions[ 5 ].Value <<= aPageRange;

				if( aPageRange.getLength() || !aSelection.hasValue() )
				{
					aSelection = Any();
					aSelection <<= mxSrcDoc;
				}
				sal_Bool		bSecondPassForImpressNotes = sal_False;
				bool bReChangeToNormalView = false;
              	::rtl::OUString sShowOnlineLayout( RTL_CONSTASCII_USTRINGPARAM( "ShowOnlineLayout"));
              	uno::Reference< beans::XPropertySet > xViewProperties;

				if ( aCreator.EqualsAscii( "Writer" ) )
				{

                    try
                    {
                        Reference< view::XViewSettingsSupplier > xVSettingsSupplier( xModel->getCurrentController(), uno::UNO_QUERY_THROW );
                        xViewProperties =  xVSettingsSupplier->getViewSettings();
                    	xViewProperties->getPropertyValue( sShowOnlineLayout ) >>= bReChangeToNormalView;
                    	if( bReChangeToNormalView )
                    	{
                    	    xViewProperties->setPropertyValue( sShowOnlineLayout, uno::makeAny( false ) );
                    	}
                    }
                    catch( const uno::Exception& )
                    {
                    }

				}

                const sal_Int32 nPageCount = xRenderable->getRendererCount( aSelection, aRenderOptions );
				const Range     aRange( 1, nPageCount );
				MultiSelection  aMultiSelection;

				if ( mbExportNotesPages && aCreator.EqualsAscii( "Impress" ) )
				{
		            uno::Reference< drawing::XShapes > xShapes;		
		            if ( ! ( aSelection >>= xShapes ) )				
						bSecondPassForImpressNotes = sal_True;		
				}

				if( !aPageRange.getLength() )
				{
    				aMultiSelection.SetTotalRange( aRange );
					aMultiSelection.Select( aRange );
				}
    			else
    			{
    				aMultiSelection = MultiSelection( aPageRange );
        			aMultiSelection.SetTotalRange( aRange );
    			}
				if ( mxStatusIndicator.is() )
				{
					ByteString aResMgrName( "pdffilter" );
					ResMgr* pResMgr = ResMgr::CreateResMgr( aResMgrName.GetBuffer(), Application::GetSettings().GetUILocale() );
					if ( pResMgr )
					{
						sal_Int32 nTotalPageCount = aMultiSelection.GetSelectCount();
						if ( bSecondPassForImpressNotes )
							nTotalPageCount *= 2;
						mxStatusIndicator->start( String( ResId( PDF_PROGRESS_BAR, *pResMgr ) ), nTotalPageCount );
						delete pResMgr;
					}
				}

                if( nPageCount > 0 )
                    bRet = ExportSelection( *pPDFWriter, xRenderable, aSelection, aMultiSelection, aRenderOptions, nPageCount );
                else
                    bRet = sal_False;

				if ( bRet && bSecondPassForImpressNotes )
				{
					rExportNotesValue <<= sal_True;
                    bRet = ExportSelection( *pPDFWriter, xRenderable, aSelection, aMultiSelection, aRenderOptions, nPageCount );
				}
				if ( mxStatusIndicator.is() )
					mxStatusIndicator->end();

                const com::sun::star::lang::Locale& rLoc( pPDFExtOutDevData->GetDocumentLocale() );
                if( rLoc.Language.getLength() )
                    pPDFWriter->SetDocumentLocale( rLoc );

				if( bRet )
				{
					pPDFExtOutDevData->PlayGlobalActions( *pPDFWriter );
					pPDFWriter->Emit();
                    aErrors = pPDFWriter->GetErrors();
				}
				pOut->SetExtOutDevData( NULL );
                if( bReChangeToNormalView )
                {
                    try
                    {
                        xViewProperties->setPropertyValue( sShowOnlineLayout, uno::makeAny( true ) );
                    }
                    catch( const uno::Exception& )
                    {
                    }
                }
			}

			delete pPDFExtOutDevData;
            delete pPDFWriter;
        }
    }

    showErrors( aErrors );

    return bRet;
}

namespace
{

typedef cppu::WeakComponentImplHelper1< task::XInteractionRequest > PDFErrorRequestBase;

class PDFErrorRequest : private cppu::BaseMutex,
                        public PDFErrorRequestBase
{
    task::PDFExportException maExc;
public:
    PDFErrorRequest( const task::PDFExportException& i_rExc );

    virtual uno::Any SAL_CALL getRequest() throw (uno::RuntimeException);
    virtual uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL getContinuations() throw (uno::RuntimeException);
};

PDFErrorRequest::PDFErrorRequest( const task::PDFExportException& i_rExc ) :
    PDFErrorRequestBase( m_aMutex ),
    maExc( i_rExc )
{
}

uno::Any SAL_CALL PDFErrorRequest::getRequest() throw (uno::RuntimeException)
{
    osl::MutexGuard const guard( m_aMutex );

    uno::Any aRet;
    aRet <<= maExc;
    return aRet;
}

uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL PDFErrorRequest::getContinuations() throw (uno::RuntimeException)
{
    return uno::Sequence< uno::Reference< task::XInteractionContinuation > >();
}

} 

void PDFExport::showErrors( const std::set< PDFWriter::ErrorCode >& rErrors )
{
    if( ! rErrors.empty() && mxIH.is() )
    {
        task::PDFExportException aExc;
        aExc.ErrorCodes.realloc( sal_Int32(rErrors.size()) );
        sal_Int32 i = 0;
        for( std::set< PDFWriter::ErrorCode >::const_iterator it = rErrors.begin();
             it != rErrors.end(); ++it, i++ )
        {
            aExc.ErrorCodes.getArray()[i] = (sal_Int32)*it;
        }
        Reference< task::XInteractionRequest > xReq( new PDFErrorRequest( aExc ) );
        mxIH->handle( xReq );
    }
}

sal_Bool PDFExport::ImplExportPage( PDFWriter& rWriter, PDFExtOutDevData& rPDFExtOutDevData, const GDIMetaFile& rMtf )
{
    const Size      aSizePDF( OutputDevice::LogicToLogic( rMtf.GetPrefSize(), rMtf.GetPrefMapMode(), MAP_POINT ) );
    Point           aOrigin;
    Rectangle       aPageRect( aOrigin, rMtf.GetPrefSize() );
    sal_Bool        bRet = sal_True;

    rWriter.NewPage( aSizePDF.Width(), aSizePDF.Height() );
    rWriter.SetMapMode( rMtf.GetPrefMapMode() );

    vcl::PDFWriter::PlayMetafileContext aCtx;
    GDIMetaFile aMtf;
    if( mbRemoveTransparencies )
    {
        aCtx.m_bTransparenciesWereRemoved = rWriter.GetReferenceDevice()->
            RemoveTransparenciesFromMetaFile( rMtf, aMtf, mnMaxImageResolution, mnMaxImageResolution,
                                              false, true, mbReduceImageResolution );
    }
    else
    {
        aMtf = rMtf;
    }
    aCtx.m_nMaxImageResolution      = mbReduceImageResolution ? mnMaxImageResolution : 0;
    aCtx.m_bOnlyLosslessCompression = mbUseLosslessCompression;
    aCtx.m_nJPEGQuality             = mnQuality;

    basegfx::B2DRectangle aB2DRect( aPageRect.Left(), aPageRect.Top(), aPageRect.Right(), aPageRect.Bottom() );
    rWriter.SetClipRegion( basegfx::B2DPolyPolygon( basegfx::tools::createPolygonFromRect( aB2DRect ) ) );

    rWriter.PlayMetafile( aMtf, aCtx, &rPDFExtOutDevData );

	rPDFExtOutDevData.ResetSyncData();

    if( mbWatermark )
        ImplWriteWatermark( rWriter, aSizePDF );

    return bRet;
}

void PDFExport::ImplWriteWatermark( PDFWriter& rWriter, const Size& rPageSize )
{
    OUString aText( RTL_CONSTASCII_USTRINGPARAM( "Watermark" ) );
    Font aFont( OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica" ) ), Size( 0, 3*rPageSize.Height()/4 ) );
    aFont.SetItalic( ITALIC_NONE );
    aFont.SetWidthType( WIDTH_NORMAL );
    aFont.SetWeight( WEIGHT_NORMAL );
    aFont.SetAlign( ALIGN_BOTTOM );
    long nTextWidth = rPageSize.Width();
    if( rPageSize.Width() < rPageSize.Height() )
    {
        nTextWidth = rPageSize.Height();
        aFont.SetOrientation( 2700 );
    }

    if( ! ( maWatermark >>= aText ) )
    {

    }

    OutputDevice* pDev = rWriter.GetReferenceDevice();
    pDev->Push( PUSH_ALL );
    pDev->SetFont( aFont );
    pDev->SetMapMode( MapMode( MAP_POINT ) );
    int w = 0;
    while( ( w = pDev->GetTextWidth( aText ) ) > nTextWidth )
    {
        long nNewHeight = aFont.GetHeight() * nTextWidth / w;
        if( nNewHeight == aFont.GetHeight() )
        {
            nNewHeight--;
            if( nNewHeight <= 0 )
                break;
        }
        aFont.SetHeight( nNewHeight );
        pDev->SetFont( aFont );
    }
    long nTextHeight = pDev->GetTextHeight();

    nTextHeight += nTextHeight/20;
    pDev->Pop();

    rWriter.Push( PUSH_ALL );
    rWriter.SetMapMode( MapMode( MAP_POINT ) );
    rWriter.SetFont( aFont );
    rWriter.SetTextColor( COL_RED );
    Point aTextPoint;
    Rectangle aTextRect;
    if( rPageSize.Width() > rPageSize.Height() )
    {
        aTextPoint = Point( (rPageSize.Width()-w)/2,
                            rPageSize.Height()-(rPageSize.Height()-nTextHeight)/2 );
        aTextRect = Rectangle( Point( (rPageSize.Width()-w)/2,
                                      (rPageSize.Height()-nTextHeight)/2 ),
                               Size( w, nTextHeight ) );
    }
    else
    {
        aTextPoint = Point( (rPageSize.Width()-nTextHeight)/2,
                            (rPageSize.Height()-w)/2 );
        aTextRect = Rectangle( aTextPoint, Size( nTextHeight, w ) );
    }
    rWriter.SetClipRegion();
    rWriter.BeginTransparencyGroup();
    rWriter.DrawText( aTextPoint, aText );
    rWriter.EndTransparencyGroup( aTextRect, 50 );
    rWriter.Pop();
}
/**************************************************************
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_filter.hxx"

#include "pdfexport.hxx"
#include "impdialog.hxx"

#include "pdf.hrc"
#include "tools/urlobj.hxx"
#include "tools/fract.hxx"
#include "tools/poly.hxx"
#include "vcl/mapmod.hxx"
#include "vcl/virdev.hxx"
#include "vcl/metaact.hxx"
#include "vcl/gdimtf.hxx"
#include "vcl/jobset.hxx"
#include "vcl/salbtype.hxx"
#include "vcl/bmpacc.hxx"
#include "vcl/svapp.hxx"
#include "toolkit/awt/vclxdevice.hxx"
#include "unotools/localfilehelper.hxx"
#include "unotools/processfactory.hxx"
#include "svtools/FilterConfigItem.hxx"
#include "svtools/filter.hxx"
#include "svl/solar.hrc"
#include "comphelper/string.hxx"
#include "comphelper/storagehelper.hxx"
#include "unotools/streamwrap.hxx"
#include "com/sun/star/io/XSeekable.hpp"

#include "basegfx/polygon/b2dpolygon.hxx"
#include "basegfx/polygon/b2dpolypolygon.hxx"
#include "basegfx/polygon/b2dpolygontools.hxx"

#include "unotools/saveopt.hxx" // only for testing of relative saving options in PDF

#include "vcl/graphictools.hxx"
#include "com/sun/star/beans/XPropertySet.hpp"
#include "com/sun/star/awt/Rectangle.hpp"
#include "com/sun/star/awt/XDevice.hpp"
#include "com/sun/star/util/MeasureUnit.hpp"
#include "com/sun/star/frame/XModel.hpp"
#include "com/sun/star/frame/XModuleManager.hpp"
#include "com/sun/star/frame/XStorable.hpp"
#include "com/sun/star/frame/XController.hpp"
#include "com/sun/star/document/XDocumentProperties.hpp"
#include "com/sun/star/document/XDocumentPropertiesSupplier.hpp"
#include "com/sun/star/container/XNameAccess.hpp"
#include "com/sun/star/view/XViewSettingsSupplier.hpp"
#include "com/sun/star/task/XInteractionRequest.hpp"
#include "com/sun/star/task/PDFExportException.hpp"

#include "unotools/configmgr.hxx"
#include "cppuhelper/exc_hlp.hxx"
#include "cppuhelper/compbase1.hxx"
#include "cppuhelper/basemutex.hxx"

#include "com/sun/star/lang/XServiceInfo.hpp"
#include "com/sun/star/drawing/XShapes.hpp"
#include "com/sun/star/graphic/XGraphicProvider.hpp"

using namespace ::rtl;
using namespace ::vcl;
using namespace ::com::sun::star;
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::PDFExport( const Reference< XComponent >& rxSrcDoc,
                      const Reference< task::XStatusIndicator >& rxStatusIndicator,
                      const Reference< task::XInteractionHandler >& rxIH,
                      const Reference< lang::XMultiServiceFactory >& xFactory ) :
    mxSrcDoc				    ( rxSrcDoc ),
    mxMSF                       ( xFactory ),
	mxStatusIndicator		    ( rxStatusIndicator ),
	mxIH                        ( rxIH ),
	mbUseTaggedPDF			    ( sal_False ),
    mnPDFTypeSelection          ( 0 ),
	mbExportNotes			    ( sal_True ),
	mbExportNotesPages		    ( sal_False ),
	mbEmbedStandardFonts        ( sal_False ),//in preparation for i54636 and i76458.
                                              //already used for i59651 (PDF/A-1)
	mbUseTransitionEffects	    ( sal_True ),
    mbExportBookmarks           ( sal_True ),
    mnOpenBookmarkLevels        ( -1 ),
	mbUseLosslessCompression    ( sal_False ),
	mbReduceImageResolution	    ( sal_False ),
    mbSkipEmptyPages            ( sal_True ),
    mbAddStream                 ( sal_False ),
	mnMaxImageResolution	    ( 300 ),
	mnQuality				    ( 90 ),
	mnFormsFormat			    ( 0 ),
    mbExportFormFields          ( sal_True ),
    mbAllowDuplicateFieldNames  ( sal_False ),
	mnProgressValue			    ( 0 ),
    mbRemoveTransparencies      ( sal_False ),
    mbWatermark                 ( sal_False ),

    mbHideViewerToolbar			( sal_False ),
    mbHideViewerMenubar			( sal_False ),
    mbHideViewerWindowControls	( sal_False ),
    mbFitWindow					( sal_False ),
    mbCenterWindow				( sal_False ),
    mbOpenInFullScreenMode		( sal_False ),
    mbDisplayPDFDocumentTitle	( sal_True ),
    mnPDFDocumentMode       	( 0 ),
    mnPDFDocumentAction     	( 0 ),
    mnZoom                      ( 100 ),
    mnInitialPage               ( 1 ),
    mnPDFPageLayout         	( 0 ),
    mbFirstPageLeft				( sal_False ),

    mbEncrypt               	( sal_False ),
	mbRestrictPermissions		( sal_False ),
    mnPrintAllowed				( 2 ),
    mnChangesAllowed			( 4 ),
    mbCanCopyOrExtract			( sal_True ),
    mbCanExtractForAccessibility( sal_True ),

    mnCachePatternId            ( -1 ),

//--->i56629
    mbExportRelativeFsysLinks	    ( sal_False ),
    mnDefaultLinkAction         ( 0 ),
    mbConvertOOoTargetToPDFTarget( sal_False ),
    mbExportBmkToDest			( sal_False )
//<---
{
}

// -----------------------------------------------------------------------------

PDFExport::~PDFExport()
{
}

// -----------------------------------------------------------------------------

sal_Bool PDFExport::ExportSelection( vcl::PDFWriter& rPDFWriter, Reference< com::sun::star::view::XRenderable >& rRenderable, Any& rSelection,
    MultiSelection aMultiSelection, Sequence< PropertyValue >& rRenderOptions, sal_Int32 nPageCount )
{
    sal_Bool        bRet = sal_False;
    try
    {
		Any* pFirstPage = NULL;
        Any* pLastPage = NULL;

		sal_Bool bExportNotesPages = sal_False;

		for( sal_Int32 nData = 0, nDataCount = rRenderOptions.getLength(); nData < nDataCount; ++nData )
        {
            if( rRenderOptions[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFirstPage" ) ) )
				pFirstPage = &rRenderOptions[ nData ].Value;
            else if( rRenderOptions[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "IsLastPage" ) ) )
                pLastPage = &rRenderOptions[ nData ].Value;
			else if( rRenderOptions[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportNotesPages" ) ) )
				rRenderOptions[ nData ].Value >>= bExportNotesPages;
        }

		OutputDevice* pOut = rPDFWriter.GetReferenceDevice();

        if( pOut )
        {
			vcl::PDFExtOutDevData* pPDFExtOutDevData = PTR_CAST( vcl::PDFExtOutDevData, pOut->GetExtOutDevData() );
			if ( nPageCount )
			{
				pPDFExtOutDevData->SetIsExportNotesPages( bExportNotesPages );

                sal_Int32 nSel = aMultiSelection.FirstSelected();
                sal_Int32 nIncreasingPageNumber(0);

                while ( nSel != sal_Int32(SFX_ENDOFSELECTION) )
                {
					Sequence< PropertyValue >   aRenderer( rRenderable->getRenderer( nSel - 1, rSelection, rRenderOptions ) );
					awt::Size                   aPageSize;

            		for( sal_Int32 nProperty = 0, nPropertyCount = aRenderer.getLength(); nProperty < nPropertyCount; ++nProperty )
					{
						if( aRenderer[ nProperty ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) )
							aRenderer[ nProperty].Value >>= aPageSize;
					}

                    // #119348# The PageNumber at PDFExtOutDevDatahas to be the target page number,
                    // e.g. when exporting only page#2 from two pages, the old mechanism would
                    // have set it to '1', but a page '1' does not yet exist in the export. This
                    // will make PDFWriterImpl::createLink and PDFWriterImpl::setLinkURL fail (see there).
                    pPDFExtOutDevData->SetCurrentPageNumber(nIncreasingPageNumber++ /* nSel - 1 */);

					GDIMetaFile	                aMtf;
					const MapMode               aMapMode( MAP_100TH_MM );
					const Size                  aMtfSize( aPageSize.Width, aPageSize.Height );

					pOut->Push();
					pOut->EnableOutput( sal_False );
					pOut->SetMapMode( aMapMode );

    				aMtf.SetPrefSize( aMtfSize );
					aMtf.SetPrefMapMode( aMapMode );
					aMtf.Record( pOut );

                    // --> FME 2004-10-08 #i35176#
                    // IsLastPage property.
                    const sal_Int32 nCurrentRenderer = nSel - 1;
                    nSel = aMultiSelection.NextSelected();
                    if ( pLastPage && sal_Int32(SFX_ENDOFSELECTION) == nSel )
                        *pLastPage <<= sal_True;
                    // <--

                    rRenderable->render( nCurrentRenderer, rSelection, rRenderOptions );

					aMtf.Stop();
					aMtf.WindStart();

                    if( aMtf.GetActionCount() &&
                             ( !mbSkipEmptyPages || aPageSize.Width || aPageSize.Height ) )
                        bRet = ImplExportPage( rPDFWriter, *pPDFExtOutDevData, aMtf ) || bRet;

					pOut->Pop();

					if ( mxStatusIndicator.is() )
						mxStatusIndicator->setValue( mnProgressValue );
					if ( pFirstPage )
						*pFirstPage <<= sal_False;

                    ++mnProgressValue;
                }
			}
			else
			{
				bRet = sal_True;						// #i18334# SJ: nPageCount == 0,
				rPDFWriter.NewPage( 10000, 10000 );		// creating dummy page
				rPDFWriter.SetMapMode( MAP_100TH_MM );	//
			}
        }
    }
    catch( RuntimeException )
    {
    }
	return bRet;
}

class PDFExportStreamDoc : public vcl::PDFOutputStream
{
    Reference< XComponent >             m_xSrcDoc;
    Sequence< beans::NamedValue >       m_aPreparedPassword;
    public:
        PDFExportStreamDoc( const Reference< XComponent >& xDoc, const Sequence<beans::NamedValue>& rPwd )
    : m_xSrcDoc( xDoc ),
      m_aPreparedPassword( rPwd )
    {}
    virtual ~PDFExportStreamDoc();

    virtual void write( const Reference< XOutputStream >& xStream );
};

PDFExportStreamDoc::~PDFExportStreamDoc()
{
}

void PDFExportStreamDoc::write( const Reference< XOutputStream >& xStream )
{
    Reference< com::sun::star::frame::XStorable > xStore( m_xSrcDoc, UNO_QUERY );
    if( xStore.is() )
    {
        Sequence< beans::PropertyValue > aArgs( 2 + ((m_aPreparedPassword.getLength() > 0) ? 1 : 0) );
        aArgs.getArray()[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterName" ) );
        aArgs.getArray()[1].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "OutputStream" ) );
        aArgs.getArray()[1].Value <<= xStream;
        if( m_aPreparedPassword.getLength() )
        {
            aArgs.getArray()[2].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "EncryptionData" ) );
            aArgs.getArray()[2].Value <<= m_aPreparedPassword;
        }

        try
        {
            xStore->storeToURL( OUString( RTL_CONSTASCII_USTRINGPARAM( "private:stream" ) ),
                                aArgs );
        }
        catch( IOException& )
        {
        }
    }
}

static OUString getMimetypeForDocument( const Reference< XMultiServiceFactory >& xFactory,
                                        const Reference< XComponent >& xDoc ) throw()
{
    OUString aDocMimetype;
        // get document service name
    Reference< com::sun::star::frame::XStorable > xStore( xDoc, UNO_QUERY );
    Reference< frame::XModuleManager > xModuleManager(
        xFactory->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.ModuleManager" ) ) ),
                               uno::UNO_QUERY );
    if( xModuleManager.is() && xStore.is() )
    {
        OUString aDocServiceName = xModuleManager->identify( Reference< XInterface >( xStore, uno::UNO_QUERY ) );
        if ( aDocServiceName.getLength() )
        {
            // get the actual filter name
            OUString aFilterName;
            Reference< lang::XMultiServiceFactory > xConfigProvider(
                xFactory->createInstance(
                        OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationProvider" ) ) ),
                        uno::UNO_QUERY );
            if( xConfigProvider.is() )
            {
                uno::Sequence< uno::Any > aArgs( 1 );
                beans::PropertyValue aPathProp;
                aPathProp.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) );
                aPathProp.Value <<= OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Setup/Office/Factories/" ) );
                aArgs[0] <<= aPathProp;

                Reference< container::XNameAccess > xSOFConfig(
                    xConfigProvider->createInstanceWithArguments(
                        OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationAccess" ) ),
                        aArgs ),
                        uno::UNO_QUERY );

                Reference< container::XNameAccess > xApplConfig;
                xSOFConfig->getByName( aDocServiceName ) >>= xApplConfig;
                if ( xApplConfig.is() )
                {
                    xApplConfig->getByName( OUString( RTL_CONSTASCII_USTRINGPARAM( "ooSetupFactoryActualFilter" ) ) ) >>= aFilterName;
                    if( aFilterName.getLength() )
                    {
                        // find the related type name
                        OUString aTypeName;
                        Reference< container::XNameAccess > xFilterFactory(
                            xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.FilterFactory" ) ),
                            uno::UNO_QUERY );

                        Sequence< beans::PropertyValue > aFilterData;
                        xFilterFactory->getByName( aFilterName ) >>= aFilterData;
                        for ( sal_Int32 nInd = 0; nInd < aFilterData.getLength(); nInd++ )
                            if ( aFilterData[nInd].Name.equalsAscii( "Type" ) )
                                aFilterData[nInd].Value >>= aTypeName;

                        if ( aTypeName.getLength() )
                        {
                            // find the mediatype
                            Reference< container::XNameAccess > xTypeDetection(
                                xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.document.TypeDetection" ) ),
                                UNO_QUERY );

                            Sequence< beans::PropertyValue > aTypeData;
                            xTypeDetection->getByName( aTypeName ) >>= aTypeData;
                            for ( sal_Int32 nInd = 0; nInd < aTypeData.getLength(); nInd++ )
                                if ( aTypeData[nInd].Name.equalsAscii( "MediaType" ) )
                                    aTypeData[nInd].Value >>= aDocMimetype;
                        }
                    }
                }
            }
        }
    }
    return aDocMimetype;
}

sal_Bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& rFilterData )
{
    INetURLObject   aURL( rFile );
    OUString        aFile;
    sal_Bool        bRet = sal_False;

    std::set< PDFWriter::ErrorCode > aErrors;

    if( aURL.GetProtocol() != INET_PROT_FILE )
    {
        String aTmp;

        if( ::utl::LocalFileHelper::ConvertPhysicalNameToURL( rFile, aTmp ) )
			aURL = INetURLObject(aTmp);
    }

    if( aURL.GetProtocol() == INET_PROT_FILE )
    {
        Reference< XRenderable > xRenderable( mxSrcDoc, UNO_QUERY );

        if( xRenderable.is() )
        {
            VCLXDevice*                 pXDevice = new VCLXDevice;
            OUString                    aPageRange;
            Any                         aSelection;
            PDFWriter::PDFWriterContext aContext;
            rtl::OUString aOpenPassword, aPermissionPassword;
            Reference< beans::XMaterialHolder > xEnc;
            Sequence< beans::NamedValue > aPreparedPermissionPassword;


			// getting the string for the creator
			String aCreator;
			Reference< XServiceInfo > xInfo( mxSrcDoc, UNO_QUERY );
			if ( xInfo.is() )
			{
				if ( xInfo->supportsService( rtl::OUString::createFromAscii( "com.sun.star.presentation.PresentationDocument" ) ) )
					aCreator.AppendAscii( "Impress" );
				else if ( xInfo->supportsService( rtl::OUString::createFromAscii( "com.sun.star.drawing.DrawingDocument" ) ) )
					aCreator.AppendAscii( "Draw" );
				else if ( xInfo->supportsService( rtl::OUString::createFromAscii( "com.sun.star.text.TextDocument" ) ) )
					aCreator.AppendAscii( "Writer" );
				else if ( xInfo->supportsService( rtl::OUString::createFromAscii( "com.sun.star.sheet.SpreadsheetDocument" ) ) )
					aCreator.AppendAscii( "Calc" );
				else if ( xInfo->supportsService( rtl::OUString::createFromAscii( "com.sun.star.formula.FormulaProperties" ) ) )
					aCreator.AppendAscii( "Math" );
			}

			Reference< document::XDocumentPropertiesSupplier > xDocumentPropsSupplier( mxSrcDoc, UNO_QUERY );
			if ( xDocumentPropsSupplier.is() )
			{
				Reference< document::XDocumentProperties > xDocumentProps( xDocumentPropsSupplier->getDocumentProperties() );
				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());
				}
			}
			// getting the string for the producer
			String aProducer;
			::utl::ConfigManager* pMgr = ::utl::ConfigManager::GetConfigManager();
			if ( pMgr )
			{
				Any aProductName = pMgr->GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTNAME );
				::rtl::OUString sProductName;
				aProductName >>= sProductName;
				aProducer = sProductName;
				aProductName = pMgr->GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTVERSION );
				aProductName >>= sProductName;
				aProducer.AppendAscii(" ");
				aProducer += String( sProductName );
			}
			aContext.DocumentInfo.Producer = aProducer;
			aContext.DocumentInfo.Creator = aCreator;

            for( sal_Int32 nData = 0, nDataCount = rFilterData.getLength(); nData < nDataCount; ++nData )
            {
				if( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "PageRange" ) ) )
				    rFilterData[ nData ].Value >>= aPageRange;
				else if( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "Selection" ) ) )
				    rFilterData[ nData ].Value >>= aSelection;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "UseLosslessCompression" ) ) )
					rFilterData[ nData ].Value >>= mbUseLosslessCompression;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "Quality" ) ) )
					rFilterData[ nData ].Value >>= mnQuality;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ReduceImageResolution" ) ) )
					rFilterData[ nData ].Value >>= mbReduceImageResolution;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "IsSkipEmptyPages" ) ) )
                    rFilterData[ nData ].Value >>= mbSkipEmptyPages;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "MaxImageResolution" ) ) )
					rFilterData[ nData ].Value >>= mnMaxImageResolution;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "UseTaggedPDF" ) ) )
					rFilterData[ nData ].Value >>= mbUseTaggedPDF;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "SelectPdfVersion" ) ) )
					rFilterData[ nData ].Value >>= mnPDFTypeSelection;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportNotes" ) ) )
					rFilterData[ nData ].Value >>= mbExportNotes;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportNotesPages" ) ) )
					rFilterData[ nData ].Value >>= mbExportNotesPages;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "EmbedStandardFonts" ) ) )
					rFilterData[ nData ].Value >>= mbEmbedStandardFonts;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "UseTransitionEffects" ) ) )
					rFilterData[ nData ].Value >>= mbUseTransitionEffects;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportFormFields" ) ) )
					rFilterData[ nData ].Value >>= mbExportFormFields;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "FormsType" ) ) )
					rFilterData[ nData ].Value >>= mnFormsFormat;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "AllowDuplicateFieldNames" ) ) )
					rFilterData[ nData ].Value >>= mbAllowDuplicateFieldNames;
//viewer properties
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "HideViewerToolbar" ) ) )
                    rFilterData[ nData ].Value >>= mbHideViewerToolbar;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "HideViewerMenubar" ) ) )
                    rFilterData[ nData ].Value >>= mbHideViewerMenubar;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "HideViewerWindowControls" ) ) )
                    rFilterData[ nData ].Value >>= mbHideViewerWindowControls;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ResizeWindowToInitialPage" ) ) )
                    rFilterData[ nData ].Value >>= mbFitWindow;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "CenterWindow" ) ) )
                    rFilterData[ nData ].Value >>= mbCenterWindow;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "OpenInFullScreenMode" ) ) )
                    rFilterData[ nData ].Value >>= mbOpenInFullScreenMode;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "DisplayPDFDocumentTitle" ) ) )
                    rFilterData[ nData ].Value >>= mbDisplayPDFDocumentTitle;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "InitialView" ) ) )
                    rFilterData[ nData ].Value >>= mnPDFDocumentMode;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "Magnification" ) ) )
                    rFilterData[ nData ].Value >>= mnPDFDocumentAction;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "Zoom" ) ) )
                    rFilterData[ nData ].Value >>= mnZoom;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "InitialPage" ) ) )
                    rFilterData[ nData ].Value >>= mnInitialPage;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "PageLayout" ) ) )
                    rFilterData[ nData ].Value >>= mnPDFPageLayout;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "FirstPageOnLeft" ) ) )
                    rFilterData[ nData ].Value >>= aContext.FirstPageLeft;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "IsAddStream" ) ) )
                    rFilterData[ nData ].Value >>= mbAddStream;
                else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "Watermark" ) ) )
                {
                    maWatermark = rFilterData[ nData ].Value;
                    mbWatermark = sal_True;
                }
//now all the security related properties...
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "EncryptFile" ) ) )
					rFilterData[ nData ].Value >>= mbEncrypt;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "DocumentOpenPassword" ) ) )
					rFilterData[ nData ].Value >>= aOpenPassword;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "RestrictPermissions" ) ) )
					rFilterData[ nData ].Value >>= mbRestrictPermissions;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "PermissionPassword" ) ) )
					rFilterData[ nData ].Value >>= aPermissionPassword;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "PreparedPasswords" ) ) )
					rFilterData[ nData ].Value >>= xEnc;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "PreparedPermissionPassword" ) ) )
					rFilterData[ nData ].Value >>= aPreparedPermissionPassword;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "Printing" ) ) )
					rFilterData[ nData ].Value >>= mnPrintAllowed;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "Changes" ) ) )
					rFilterData[ nData ].Value >>= mnChangesAllowed;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "EnableCopyingOfContent" ) ) )
					rFilterData[ nData ].Value >>= mbCanCopyOrExtract;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "EnableTextAccessForAccessibilityTools" ) ) )
					rFilterData[ nData ].Value >>= mbCanExtractForAccessibility;
//--->i56629 links extra (relative links and other related stuff)
 				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportLinksRelativeFsys" ) ) )
 					rFilterData[ nData ].Value >>= mbExportRelativeFsysLinks;
 				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "PDFViewSelection" ) ) )
 					rFilterData[ nData ].Value >>= mnDefaultLinkAction;
 				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ConvertOOoTargetToPDFTarget" ) ) )
 					rFilterData[ nData ].Value >>= mbConvertOOoTargetToPDFTarget;
  				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportBookmarksToPDFDestination" ) ) )
  					rFilterData[ nData ].Value >>= mbExportBmkToDest;
//<---
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportBookmarks" ) ) )
					rFilterData[ nData ].Value >>= mbExportBookmarks;
				else if ( rFilterData[ nData ].Name == OUString( RTL_CONSTASCII_USTRINGPARAM( "OpenBookmarkLevels" ) ) )
					rFilterData[ nData ].Value >>= mnOpenBookmarkLevels;
            }
            aContext.URL		= aURL.GetMainURL(INetURLObject::DECODE_TO_IURI);

//set the correct version, depending on user request
            switch( mnPDFTypeSelection )
            {
            default:
            case 0:
                aContext.Version	= PDFWriter::PDF_1_4;
                break;
            case 1:
                aContext.Version	= PDFWriter::PDF_A_1;
                //force the tagged PDF as well
                mbUseTaggedPDF = sal_True;
                //force embedding of standard fonts
                mbEmbedStandardFonts = sal_True;
                //force disabling of form conversion
                mbExportFormFields = sal_False;
                // PDF/A does not allow transparencies
                mbRemoveTransparencies = sal_True;
                // no encryption
                mbEncrypt = sal_False;
                xEnc.clear();
                break;
            }

//copy in context the values default in the constructor or set by the FilterData sequence of properties
			aContext.Tagged		= mbUseTaggedPDF;

//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;
            aContext.EmbedStandardFonts         = mbEmbedStandardFonts;

            switch( mnPDFDocumentMode )
            {
                default:
                case 0:
                    aContext.PDFDocumentMode = PDFWriter::ModeDefault;
                    break;
                case 1:
                    aContext.PDFDocumentMode = PDFWriter::UseOutlines;
                    break;
                case 2:
                    aContext.PDFDocumentMode = PDFWriter::UseThumbs;
                    break;
            }
            switch( mnPDFDocumentAction )
            {
                default:
                case 0:
                    aContext.PDFDocumentAction = PDFWriter::ActionDefault;
                    break;
                case 1:
                    aContext.PDFDocumentAction = PDFWriter::FitInWindow;
                    break;
                case 2:
                    aContext.PDFDocumentAction = PDFWriter::FitWidth;
                    break;
                case 3:
                    aContext.PDFDocumentAction = PDFWriter::FitVisible;
                    break;
                case 4:
                    aContext.PDFDocumentAction = PDFWriter::ActionZoom;
                    aContext.Zoom = mnZoom;
                    break;
            }

            switch( mnPDFPageLayout )
            {
                default:
                case 0:
                    aContext.PageLayout = PDFWriter::DefaultLayout;
                    break;
                case 1:
                    aContext.PageLayout = PDFWriter::SinglePage;
                    break;
                case 2:
                    aContext.PageLayout = PDFWriter::Continuous;
                    break;
                case 3:
                    aContext.PageLayout = PDFWriter::ContinuousFacing;
                    break;
            }

            aContext.FirstPageLeft = mbFirstPageLeft;

//check if PDF/A, which does not allow encryption
            if( aContext.Version != PDFWriter::PDF_A_1 )
            {
//set values needed in encryption
//set encryption level, fixed, but here it can set by the UI if needed.
// true is 128 bit, false 40
//note that in 40 bit mode the UI needs reworking, since the current UI is meaningful only for
//128bit security mode
                aContext.Encryption.Security128bit = sal_True;

//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.getLength() > 0) )
                {
                    mbEncrypt = sal_True;
//permission set as desired, done after
                }
                else
                {
//force permission to default
                    mnPrintAllowed					= 2 ;
                    mnChangesAllowed				= 4 ;
                    mbCanCopyOrExtract				= sal_True;
                    mbCanExtractForAccessibility 	= sal_True ;
                }

                switch( mnPrintAllowed )
                {
                case 0: //initialized when aContext is build, means no printing
                    break;
                default:
                case 2:
                    aContext.Encryption.CanPrintFull			= sal_True;
                case 1:
                    aContext.Encryption.CanPrintTheDocument	    = sal_True;
                    break;
                }

                switch( mnChangesAllowed )
                {
                case 0: //already in struct PDFSecPermissions CTOR
                    break;
                case 1:
                    aContext.Encryption.CanAssemble				= sal_True;
                    break;
                case 2:
                    aContext.Encryption.CanFillInteractive		= sal_True;
                    break;
                case 3:
                    aContext.Encryption.CanAddOrModify			= sal_True;
                    break;
                default:
                case 4:
                    aContext.Encryption.CanModifyTheContent		=
                        aContext.Encryption.CanCopyOrExtract	=
                        aContext.Encryption.CanAddOrModify		=
                        aContext.Encryption.CanFillInteractive	= sal_True;
                    break;
                }

                aContext.Encryption.CanCopyOrExtract				= mbCanCopyOrExtract;
                aContext.Encryption.CanExtractForAccessibility	= mbCanExtractForAccessibility;
                if( mbEncrypt && ! xEnc.is() )
                    xEnc = PDFWriter::InitEncryption( aPermissionPassword, aOpenPassword, aContext.Encryption.Security128bit );
                if( mbEncrypt && aPermissionPassword.getLength() && ! aPreparedPermissionPassword.getLength() )
                    aPreparedPermissionPassword = comphelper::OStorageHelper::CreatePackageEncryptionData( aPermissionPassword );
            }
            // after this point we don't need the legacy clear passwords anymore
            // however they are still inside the passed filter data sequence
            // which is sadly out of our control
            aPermissionPassword = rtl::OUString();
            aOpenPassword = rtl::OUString();

            /*
            * 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 )
            {
                case 1:
                    aContext.SubmitFormat = PDFWriter::PDF;
                    break;
                case 2:
                    aContext.SubmitFormat = PDFWriter::HTML;
                    break;
                case 3:
                    aContext.SubmitFormat = PDFWriter::XML;
                    break;
                default:
                case 0:
                    aContext.SubmitFormat = PDFWriter::FDF;
                    break;
            }
            aContext.AllowDuplicateFieldNames = mbAllowDuplicateFieldNames;

            //get model
            Reference< frame::XModel > xModel( mxSrcDoc, UNO_QUERY );
			{
//---> i56629 Relative link stuff
//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 action for PDF links
                switch( mnDefaultLinkAction )
                {
                default:
//default: URI, without fragment conversion (the bookmark in PDF may not work)
                case 0:
                    aContext.DefaultLinkAction = PDFWriter::URIAction;
                    break;
//view PDF through the reader application
                case 1:
                    aContext.ForcePDFAction = sal_True;
                    aContext.DefaultLinkAction = PDFWriter::LaunchAction;
                    break;
//view PDF through an Internet browser
                case 2:
                    aContext.DefaultLinkAction = PDFWriter::URIActionDestination;
                    break;
                }
                aContext.ConvertOOoTargetToPDFTarget = mbConvertOOoTargetToPDFTarget;
// check for Link Launch action, not allowed on PDF/A-1
// this code chunk checks when the filter is called from scripting
                if( aContext.Version == PDFWriter::PDF_A_1 &&
                    aContext.DefaultLinkAction == PDFWriter::LaunchAction )
                {   //force the similar allowed URI action
                    aContext.DefaultLinkAction = PDFWriter::URIActionDestination;
                    //and remove the remote goto action forced on PDF file
                    aContext.ForcePDFAction = sal_False;
                }
//<---
			}
// all context data set, time to create the printing device
            PDFWriter*			pPDFWriter = new PDFWriter( aContext, xEnc );
            OutputDevice*		pOut = pPDFWriter->GetReferenceDevice();
			vcl::PDFExtOutDevData* pPDFExtOutDevData = NULL;

            DBG_ASSERT( pOut, "PDFExport::Export: no reference device" );
            pXDevice->SetOutputDevice( pOut );

            if( mbAddStream )
            {
                // export stream
                // get mimetype
                OUString aSrcMimetype = getMimetypeForDocument( mxMSF, mxSrcDoc );
                pPDFWriter->AddStream( aSrcMimetype,
                                       new PDFExportStreamDoc( mxSrcDoc, aPreparedPermissionPassword ),
                                       false
                                       );
            }

			if ( pOut )
			{
				DBG_ASSERT( pOut->GetExtOutDevData() == NULL, "PDFExport: ExtOutDevData already set!!!" );
				pPDFExtOutDevData = new vcl::PDFExtOutDevData( *pOut );
				pOut->SetExtOutDevData( pPDFExtOutDevData );
				pPDFExtOutDevData->SetIsExportNotes( mbExportNotes );
				pPDFExtOutDevData->SetIsExportTaggedPDF( mbUseTaggedPDF );
				pPDFExtOutDevData->SetIsExportTransitionEffects( mbUseTransitionEffects );
				pPDFExtOutDevData->SetFormsFormat( mnFormsFormat );
                pPDFExtOutDevData->SetIsExportFormFields( mbExportFormFields );
                pPDFExtOutDevData->SetIsExportBookmarks( mbExportBookmarks );
				pPDFExtOutDevData->SetIsLosslessCompression( mbUseLosslessCompression );
				pPDFExtOutDevData->SetIsReduceImageResolution( mbReduceImageResolution );
                pPDFExtOutDevData->SetIsExportNamedDestinations( mbExportBmkToDest );

                Sequence< PropertyValue > aRenderOptions( 6 );
				aRenderOptions[ 0 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "RenderDevice" ) );
				aRenderOptions[ 0 ].Value <<= Reference< awt::XDevice >( pXDevice );
				aRenderOptions[ 1 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportNotesPages" ) );
				aRenderOptions[ 1 ].Value <<= sal_False;
				Any& rExportNotesValue = aRenderOptions[ 1 ].Value;
                aRenderOptions[ 2 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFirstPage" ) );
				aRenderOptions[ 2 ].Value <<= sal_True;
                aRenderOptions[ 3 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "IsLastPage" ) );
                aRenderOptions[ 3 ].Value <<= sal_False;
                aRenderOptions[ 4 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "IsSkipEmptyPages" ) );
                aRenderOptions[ 4 ].Value <<= mbSkipEmptyPages;
                aRenderOptions[ 5 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "PageRange" ) );
                aRenderOptions[ 5 ].Value <<= aPageRange;

				if( aPageRange.getLength() || !aSelection.hasValue() )
				{
					aSelection = Any();
					aSelection <<= mxSrcDoc;
				}
				sal_Bool		bSecondPassForImpressNotes = sal_False;
				bool bReChangeToNormalView = false;
              	::rtl::OUString sShowOnlineLayout( RTL_CONSTASCII_USTRINGPARAM( "ShowOnlineLayout"));
              	uno::Reference< beans::XPropertySet > xViewProperties;

				if ( aCreator.EqualsAscii( "Writer" ) )
				{
				    //i92835 if Writer is in web layout mode this has to be switched to normal view and back to web view in the end
                    try
                    {
                        Reference< view::XViewSettingsSupplier > xVSettingsSupplier( xModel->getCurrentController(), uno::UNO_QUERY_THROW );
                        xViewProperties =  xVSettingsSupplier->getViewSettings();
                    	xViewProperties->getPropertyValue( sShowOnlineLayout ) >>= bReChangeToNormalView;
                    	if( bReChangeToNormalView )
                    	{
                    	    xViewProperties->setPropertyValue( sShowOnlineLayout, uno::makeAny( false ) );
                    	}
                    }
                    catch( const uno::Exception& )
                    {
                    }

				}

                const sal_Int32 nPageCount = xRenderable->getRendererCount( aSelection, aRenderOptions );
				const Range     aRange( 1, nPageCount );
				MultiSelection  aMultiSelection;

				if ( mbExportNotesPages && aCreator.EqualsAscii( "Impress" ) )
				{
		            uno::Reference< drawing::XShapes > xShapes;		// sj: do not allow to export notes when
		            if ( ! ( aSelection >>= xShapes ) )				// exporting a selection -> todo: in the dialog
						bSecondPassForImpressNotes = sal_True;		// the export notes checkbox needs to be disabled
				}

				if( !aPageRange.getLength() )
				{
    				aMultiSelection.SetTotalRange( aRange );
					aMultiSelection.Select( aRange );
				}
    			else
    			{
    				aMultiSelection = MultiSelection( aPageRange );
        			aMultiSelection.SetTotalRange( aRange );
    			}
				if ( mxStatusIndicator.is() )
				{
					ByteString aResMgrName( "pdffilter" );
					ResMgr* pResMgr = ResMgr::CreateResMgr( aResMgrName.GetBuffer(), Application::GetSettings().GetUILocale() );
					if ( pResMgr )
					{
						sal_Int32 nTotalPageCount = aMultiSelection.GetSelectCount();
						if ( bSecondPassForImpressNotes )
							nTotalPageCount *= 2;
						mxStatusIndicator->start( String( ResId( PDF_PROGRESS_BAR, *pResMgr ) ), nTotalPageCount );
						delete pResMgr;
					}
				}

                if( nPageCount > 0 )
                    bRet = ExportSelection( *pPDFWriter, xRenderable, aSelection, aMultiSelection, aRenderOptions, nPageCount );
                else
                    bRet = sal_False;

				if ( bRet && bSecondPassForImpressNotes )
				{
					rExportNotesValue <<= sal_True;
                    bRet = ExportSelection( *pPDFWriter, xRenderable, aSelection, aMultiSelection, aRenderOptions, nPageCount );
				}
				if ( mxStatusIndicator.is() )
					mxStatusIndicator->end();

                // if during the export the doc locale was set copy it to PDF writer
                const com::sun::star::lang::Locale& rLoc( pPDFExtOutDevData->GetDocumentLocale() );
                if( rLoc.Language.getLength() )
                    pPDFWriter->SetDocumentLocale( rLoc );

				if( bRet )
				{
					pPDFExtOutDevData->PlayGlobalActions( *pPDFWriter );
					pPDFWriter->Emit();
                    aErrors = pPDFWriter->GetErrors();
				}
				pOut->SetExtOutDevData( NULL );
                if( bReChangeToNormalView )
                {
                    try
                    {
                        xViewProperties->setPropertyValue( sShowOnlineLayout, uno::makeAny( true ) );
                    }
                    catch( const uno::Exception& )
                    {
                    }
                }
			}

			delete pPDFExtOutDevData;
            delete pPDFWriter;
        }
    }

    // show eventual errors during export
    showErrors( aErrors );

    return bRet;
}

namespace
{

typedef cppu::WeakComponentImplHelper1< task::XInteractionRequest > PDFErrorRequestBase;

class PDFErrorRequest : private cppu::BaseMutex,
                        public PDFErrorRequestBase
{
    task::PDFExportException maExc;
public:
    PDFErrorRequest( const task::PDFExportException& i_rExc );

    // XInteractionRequest
    virtual uno::Any SAL_CALL getRequest() throw (uno::RuntimeException);
    virtual uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL getContinuations() throw (uno::RuntimeException);
};

PDFErrorRequest::PDFErrorRequest( const task::PDFExportException& i_rExc ) :
    PDFErrorRequestBase( m_aMutex ),
    maExc( i_rExc )
{
}

uno::Any SAL_CALL PDFErrorRequest::getRequest() throw (uno::RuntimeException)
{
    osl::MutexGuard const guard( m_aMutex );

    uno::Any aRet;
    aRet <<= maExc;
    return aRet;
}

uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL PDFErrorRequest::getContinuations() throw (uno::RuntimeException)
{
    return uno::Sequence< uno::Reference< task::XInteractionContinuation > >();
}

} // namespace

void PDFExport::showErrors( const std::set< PDFWriter::ErrorCode >& rErrors )
{
    if( ! rErrors.empty() && mxIH.is() )
    {
        task::PDFExportException aExc;
        aExc.ErrorCodes.realloc( sal_Int32(rErrors.size()) );
        sal_Int32 i = 0;
        for( std::set< PDFWriter::ErrorCode >::const_iterator it = rErrors.begin();
             it != rErrors.end(); ++it, i++ )
        {
            aExc.ErrorCodes.getArray()[i] = (sal_Int32)*it;
        }
        Reference< task::XInteractionRequest > xReq( new PDFErrorRequest( aExc ) );
        mxIH->handle( xReq );
    }
}

// -----------------------------------------------------------------------------

sal_Bool PDFExport::ImplExportPage( PDFWriter& rWriter, PDFExtOutDevData& rPDFExtOutDevData, const GDIMetaFile& rMtf )
{
    const Size      aSizePDF( OutputDevice::LogicToLogic( rMtf.GetPrefSize(), rMtf.GetPrefMapMode(), MAP_POINT ) );
    Point           aOrigin;
    Rectangle       aPageRect( aOrigin, rMtf.GetPrefSize() );
    sal_Bool        bRet = sal_True;

    rWriter.NewPage( aSizePDF.Width(), aSizePDF.Height() );
    rWriter.SetMapMode( rMtf.GetPrefMapMode() );

    vcl::PDFWriter::PlayMetafileContext aCtx;
    GDIMetaFile aMtf;
    if( mbRemoveTransparencies )
    {
        aCtx.m_bTransparenciesWereRemoved = rWriter.GetReferenceDevice()->
            RemoveTransparenciesFromMetaFile( rMtf, aMtf, mnMaxImageResolution, mnMaxImageResolution,
                                              false, true, mbReduceImageResolution );
    }
    else
    {
        aMtf = rMtf;
    }
    aCtx.m_nMaxImageResolution      = mbReduceImageResolution ? mnMaxImageResolution : 0;
    aCtx.m_bOnlyLosslessCompression = mbUseLosslessCompression;
    aCtx.m_nJPEGQuality             = mnQuality;


    basegfx::B2DRectangle aB2DRect( aPageRect.Left(), aPageRect.Top(), aPageRect.Right(), aPageRect.Bottom() );
    rWriter.SetClipRegion( basegfx::B2DPolyPolygon( basegfx::tools::createPolygonFromRect( aB2DRect ) ) );

    rWriter.PlayMetafile( aMtf, aCtx, &rPDFExtOutDevData );

	rPDFExtOutDevData.ResetSyncData();

    if( mbWatermark )
        ImplWriteWatermark( rWriter, aSizePDF );

    return bRet;
}

// -----------------------------------------------------------------------------

void PDFExport::ImplWriteWatermark( PDFWriter& rWriter, const Size& rPageSize )
{
    OUString aText( RTL_CONSTASCII_USTRINGPARAM( "Watermark" ) );
    Font aFont( OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica" ) ), Size( 0, 3*rPageSize.Height()/4 ) );
    aFont.SetItalic( ITALIC_NONE );
    aFont.SetWidthType( WIDTH_NORMAL );
    aFont.SetWeight( WEIGHT_NORMAL );
    aFont.SetAlign( ALIGN_BOTTOM );
    long nTextWidth = rPageSize.Width();
    if( rPageSize.Width() < rPageSize.Height() )
    {
        nTextWidth = rPageSize.Height();
        aFont.SetOrientation( 2700 );
    }

    if( ! ( maWatermark >>= aText ) )
    {
        // more complicated watermark ?
    }

    // adjust font height for text to fit
    OutputDevice* pDev = rWriter.GetReferenceDevice();
    pDev->Push( PUSH_ALL );
    pDev->SetFont( aFont );
    pDev->SetMapMode( MapMode( MAP_POINT ) );
    int w = 0;
    while( ( w = pDev->GetTextWidth( aText ) ) > nTextWidth )
    {
        long nNewHeight = aFont.GetHeight() * nTextWidth / w;
        if( nNewHeight == aFont.GetHeight() )
        {
            nNewHeight--;
            if( nNewHeight <= 0 )
                break;
        }
        aFont.SetHeight( nNewHeight );
        pDev->SetFont( aFont );
    }
    long nTextHeight = pDev->GetTextHeight();
    // leave some maneuvering room for rounding issues, also
    // some fonts go a little outside ascent/descent
    nTextHeight += nTextHeight/20;
    pDev->Pop();

    rWriter.Push( PUSH_ALL );
    rWriter.SetMapMode( MapMode( MAP_POINT ) );
    rWriter.SetFont( aFont );
    rWriter.SetTextColor( COL_RED );
    Point aTextPoint;
    Rectangle aTextRect;
    if( rPageSize.Width() > rPageSize.Height() )
    {
        aTextPoint = Point( (rPageSize.Width()-w)/2,
                            rPageSize.Height()-(rPageSize.Height()-nTextHeight)/2 );
        aTextRect = Rectangle( Point( (rPageSize.Width()-w)/2,
                                      (rPageSize.Height()-nTextHeight)/2 ),
                               Size( w, nTextHeight ) );
    }
    else
    {
        aTextPoint = Point( (rPageSize.Width()-nTextHeight)/2,
                            (rPageSize.Height()-w)/2 );
        aTextRect = Rectangle( aTextPoint, Size( nTextHeight, w ) );
    }
    rWriter.SetClipRegion();
    rWriter.BeginTransparencyGroup();
    rWriter.DrawText( aTextPoint, aText );
    rWriter.EndTransparencyGroup( aTextRect, 50 );
    rWriter.Pop();
}

