diff options
Diffstat (limited to 'svx/source/unodraw/UnoGraphicExporter.cxx')
-rw-r--r-- | svx/source/unodraw/UnoGraphicExporter.cxx | 1284 |
1 files changed, 1284 insertions, 0 deletions
diff --git a/svx/source/unodraw/UnoGraphicExporter.cxx b/svx/source/unodraw/UnoGraphicExporter.cxx new file mode 100644 index 000000000000..55ae13c43696 --- /dev/null +++ b/svx/source/unodraw/UnoGraphicExporter.cxx @@ -0,0 +1,1284 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include <vector> +#include <osl/mutex.hxx> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/document/XMimeTypeInfo.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/graphic/XGraphicRenderer.hpp> +#include <com/sun/star/task/XStatusIndicator.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/task/XInteractionContinuation.hpp> + +#include <comphelper/interaction.hxx> +#include <framework/interaction.hxx> +#include <com/sun/star/drawing/GraphicFilterRequest.hpp> +#include <com/sun/star/util/URL.hpp> +#include <cppuhelper/implbase4.hxx> +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <vcl/metaact.hxx> +#include <vcl/svapp.hxx> +#include <vcl/virdev.hxx> +#include <svtools/FilterConfigItem.hxx> +#include <svl/outstrm.hxx> +#include <svx/sdr/contact/objectcontactofobjlistpainter.hxx> +#include <svx/sdr/contact/viewobjectcontact.hxx> +#include <svx/sdr/contact/viewcontact.hxx> +#include <svx/sdr/contact/displayinfo.hxx> +#include <svx/sdr/contact/viewcontactofsdrobj.hxx> +#include <editeng/numitem.hxx> +#include <svx/svdpagv.hxx> +#include <svx/svdograf.hxx> +#include "svx/xoutbmp.hxx" +#include "svtools/filter.hxx" +#include "svx/unoapi.hxx" +#include <svx/svdpage.hxx> +#include <svx/svdmodel.hxx> +#include <svx/fmview.hxx> +#include <svx/fmmodel.hxx> +#include <svx/unopage.hxx> +#include <svx/pageitem.hxx> +#include <editeng/eeitem.hxx> +#include <svx/svdoutl.hxx> +#include <editeng/flditem.hxx> + +#include "boost/scoped_ptr.hpp" + +#define MAX_EXT_PIX 2048 + +using namespace ::comphelper; +using namespace ::osl; +using ::rtl::OUString; +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::task; +#include <svx/sdr/contact/viewobjectcontactredirector.hxx> +#include <svx/sdr/contact/viewobjectcontact.hxx> +#include <svx/sdr/contact/viewcontact.hxx> + +// #i102251# +#include <editeng/editstat.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svx +{ + struct ExportSettings + { + OUString maFilterName; + OUString maMediaType; + URL maURL; + com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > mxOutputStream; + com::sun::star::uno::Reference< com::sun::star::graphic::XGraphicRenderer > mxGraphicRenderer; + com::sun::star::uno::Reference< com::sun::star::task::XStatusIndicator > mxStatusIndicator; + com::sun::star::uno::Reference< com::sun::star::task::XInteractionHandler > mxInteractionHandler; + + sal_Int32 mnWidth; + sal_Int32 mnHeight; + sal_Bool mbExportOnlyBackground; + sal_Bool mbVerboseComments; + sal_Bool mbScrollText; + sal_Bool mbUseHighContrast; + sal_Bool mbTranslucent; + + Sequence< PropertyValue > maFilterData; + + Fraction maScaleX; + Fraction maScaleY; + + ExportSettings( SdrModel* pDoc ); + }; + + ExportSettings::ExportSettings( SdrModel* pDoc ) + : mnWidth( 0 ) + , mnHeight( 0 ) + , mbExportOnlyBackground( false ) + , mbVerboseComments( false ) + , mbScrollText( false ) + , mbUseHighContrast( false ) + , mbTranslucent( sal_False ) + , maScaleX( 1, 1 ) + , maScaleY( 1, 1 ) + { + if( pDoc ) + { + maScaleX = pDoc->GetScaleFraction(); + maScaleY = pDoc->GetScaleFraction(); + } + } + + /** implements a component to export shapes or pages to external graphic formats. + + @implements com.sun.star.drawing.GraphicExportFilter + */ + class GraphicExporter : public WeakImplHelper4< XFilter, XExporter, XServiceInfo, XMimeTypeInfo > + { + public: + GraphicExporter(); + virtual ~GraphicExporter(); + + // XFilter + virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& aDescriptor ) throw(RuntimeException); + virtual void SAL_CALL cancel( ) throw(RuntimeException); + + // XExporter + virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) throw(IllegalArgumentException, RuntimeException); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) throw(RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw(RuntimeException); + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) throw(RuntimeException); + + // XMimeTypeInfo + virtual sal_Bool SAL_CALL supportsMimeType( const ::rtl::OUString& MimeTypeName ) throw (RuntimeException); + virtual Sequence< OUString > SAL_CALL getSupportedMimeTypeNames( ) throw (RuntimeException); + + VirtualDevice* CreatePageVDev( SdrPage* pPage, sal_uIntPtr nWidthPixel, sal_uIntPtr nHeightPixel ) const; + + DECL_LINK( CalcFieldValueHdl, EditFieldInfo* ); + + void ParseSettings( const Sequence< PropertyValue >& aDescriptor, ExportSettings& rSettings ); + bool GetGraphic( ExportSettings& rSettings, Graphic& aGraphic, sal_Bool bVectorType ); + + private: + Reference< XShape > mxShape; + Reference< XDrawPage > mxPage; + Reference< XShapes > mxShapes; + + SvxDrawPage* mpUnoPage; + + Link maOldCalcFieldValueHdl; + sal_Int32 mnPageNumber; + SdrPage* mpCurrentPage; + SdrModel* mpDoc; + }; + + SVX_DLLPUBLIC Reference< XInterface > SAL_CALL GraphicExporter_createInstance(const Reference< XMultiServiceFactory > & ) + throw( Exception ) + { + return (XWeak*)new GraphicExporter(); + } + + SVX_DLLPUBLIC Sequence< OUString > SAL_CALL GraphicExporter_getSupportedServiceNames() + throw() + { + Sequence< OUString > aSupportedServiceNames( 1 ); + aSupportedServiceNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.GraphicExportFilter" ) ); + return aSupportedServiceNames; + } + + SVX_DLLPUBLIC OUString SAL_CALL GraphicExporter_getImplementationName() + throw() + { + return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.Draw.GraphicExporter" ) ); + } + + /** creates a bitmap that is optionaly transparent from a metafile + */ + BitmapEx GetBitmapFromMetaFile( const GDIMetaFile& rMtf, sal_Bool bTransparent, const Size* pSize ) + { + Graphic aGraphic( rMtf ); + BitmapEx aBmpEx; + + // #i102089# support user's settings of AA and LineSnap when the MetaFile gets + // rasterconverted to a bitmap + const SvtOptionsDrawinglayer aDrawinglayerOpt; + const GraphicConversionParameters aParameters( + pSize ? *pSize : Size(0, 0), + true, // allow unlimited size + aDrawinglayerOpt.IsAntiAliasing(), + aDrawinglayerOpt.IsSnapHorVerLinesToDiscrete()); + + if( bTransparent ) + { + Graphic aMaskGraphic(rMtf.GetMonochromeMtf(COL_BLACK)); + Bitmap aMaskBmp(aMaskGraphic.GetBitmap(aParameters)); + + aMaskBmp.Convert(BMP_CONVERSION_1BIT_THRESHOLD); + aBmpEx = BitmapEx(aGraphic.GetBitmap(aParameters), aMaskBmp); + } + else + { + aBmpEx = BitmapEx(aGraphic.GetBitmap(aParameters)); + } + + aBmpEx.SetPrefMapMode( rMtf.GetPrefMapMode() ); + aBmpEx.SetPrefSize( rMtf.GetPrefSize() ); + + return aBmpEx; + } + + Size* CalcSize( sal_Int32 nWidth, sal_Int32 nHeight, const Size& aBoundSize, Size& aOutSize ) + { + if( (nWidth == 0) && (nHeight == 0) ) + return NULL; + + if( (nWidth == 0) && (nHeight != 0) && (aBoundSize.Height() != 0) ) + { + nWidth = ( nHeight * aBoundSize.Width() ) / aBoundSize.Height(); + } + else if( (nWidth != 0) && (nHeight == 0) && (aBoundSize.Width() != 0) ) + { + nHeight = ( nWidth * aBoundSize.Height() ) / aBoundSize.Width(); + } + + aOutSize.Width() = nWidth; + aOutSize.Height() = nHeight; + + return &aOutSize; + } +} + +class ImplExportCheckVisisbilityRedirector : public ::sdr::contact::ViewObjectContactRedirector +{ +public: + ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage ); + virtual ~ImplExportCheckVisisbilityRedirector(); + + virtual drawinglayer::primitive2d::Primitive2DSequence createRedirectedPrimitive2DSequence( + const sdr::contact::ViewObjectContact& rOriginal, + const sdr::contact::DisplayInfo& rDisplayInfo); + +private: + SdrPage* mpCurrentPage; +}; + +ImplExportCheckVisisbilityRedirector::ImplExportCheckVisisbilityRedirector( SdrPage* pCurrentPage ) +: ViewObjectContactRedirector(), mpCurrentPage( pCurrentPage ) +{ +} + +ImplExportCheckVisisbilityRedirector::~ImplExportCheckVisisbilityRedirector() +{ +} + +drawinglayer::primitive2d::Primitive2DSequence ImplExportCheckVisisbilityRedirector::createRedirectedPrimitive2DSequence( + const sdr::contact::ViewObjectContact& rOriginal, + const sdr::contact::DisplayInfo& rDisplayInfo) +{ + SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject(); + + if(pObject) + { + SdrPage* pPage = mpCurrentPage; + if( pPage == 0 ) + pPage = pObject->GetPage(); + + if( (pPage == 0) || pPage->checkVisibility(rOriginal, rDisplayInfo, false) ) + { + return ::sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo); + } + + return drawinglayer::primitive2d::Primitive2DSequence(); + } + else + { + // not an object, maybe a page + return ::sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo); + } +} + +using namespace ::svx; + +GraphicExporter::GraphicExporter() +: mpUnoPage( NULL ), mnPageNumber(-1), mpCurrentPage(0), mpDoc( NULL ) +{ +} + +GraphicExporter::~GraphicExporter() +{ +} + +IMPL_LINK(GraphicExporter, CalcFieldValueHdl, EditFieldInfo*, pInfo) +{ + if( pInfo ) + { + if( mpCurrentPage ) + { + pInfo->SetSdrPage( mpCurrentPage ); + } + else if( mnPageNumber != -1 ) + { + const SvxFieldData* pField = pInfo->GetField().GetField(); + if( pField && pField->ISA( SvxPageField ) ) + { + String aPageNumValue; + sal_Bool bUpper = sal_False; + + switch(mpDoc->GetPageNumType()) + { + case SVX_CHARS_UPPER_LETTER: + aPageNumValue += (sal_Unicode)(char)((mnPageNumber - 1) % 26 + 'A'); + break; + case SVX_CHARS_LOWER_LETTER: + aPageNumValue += (sal_Unicode)(char)((mnPageNumber - 1) % 26 + 'a'); + break; + case SVX_ROMAN_UPPER: + bUpper = sal_True; + case SVX_ROMAN_LOWER: + aPageNumValue += SvxNumberFormat::CreateRomanString(mnPageNumber, bUpper); + break; + case SVX_NUMBER_NONE: + aPageNumValue.Erase(); + aPageNumValue += sal_Unicode(' '); + break; + default: + aPageNumValue += String::CreateFromInt32( (sal_Int32)mnPageNumber ); + } + + pInfo->SetRepresentation( aPageNumValue ); + + return(0); + } + } + } + + long nRet = maOldCalcFieldValueHdl.Call( pInfo ); + + if( pInfo && mpCurrentPage ) + pInfo->SetSdrPage( 0 ); + + return nRet; +} + +/** creates an virtual device for the given page + + @return the returned VirtualDevice is owned by the caller +*/ +VirtualDevice* GraphicExporter::CreatePageVDev( SdrPage* pPage, sal_uIntPtr nWidthPixel, sal_uIntPtr nHeightPixel ) const +{ + VirtualDevice* pVDev = new VirtualDevice(); + MapMode aMM( MAP_100TH_MM ); + + Point aPoint( 0, 0 ); + Size aPageSize(pPage->GetSize()); + + // use scaling? + if( nWidthPixel ) + { + const Fraction aFrac( (long) nWidthPixel, pVDev->LogicToPixel( aPageSize, aMM ).Width() ); + + aMM.SetScaleX( aFrac ); + + if( nHeightPixel == 0 ) + aMM.SetScaleY( aFrac ); + } + + if( nHeightPixel ) + { + const Fraction aFrac( (long) nHeightPixel, pVDev->LogicToPixel( aPageSize, aMM ).Height() ); + + if( nWidthPixel == 0 ) + aMM.SetScaleX( aFrac ); + + aMM.SetScaleY( aFrac ); + } + + pVDev->SetMapMode( aMM ); +#ifdef DBG_UTIL + sal_Bool bAbort = ! +#endif + pVDev->SetOutputSize(aPageSize); + DBG_ASSERT(!bAbort, "virt. Device nicht korrekt erzeugt"); + + SdrView* pView = new SdrView(mpDoc, pVDev); + pView->SetPageVisible( sal_False ); + pView->SetBordVisible( sal_False ); + pView->SetGridVisible( sal_False ); + pView->SetHlplVisible( sal_False ); + pView->SetGlueVisible( sal_False ); + pView->ShowSdrPage(pPage); + Region aRegion (Rectangle( aPoint, aPageSize ) ); + + ImplExportCheckVisisbilityRedirector aRedirector( mpCurrentPage ); + + pView->CompleteRedraw(pVDev, aRegion, &aRedirector); + + delete pView; + return pVDev; +} + +void GraphicExporter::ParseSettings( const Sequence< PropertyValue >& aDescriptor, ExportSettings& rSettings ) +{ + sal_Int32 nArgs = aDescriptor.getLength(); + const PropertyValue* pValues = aDescriptor.getConstArray(); + while( nArgs-- ) + { + if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "FilterName" ) ) ) + { + pValues->Value >>= rSettings.maFilterName; + } + else if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ) + { + pValues->Value >>= rSettings.maMediaType; + } + else if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "URL" ) ) ) + { + if( !( pValues->Value >>= rSettings.maURL ) ) + { + pValues->Value >>= rSettings.maURL.Complete; + } + } + else if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "OutputStream" ) ) ) + { + pValues->Value >>= rSettings.mxOutputStream; + } + else if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "GraphicRenderer" ) ) ) + { + pValues->Value >>= rSettings.mxGraphicRenderer; + } + else if ( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "StatusIndicator" ) ) ) + { + pValues->Value >>= rSettings.mxStatusIndicator; + } + else if ( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "InteractionHandler" ) ) ) + { + pValues->Value >>= rSettings.mxInteractionHandler; + } + else if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Width" ) ) ) // for compatibility reasons, deprecated + { + pValues->Value >>= rSettings.mnWidth; + } + else if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Height" ) ) ) // for compatibility reasons, deprecated + { + pValues->Value >>= rSettings.mnHeight; + } + else if( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ExportOnlyBackground" ) ) ) // for compatibility reasons, deprecated + { + pValues->Value >>= rSettings.mbExportOnlyBackground; + } + else if ( pValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "FilterData" ) ) ) + { + pValues->Value >>= rSettings.maFilterData; + + sal_Int32 nFilterArgs = rSettings.maFilterData.getLength(); + PropertyValue* pDataValues = rSettings.maFilterData.getArray(); + while( nFilterArgs-- ) + { + if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Translucent" ) ) ) + { + if ( !( pDataValues->Value >>= rSettings.mbTranslucent ) ) // SJ: TODO: The GIF Transparency is stored as int32 in + { // configuration files, this has to be changed to boolean + sal_Int32 nTranslucent = 0; + if ( pDataValues->Value >>= nTranslucent ) + rSettings.mbTranslucent = nTranslucent != 0; + } + } + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "PixelWidth" ) ) ) + { + pDataValues->Value >>= rSettings.mnWidth; + } + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "PixelHeight" ) ) ) + { + pDataValues->Value >>= rSettings.mnHeight; + } + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Width" ) ) ) // for compatibility reasons, deprecated + { + pDataValues->Value >>= rSettings.mnWidth; + pDataValues->Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "PixelWidth" ) ); + } + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Height" ) ) ) // for compatibility reasons, deprecated + { + pDataValues->Value >>= rSettings.mnHeight; + pDataValues->Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "PixelHeight" ) ); + } + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ExportOnlyBackground" ) ) ) + { + pDataValues->Value >>= rSettings.mbExportOnlyBackground; + } + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "HighContrast" ) ) ) + { + pDataValues->Value >>= rSettings.mbUseHighContrast; + } + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "PageNumber" ) ) ) + { + pDataValues->Value >>= mnPageNumber; + } + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "VerboseComments" ) ) ) + { + // #110496# Read flag for verbose metafile comments + pDataValues->Value >>= rSettings.mbVerboseComments; + } + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScrollText" ) ) ) + { + // #110496# Read flag solitary scroll text metafile + pDataValues->Value >>= rSettings.mbScrollText; + } + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CurrentPage" ) ) ) + { + Reference< XDrawPage > xPage; + pDataValues->Value >>= xPage; + if( xPage.is() ) + { + SvxDrawPage* pUnoPage = SvxDrawPage::getImplementation( xPage ); + if( pUnoPage && pUnoPage->GetSdrPage() ) + mpCurrentPage = pUnoPage->GetSdrPage(); + } + } + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleXNumerator" ) ) ) + { + sal_Int32 nVal = 1; + if( pDataValues->Value >>= nVal ) + rSettings.maScaleX = Fraction( nVal, rSettings.maScaleX.GetDenominator() ); + } + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleXDenominator" ) ) ) + { + sal_Int32 nVal = 1; + if( pDataValues->Value >>= nVal ) + rSettings.maScaleX = Fraction( rSettings.maScaleX.GetNumerator(), nVal ); + } + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleYNumerator" ) ) ) + { + sal_Int32 nVal = 1; + if( pDataValues->Value >>= nVal ) + rSettings.maScaleY = Fraction( nVal, rSettings.maScaleY.GetDenominator() ); + } + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleYDenominator" ) ) ) + { + sal_Int32 nVal = 1; + if( pDataValues->Value >>= nVal ) + rSettings.maScaleY = Fraction( rSettings.maScaleY.GetNumerator(), nVal ); + } + + pDataValues++; + } + } + + pValues++; + } + + // putting the StatusIndicator that we got from the MediaDescriptor into our local FilterData copy + if ( rSettings.mxStatusIndicator.is() ) + { + rtl::OUString sStatusIndicator( RTL_CONSTASCII_USTRINGPARAM( "StatusIndicator" ) ); + int i = rSettings.maFilterData.getLength(); + rSettings.maFilterData.realloc( i + 1 ); + rSettings.maFilterData[ i ].Name = sStatusIndicator; + rSettings.maFilterData[ i ].Value <<= rSettings.mxStatusIndicator; + } +} + +bool GraphicExporter::GetGraphic( ExportSettings& rSettings, Graphic& aGraphic, sal_Bool bVectorType ) +{ + if( !mpDoc || !mpUnoPage ) + return false; + + SdrPage* pPage = mpUnoPage->GetSdrPage(); + if( !pPage ) + return false; + + VirtualDevice aVDev; + const MapMode aMap( mpDoc->GetScaleUnit(), Point(), rSettings.maScaleX, rSettings.maScaleY ); + + SdrOutliner& rOutl=mpDoc->GetDrawOutliner(NULL); + maOldCalcFieldValueHdl = rOutl.GetCalcFieldValueHdl(); + rOutl.SetCalcFieldValueHdl( LINK(this, GraphicExporter, CalcFieldValueHdl) ); + rOutl.SetBackgroundColor( pPage->GetPageBackgroundColor() ); + + // #i102251# + const sal_uInt32 nOldCntrl(rOutl.GetControlWord()); + sal_uInt32 nCntrl = nOldCntrl & ~EE_CNTRL_ONLINESPELLING; + rOutl.SetControlWord(nCntrl); + + SdrObject* pTempBackgroundShape = 0; + std::vector< SdrObject* > aShapes; + bool bRet = true; + + // export complete page? + if ( !mxShape.is() ) + { + if( rSettings.mbExportOnlyBackground ) + { + const SdrPageProperties* pCorrectProperties = pPage->getCorrectSdrPageProperties(); + + if(pCorrectProperties) + { + pTempBackgroundShape = new SdrRectObj(Rectangle(Point(0,0), pPage->GetSize())); + pTempBackgroundShape->SetMergedItemSet(pCorrectProperties->GetItemSet()); + pTempBackgroundShape->SetMergedItem(XLineStyleItem(XLINE_NONE)); + pTempBackgroundShape->NbcSetStyleSheet(pCorrectProperties->GetStyleSheet(), true); + aShapes.push_back(pTempBackgroundShape); + } + } + else + { + const Size aSize( pPage->GetSize() ); + + // generate a bitmap to convert it to a pixel format. + // For gif pictures there can also be a vector format used (bTranslucent) + if ( !bVectorType && !rSettings.mbTranslucent ) + { + long nWidthPix = 0; + long nHeightPix = 0; + if ( rSettings.mnWidth > 0 && rSettings.mnHeight > 0 ) + { + nWidthPix = rSettings.mnWidth; + nHeightPix = rSettings.mnHeight; + } + else + { + const Size aSizePix( Application::GetDefaultDevice()->LogicToPixel( aSize, aMap ) ); + if (aSizePix.Width() > MAX_EXT_PIX || aSizePix.Height() > MAX_EXT_PIX) + { + if (aSizePix.Width() > MAX_EXT_PIX) + nWidthPix = MAX_EXT_PIX; + else + nWidthPix = aSizePix.Width(); + if (aSizePix.Height() > MAX_EXT_PIX) + nHeightPix = MAX_EXT_PIX; + else + nHeightPix = aSizePix.Height(); + + double fWidthDif = aSizePix.Width() / nWidthPix; + double fHeightDif = aSizePix.Height() / nHeightPix; + + if (fWidthDif > fHeightDif) + nHeightPix = static_cast<long>(aSizePix.Height() / fWidthDif); + else + nWidthPix = static_cast<long>(aSizePix.Width() / fHeightDif); + } + else + { + nWidthPix = aSizePix.Width(); + nHeightPix = aSizePix.Height(); + } + } + + boost::scoped_ptr< SdrView > pLocalView; + if( PTR_CAST( FmFormModel, mpDoc ) ) + { + pLocalView.reset( new FmFormView( PTR_CAST( FmFormModel, mpDoc ), &aVDev ) ); + } + else + { + pLocalView.reset( new SdrView( mpDoc, &aVDev ) ); + } + + + VirtualDevice* pVDev = CreatePageVDev( pPage, nWidthPix, nHeightPix ); + + if( pVDev ) + { + aGraphic = pVDev->GetBitmap( Point(), pVDev->GetOutputSize() ); + aGraphic.SetPrefMapMode( aMap ); + aGraphic.SetPrefSize( aSize ); + delete pVDev; + } + } + // create a metafile to export a vector format + else + { + GDIMetaFile aMtf; + + aVDev.SetMapMode( aMap ); + if( rSettings.mbUseHighContrast ) + aVDev.SetDrawMode( aVDev.GetDrawMode() | DRAWMODE_SETTINGSLINE | DRAWMODE_SETTINGSFILL | DRAWMODE_SETTINGSTEXT | DRAWMODE_SETTINGSGRADIENT ); + aVDev.EnableOutput( sal_False ); + aMtf.Record( &aVDev ); + Size aNewSize; + + // create a view + SdrView* pView; + + if( PTR_CAST( FmFormModel, mpDoc ) ) + { + pView = new FmFormView( PTR_CAST( FmFormModel, mpDoc ), &aVDev ); + } + else + { + pView = new SdrView( mpDoc, &aVDev ); + } + + pView->SetBordVisible( sal_False ); + pView->SetPageVisible( sal_False ); + pView->ShowSdrPage( pPage ); + + if ( pView && pPage ) + { + pView->SetBordVisible( sal_False ); + pView->SetPageVisible( sal_False ); + pView->ShowSdrPage( pPage ); + + const Point aNewOrg( pPage->GetLftBorder(), pPage->GetUppBorder() ); + aNewSize = Size( aSize.Width() - pPage->GetLftBorder() - pPage->GetRgtBorder(), + aSize.Height() - pPage->GetUppBorder() - pPage->GetLwrBorder() ); + const Rectangle aClipRect( aNewOrg, aNewSize ); + MapMode aVMap( aMap ); + + aVDev.Push(); + aVMap.SetOrigin( Point( -aNewOrg.X(), -aNewOrg.Y() ) ); + aVDev.SetRelativeMapMode( aVMap ); + aVDev.IntersectClipRegion( aClipRect ); + + // Use new StandardCheckVisisbilityRedirector + ImplExportCheckVisisbilityRedirector aRedirector( mpCurrentPage ); + + pView->CompleteRedraw(&aVDev, Region(Rectangle(Point(), aNewSize)), &aRedirector); + + aVDev.Pop(); + + aMtf.Stop(); + aMtf.WindStart(); + aMtf.SetPrefMapMode( aMap ); + aMtf.SetPrefSize( aNewSize ); + + // AW: Here the current version was filtering out the META_CLIPREGION_ACTIONs + // from the metafile. I asked some other developers why this was done, but no + // one knew a direct reason. Since it's in for long time, it may be an old + // piece of code. MetaFiles save and load ClipRegions with polygons with preserving + // the polygons, so a resolution-indepent roundtrip is supported. Removed this + // code since it destroys some MetaFiles where ClipRegions are used. Anyways, + // just filtering them out is a hack, at least the encapsulated content would need + // to be clipped geometrically. + aGraphic = Graphic(aMtf); + } + + if ( pView ) + { + pView->HideSdrPage(); + delete pView; + } + + if( rSettings.mbTranslucent ) + { + Size aOutSize; + aGraphic = GetBitmapFromMetaFile( aGraphic.GetGDIMetaFile(), sal_True, CalcSize( rSettings.mnWidth, rSettings.mnHeight, aNewSize, aOutSize ) ); + } + } + } + } + + // export only single shape or shape collection + else + { + // build list of SdrObject + if( mxShapes.is() ) + { + Reference< XShape > xShape; + const sal_Int32 nCount = mxShapes->getCount(); + + for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ ) + { + mxShapes->getByIndex( nIndex ) >>= xShape; + SdrObject* pObj = GetSdrObjectFromXShape( xShape ); + if( pObj ) + aShapes.push_back( pObj ); + } + } + else + { + // only one shape + SdrObject* pObj = GetSdrObjectFromXShape( mxShape ); + if( pObj ) + aShapes.push_back( pObj ); + } + + if( 0 == aShapes.size() ) + bRet = false; + } + + if( bRet && aShapes.size() ) + { + // special treatment for only one SdrGrafObj that has text + sal_Bool bSingleGraphic = sal_False; + + if( 1 == aShapes.size() ) + { + if( !bVectorType ) + { + SdrObject* pObj = aShapes.front(); + if( pObj && pObj->ISA( SdrGrafObj ) && !( (SdrGrafObj*) pObj )->HasText() ) + { + aGraphic = ( (SdrGrafObj*) pObj )->GetTransformedGraphic(); + if ( aGraphic.GetType() == GRAPHIC_BITMAP ) + { + Size aSizePixel( aGraphic.GetSizePixel() ); + if( rSettings.mnWidth && rSettings.mnHeight && + ( ( rSettings.mnWidth != aSizePixel.Width() ) || + ( rSettings.mnHeight != aSizePixel.Height() ) ) ) + { + BitmapEx aBmpEx( aGraphic.GetBitmapEx() ); + aBmpEx.Scale( Size( rSettings.mnWidth, rSettings.mnHeight ) ); + aGraphic = aBmpEx; + } + } + bSingleGraphic = sal_True; + } + } + else if( rSettings.mbScrollText ) + { + SdrObject* pObj = aShapes.front(); + if( pObj && pObj->ISA( SdrTextObj ) + && ( (SdrTextObj*) pObj )->HasText() ) + { + Rectangle aScrollRectangle; + Rectangle aPaintRectangle; + + const boost::scoped_ptr< GDIMetaFile > pMtf( + ( (SdrTextObj*) pObj )->GetTextScrollMetaFileAndRectangle( + aScrollRectangle, aPaintRectangle ) ); + + // take the larger one of the two rectangles (that + // should be the bound rect of the retrieved + // metafile) + Rectangle aTextRect; + + if( aScrollRectangle.IsInside( aPaintRectangle ) ) + aTextRect = aScrollRectangle; + else + aTextRect = aPaintRectangle; + + // setup pref size and mapmode + pMtf->SetPrefSize( aTextRect.GetSize() ); + + // set actual origin (mtf is at actual shape + // output position) + MapMode aLocalMapMode( aMap ); + aLocalMapMode.SetOrigin( + Point( -aPaintRectangle.Left(), + -aPaintRectangle.Top() ) ); + pMtf->SetPrefMapMode( aLocalMapMode ); + + pMtf->AddAction( new MetaCommentAction( + "XTEXT_SCROLLRECT", 0, + reinterpret_cast<sal_uInt8 const*>(&aScrollRectangle), + sizeof( Rectangle ) ) ); + pMtf->AddAction( new MetaCommentAction( + "XTEXT_PAINTRECT", 0, + reinterpret_cast<sal_uInt8 const*>(&aPaintRectangle), + sizeof( Rectangle ) ) ); + + aGraphic = Graphic( *pMtf ); + + bSingleGraphic = sal_True; + } + } + } + + if( !bSingleGraphic ) + { + // create a metafile for all shapes + VirtualDevice aOut; + + // calculate bound rect for all shapes + Rectangle aBound; + + { + std::vector< SdrObject* >::iterator aIter = aShapes.begin(); + const std::vector< SdrObject* >::iterator aEnd = aShapes.end(); + + while( aIter != aEnd ) + { + SdrObject* pObj = (*aIter++); + Rectangle aR1(pObj->GetCurrentBoundRect()); + if (aBound.IsEmpty()) + aBound=aR1; + else + aBound.Union(aR1); + } + } + + aOut.EnableOutput( sal_False ); + aOut.SetMapMode( aMap ); + if( rSettings.mbUseHighContrast ) + aOut.SetDrawMode( aVDev.GetDrawMode() | DRAWMODE_SETTINGSLINE | DRAWMODE_SETTINGSFILL | DRAWMODE_SETTINGSTEXT | DRAWMODE_SETTINGSGRADIENT ); + + GDIMetaFile aMtf; + aMtf.Clear(); + aMtf.Record( &aOut ); + + MapMode aOutMap( aMap ); + aOutMap.SetOrigin( Point( -aBound.TopLeft().X(), -aBound.TopLeft().Y() ) ); + aOut.SetRelativeMapMode( aOutMap ); + + sdr::contact::DisplayInfo aDisplayInfo; + + if(mpCurrentPage) + { + if(mpCurrentPage->TRG_HasMasterPage() && pPage->IsMasterPage()) + { + // MasterPage is processed as another page's SubContent + aDisplayInfo.SetProcessLayers(mpCurrentPage->TRG_GetMasterPageVisibleLayers()); + aDisplayInfo.SetSubContentActive(true); + } + } + + if(aShapes.size()) + { + // more effective way to paint a vector of SdrObjects. Hand over the processed page + // to have it in the + sdr::contact::ObjectContactOfObjListPainter aMultiObjectPainter(aOut, aShapes, mpCurrentPage); + ImplExportCheckVisisbilityRedirector aCheckVisibilityRedirector(mpCurrentPage); + aMultiObjectPainter.SetViewObjectContactRedirector(&aCheckVisibilityRedirector); + + aMultiObjectPainter.ProcessDisplay(aDisplayInfo); + } + + aMtf.Stop(); + aMtf.WindStart(); + + const Size aExtSize( aOut.PixelToLogic( Size( 0, 0 ) ) ); + Size aBoundSize( aBound.GetWidth() + ( aExtSize.Width() ), + aBound.GetHeight() + ( aExtSize.Height() ) ); + + aMtf.SetPrefMapMode( aMap ); + aMtf.SetPrefSize( aBoundSize ); + + if( !bVectorType ) + { + Size aOutSize; + aGraphic = GetBitmapFromMetaFile( aMtf, rSettings.mbTranslucent, CalcSize( rSettings.mnWidth, rSettings.mnHeight, aBoundSize, aOutSize ) ); + } + else + { + aGraphic = aMtf; + } + } + } + + if(pTempBackgroundShape) + { + SdrObject::Free(pTempBackgroundShape); + } + + rOutl.SetCalcFieldValueHdl( maOldCalcFieldValueHdl ); + + // #i102251# + rOutl.SetControlWord(nOldCntrl); + + return bRet; + +} + +// XFilter +sal_Bool SAL_CALL GraphicExporter::filter( const Sequence< PropertyValue >& aDescriptor ) + throw(RuntimeException) +{ + ::SolarMutexGuard aGuard; + + if( NULL == mpUnoPage ) + return sal_False; + + GraphicFilter* pFilter = GraphicFilter::GetGraphicFilter(); + + if( NULL == pFilter || NULL == mpUnoPage->GetSdrPage() || NULL == mpDoc ) + return sal_False; + + // get the arguments from the descriptor + ExportSettings aSettings( mpDoc ); + ParseSettings( aDescriptor, aSettings ); + + const sal_uInt16 nFilter = aSettings.maMediaType.getLength() + ? pFilter->GetExportFormatNumberForMediaType( aSettings.maMediaType ) + : pFilter->GetExportFormatNumberForShortName( aSettings.maFilterName ); + sal_Bool bVectorType = !pFilter->IsExportPixelFormat( nFilter ); + + // create the output stuff + Graphic aGraphic; + + sal_uInt16 nStatus = GetGraphic( aSettings, aGraphic, bVectorType ) ? GRFILTER_OK : GRFILTER_FILTERERROR; + + if( nStatus == GRFILTER_OK ) + { + // export graphic only if it has a size + const Size aGraphSize( aGraphic.GetPrefSize() ); + if ( ( aGraphSize.Width() == 0 ) || ( aGraphSize.Height() == 0 ) ) + { + nStatus = GRFILTER_FILTERERROR; + } + else + { + // now we have a graphic, so export it + if( aSettings.mxGraphicRenderer.is() ) + { + // render graphic directly into given renderer + aSettings.mxGraphicRenderer->render( aGraphic.GetXGraphic() ); + } + else if( aSettings.mxOutputStream.is() ) + { + // TODO: Either utilize optional XSeekable functionality for the + // SvOutputStream, or adapt the graphic filter to not seek anymore. + SvMemoryStream aStream( 1024, 1024 ); + + nStatus = pFilter->ExportGraphic( aGraphic, String(), aStream, nFilter, &aSettings.maFilterData ); + + // copy temp stream to XOutputStream + SvOutputStream aOutputStream( aSettings.mxOutputStream ); + aStream.Seek(0); + aOutputStream << aStream; + } + else + { + INetURLObject aURLObject( aSettings.maURL.Complete ); + DBG_ASSERT( aURLObject.GetProtocol() != INET_PROT_NOT_VALID, "invalid URL" ); + + nStatus = XOutBitmap::ExportGraphic( aGraphic, aURLObject, *pFilter, nFilter, &aSettings.maFilterData ); + } + } + } + + if ( aSettings.mxInteractionHandler.is() && ( nStatus != GRFILTER_OK ) ) + { + Any aInteraction; + Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionContinuation > > lContinuations(1); + ::comphelper::OInteractionApprove* pApprove = new ::comphelper::OInteractionApprove(); + lContinuations[0] = Reference< XInteractionContinuation >(static_cast< XInteractionContinuation* >(pApprove), UNO_QUERY); + + GraphicFilterRequest aErrorCode; + aErrorCode.ErrCode = nStatus; + aInteraction <<= aErrorCode; + aSettings.mxInteractionHandler->handle( framework::InteractionRequest::CreateRequest( aInteraction, lContinuations ) ); + } + return nStatus == GRFILTER_OK; +} + +void SAL_CALL GraphicExporter::cancel() + throw(RuntimeException) +{ +} + +// XExporter + +/** the source 'document' could be a XDrawPage, a XShape or a generic XShapes */ +void SAL_CALL GraphicExporter::setSourceDocument( const Reference< lang::XComponent >& xComponent ) + throw(IllegalArgumentException, RuntimeException) +{ + ::SolarMutexGuard aGuard; + + mxShapes = NULL; + mpUnoPage = NULL; + + try + { + // any break inside this one loop while will throw a IllegalArgumentException + do + { + mxPage = Reference< XDrawPage >::query( xComponent ); + mxShapes = Reference< XShapes >::query( xComponent ); + mxShape = Reference< XShape >::query( xComponent ); + + // Step 1: try a generic XShapes + if( !mxPage.is() && !mxShape.is() && mxShapes.is() ) + { + // we do not support empty shape collections + if( 0 == mxShapes->getCount() ) + break; + + // get first shape to detect corresponding page and model + mxShapes->getByIndex(0) >>= mxShape; + } + else + { + mxShapes = NULL; + } + + // Step 2: try a shape + if( mxShape.is() ) + { + if( NULL == GetSdrObjectFromXShape( mxShape ) ) + break; + + // get page for this shape + Reference< XChild > xChild( mxShape, UNO_QUERY ); + if( !xChild.is() ) + break; + + Reference< XInterface > xInt; + do + { + xInt = xChild->getParent(); + mxPage = Reference< XDrawPage >::query( xInt ); + if( !mxPage.is() ) + xChild = Reference< XChild >::query( xInt ); + } + while( !mxPage.is() && xChild.is() ); + + if( !mxPage.is() ) + break; + } + + // Step 3: check the page + if( !mxPage.is() ) + break; + + mpUnoPage = SvxDrawPage::getImplementation( mxPage ); + + if( NULL == mpUnoPage || NULL == mpUnoPage->GetSdrPage() ) + break; + + mpDoc = mpUnoPage->GetSdrPage()->GetModel(); + + // Step 4: If we got a generic XShapes test all contained shapes + // if they belong to the same XDrawPage + + if( mxShapes.is() ) + { + SdrPage* pPage = mpUnoPage->GetSdrPage(); + SdrObject* pObj; + Reference< XShape > xShape; + + sal_Bool bOk = sal_True; + + const sal_Int32 nCount = mxShapes->getCount(); + + // test all but the first shape if they have the same page than + // the first shape + for( sal_Int32 nIndex = 1; bOk && ( nIndex < nCount ); nIndex++ ) + { + mxShapes->getByIndex( nIndex ) >>= xShape; + pObj = GetSdrObjectFromXShape( xShape ); + bOk = pObj && pObj->GetPage() == pPage; + } + + if( !bOk ) + break; + } + + // no errors so far + return; + } + while( 0 ); + } + catch( Exception& ) + { + } + + throw IllegalArgumentException(); +} + +// XServiceInfo +OUString SAL_CALL GraphicExporter::getImplementationName( ) + throw(RuntimeException) +{ + return GraphicExporter_getImplementationName(); +} + +sal_Bool SAL_CALL GraphicExporter::supportsService( const OUString& ServiceName ) + throw(RuntimeException) +{ + Sequence< OUString > aSeq( GraphicExporter_getSupportedServiceNames() ); + sal_Int32 nArgs = aSeq.getLength(); + const OUString* pService = aSeq.getConstArray(); + while( nArgs-- ) + if( *pService++ == ServiceName ) + return sal_True; + + return sal_False; +} + +Sequence< OUString > SAL_CALL GraphicExporter::getSupportedServiceNames( ) + throw(RuntimeException) +{ + return GraphicExporter_getSupportedServiceNames(); +} + +// XMimeTypeInfo +sal_Bool SAL_CALL GraphicExporter::supportsMimeType( const OUString& MimeTypeName ) throw (RuntimeException) +{ + const String aMimeTypeName( MimeTypeName ); + + GraphicFilter* pFilter = GraphicFilter::GetGraphicFilter(); + sal_uInt16 nCount = pFilter->GetExportFormatCount(); + sal_uInt16 nFilter; + for( nFilter = 0; nFilter < nCount; nFilter++ ) + { + if( aMimeTypeName.Equals( pFilter->GetExportFormatMediaType( nFilter ) ) ) + { + return sal_True; + } + } + + return sal_False; +} + +Sequence< OUString > SAL_CALL GraphicExporter::getSupportedMimeTypeNames( ) throw (RuntimeException) +{ + GraphicFilter* pFilter = GraphicFilter::GetGraphicFilter(); + sal_uInt16 nCount = pFilter->GetExportFormatCount(); + sal_uInt16 nFilter; + sal_uInt16 nFound = 0; + + Sequence< OUString > aSeq( nCount ); + OUString* pStr = aSeq.getArray(); + + for( nFilter = 0; nFilter < nCount; nFilter++ ) + { + OUString aMimeType( pFilter->GetExportFormatMediaType( nFilter ) ); + if( aMimeType.getLength() ) + { + *pStr++ = aMimeType; + nFound++; + } + } + + if( nFound < nCount ) + aSeq.realloc( nFound ); + + return aSeq; +} + +Graphic SvxGetGraphicForShape( SdrObject& rShape, bool bVector ) +{ + Graphic aGraphic; + try + { + rtl::Reference< GraphicExporter > xExporter( new GraphicExporter() ); + Reference< XComponent > xComp( rShape.getUnoShape(), UNO_QUERY_THROW ); + xExporter->setSourceDocument( xComp ); + ExportSettings aSettings( rShape.GetModel() ); + xExporter->GetGraphic( aSettings, aGraphic, bVector ); + } + catch( Exception& ) + { + OSL_FAIL("SvxGetGraphicForShape(), exception caught!"); + } + return aGraphic; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |