diff options
author | Christian Lippka <cl@openoffice.org> | 2002-11-21 13:58:04 +0000 |
---|---|---|
committer | Christian Lippka <cl@openoffice.org> | 2002-11-21 13:58:04 +0000 |
commit | ac9fe009be9867ffda85990425d054a759f42caf (patch) | |
tree | ceec1d86d460038b845fd5fad22ace6bbf67b90f /filter/source/flash | |
parent | 7540c56ec699d18b2a30923a4c15a0ce2232bb40 (diff) |
#105361# adding augustus changes and putting flash into srx644
Diffstat (limited to 'filter/source/flash')
-rw-r--r-- | filter/source/flash/impswfdialog.cxx | 56 | ||||
-rw-r--r-- | filter/source/flash/impswfdialog.hrc | 18 | ||||
-rw-r--r-- | filter/source/flash/impswfdialog.hxx | 21 | ||||
-rw-r--r-- | filter/source/flash/impswfdialog.src | 131 | ||||
-rw-r--r-- | filter/source/flash/makefile.mk | 16 | ||||
-rw-r--r-- | filter/source/flash/swfexporter.cxx | 804 | ||||
-rw-r--r-- | filter/source/flash/swfexporter.hxx | 270 | ||||
-rw-r--r-- | filter/source/flash/swffilter.cxx | 601 | ||||
-rw-r--r-- | filter/source/flash/swfuno.cxx | 170 | ||||
-rw-r--r-- | filter/source/flash/swfwriter.cxx | 704 | ||||
-rw-r--r-- | filter/source/flash/swfwriter.hxx | 522 | ||||
-rw-r--r-- | filter/source/flash/swfwriter1.cxx | 1870 | ||||
-rw-r--r-- | filter/source/flash/swfwriter2.cxx | 727 |
13 files changed, 5874 insertions, 36 deletions
diff --git a/filter/source/flash/impswfdialog.cxx b/filter/source/flash/impswfdialog.cxx index 71425b19af81..a19c33126cc3 100644 --- a/filter/source/flash/impswfdialog.cxx +++ b/filter/source/flash/impswfdialog.cxx @@ -2,9 +2,9 @@ * * $RCSfile: impswfdialog.cxx,v $ * - * $Revision: 1.2 $ + * $Revision: 1.3 $ * - * last change: $Author: cl $ $Date: 2002-10-30 12:34:34 $ + * last change: $Author: cl $ $Date: 2002-11-21 14:58:01 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -74,6 +74,21 @@ ImpSWFDialog::ImpSWFDialog( Window* pParent, ResMgr& rResMgr, Sequence< Property ModalDialog( pParent, ResId( DLG_OPTIONS, &rResMgr ) ), maFiDescr( this, ResId( FI_DESCR ) ), maNumFldQuality( this, ResId( NUM_FLD_QUALITY ) ), + maFiExportAllDescr( this, ResId( FI_EXPORT_ALL_DESCR ) ), + maCheckExportAll( this, ResId( BOOL_EXPORT_ALL ) ), + maFiExportBackgroundsDescr( this, ResId( FI_EXPORT_BACKGROUNDS_DESCR ) ), + maCheckExportBackgrounds( this, ResId( BOOL_EXPORT_BACKGROUNDS ) ), + maFiExportBackgroundObjectsDescr( this, ResId( FI_EXPORT_BACKGROUND_OBJECTS_DESCR ) ), + maCheckExportBackgroundObjects( this, ResId( BOOL_EXPORT_BACKGROUND_OBJECTS ) ), + maFiExportSlideContentsDescr( this, ResId( FI_EXPORT_SLIDE_CONTENTS_DESCR ) ), + maCheckExportSlideContents( this, ResId( BOOL_EXPORT_SLIDE_CONTENTS ) ), + maFiExportSoundDescr( this, ResId( FI_EXPORT_SOUND_DESCR ) ), + maCheckExportSound( this, ResId( BOOL_EXPORT_SOUND ) ), + maFiExportOLEAsJPEGDescr( this, ResId( FI_EXPORT_OLE_AS_JPEG_DESCR ) ), + maCheckExportOLEAsJPEG( this, ResId( BOOL_EXPORT_OLE_AS_JPEG ) ), + maFiExportMultipleFilesDescr( this, ResId( FI_EXPORT_MULTIPLE_FILES_DESCR ) ), + maCheckExportMultipleFiles( this, ResId( BOOL_EXPORT_MULTIPLE_FILES ) ), + maBtnOK( this, ResId( BTN_OK ) ), maBtnCancel( this, ResId( BTN_CANCEL ) ), maBtnHelp( this, ResId( BTN_HELP ) ), @@ -82,6 +97,20 @@ ImpSWFDialog::ImpSWFDialog( Window* pParent, ResMgr& rResMgr, Sequence< Property const ULONG nCompressMode = maConfigItem.ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "CompressMode" ) ), 75 ); maNumFldQuality.SetValue( nCompressMode ); + maCheckExportAll.Check(); + maCheckExportSlideContents.Check(); + maCheckExportSound.Check(); + + maCheckExportAll.SetToggleHdl( LINK( this, ImpSWFDialog, OnToggleCheckbox ) ); + + maCheckExportBackgrounds.Disable(); maFiExportBackgroundsDescr.Disable(); + maCheckExportBackgroundObjects.Disable(); maFiExportBackgroundObjectsDescr.Disable(); + maCheckExportSlideContents.Disable(); maFiExportSlideContentsDescr.Disable(); + +#ifdef AUGUSTUS + maCheckExportMultipleFiles.Check(); +#endif + FreeResource(); } @@ -97,8 +126,31 @@ Sequence< PropertyValue > ImpSWFDialog::GetFilterData() { sal_Int32 nCompressMode = (sal_Int32)maNumFldQuality.GetValue(); maConfigItem.WriteInt32( OUString( RTL_CONSTASCII_USTRINGPARAM( "CompressMode" ) ), nCompressMode ); + maConfigItem.WriteBool( OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportAll" ) ), maCheckExportAll.IsChecked() ); + maConfigItem.WriteBool( OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportBackgrounds" ) ), maCheckExportBackgrounds.IsChecked() ); + maConfigItem.WriteBool( OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportBackgroundObjects" ) ), maCheckExportBackgroundObjects.IsChecked() ); + maConfigItem.WriteBool( OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportSlideContents" ) ), maCheckExportSlideContents.IsChecked() ); + maConfigItem.WriteBool( OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportSound" ) ), maCheckExportSound.IsChecked() ); + maConfigItem.WriteBool( OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportOLEAsJPEG" ) ), maCheckExportOLEAsJPEG.IsChecked() ); + maConfigItem.WriteBool( OUString( RTL_CONSTASCII_USTRINGPARAM( "ExportMultipleFiles" ) ), maCheckExportMultipleFiles.IsChecked() ); + Sequence< PropertyValue > aRet( maConfigItem.GetFilterData() ); return aRet; } +// AS: This is called whenever the user toggles one of the checkboxes +IMPL_LINK( ImpSWFDialog, OnToggleCheckbox, CheckBox*, pBox ) +{ + if (pBox == &maCheckExportAll) + { + maCheckExportBackgrounds.Enable(!maCheckExportBackgrounds.IsEnabled()); + maFiExportBackgroundsDescr.Enable(!maFiExportBackgroundsDescr.IsEnabled()); + maCheckExportBackgroundObjects.Enable(!maCheckExportBackgroundObjects.IsEnabled()); + maFiExportBackgroundObjectsDescr.Enable(!maFiExportBackgroundObjectsDescr.IsEnabled()); + maCheckExportSlideContents.Enable(!maCheckExportSlideContents.IsEnabled()); + maFiExportSlideContentsDescr.Enable(!maFiExportSlideContentsDescr.IsEnabled()); + } + + return 0; +}
\ No newline at end of file diff --git a/filter/source/flash/impswfdialog.hrc b/filter/source/flash/impswfdialog.hrc index 64e309902540..b8575ac98084 100644 --- a/filter/source/flash/impswfdialog.hrc +++ b/filter/source/flash/impswfdialog.hrc @@ -2,9 +2,9 @@ * * $RCSfile: impswfdialog.hrc,v $ * - * $Revision: 1.1 $ + * $Revision: 1.2 $ * - * last change: $Author: cl $ $Date: 2002-10-24 16:24:23 $ + * last change: $Author: cl $ $Date: 2002-11-21 14:58:01 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -65,4 +65,18 @@ #define BTN_CANCEL 1 #define BTN_HELP 1 #define FI_DESCR 1 +#define FI_EXPORT_ALL_DESCR 2 +#define FI_EXPORT_BACKGROUNDS_DESCR 3 +#define FI_EXPORT_BACKGROUND_OBJECTS_DESCR 4 +#define FI_EXPORT_SLIDE_CONTENTS_DESCR 5 +#define FI_EXPORT_SOUND_DESCR 6 +#define FI_EXPORT_OLE_AS_JPEG_DESCR 7 +#define FI_EXPORT_MULTIPLE_FILES_DESCR 8 #define NUM_FLD_QUALITY 1 +#define BOOL_EXPORT_ALL 1 +#define BOOL_EXPORT_BACKGROUNDS 2 +#define BOOL_EXPORT_BACKGROUND_OBJECTS 3 +#define BOOL_EXPORT_SLIDE_CONTENTS 4 +#define BOOL_EXPORT_SOUND 5 +#define BOOL_EXPORT_OLE_AS_JPEG 6 +#define BOOL_EXPORT_MULTIPLE_FILES 7
\ No newline at end of file diff --git a/filter/source/flash/impswfdialog.hxx b/filter/source/flash/impswfdialog.hxx index 00147cdb8316..17acf61fb24d 100644 --- a/filter/source/flash/impswfdialog.hxx +++ b/filter/source/flash/impswfdialog.hxx @@ -2,9 +2,9 @@ * * $RCSfile: impswfdialog.hxx,v $ * - * $Revision: 1.1 $ + * $Revision: 1.2 $ * - * last change: $Author: cl $ $Date: 2002-10-24 16:24:24 $ + * last change: $Author: cl $ $Date: 2002-11-21 14:58:01 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -93,12 +93,29 @@ class ImpSWFDialog : public ModalDialog private: FixedInfo maFiDescr; NumericField maNumFldQuality; + FixedInfo maFiExportAllDescr; + CheckBox maCheckExportAll; + FixedInfo maFiExportBackgroundsDescr; + CheckBox maCheckExportBackgrounds; + FixedInfo maFiExportBackgroundObjectsDescr; + CheckBox maCheckExportBackgroundObjects; + FixedInfo maFiExportSlideContentsDescr; + CheckBox maCheckExportSlideContents; + FixedInfo maFiExportSoundDescr; + CheckBox maCheckExportSound; + FixedInfo maFiExportOLEAsJPEGDescr; + CheckBox maCheckExportOLEAsJPEG; + FixedInfo maFiExportMultipleFilesDescr; + CheckBox maCheckExportMultipleFiles; + OKButton maBtnOK; CancelButton maBtnCancel; HelpButton maBtnHelp; FilterConfigItem maConfigItem; + DECL_LINK( OnToggleCheckbox, CheckBox* ); + public: ImpSWFDialog( Window* pParent, ResMgr& rResMgr, com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& rFilterData ); diff --git a/filter/source/flash/impswfdialog.src b/filter/source/flash/impswfdialog.src index 924b86f2b921..8b5ae964e41d 100644 --- a/filter/source/flash/impswfdialog.src +++ b/filter/source/flash/impswfdialog.src @@ -2,9 +2,9 @@ * * $RCSfile: impswfdialog.src,v $ * - * $Revision: 1.1 $ + * $Revision: 1.2 $ * - * last change: $Author: cl $ $Date: 2002-10-24 16:24:25 $ + * last change: $Author: cl $ $Date: 2002-11-21 14:58:02 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -63,7 +63,7 @@ ModalDialog DLG_OPTIONS { - Size = MAP_APPFONT ( 159 , 92 ) ; + Size = MAP_APPFONT ( 200 , 200 ) ; OutputSize = TRUE ; SVLook = TRUE ; Moveable = TRUE ; @@ -72,25 +72,6 @@ ModalDialog DLG_OPTIONS Text [ ENGLISH ] = "Flash Optionen" ; Text [ english_us ] = "Flash Options" ; - OKButton BTN_OK - { - Pos = MAP_APPFONT ( 103 , 6 ) ; - Size = MAP_APPFONT ( 50 , 14 ) ; - TabStop = TRUE ; - DefButton = TRUE ; - }; - CancelButton BTN_CANCEL - { - Pos = MAP_APPFONT ( 103 , 23 ) ; - Size = MAP_APPFONT ( 50 , 14 ) ; - TabStop = TRUE ; - }; - HelpButton BTN_HELP - { - Pos = MAP_APPFONT ( 103 , 43 ) ; - Size = MAP_APPFONT ( 50 , 14 ) ; - TabStop = TRUE ; - }; FixedText FI_DESCR { Pos = MAP_APPFONT ( 12 , 14 ) ; @@ -135,4 +116,110 @@ ModalDialog DLG_OPTIONS Last = 100 ; Repeat = TRUE ; }; + CheckBox BOOL_EXPORT_ALL + { + Pos = MAP_APPFONT ( 12 , 65 ) ; + Size = MAP_APPFONT ( 10 , 14 ) ; + TabStop = TRUE ; + }; + FixedText FI_EXPORT_ALL_DESCR + { + Pos = MAP_APPFONT ( 25 , 65 ) ; + Size = MAP_APPFONT ( 150 , 16 ) ; + Text = "Export All Slides (Uncheck exports current slide)" ; + }; + CheckBox BOOL_EXPORT_MULTIPLE_FILES + { + Pos = MAP_APPFONT ( 12 , 80 ) ; + Size = MAP_APPFONT ( 10 , 14 ) ; + TabStop = TRUE ; + }; + FixedText FI_EXPORT_MULTIPLE_FILES_DESCR + { + Pos = MAP_APPFONT ( 25 , 80 ) ; + Size = MAP_APPFONT ( 150 , 16 ) ; + Text = "Export As Multiple Files" ; + }; + CheckBox BOOL_EXPORT_BACKGROUNDS + { + Pos = MAP_APPFONT ( 22 , 95 ) ; + Size = MAP_APPFONT ( 10 , 14 ) ; + TabStop = TRUE ; + }; + FixedText FI_EXPORT_BACKGROUNDS_DESCR + { + Pos = MAP_APPFONT ( 35 , 95 ) ; + Size = MAP_APPFONT ( 100 , 16 ) ; + Text = "Export Backgrounds" ; + }; + CheckBox BOOL_EXPORT_BACKGROUND_OBJECTS + { + Pos = MAP_APPFONT ( 22 , 107) ; + Size = MAP_APPFONT ( 10 , 14 ) ; + TabStop = TRUE ; + }; + FixedText FI_EXPORT_BACKGROUND_OBJECTS_DESCR + { + Pos = MAP_APPFONT ( 35 , 107) ; + Size = MAP_APPFONT ( 100 , 16 ) ; + Text = "Export Background Objects" ; + }; + CheckBox BOOL_EXPORT_SLIDE_CONTENTS + { + Pos = MAP_APPFONT ( 22 , 119 ) ; + Size = MAP_APPFONT ( 10 , 14 ) ; + TabStop = TRUE ; + }; + FixedText FI_EXPORT_SLIDE_CONTENTS_DESCR + { + Pos = MAP_APPFONT ( 35 , 119 ) ; + Size = MAP_APPFONT ( 100 , 16 ) ; + Text = "Export Slide Contents" ; + }; + CheckBox BOOL_EXPORT_SOUND + { + Pos = MAP_APPFONT ( 12 , 134 ) ; + Size = MAP_APPFONT ( 10 , 14 ) ; + TabStop = TRUE ; + }; + FixedText FI_EXPORT_SOUND_DESCR + { + Pos = MAP_APPFONT ( 25 , 134 ) ; + Size = MAP_APPFONT ( 100 , 16 ) ; + Text = "Export Verilogix Slide Annotations" ; + }; + CheckBox BOOL_EXPORT_OLE_AS_JPEG + { + Pos = MAP_APPFONT ( 12 , 146 ) ; + Size = MAP_APPFONT ( 10 , 14 ) ; + TabStop = TRUE ; + }; + FixedText FI_EXPORT_OLE_AS_JPEG_DESCR + { + Pos = MAP_APPFONT ( 25 , 146 ) ; + Size = MAP_APPFONT ( 100 , 16 ) ; + Text = "Export OLE Objects as JPEG images" ; + }; + + + OKButton BTN_OK + { + Pos = MAP_APPFONT ( 12 , 180 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + DefButton = TRUE ; + }; + CancelButton BTN_CANCEL + { + Pos = MAP_APPFONT ( 70 , 180 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + HelpButton BTN_HELP + { + Pos = MAP_APPFONT ( 140 , 180 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; + }; diff --git a/filter/source/flash/makefile.mk b/filter/source/flash/makefile.mk index a7813ef83f72..646de1291bbe 100644 --- a/filter/source/flash/makefile.mk +++ b/filter/source/flash/makefile.mk @@ -2,9 +2,9 @@ # # $RCSfile: makefile.mk,v $ # -# $Revision: 1.3 $ +# $Revision: 1.4 $ # -# last change: $Author: cl $ $Date: 2002-10-24 16:24:26 $ +# last change: $Author: cl $ $Date: 2002-11-21 14:58:02 $ # # The Contents of this file are made available subject to the terms of # either of the following licenses @@ -98,12 +98,12 @@ UNOTYPES=\ SRCFILES = impswfdialog.src -SLOFILES= $(SLO)$/filter.obj \ - $(SLO)$/writer.obj \ - $(SLO)$/writer1.obj \ - $(SLO)$/writer2.obj \ - $(SLO)$/uno.obj \ - $(SLO)$/exporter.obj \ +SLOFILES= $(SLO)$/swffilter.obj \ + $(SLO)$/swfwriter.obj \ + $(SLO)$/swfwriter1.obj \ + $(SLO)$/swfwriter2.obj \ + $(SLO)$/swfuno.obj \ + $(SLO)$/swfexporter.obj \ $(SLO)$/swfdialog.obj \ $(SLO)$/impswfdialog.obj diff --git a/filter/source/flash/swfexporter.cxx b/filter/source/flash/swfexporter.cxx new file mode 100644 index 000000000000..9d8d5c0f9b88 --- /dev/null +++ b/filter/source/flash/swfexporter.cxx @@ -0,0 +1,804 @@ +/************************************************************************* + * + * $RCSfile: swfexporter.cxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: cl $ $Date: 2002-11-21 14:58:02 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Christian Lippka (christian.lippka@sun.com) + * + * + ************************************************************************/ + +#ifndef _COM_SUN_STAR_AWT_RECTANGLE_HPP_ +#include <com/sun/star/awt/Rectangle.hpp> +#endif +#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_ +#include <com/sun/star/beans/PropertyValue.hpp> +#endif +#ifndef _COM_SUN_STAR_DRAWING_XMASTERPAGETARGET_HPP_ +#include <com/sun/star/drawing/XMasterPageTarget.hpp> +#endif +#ifndef _COM_SUN_STAR_DRAWING_XDRAWPAGESSUPPLIER_HPP_ +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#endif +#ifndef _COM_SUN_STAR_CONTAINER_XINDEXACCESS_HPP_ +#include <com/sun/star/container/XIndexAccess.hpp> +#endif +#ifndef _COM_SUN_STAR_DRAWING_XDRAWPAGESSUPPLIER_HPP_ +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#endif +#ifndef _COM_SUN_STAR_DOCUMENT_XFILTER_HPP_ +#include <com/sun/star/document/XFilter.hpp> +#endif +#ifndef _COM_SUN_STAR_DOCUMENT_XEXPORTER_HPP_ +#include <com/sun/star/document/XExporter.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XMODEL_HPP_ +#include <com/sun/star/frame/XModel.hpp> +#endif +#ifndef _COM_SUN_STAR_TASK_XSTATUSINDICATORFACTORY_HPP_ +#include <com/sun/star/task/XStatusIndicatorFactory.hpp> +#endif + +#ifndef _SV_GDIMTF_HXX +#include <vcl/gdimtf.hxx> +#endif + +#ifndef _UNOTOOLS_TEMPFILE_HXX +#include <unotools/tempfile.hxx> +#endif + +#ifndef _OSL_DIAGNOSE_H_ +#include <osl/diagnose.h> +#endif +#ifndef _OSL_FILE_HXX_ +#include <osl/file.hxx> +#endif +#ifndef _SV_METAACT_HXX +#include <vcl/metaact.hxx> +#endif + +#ifndef _WMF_HXX +#include <svtools/wmf.hxx> +#endif +#ifndef _FILTER_HXX +#include <svtools/Filter.hxx> +#endif + +#include "swfexporter.hxx" +#include "swfwriter.hxx" + +using rtl::OUString; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::presentation; +using namespace ::com::sun::star::task; +using namespace ::std; +using namespace ::swf; + +using com::sun::star::lang::XMultiServiceFactory; +using com::sun::star::io::XOutputStream; +using com::sun::star::beans::PropertyValue; +using com::sun::star::container::XIndexAccess; +using com::sun::star::beans::XPropertySet; +using com::sun::star::lang::XComponent; +using com::sun::star::lang::IllegalArgumentException; +using com::sun::star::document::XExporter; +using com::sun::star::document::XFilter; +using com::sun::star::frame::XModel; + +// ----------------------------------------------------------------------------- + +static const char* pszCurrentPageName = "current_page"; // TODO: Size optimize later? +static const char* pszLastPageName = "last_page"; // TODO: Size optimize later? + +// ----------------------------------------------------------------------------- + +PageInfo::PageInfo() +: meFadeEffect( FadeEffect_NONE ), + meFadeSpeed( AnimationSpeed_MEDIUM ), + mnDuration( 0 ), + mnChange( 0 ) +{ +} + +// ----------------------------------------------------------------------------- + +PageInfo::~PageInfo() +{ + vector<ShapeInfo*>::iterator aIter( maShapesVector.begin() ); + const vector<ShapeInfo*>::iterator aEnd( maShapesVector.end() ); + while( aIter != aEnd ) + { + delete (*aIter++); + } +} + +// ----------------------------------------------------------------------------- + +void PageInfo::addShape( ShapeInfo* pShapeInfo ) +{ + maShapesVector.push_back( pShapeInfo ); +} + + +// ----------------------------------------------------------------------------- + +FlashExporter::FlashExporter(const Reference< XMultiServiceFactory > &rxMSF, sal_Int32 nJPEGCompressMode, sal_Bool bExportOLEAsJPEG) +: mxMSF( rxMSF ), mpWriter( NULL ), mnJPEGcompressMode(nJPEGCompressMode), mbExportOLEAsJPEG(bExportOLEAsJPEG) +{ +} + +// ----------------------------------------------------------------------------- + +FlashExporter::~FlashExporter() +{ + Flush(); +} + +void FlashExporter::Flush() +{ + delete mpWriter; + mpWriter = NULL; + + maPagesMap.clear(); +} + +// ----------------------------------------------------------------------------- + +const sal_uInt16 cBackgroundDepth = 2; +const sal_uInt16 cBackgroundObjectsDepth = 3; +const sal_uInt16 cPageObjectsDepth = 4; +const sal_uInt16 cWaitButtonDepth = 10; + +sal_Bool FlashExporter::exportAll( Reference< XComponent > xDoc, Reference< XOutputStream > &xOutputStream, Reference< XStatusIndicator> &xStatusIndicator ) +{ + Reference< XDrawPagesSupplier > xDrawPagesSupplier(xDoc, UNO_QUERY); + if(!xDrawPagesSupplier.is()) + return sal_False; + + Reference< XIndexAccess > xDrawPages( xDrawPagesSupplier->getDrawPages(), UNO_QUERY ); + if(!xDrawPages.is()) + return sal_False; + + Reference< XDrawPage > xDrawPage; + xDrawPages->getByIndex(0) >>= xDrawPage; + + Reference< XPropertySet > xProp( xDrawPage, UNO_QUERY ); + try + { + xProp->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("Width") ) ) >>= mnDocWidth; + xProp->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("Height") ) ) >>= mnDocHeight; + + delete mpWriter; + mpWriter = new Writer( 14400, 10800, mnDocWidth, mnDocHeight, mnJPEGcompressMode ); + } + catch( exception& ) + { + OSL_ASSERT( false ); + } + + const sal_Int32 nPageCount = xDrawPages->getCount(); + sal_uInt16 nPage; + xStatusIndicator->start(OUString( RTL_CONSTASCII_USTRINGPARAM( "Saving :" )), nPageCount); + for( nPage = 0; nPage < nPageCount; nPage++) + { + xStatusIndicator->setValue( nPage ); + xDrawPages->getByIndex(nPage) >>= xDrawPage; + + if( !xDrawPage.is()) + continue; + + Reference< XPropertySet > xPropSet( xDrawPage, UNO_QUERY ); + sal_Bool bVisible; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("Visible") ) ) >>= bVisible; + if( !bVisible ) + continue; + + exportBackgrounds( xDrawPage, nPage, false ); + exportBackgrounds( xDrawPage, nPage, true ); + + maPagesMap[nPage].mnForegroundID = mpWriter->startSprite(); + exportDrawPageContents( xDrawPage, false ); + mpWriter->endSprite(); + + // AS: If the background is different than the previous slide, + // we have to remove the old one and place the new one. + if (nPage) + { + if (maPagesMap[nPage].mnBackgroundID != maPagesMap[nPage-1].mnBackgroundID) + { + mpWriter->removeShape(cBackgroundDepth); + mpWriter->placeShape( maPagesMap[nPage].mnBackgroundID, cBackgroundDepth, 0, 0 ); + } + + if (maPagesMap[nPage].mnObjectsID != maPagesMap[nPage-1].mnObjectsID) + { + mpWriter->removeShape(cBackgroundObjectsDepth); + mpWriter->placeShape( maPagesMap[nPage].mnObjectsID, cBackgroundObjectsDepth, 0, 0 ); + } + + // AS: Remove the Foreground of the previous slide. + mpWriter->removeShape(cPageObjectsDepth); + } + else + { + mpWriter->placeShape( maPagesMap[nPage].mnBackgroundID, cBackgroundDepth, 0, 0 ); + mpWriter->placeShape( maPagesMap[nPage].mnObjectsID, cBackgroundObjectsDepth, 0, 0 ); + } + + mpWriter->placeShape( maPagesMap[nPage].mnForegroundID, cPageObjectsDepth, 0, 0 ); + + mpWriter->waitOnClick( cWaitButtonDepth ); + mpWriter->showFrame(); + } + + mpWriter->removeShape( cBackgroundDepth ); + mpWriter->removeShape( cBackgroundObjectsDepth ); + mpWriter->removeShape( cPageObjectsDepth ); + mpWriter->gotoFrame( 0 ); + mpWriter->showFrame(); + + mpWriter->storeTo( xOutputStream ); + + return sal_True; +} + + +sal_Bool FlashExporter::exportSlides( Reference< XDrawPage > xDrawPage, Reference< XOutputStream > &xOutputStream, sal_uInt16 nPage) +{ + Reference< XPropertySet > xPropSet( xDrawPage, UNO_QUERY ); + if( !xDrawPage.is() || !xPropSet.is() ) + return sal_False; + + try + { + if( NULL == mpWriter ) + { + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("Width") ) ) >>= mnDocWidth; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("Height") ) ) >>= mnDocHeight; + + mpWriter = new Writer( 14400, 10800, mnDocWidth, mnDocHeight, mnJPEGcompressMode ); + } + + sal_Bool bVisible; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("Visible") ) ) >>= bVisible; + if( !bVisible ) + return sal_False; + } + catch( exception& ) + { + OSL_ASSERT( false ); + } + + exportDrawPageContents(xDrawPage, true); + + mpWriter->storeTo( xOutputStream ); + + return sal_True; +} + +sal_uInt16 FlashExporter::exportBackgrounds( Reference< XDrawPage > xDrawPage, Reference< XOutputStream > &xOutputStream, sal_uInt16 nPage, sal_Bool bExportObjects ) +{ + Reference< XPropertySet > xPropSet( xDrawPage, UNO_QUERY ); + if( !xDrawPage.is() || !xPropSet.is() ) + return sal_False; + + if( NULL == mpWriter ) + { + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("Width") ) ) >>= mnDocWidth; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("Height") ) ) >>= mnDocHeight; + + mpWriter = new Writer( 14400, 10800, mnDocWidth, mnDocHeight, mnJPEGcompressMode ); + } + + sal_uInt16 ret = exportBackgrounds(xDrawPage, nPage, bExportObjects); + + if (ret != nPage) + return ret; + + if (bExportObjects) + mpWriter->placeShape( maPagesMap[nPage].mnObjectsID, _uInt16(1), 0, 0 ); + else + mpWriter->placeShape( maPagesMap[nPage].mnBackgroundID, _uInt16(0), 0, 0 ); + + mpWriter->storeTo( xOutputStream ); + + return nPage; +} + +sal_uInt16 FlashExporter::exportBackgrounds( Reference< XDrawPage > xDrawPage, sal_uInt16 nPage, sal_Bool bExportObjects ) +{ + Reference< XPropertySet > xPropSet( xDrawPage, UNO_QUERY ); + if( !xDrawPage.is() || !xPropSet.is() ) + return sal_False; + + sal_Bool bBackgroundVisible, bBackgroundObjectsVisible; + + try + { + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("IsBackgroundVisible") ) ) >>= bBackgroundVisible; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("IsBackgroundObjectsVisible") ) ) >>= bBackgroundObjectsVisible; + } + catch( exception& ) + { + OSL_ASSERT( false ); + } + + + if (bExportObjects) + { + if (bBackgroundObjectsVisible) + { + Reference< XMasterPageTarget > xMasterPageTarget( xDrawPage, UNO_QUERY ); + if( !xMasterPageTarget.is() ) + { + maPagesMap[nPage].mnObjectsID = -1; + return -1; + } + + sal_uInt16 ret = exportMasterPageObjects(nPage, xMasterPageTarget->getMasterPage()); + if (ret != nPage) + return ret; + } + else + { + maPagesMap[nPage].mnObjectsID = -1; + return -1; + } + } + else + { + if (bBackgroundVisible) + { + sal_uInt16 ret = exportDrawPageBackground(nPage, xDrawPage); + + if (ret != nPage) + return ret; + } + else + { + maPagesMap[nPage].mnBackgroundID = -1; + return -1; + } + } + + return nPage; +} + +#ifdef AUGUSTUS +sal_Bool FlashExporter::exportSound( Reference< XOutputStream > &xOutputStream, const char* wavfilename ) +{ + try + { + delete mpWriter; + mpWriter = new Writer( 0, 0, 0, 0 ); + } + catch( exception& ) + { + OSL_ASSERT( false ); + } + + if (!mpWriter->streamSound(wavfilename)) + return sal_False; + else + mpWriter->storeTo( xOutputStream ); + + return sal_True; +} +#endif // defined AUGUSTUS + +// ----------------------------------------------------------------------------- + +sal_Int32 nPlaceDepth; +// AS: A Slide can have a private background or use its masterpage's background. +// We use the checksums on the metafiles to tell if backgrounds are the same and +// should be reused. The return value indicates which slide's background to use. +// If the return value != nPage, then there is no background (if == -1) or the +// background has already been exported. +sal_uInt16 FlashExporter::exportDrawPageBackground(sal_uInt16 nPage, Reference< XDrawPage >& xPage) +{ + sal_uInt16 rBackgroundID; + + GDIMetaFile aMtfPrivate, aMtfMaster; + Reference< XComponent > xComponent( xPage, UNO_QUERY ); + + Reference< XMasterPageTarget > xMasterPageTarget( xPage, UNO_QUERY ); + if( !xMasterPageTarget.is() ) + return -1; + + Reference< XDrawPage > xMasterPage = xMasterPageTarget->getMasterPage(); + if( !xMasterPage.is()) + return -1; + + Reference< XComponent > xCompMaster( xMasterPage, UNO_QUERY ); + + getMetaFile( xCompMaster, aMtfMaster, true ); + getMetaFile( xComponent, aMtfPrivate, true ); + + sal_uInt32 masterchecksum = aMtfMaster.GetChecksum(); + sal_uInt32 privatechecksum = aMtfPrivate.GetChecksum(); + + // AS: If the slide has its own background + if (privatechecksum) + { + ChecksumCache::iterator it = gPrivateCache.find(privatechecksum); + + // AS: and we've previously encountered this background, just return + // the previous index. + if (gPrivateCache.end() != it) + { + maPagesMap[nPage].mnBackgroundID = + maPagesMap[it->second].mnBackgroundID; + return it->second; + } + else + { + // AS: Otherwise, cache this checksum. + gPrivateCache[privatechecksum] = nPage; + + rBackgroundID = mpWriter->defineShape( aMtfPrivate ); + + mpWriter->placeShape( rBackgroundID, _uInt16(0), 0, 0 ); + + maPagesMap[nPage].mnBackgroundID = rBackgroundID; + return nPage; + } + } + + // AS: Ok, no private background. Use the master page's. + // AS: Have we already exported this master page? + ChecksumCache::iterator it = gMasterCache.find(masterchecksum); + + if (gMasterCache.end() != it) + { + maPagesMap[nPage].mnBackgroundID = + maPagesMap[it->second].mnBackgroundID; + + return it->second; // AS: Yes, so don't export it again. + } + + gMasterCache[masterchecksum] = nPage; + + rBackgroundID = mpWriter->defineShape( aMtfMaster ); + + maPagesMap[nPage].mnBackgroundID = rBackgroundID; + + return nPage; +} + +sal_uInt16 FlashExporter::exportMasterPageObjects(sal_uInt16 nPage, Reference< XDrawPage >& xMasterPage) +{ + Reference< XShapes > xShapes( xMasterPage, UNO_QUERY ); + + sal_uInt32 shapesum = ActionSummer(xShapes); + + ChecksumCache::iterator it = gObjectCache.find(shapesum); + + if (gObjectCache.end() != it) + { + maPagesMap[nPage].mnObjectsID = + maPagesMap[it->second].mnObjectsID; + + return it->second; // AS: Yes, so don't export it again. + } + + gObjectCache[shapesum] = nPage; + + sal_uInt16 rObjectsID = mpWriter->startSprite(); + exportDrawPageContents( xMasterPage, sal_False ); + mpWriter->endSprite(); + + maPagesMap[nPage].mnObjectsID = rObjectsID; + + return nPage; +} + +// ----------------------------------------------------------------------------- + +/** export's the definition of the shapes inside this drawing page and adds the + shape infos to the current PageInfo */ +void FlashExporter::exportDrawPageContents( Reference< XDrawPage >& xPage, sal_Bool bStream ) +{ + Reference< XShapes > xShapes( xPage, UNO_QUERY ); + exportShapes(xShapes, bStream); +} + +// ----------------------------------------------------------------------------- + +/** export's the definition of the shapes inside this XShapes container and adds the + shape infos to the current PageInfo */ +void FlashExporter::exportShapes( Reference< XShapes >& xShapes, sal_Bool bStream) +{ + OSL_ENSURE( (xShapes->getCount() <= 0xffff), "overflow in FlashExporter::exportDrawPageContents()" ); + + sal_uInt16 nShapeCount = (sal_uInt16)min( xShapes->getCount(), (sal_Int32)0xffff ); + sal_uInt16 nShape; + + Reference< XShape > xShape; + + for( nShape = 0; nShape < nShapeCount; nShape++ ) + { + xShapes->getByIndex( nShape ) >>= xShape; + + if( xShape.is() ) + { + Reference< XShapes > xShapes( xShape, UNO_QUERY ); + if( xShapes.is() && xShape->getShapeType().equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("com.sun.star.drawing.GroupShape"))) + // export the contents of group shapes, but we only ever stream at the top + // recursive level anyway, so pass false for streaming. + exportShapes( xShapes, false); + else + exportShape( xShape); + } + + if (bStream) + mpWriter->showFrame(); + } +} + +// ----------------------------------------------------------------------------- + +/** export this shape definition and adds it's info to the current PageInfo */ +void FlashExporter::exportShape( Reference< XShape >& xShape) +{ + Reference< XPropertySet > xPropSet( xShape, UNO_QUERY ); + if( !xPropSet.is() ) + return; + + try + { + // skip empty presentation objects + sal_Bool bEmpty; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("IsEmptyPresentationObject") ) ) >>= bEmpty; + if( bEmpty ) + return; + } + catch( Exception& ) + { + // TODO: If we are exporting a draw, this property is not available + } + + try + { + com::sun::star::awt::Point aPosition( xShape->getPosition() ); + com::sun::star::awt::Size aSize( xShape->getSize() ); + + com::sun::star::awt::Rectangle aBoundRect;//(aPosition.X, aPosition.Y, aSize.Width, aSize.Height); + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("BoundRect") ) ) >>= aBoundRect; + + ShapeInfo* pShapeInfo = new ShapeInfo(); + pShapeInfo->mnX = aBoundRect.X; + pShapeInfo->mnY = aBoundRect.Y; + pShapeInfo->mnWidth = aBoundRect.Width; + pShapeInfo->mnHeight = aBoundRect.Height; + + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("Bookmark") ) ) >>= pShapeInfo->maBookmark; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("DimColor") ) ) >>= pShapeInfo->mnDimColor; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("DimHide") ) ) >>= pShapeInfo->mbDimHide; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("DimPrevious") ) ) >>= pShapeInfo->mbDimPrev; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("Effect") ) ) >>= pShapeInfo->meEffect; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("PlayFull") ) ) >>= pShapeInfo->mbPlayFull; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("PresentationOrder") ) ) >>= pShapeInfo->mnPresOrder; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("Sound") ) ) >>= pShapeInfo->maSoundURL; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("SoundOn") ) ) >>= pShapeInfo->mbSoundOn; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("Speed") ) ) >>= pShapeInfo->meEffectSpeed; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("TextEffect") ) ) >>= pShapeInfo->meTextEffect; + xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("TransparentColor") ) ) >>= pShapeInfo->mnBlueScreenColor; + +// long ZOrder; +// xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("ZOrder") ) ) >>= ZOrder; + + GDIMetaFile aMtf; + Reference< XComponent > xComponent( xShape, UNO_QUERY ); + + bool bIsOleObject = xShape->getShapeType().equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("com.sun.star.presentation.OLE2Shape")) + || xShape->getShapeType().equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("com.sun.star.drawing.OLE2Shape")); + + getMetaFile( xComponent, aMtf ); + + // AS: If it's an OLE object, then export a JPEG if the user requested. + // In this case, we use the bounding rect info generated in the first getMetaFile + // call, and then clear the metafile and add a BMP action. This may be turned into + // a JPEG, depending on what gives the best compression. + if (bIsOleObject && mbExportOLEAsJPEG) + getMetaFile( xComponent, aMtf, false, true ); + + sal_uInt16 nID; + sal_uInt32 checksum = aMtf.GetChecksum(); + + ChecksumCache::iterator it = gMetafileCache.find(checksum); + + if (gMetafileCache.end() != it) + nID = it->second; + else + { + nID = mpWriter->defineShape( aMtf ); + gMetafileCache[checksum] = nID; + } + + if (!nID) + return; + + pShapeInfo->mnID = nID; + +// pPageInfo->addShape( pShapeInfo ); + + mpWriter->placeShape( pShapeInfo->mnID, _uInt16(nPlaceDepth++), pShapeInfo->mnX, pShapeInfo->mnY ); + + delete pShapeInfo; + } + catch( Exception& ) + { + OSL_ASSERT(false); + } +} + +// ----------------------------------------------------------------------------- + +bool FlashExporter::getMetaFile( Reference< XComponent >&xComponent, GDIMetaFile& rMtf, bool bOnlyBackground /* = false */, bool bExportAsJPEG /* = false */) +{ + if( !mxGraphicExporter.is() ) + mxGraphicExporter = Reference< XExporter >::query( mxMSF->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.GraphicExportFilter") ) ) ); + + Reference< XFilter > xFilter( mxGraphicExporter, UNO_QUERY ); + + utl::TempFile aFile; + aFile.EnableKillingFile(); + + Sequence< PropertyValue > aFilterData( false && bExportAsJPEG ? 2 : 1); + aFilterData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM("Version") ); + aFilterData[0].Value <<= (sal_Int32)6000; + + if (false && bExportAsJPEG) + { + aFilterData[1].Name = OUString( RTL_CONSTASCII_USTRINGPARAM("Translucent") ); + aFilterData[1].Value <<= (sal_Bool)sal_True; + } + + Sequence< PropertyValue > aDescriptor( bOnlyBackground ? 4 : 3 ); + aDescriptor[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM("FilterName") ); + + // AS: If we've been asked to export as an image, then use the BMP filter. + // Otherwise, use SVM. This is useful for things that don't convert well as + // metafiles, like the occasional OLE object. + aDescriptor[0].Value <<= OUString( RTL_CONSTASCII_USTRINGPARAM(bExportAsJPEG ? "PNG" : "SVM") ); + + aDescriptor[1].Name = OUString( RTL_CONSTASCII_USTRINGPARAM("URL") ); + aDescriptor[1].Value <<= OUString( aFile.GetURL() ); + aDescriptor[2].Name = OUString( RTL_CONSTASCII_USTRINGPARAM("FilterData") ); + aDescriptor[2].Value <<= aFilterData; + if( bOnlyBackground ) + { + aDescriptor[3].Name = OUString( RTL_CONSTASCII_USTRINGPARAM("ExportOnlyBackground") ); + aDescriptor[3].Value <<= (sal_Bool)bOnlyBackground; + } + mxGraphicExporter->setSourceDocument( xComponent ); + xFilter->filter( aDescriptor ); + + if (bExportAsJPEG) + { + Graphic aGraphic; + GraphicFilter aFilter(false); + + USHORT nRet = aFilter.ImportGraphic( aGraphic, String(aFile.GetURL()), *aFile.GetStream( STREAM_READ ) ); + BitmapEx rBitmapEx( aGraphic.GetBitmap(), Color(255,255,255) ); + + sal_Bool bHasAlpha = rBitmapEx.IsAlpha(); + sal_Bool bIsTransparent = rBitmapEx.IsTransparent(); + + Rectangle clipRect; + for( ULONG i = 0, nCount = rMtf.GetActionCount(); i < nCount; i++ ) + { + const MetaAction* pAction = rMtf.GetAction( i ); + const USHORT nType = pAction->GetType(); + + switch( nType ) + { + case( META_ISECTRECTCLIPREGION_ACTION ): + { + const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*) pAction; + clipRect = pA->GetRect(); + i = nCount; + break; + } + } + } + MetaBmpExScaleAction *pmetaAct = new MetaBmpExScaleAction(Point(clipRect.Left(), clipRect.Top()), Size(clipRect.GetWidth(), clipRect.GetHeight()), rBitmapEx); + + rMtf.Clear(); + rMtf.AddAction(pmetaAct); + + } + else + rMtf.Read( *aFile.GetStream( STREAM_READ ) ); + + int icount = rMtf.GetActionCount(); + return icount != 0; +} + +sal_uInt32 FlashExporter::ActionSummer(Reference< XShape >& xShape) +{ + Reference< XShapes > xShapes( xShape, UNO_QUERY ); + + if( xShapes.is() ) + { + return ActionSummer(xShapes); + } + else + { + Reference< XComponent > xComponentShape( xShape, UNO_QUERY ); + + GDIMetaFile aMtf; + getMetaFile( xComponentShape, aMtf); + + return aMtf.GetChecksum(); + } +} + +sal_uInt32 FlashExporter::ActionSummer(Reference< XShapes >& xShapes) +{ + sal_uInt32 nShapeCount = xShapes->getCount(); + sal_uInt32 shapecount = 0; + + Reference< XShape > xShape2; + + for( sal_uInt16 nShape = 0; nShape < nShapeCount; nShape++ ) + { + xShapes->getByIndex( nShape ) >>= xShape2; + + shapecount += ActionSummer(xShape2); + } + + return shapecount; +}
\ No newline at end of file diff --git a/filter/source/flash/swfexporter.hxx b/filter/source/flash/swfexporter.hxx new file mode 100644 index 000000000000..068021dd9d15 --- /dev/null +++ b/filter/source/flash/swfexporter.hxx @@ -0,0 +1,270 @@ +/************************************************************************* + * + * $RCSfile: swfexporter.hxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: cl $ $Date: 2002-11-21 14:58:02 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Christian Lippka (christian.lippka@sun.com) + * + * + ************************************************************************/ +#ifndef _FLASH_EXPORTER_HXX +#define _FLASH_EXPORTER_HXX + +#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_ +#include <com/sun/star/beans/XPropertySet.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_ +#include <com/sun/star/lang/XComponent.hpp> +#endif +#ifndef _COM_SUN_STAR_IO_XOUTPUTSTREAM_HPP_ +#include <com/sun/star/io/XOutputStream.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_ +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#endif +#ifndef _COM_SUN_STAR_DOCUMENT_XEXPORTER_HPP_ +#include <com/sun/star/document/XExporter.hpp> +#endif +#ifndef _COM_SUN_STAR_DRAWING_XDRAWPAGE_HPP_ +#include <com/sun/star/drawing/XDrawPage.hpp> +#endif +#ifndef _COM_SUN_STAR_PRESENTATION_ANIMATIONEFFECT_HPP_ +#include <com/sun/star/presentation/AnimationEffect.hpp> +#endif +#ifndef _COM_SUN_STAR_PRESENTATION_ANIMATIONSPEED_HPP_ +#include <com/sun/star/presentation/AnimationSpeed.hpp> +#endif +#ifndef _COM_SUN_STAR_PRESENTATION_CLICKACTION_HPP_ +#include <com/sun/star/presentation/ClickAction.hpp> +#endif +#ifndef _COM_SUN_STAR_PRESENTATION_FADEEFFECT_HPP_ +#include <com/sun/star/presentation/FadeEffect.hpp> +#endif + +#ifndef _OSL_FILE_HXX_ +#include <osl/file.hxx> +#endif + +#include <vector> +#include <map> + +#include <stdio.h> + +typedef ::std::map<sal_uInt32, sal_uInt16> ChecksumCache; + +class GDIMetaFile; + +inline ::rtl::OUString STR(const sal_Char * in) +{ + return ::rtl::OUString::createFromAscii(in); +} + +inline ::rtl::OUString VAL(sal_Int32 in) +{ + return ::rtl::OUString::valueOf(in); +} + +namespace swf { + +class Writer; +// ----------------------------------------------------------------------------- + +class ShapeInfo +{ +public: + sal_uInt16 mnID; // the character id for the sprite definition of this shape + + sal_Int32 mnX; + sal_Int32 mnY; + + sal_Int32 mnWidth; + sal_Int32 mnHeight; + + ::com::sun::star::presentation::AnimationEffect meEffect; + ::com::sun::star::presentation::AnimationEffect meTextEffect; + ::com::sun::star::presentation::AnimationSpeed meEffectSpeed; + + sal_Int32 mnPresOrder; + + ::com::sun::star::presentation::ClickAction meClickAction; + ::rtl::OUString maBookmark; + + sal_Int32 mnDimColor; + sal_Bool mbDimHide; + sal_Bool mbDimPrev; + + sal_Bool mbSoundOn; + sal_Bool mbPlayFull; + ::rtl::OUString maSoundURL; + + sal_Int32 mnBlueScreenColor; + + ShapeInfo() : + mnID(0), mnX(0), mnY(0), + meEffect( ::com::sun::star::presentation::AnimationEffect_NONE ), + meTextEffect( ::com::sun::star::presentation::AnimationEffect_NONE ), + meEffectSpeed( ::com::sun::star::presentation::AnimationSpeed_MEDIUM ), + mnPresOrder( 0 ), + meClickAction( ::com::sun::star::presentation::ClickAction_NONE ), + mnDimColor( 0 ), + mbDimHide( false ), + mbDimPrev( false ), + mbSoundOn( false ), + mbPlayFull( false ), + mnBlueScreenColor( 0 ) {} +}; + +typedef ::std::vector<ShapeInfo*> ShapeInfoVector; + +// ----------------------------------------------------------------------------- + +struct ShapeAnimationInfo +{ + ShapeInfo* mpShapeInfo; + sal_uInt16 mnDepth; + + ShapeAnimationInfo( ShapeInfo* pShapeInfo, sal_uInt16 nDepth ) : mpShapeInfo( pShapeInfo ), mnDepth( nDepth ) {} +}; + +typedef std::vector<ShapeAnimationInfo> ShapeAnimationInfoVector; + +// ----------------------------------------------------------------------------- + +struct PageInfo +{ + sal_uInt16 mnBackgroundID; + sal_uInt16 mnObjectsID; + sal_uInt16 mnForegroundID; + + sal_Int32 mnChange; + + ::com::sun::star::presentation::FadeEffect meFadeEffect; + ::com::sun::star::presentation::AnimationSpeed meFadeSpeed; + + sal_Int32 mnDuration; + + sal_Bool mbBackgroundVisible; + sal_Bool mbBackgroundObjectsVisible; + + ShapeInfoVector maShapesVector; + + PageInfo(); + ~PageInfo(); + + void addShape( ShapeInfo* pShapeInfo ); + +}; + +// ----------------------------------------------------------------------------- + +typedef ::std::map<sal_uInt32, PageInfo> PageInfoMap; + +// ----------------------------------------------------------------------------- + +class FlashExporter +{ +public: + FlashExporter( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& rxMSF, sal_Int32 nJPEGCompressMode = -1, sal_Bool bExportOLEAsJPEG = false); + ~FlashExporter(); + + void Flush(); + + sal_Bool exportAll( ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > xDoc, com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > &xOutputStream, ::com::sun::star::uno::Reference< ::com::sun::star::task::XStatusIndicator> &xStatusIndicator ); + sal_Bool exportSlides( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage > xDrawPage, com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > &xOutputStream, sal_uInt16 nPage); + sal_uInt16 exportBackgrounds( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage > xDrawPage, com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > &xOutputStream, sal_uInt16 nPage, sal_Bool bExportObjects ); + sal_uInt16 exportBackgrounds( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage > xDrawPage, sal_uInt16 nPage, sal_Bool bExportObjects ); + +#ifdef AUGUSTUS + sal_Bool exportSound( com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > &xOutputStream, const char* wavfilename ); +#endif + + ChecksumCache gMasterCache; + ChecksumCache gPrivateCache; + ChecksumCache gObjectCache; + ChecksumCache gMetafileCache; + +private: + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > mxMSF; + ::com::sun::star::uno::Reference< ::com::sun::star::document::XExporter > mxGraphicExporter; + + PageInfoMap maPagesMap; + + sal_uInt16 exportDrawPageBackground(sal_uInt16 nPage, ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& xPage); + sal_uInt16 exportMasterPageObjects(sal_uInt16 nPage, ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& xMasterPage); + + void exportDrawPageContents( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage >& xPage, sal_Bool bStream ); + void exportShapes( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xShapes, sal_Bool bStream ); + void exportShape( ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xShape); + + sal_uInt32 ActionSummer(::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xShape); + sal_uInt32 ActionSummer(::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xShapes); + + void animateShape( ShapeAnimationInfo& rAnimInfo ); + void animatePage( PageInfo* pPageInfo ); + + bool getMetaFile( ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >&xComponent, GDIMetaFile& rMtf, bool bOnlyBackground = false, bool bExportAsJPEG = false ); + + Writer* mpWriter; + + sal_Int32 mnDocWidth; + sal_Int32 mnDocHeight; + + sal_Int32 mnJPEGcompressMode; + + sal_Bool mbExportOLEAsJPEG; +}; + +} + +#endif diff --git a/filter/source/flash/swffilter.cxx b/filter/source/flash/swffilter.cxx new file mode 100644 index 000000000000..61fcfc757aa9 --- /dev/null +++ b/filter/source/flash/swffilter.cxx @@ -0,0 +1,601 @@ +/************************************************************************* + * + * $RCSfile: swffilter.cxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: cl $ $Date: 2002-11-21 14:58:02 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Christian Lippka (christian.lippka@sun.com) + * + * + ************************************************************************/ + +#ifndef _COM_SUN_STAR_FRAME_XDESKTOP_HPP_ +#include <com/sun/star/frame/XDesktop.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XSTORABLE_HPP_ +#include <com/sun/star/frame/XStorable.hpp> +#endif +#ifndef _COM_SUN_STAR_DOCUMENT_XFILTER_HPP_ +#include <com/sun/star/document/XFilter.hpp> +#endif +#ifndef _COM_SUN_STAR_DOCUMENT_XEXPORTER_HPP_ +#include <com/sun/star/document/XExporter.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_XINITIALIZATION_HPP_ +#include <com/sun/star/lang/XInitialization.hpp> +#endif +#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_ +#include <com/sun/star/lang/XServiceInfo.hpp> +#endif +#ifndef _COM_SUN_STAR_DRAWING_XDRAWPAGESSUPPLIER_HPP_ +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#endif +#ifndef _COM_SUN_STAR_DRAWING_XDRAWVIEW_HPP_ +#include <com/sun/star/drawing/XDrawView.hpp> +#endif +#ifndef _COM_SUN_STAR_CONTAINER_XINDEXACCESS_HPP_ +#include <com/sun/star/container/XIndexAccess.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XMODEL_HPP_ +#include <com/sun/star/frame/XModel.hpp> +#endif +#ifndef _COM_SUN_STAR_TASK_XSTATUSINDICATORFACTORY_HPP_ +#include <com/sun/star/task/XStatusIndicatorFactory.hpp> +#endif +#ifndef _COM_SUN_STAR_IO_XOUTPUTSTREAM_HPP_ +#include <com/sun/star/io/XOutputStream.hpp> +#endif +#ifndef _CPPUHELPER_IMPLBASE1_HXX_ +#include <cppuhelper/implbase1.hxx> +#endif + +#ifndef _CPPUHELPER_IMPLBASE4_HXX_ +#include <cppuhelper/implbase4.hxx> +#endif + +#ifndef _OSL_FILE_HXX_ +#include <osl/file.hxx> +#endif + +#include "swfexporter.hxx" + +//#include <stdlib.h> +//#include <windows.h> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::presentation; +using namespace ::com::sun::star::task; + +using ::rtl::OUString; +using ::rtl::OString; +using ::com::sun::star::lang::XComponent; +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::io::XOutputStream; +using ::com::sun::star::container::XIndexAccess; +using ::osl::FileBase; +using ::com::sun::star::frame::XModel; + +namespace swf { + +typedef ::cppu::WeakImplHelper1<com::sun::star::io::XOutputStream> OslOutputStreamWrapper_Base; + // needed for some compilers +class OslOutputStreamWrapper : public OslOutputStreamWrapper_Base +{ + osl::File mrFile; + +public: + OslOutputStreamWrapper(const OUString& sFileName) : mrFile(sFileName) + { + osl_removeFile(sFileName.pData); + mrFile.open(OpenFlag_Create|OpenFlag_Write); + } + + // stario::XOutputStream + virtual void SAL_CALL writeBytes( const ::com::sun::star::uno::Sequence< sal_Int8 >& aData ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL flush( ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeOutput( ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); +}; + +void SAL_CALL OslOutputStreamWrapper::writeBytes( const ::com::sun::star::uno::Sequence< sal_Int8 >& aData ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) +{ + sal_uInt64 uBytesToWrite = aData.getLength(); + sal_uInt64 uBytesWritten = 0; + + sal_Int8 const * pBuffer = aData.getConstArray(); + + while( uBytesToWrite ) + { + osl::File::RC eRC = mrFile.write( pBuffer, uBytesToWrite, uBytesWritten); + + switch( eRC ) + { + case osl::File::E_INVAL: // the format of the parameters was not valid + case osl::File::E_FBIG: // File too large + + case osl::File::E_AGAIN: // Operation would block + case osl::File::E_BADF: // Bad file + case osl::File::E_FAULT: // Bad address + case osl::File::E_INTR: // function call was interrupted + case osl::File::E_IO: // I/O error + case osl::File::E_NOLCK: // No record locks available + case osl::File::E_NOLINK: // Link has been severed + case osl::File::E_NOSPC: // No space left on device + case osl::File::E_NXIO: // No such device or address + throw com::sun::star::io::IOException(); // TODO: Better error handling + } + + uBytesToWrite -= uBytesWritten; + pBuffer += uBytesWritten; + } +} + +void SAL_CALL OslOutputStreamWrapper::flush( ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) +{ +} + +void SAL_CALL OslOutputStreamWrapper::closeOutput( ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) +{ + osl::File::RC eRC = mrFile.close(); + + switch( eRC ) + { + case osl::File::E_INVAL: // the format of the parameters was not valid + + case osl::File::E_BADF: // Bad file + case osl::File::E_INTR: // function call was interrupted + case osl::File::E_NOLINK: // Link has been severed + case osl::File::E_NOSPC: // No space left on device + case osl::File::E_IO: // I/O error + throw com::sun::star::io::IOException(); // TODO: Better error handling + } +} + +// ----------------------------------------------------------------------------- + +class FlashExportFilter : public cppu::WeakImplHelper4 +< + com::sun::star::document::XFilter, + com::sun::star::document::XExporter, + com::sun::star::lang::XInitialization, + com::sun::star::lang::XServiceInfo +> +{ + Reference< XComponent > mxDoc; + Reference< XMultiServiceFactory > mxMSF; + Reference< XStatusIndicator> mxStatusIndicator; + + osl::File* mpFile; + +public: + FlashExportFilter( const Reference< XMultiServiceFactory > &rxMSF); + + // XFilter + virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& aDescriptor ) throw(RuntimeException); + + sal_Bool ExportAsMultipleFiles( const Sequence< PropertyValue >& aDescriptor ); + sal_Bool ExportAsSingleFile( const Sequence< PropertyValue >& aDescriptor ); + + virtual void SAL_CALL cancel( ) throw (RuntimeException); + + // XExporter + virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) throw(IllegalArgumentException, RuntimeException); + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw(Exception, 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); +}; + +// ----------------------------------------------------------------------------- + +FlashExportFilter::FlashExportFilter(const Reference< XMultiServiceFactory > &rxMSF) +: mxMSF( rxMSF ) +{ +} + + +// ----------------------------------------------------------------------------- + +OUString exportBackground(FlashExporter &aFlashExporter, Reference< XDrawPage > xDrawPage, OUString sPath, sal_uInt32 nPage, const char* suffix) +{ + OUString filename = STR("slide") + VAL(nPage+1) + STR(suffix) + STR(".swf"); + OUString fullpath = sPath + STR("/") + filename; + + // AS: If suffix is "o" then the last paramter is true (for exporting objects). + Reference<XOutputStream> xOutputStreamWrap(*(new OslOutputStreamWrapper(fullpath)), UNO_QUERY); + sal_uInt32 nCached = aFlashExporter.exportBackgrounds( xDrawPage, xOutputStreamWrap, nPage, *suffix == 'o' ); + aFlashExporter.Flush(); + xOutputStreamWrap.clear(); + + if (nCached != nPage) + { + osl_removeFile(fullpath.pData); + if (-1 == nCached) + return STR("NULL"); + else + return STR("slide") + VAL(nCached+1) + STR(suffix) + STR(".swf"); + } + + return filename; +} + +template <typename TYPE> +TYPE findPropertyValue(const Sequence< PropertyValue >& aPropertySequence, const sal_Char* name, TYPE def) +{ + TYPE temp; + + sal_Int32 nLength = aPropertySequence.getLength(); + const PropertyValue * pValue = aPropertySequence.getConstArray(); + + for ( sal_Int32 i = 0 ; i < nLength; i++) + { + if ( pValue[i].Name.equalsAsciiL ( name, strlen(name) ) ) + { + pValue[i].Value >>= temp; + return temp; + } + } + + return def; +} + +sal_Bool SAL_CALL FlashExportFilter::filter( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aDescriptor ) + throw (RuntimeException) +{ + Sequence< PropertyValue > aFilterData; + + aFilterData = findPropertyValue<Sequence< PropertyValue > >(aDescriptor, "FilterData", aFilterData); + + if (findPropertyValue<sal_Bool>(aFilterData, "ExportMultipleFiles", false )) + { + ExportAsMultipleFiles(aDescriptor); + } + else + { + ExportAsSingleFile(aDescriptor); + } + + if( mxStatusIndicator.is() ) + mxStatusIndicator->end(); + + return sal_True; +} + + +// AS: When exporting as multiple files, each background, object layer, and slide gets its own +// file. Additionally, a file called BackgroundConfig.txt is generated, indicating which +// background and objects (if any) go with each slide. The files are named slideNb.swf, +// slideNo.swf, and slideNp.swf, where N is the slide number, and b=background, o=objects, and +// p=slide contents. Note that under normal circumstances, there will be very few b and o files. + +// AS: HACK! Right now, I create a directory as a sibling to the swf file selected in the Export +// dialog. This directory is called presentation.sxi-swf-files. The name of the swf file selected +// in the Export dialog has no impact on this. All files created are placed in this directory. +sal_Bool FlashExportFilter::ExportAsMultipleFiles(const Sequence< PropertyValue >& aDescriptor) +{ + Reference< XDrawPagesSupplier > xDrawPagesSupplier(mxDoc, UNO_QUERY); + if(!xDrawPagesSupplier.is()) + return sal_False; + + Reference< XIndexAccess > xDrawPages( xDrawPagesSupplier->getDrawPages(), UNO_QUERY ); + if(!xDrawPages.is()) + return sal_False; + + Reference< XDesktop > rDesktop( mxMSF->createInstance(OUString::createFromAscii("com.sun.star.frame.Desktop")), UNO_QUERY); + if (!rDesktop.is()) + return sal_False; + + Reference< XStorable > xStorable(rDesktop->getCurrentComponent(), UNO_QUERY); + if (!xStorable.is()) + return sal_False; + + Reference< XDrawPage > xDrawPage; + + Reference< XFrame > rFrame = rDesktop->getCurrentFrame(); + Reference< XDrawView > rDrawView = Reference< XDrawView >( rFrame->getController(), UNO_QUERY ); + + Reference< XDrawPage > rCurrentPage = rDrawView->getCurrentPage(); + + Sequence< PropertyValue > aFilterData; + + aFilterData = findPropertyValue<Sequence< PropertyValue > >(aDescriptor, "FilterData", aFilterData); + + //AS: Do a bunch of path mangling to figure out where to put the files. + + OUString sOriginalPath = findPropertyValue<OUString>(aDescriptor, "URL", OUString()); + + // AS: sPath is the parent directory, where everything else exists (like the sxi, + // the -swf-files folder, the -audio files, etc. + int lastslash = sOriginalPath.lastIndexOf('/'); + OUString sPath( sOriginalPath.copy(0, lastslash) ); + + OUString sPresentation(xStorable->getLocation()); + + lastslash = sPresentation.lastIndexOf('/') + 1; + int lastdot = sPresentation.lastIndexOf('.'); + + // AS: The name of the presentation, without 3 character extension. + OUString sPresentationName = sPresentation.copy(lastslash, lastdot - lastslash); + + OUString fullpath, swfdirpath, backgroundfilename, objectsfilename; + + swfdirpath = sPath + STR("/") + sPresentationName + STR(".sxi-swf-files"); + + oslFileError err; + err = osl_createDirectory( swfdirpath.pData ); + + fullpath = swfdirpath + STR("/backgroundconfig.txt"); + + oslFileHandle xBackgroundConfig; + + // AS: Only export the background config if we're exporting all of the pages, otherwise we'll + // screw it up. + sal_Bool bExportAll = findPropertyValue<sal_Bool>(aFilterData, "ExportAll", true); + if (bExportAll) + { + osl_removeFile(fullpath.pData); + osl_openFile( fullpath.pData, &xBackgroundConfig, osl_File_OpenFlag_Create | osl_File_OpenFlag_Write ); + + sal_uInt64 bytesWritten; + err = osl_writeFile(xBackgroundConfig, "slides=", strlen("slides="), &bytesWritten); + } + + FlashExporter aFlashExporter( mxMSF, findPropertyValue<sal_Int32>(aFilterData, "CompressMode", 75), + findPropertyValue<sal_Bool>(aFilterData, "ExportOLEAsJPEG", false)); + + const sal_Int32 nPageCount = xDrawPages->getCount(); + mxStatusIndicator->start(OUString( RTL_CONSTASCII_USTRINGPARAM( "Saving :" )), nPageCount); + + for(sal_Int32 nPage = 0; nPage < nPageCount; nPage++) + { + mxStatusIndicator->setValue( nPage ); + xDrawPages->getByIndex(nPage) >>= xDrawPage; + + // AS: If we're only exporting the current page, then skip the rest. + if (!bExportAll && xDrawPage != rCurrentPage) + continue; + + // AS: Export the background, the background objects, and then the slide contents. + if (bExportAll || findPropertyValue<sal_Bool>(aFilterData, "ExportBackgrounds", true)) + { + backgroundfilename = exportBackground(aFlashExporter, xDrawPage, swfdirpath, nPage, "b"); + } + + if (bExportAll || findPropertyValue<sal_Bool>(aFilterData, "ExportBackgroundObjects", true)) + { + objectsfilename = exportBackground(aFlashExporter, xDrawPage, swfdirpath, nPage, "o"); + } + + if (bExportAll || findPropertyValue<sal_Bool>(aFilterData, "ExportSlideContents", true)) + { + fullpath = swfdirpath + STR("/slide") + VAL(nPage+1) + STR("p.swf"); + + Reference<XOutputStream> xOutputStreamWrap(*(new OslOutputStreamWrapper(fullpath)), UNO_QUERY); + sal_Bool ret = aFlashExporter.exportSlides( xDrawPage, xOutputStreamWrap, nPage ); + aFlashExporter.Flush(); + xOutputStreamWrap.clear(); + + if (!ret) + osl_removeFile(fullpath.pData); + } + + // AS: Write out to the background config what backgrounds and objects this + // slide used. + if (bExportAll) + { + OUString temp = backgroundfilename + STR("|") + objectsfilename; + OString ASCIItemp(temp.getStr(), temp.getLength(), RTL_TEXTENCODING_ASCII_US); + + sal_uInt64 bytesWritten; + osl_writeFile(xBackgroundConfig, ASCIItemp.getStr(), ASCIItemp.getLength(), &bytesWritten); + + if (nPage < nPageCount - 1) + osl_writeFile(xBackgroundConfig, "|", 1, &bytesWritten); + } + +#ifdef AUGUSTUS + if (findPropertyValue<sal_Bool>(aFilterData, "ExportSound", true)) + { + fullpath = swfdirpath + STR("/slide") + VAL(nPage+1) + STR("s.swf"); + + OUString wavpath = sPath + STR("/") + sPresentationName + STR(".ppt-audio/slide") + VAL(nPage+1) + STR(".wav"); + FileBase::getSystemPathFromFileURL(wavpath, wavpath); + OString sASCIIPath(wavpath.getStr(), wavpath.getLength(), RTL_TEXTENCODING_ASCII_US); + + Reference<XOutputStream> xOutputStreamWrap(*(new OslOutputStreamWrapper(fullpath)), UNO_QUERY); + sal_Bool ret = aFlashExporter.exportSound(xOutputStreamWrap, sASCIIPath.getStr()); + aFlashExporter.Flush(); + xOutputStreamWrap.clear(); + + if (!ret) + osl_removeFile(fullpath.pData); + } +#endif // defined AUGUSTUS + } + + if (bExportAll) + osl_closeFile(xBackgroundConfig); + + return sal_True; +} + +sal_Bool FlashExportFilter::ExportAsSingleFile(const Sequence< PropertyValue >& aDescriptor) +{ + Reference < XOutputStream > xOutputStream = findPropertyValue<Reference<XOutputStream> >(aDescriptor, "OutputStream", 0); + Sequence< PropertyValue > aFilterData; + + if (!xOutputStream.is() ) + { + OSL_ASSERT ( 0 ); + return sal_False; + } + + FlashExporter aFlashExporter( mxMSF, findPropertyValue<sal_Int32>(aFilterData, "CompressMode", 75), + findPropertyValue<sal_Bool>(aFilterData, "ExportOLEAsJPEG", false)); + + return aFlashExporter.exportAll( mxDoc, xOutputStream, mxStatusIndicator ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL FlashExportFilter::cancel( ) + throw (RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +// XExporter +void SAL_CALL FlashExportFilter::setSourceDocument( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& xDoc ) + throw (::com::sun::star::lang::IllegalArgumentException, RuntimeException) +{ + mxDoc = xDoc; + + // create the status indicator + Reference< XModel > xModel( mxDoc, UNO_QUERY ); + if( xModel.is() ) + { + Reference< com::sun::star::frame::XController >xController(xModel->getCurrentController()); + if(xController.is()) + { + Reference < com::sun::star::frame::XFrame >xFrame(xController->getFrame()); + if(xFrame.is()) + { + Reference<com::sun::star::task::XStatusIndicatorFactory> xFactory(xFrame,UNO_QUERY); + if (xFactory.is()) + mxStatusIndicator = xFactory->createStatusIndicator(); + } + } + } +} + +// ----------------------------------------------------------------------------- + +// XInitialization +void SAL_CALL FlashExportFilter::initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) + throw (Exception, RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +OUString FlashExportFilter_getImplementationName () + throw (RuntimeException) +{ + return OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.comp.Impress.FlashExportFilter" ) ); +} + +// ----------------------------------------------------------------------------- + +#define SERVICE_NAME "com.sun.star.document.ExportFilter" + +sal_Bool SAL_CALL FlashExportFilter_supportsService( const OUString& ServiceName ) + throw (RuntimeException) +{ + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); +} + +// ----------------------------------------------------------------------------- + +Sequence< OUString > SAL_CALL FlashExportFilter_getSupportedServiceNames( ) + throw (RuntimeException) +{ + Sequence < OUString > aRet(1); + OUString* pArray = aRet.getArray(); + pArray[0] = OUString ( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) ); + return aRet; +} +#undef SERVICE_NAME + +// ----------------------------------------------------------------------------- + +Reference< XInterface > SAL_CALL FlashExportFilter_createInstance( const Reference< XMultiServiceFactory > & rSMgr) + throw( Exception ) +{ + return (cppu::OWeakObject*) new FlashExportFilter( rSMgr ); +} + +// ----------------------------------------------------------------------------- + +// XServiceInfo +OUString SAL_CALL FlashExportFilter::getImplementationName( ) + throw (RuntimeException) +{ + return FlashExportFilter_getImplementationName(); +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL FlashExportFilter::supportsService( const OUString& rServiceName ) + throw (RuntimeException) +{ + return FlashExportFilter_supportsService( rServiceName ); +} + +// ----------------------------------------------------------------------------- + +::com::sun::star::uno::Sequence< OUString > SAL_CALL FlashExportFilter::getSupportedServiceNames( ) + throw (RuntimeException) +{ + return FlashExportFilter_getSupportedServiceNames(); +} + +// ----------------------------------------------------------------------------- + +} diff --git a/filter/source/flash/swfuno.cxx b/filter/source/flash/swfuno.cxx new file mode 100644 index 000000000000..e94418eee77a --- /dev/null +++ b/filter/source/flash/swfuno.cxx @@ -0,0 +1,170 @@ +/************************************************************************* + * + * $RCSfile: swfuno.cxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: cl $ $Date: 2002-11-21 14:58:03 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ +#include <stdio.h> + +#include <osl/mutex.hxx> +#include <osl/thread.h> +#include <cppuhelper/factory.hxx> + +#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_ +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#endif + +using namespace ::rtl; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::registry; + +namespace swf { +extern OUString FlashExportFilter_getImplementationName() throw ( RuntimeException ); +extern sal_Bool SAL_CALL FlashExportFilter_supportsService( const OUString& ServiceName ) throw ( RuntimeException ); +extern Sequence< OUString > SAL_CALL FlashExportFilter_getSupportedServiceNames() throw ( RuntimeException ); +extern Reference< XInterface > SAL_CALL FlashExportFilter_createInstance( const Reference< XMultiServiceFactory > & rSMgr) throw ( Exception ); +} + +extern rtl::OUString SWFDialog_getImplementationName () throw (com::sun::star::uno::RuntimeException); +extern com::sun::star::uno::Sequence< rtl::OUString > SAL_CALL SWFDialog_getSupportedServiceNames() throw (com::sun::star::uno::RuntimeException); +extern com::sun::star::uno::Reference< com::sun::star::uno::XInterface > SAL_CALL SWFDialog_createInstance( const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > & rSMgr) throw( com::sun::star::uno::Exception ); + +using namespace ::swf; + +extern "C" +{ +//================================================================================================== +void SAL_CALL component_getImplementationEnvironment( + const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} +//================================================================================================== + +void singlecomponent_writeInfo( Reference< XRegistryKey >& xNewKey, const Sequence< OUString > & rSNL ) +{ + const OUString * pArray = rSNL.getConstArray(); + for ( sal_Int32 nPos = rSNL.getLength(); nPos--; ) + xNewKey->createKey( pArray[nPos] ); +} + +sal_Bool SAL_CALL component_writeInfo( + void * pServiceManager, void * pRegistryKey ) +{ + if (pRegistryKey) + { + try + { + Reference< XRegistryKey > xNewKey( + reinterpret_cast< XRegistryKey * >( pRegistryKey )->createKey( FlashExportFilter_getImplementationName() ) ); + xNewKey = xNewKey->createKey( OUString::createFromAscii( "/UNO/SERVICES" ) ); + + singlecomponent_writeInfo( xNewKey, FlashExportFilter_getSupportedServiceNames() ); + + xNewKey = reinterpret_cast< XRegistryKey * >( pRegistryKey )->createKey( SWFDialog_getImplementationName() ); + xNewKey = xNewKey->createKey( OUString::createFromAscii( "/UNO/SERVICES" ) ); + + singlecomponent_writeInfo( xNewKey, SWFDialog_getSupportedServiceNames() ); + + return sal_True; + } + catch (InvalidRegistryException &) + { + OSL_ENSURE( sal_False, "### InvalidRegistryException!" ); + } + } + return sal_False; +} +//================================================================================================== +void * SAL_CALL component_getFactory( + const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey ) +{ + void * pRet = 0; + + if( pServiceManager ) + { + Reference< XSingleServiceFactory > xFactory; + + OUString implName = OUString::createFromAscii( pImplName ); + if ( implName.equals(FlashExportFilter_getImplementationName()) ) + { + xFactory = createSingleFactory( + reinterpret_cast< XMultiServiceFactory * >( pServiceManager ), + OUString::createFromAscii( pImplName ), + FlashExportFilter_createInstance, FlashExportFilter_getSupportedServiceNames() ); + + } + else if ( implName.equals(SWFDialog_getImplementationName()) ) + { + xFactory = createSingleFactory( + reinterpret_cast< XMultiServiceFactory * >( pServiceManager ), + OUString::createFromAscii( pImplName ), + SWFDialog_createInstance, SWFDialog_getSupportedServiceNames() ); + } + + if (xFactory.is()) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + } + + return pRet; +} +} diff --git a/filter/source/flash/swfwriter.cxx b/filter/source/flash/swfwriter.cxx new file mode 100644 index 000000000000..4afc13b0eba6 --- /dev/null +++ b/filter/source/flash/swfwriter.cxx @@ -0,0 +1,704 @@ +/************************************************************************* + * + * $RCSfile: swfwriter.cxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: cl $ $Date: 2002-11-21 14:58:03 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Christian Lippka (christian.lippka@sun.com) + * + * + ************************************************************************/ + +#ifndef _SWF_WRITER_HXX_ +#include "swfwriter.hxx" +#endif + +#ifndef _SV_VIRDEV_HXX +#include <vcl/virdev.hxx> +#endif +#ifndef _SV_GDIMTF_HXX +#include <vcl/gdimtf.hxx> +#endif + +using namespace ::swf; +using namespace ::std; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; + +// ----------------------------------------------------------------------------- + +static MapMode aTWIPSMode( MAP_TWIP ); +static MapMode a100thmmMode( MAP_100TH_MM ); + +static sal_Int32 map100thmm( sal_Int32 n100thMM ) +{ + Point aPoint( n100thMM, n100thMM ); + sal_Int32 nX = OutputDevice::LogicToLogic( aPoint, a100thmmMode, aTWIPSMode ).X(); + return nX; +} + +// ----------------------------------------------------------------------------- + +Writer::Writer( sal_Int32 nTWIPWidthOutput, sal_Int32 nTWIPHeightOutput, sal_Int32 nDocWidthInput, sal_Int32 nDocHeightInput, sal_Int32 nJPEGcompressMode ) +: mpClipPolyPolygon( NULL ), + mpSprite( NULL ), + mpTag( NULL ), + mnNextId( 1 ), + mnJPEGCompressMode(nJPEGcompressMode), + mbWrittenJPEGTables(false), + mnGlobalTransparency(0) +{ + mpVDev = new VirtualDevice; + mpVDev->EnableOutput( sal_False ); + + maMovieTempFile.EnableKillingFile(); + maFontsTempFile.EnableKillingFile(); + + mpMovieStream = maMovieTempFile.GetStream( STREAM_WRITE|STREAM_TRUNC ); + mpFontsStream = maFontsTempFile.GetStream( STREAM_WRITE|STREAM_TRUNC ); + + mnFrames = 0; + + mnDocWidth = map100thmm( nDocWidthInput ); + mnDocHeight = map100thmm( nDocHeightInput ); + + mnDocXScale = (double)nTWIPWidthOutput / mnDocWidth; + mnDocYScale = (double)nTWIPHeightOutput / mnDocHeight; + +#ifndef AUGUSTUS + // define an invisible button with the size of a page + Rectangle aRect( 0, 0, mnDocWidth * mnDocXScale, mnDocHeight * mnDocYScale ); + Polygon aPoly( aRect ); + FillStyle aFill( Color(COL_WHITE) ); + mnWhiteBackgroundShapeId = defineShape( aPoly, aFill ); + + Matrix3D m; + mnPageButtonId = createID(); + startTag( TAG_DEFINEBUTTON ); + mpTag->addUI16( mnPageButtonId ); // character id for button + + // button records + mpTag->addUI8( 0x08 ); // only hit state + mpTag->addUI16( mnWhiteBackgroundShapeId ); // shape id of background rectangle + mpTag->addUI16( 0 ); // depth for button DANGER! + mpTag->addMatrix( m ); // identity matrix + mpTag->addUI8( 0 ); // empty color transform + +// mpTag->addUI8( 0 ); // end of button records + + // action records + mpTag->addUI8( 0x06 ); // ActionPlay + mpTag->addUI8( 0 ); // end of action records + + endTag(); + + // place a shape that clips shapes depth 2-3 to document boundaries +// placeShape( mnWhiteBackgroundShapeId, 1, 0, 0, 4 ); +#endif +} + +// ----------------------------------------------------------------------------- + +Writer::~Writer() +{ + delete mpVDev; + delete mpSprite; + delete mpTag; +} + +// ----------------------------------------------------------------------------- + +void ImplCopySvStreamToXOutputStream( SvStream& rIn, Reference< XOutputStream > &xOut ) +{ + sal_uInt32 nBufferSize = 64*1024; + + rIn.Seek( STREAM_SEEK_TO_END ); + sal_uInt32 nSize = rIn.Tell(); + rIn.Seek( STREAM_SEEK_TO_BEGIN ); + + Sequence< sal_Int8 > aBuffer( min( nBufferSize, nSize ) ); + + while( nSize ) + { + if( nSize < nBufferSize ) + { + nBufferSize = nSize; + aBuffer.realloc( nSize ); + } + + sal_uInt32 nRead = rIn.Read( aBuffer.getArray(), nBufferSize ); + DBG_ASSERT( nRead == nBufferSize, "ImplCopySvStreamToXOutputStream failed!" ); + xOut->writeBytes( aBuffer ); + + nSize -= nBufferSize; + } +} + +// ----------------------------------------------------------------------------- + +void Writer::storeTo( Reference< XOutputStream > &xOutStream ) +{ + for(FontMap::iterator i = maFonts.begin(); i != maFonts.end(); i++) + { + FlashFont* pFont = (*i); + pFont->write( *mpFontsStream ); + delete pFont; + } + + // Endtag + *mpMovieStream << (sal_uInt8)0; + + Tag aHeader( 0xff ); + + aHeader.addUI8( 'F' ); + aHeader.addUI8( 'W' ); + aHeader.addUI8( 'S' ); + aHeader.addUI8( 5 ); + + sal_uInt32 nSizePos = aHeader.Tell(); + + aHeader << (sal_uInt32)0; + + Rectangle aDocRect( 0, 0, static_cast<long>(mnDocWidth*mnDocXScale), static_cast<long>(mnDocHeight*mnDocYScale) ); + + aHeader.addRect( aDocRect ); + + // frame delay in 8.8 fixed number of frames per second + aHeader.addUI8( 0 ); + aHeader.addUI8( 12 ); + + aHeader.addUI16( _uInt16(mnFrames) ); + + const sal_uInt32 nSize = aHeader.Tell() + mpFontsStream->Tell() + mpMovieStream->Tell(); + + aHeader.Seek( nSizePos ); + aHeader << (sal_uInt32)nSize; + + ImplCopySvStreamToXOutputStream( aHeader, xOutStream ); + ImplCopySvStreamToXOutputStream( *mpFontsStream, xOutStream ); + ImplCopySvStreamToXOutputStream( *mpMovieStream, xOutStream ); +} + +// ----------------------------------------------------------------------------- + +sal_uInt16 Writer::startSprite() +{ + sal_uInt16 nShapeId = createID(); + mvSpriteStack.push(mpSprite); + mpSprite = new Sprite( nShapeId ); + return nShapeId; +} + +// ----------------------------------------------------------------------------- + +void Writer::endSprite() +{ + if( mpSprite ) + { + startTag( TAG_END ); + endTag(); + + mpSprite->write( *mpMovieStream ); + delete mpSprite; + + if (mvSpriteStack.size() > 0) + { + mpSprite = mvSpriteStack.top(); + mvSpriteStack.pop(); + } + else + mpSprite = NULL; + } +} + +// ----------------------------------------------------------------------------- + +void Writer::placeShape( sal_uInt16 nID, sal_uInt16 nDepth, sal_Int32 x, sal_Int32 y, sal_uInt16 nClip, const char* pName ) +{ + startTag( TAG_PLACEOBJECT2 ); + + BitStream aBits; + + aBits.writeUB( nClip != 0, 1 ); // Has Clip Actions? + aBits.writeUB( 0, 1 ); // reserved + aBits.writeUB( pName != NULL, 1 ); // has a name + aBits.writeUB( 0, 1 ); // no ratio + aBits.writeUB( 0, 1 ); // no color transform + aBits.writeUB( 1, 1 ); // has a matrix + aBits.writeUB( 1, 1 ); // places a character + aBits.writeUB( 0, 1 ); // does not define a character to be moved + + mpTag->addBits( aBits ); + mpTag->addUI16( nDepth ); // depth + mpTag->addUI16( nID ); // character Id + + Matrix3D aMatrix; + aMatrix.Translate( _Int16(static_cast<long>(map100thmm(x)*mnDocXScale)), _Int16(static_cast<long>(map100thmm(y)*mnDocYScale)) ); + mpTag->addMatrix( aMatrix ); // transformation matrix + + if( pName ) + mpTag->addString( pName ); + + if( nClip != 0 ) + mpTag->addUI16( nClip ); + + endTag(); +} + +// ----------------------------------------------------------------------------- + +void Writer::moveShape( sal_uInt16 nDepth, sal_Int32 x, sal_Int32 y ) +{ + startTag( TAG_PLACEOBJECT2 ); + + BitStream aBits; + aBits.writeUB( 0, 1 ); // Has no Clip Actions + aBits.writeUB( 0, 1 ); // reserved + aBits.writeUB( 0, 1 ); // has no name + aBits.writeUB( 0, 1 ); // no ratio + aBits.writeUB( 0, 1 ); // no color transform + aBits.writeUB( 1, 1 ); // has a matrix + aBits.writeUB( 0, 1 ); // places a character + aBits.writeUB( 1, 1 ); // defines a character to be moved + + mpTag->addBits( aBits ); + mpTag->addUI16( nDepth ); // depth + + Matrix3D aMatrix; + aMatrix.Translate( _Int16(static_cast<long>(map100thmm(x)*mnDocXScale)), _Int16(static_cast<long>(map100thmm(y)*mnDocYScale)) ); + mpTag->addMatrix( aMatrix ); // transformation matrix + + endTag(); +} + +// ----------------------------------------------------------------------------- + +void Writer::removeShape( sal_uInt16 nDepth ) +{ + startTag( TAG_REMOVEOBJECT2 ); + mpTag->addUI16( nDepth ); // depth + endTag(); +} + +// ----------------------------------------------------------------------------- + +void Writer::setBackgroundColor( Color& rColor ) +{ + startTag( TAG_BACKGROUNDCOLOR ); + mpTag->addRGBA( rColor ); + endTag(); +} + +// ----------------------------------------------------------------------------- + +void Writer::startTag( sal_uInt8 nTagId ) +{ + DBG_ASSERT( mpTag == NULL, "Last tag was not ended"); + + mpTag = new Tag( nTagId ); +} + +// ----------------------------------------------------------------------------- + +void Writer::endTag() +{ + sal_uInt8 nTag = mpTag->getTagId(); + + if( mpSprite && ( (nTag == TAG_END) || (nTag == TAG_SHOWFRAME) || (nTag == TAG_DOACTION) || (nTag == TAG_STARTSOUND) || (nTag == TAG_PLACEOBJECT) || (nTag == TAG_PLACEOBJECT2) || (nTag == TAG_REMOVEOBJECT2) || (nTag == TAG_FRAMELABEL) ) ) + { + mpSprite->addTag( mpTag ); + mpTag = NULL; + } + else + { + mpTag->write( *mpMovieStream ); + delete mpTag; + mpTag = NULL; + } +} + +// ----------------------------------------------------------------------------- + +sal_uInt16 Writer::createID() +{ + return mnNextId++; +} + +// ----------------------------------------------------------------------------- + +void Writer::showFrame() +{ + startTag( TAG_SHOWFRAME ); + endTag(); + + if(NULL == mpSprite) + mnFrames++; +} + +// ----------------------------------------------------------------------------- + +sal_uInt16 Writer::defineShape( const GDIMetaFile& rMtf, sal_Int16 x, sal_Int16 y ) +{ + mpVDev->SetMapMode( rMtf.GetPrefMapMode() ); + Impl_writeActions( rMtf ); + + sal_uInt16 nId = 0; + sal_uInt16 iDepth = 1; + { + CharacterIdVector::iterator aIter( maShapeIds.begin() ); + const CharacterIdVector::iterator aEnd( maShapeIds.end() ); + + sal_Bool bHaveShapes = aIter != aEnd; + + if (bHaveShapes) + { + nId = startSprite(); + + while( aIter != aEnd ) + { + placeShape( *aIter, iDepth++, x, y ); + aIter++; + } + + endSprite(); + } + } + + maShapeIds.clear(); + + return nId; +} + +// ----------------------------------------------------------------------------- + +sal_uInt16 Writer::defineShape( const Polygon& rPoly, const FillStyle& rFillStyle ) +{ + const PolyPolygon aPolyPoly( rPoly ); + return defineShape( aPolyPoly, rFillStyle ); +} + +// ----------------------------------------------------------------------------- + +sal_uInt16 Writer::defineShape( const Polygon& rPoly, sal_uInt16 nLineWidth, const Color& rLineColor ) +{ + const PolyPolygon aPolyPoly( rPoly ); + return defineShape( aPolyPoly, nLineWidth, rLineColor ); +} + +// ----------------------------------------------------------------------------- + +sal_uInt16 Writer::defineShape( const PolyPolygon& rPolyPoly, const FillStyle& rFillStyle ) +{ + sal_uInt16 nShapeId = createID(); + + // start a DefineShape3 tag + startTag( TAG_DEFINESHAPE3 ); + + mpTag->addUI16( nShapeId ); + mpTag->addRect( rPolyPoly.GetBoundRect() ); + + + // FILLSTYLEARRAY + mpTag->addUI8( 1 ); // FillStyleCount + + // FILLSTYLE + rFillStyle.addTo( mpTag ); + + // LINESTYLEARRAY + mpTag->addUI8( 0 ); // LineStyleCount + + // Number of fill and line index bits to 1 + mpTag->addUI8( 0x11 ); + + BitStream aBits; + + const sal_uInt16 nCount = rPolyPoly.Count(); + sal_uInt16 i; + for( i = 0; i < nCount; i++ ) + { + const Polygon& rPoly = rPolyPoly[ i ]; + if( rPoly.GetSize() ) + Impl_addPolygon( aBits, rPoly, true ); + } + + Impl_addEndShapeRecord( aBits ); + + mpTag->addBits( aBits ); + endTag(); + + return nShapeId; +} + +// ----------------------------------------------------------------------------- + +sal_uInt16 Writer::defineShape( const PolyPolygon& rPolyPoly, sal_uInt16 nLineWidth, const Color& rLineColor ) +{ + sal_uInt16 nShapeId = createID(); + + // start a DefineShape3 tag + startTag( TAG_DEFINESHAPE3 ); + + mpTag->addUI16( nShapeId ); + mpTag->addRect( rPolyPoly.GetBoundRect() ); + + + // FILLSTYLEARRAY + mpTag->addUI8( 0 ); // FillStyleCount + + // LINESTYLEARRAY + mpTag->addUI8( 1 ); // LineStyleCount + + // LINESTYLE + mpTag->addUI16( nLineWidth ); // Width of line in twips + mpTag->addRGBA( rLineColor ); // Color + + // Number of fill and line index bits to 1 + mpTag->addUI8( 0x11 ); + + BitStream aBits; + + const sal_uInt16 nCount = rPolyPoly.Count(); + sal_uInt16 i; + for( i = 0; i < nCount; i++ ) + { + const Polygon& rPoly = rPolyPoly[ i ]; + if( rPoly.GetSize() ) + Impl_addPolygon( aBits, rPoly, false ); + } + + Impl_addEndShapeRecord( aBits ); + + mpTag->addBits( aBits ); + endTag(); + + return nShapeId; +} + +#ifdef AUGUSTUS +enum {NO_COMPRESSION, ADPCM_COMPRESSION, MP3_COMPRESSION } COMPRESSION_TYPE; +sal_Bool Writer::streamSound( const char * filename ) +{ + SF_INFO info; + SNDFILE *sf = sf_open(filename, SFM_READ, &info); + + if (NULL == sf) + return sal_False; + else + { + // AS: Start up lame. + m_lame_flags = lame_init(); + + // The default (if you set nothing) is a a J-Stereo, 44.1khz + // 128kbps CBR mp3 file at quality 5. Override various default settings + // as necessary, for example: + + lame_set_num_channels(m_lame_flags,1); + lame_set_in_samplerate(m_lame_flags,22050); + lame_set_brate(m_lame_flags,48); + lame_set_mode(m_lame_flags,MONO); + lame_set_quality(m_lame_flags,2); /* 2=high 5 = medium 7=low */ + + // See lame.h for the complete list of options. Note that there are + // some lame_set_*() calls not documented in lame.h. These functions + // are experimental and for testing only. They may be removed in + // the future. + + //4. Set more internal configuration based on data provided above, + // as well as checking for problems. Check that ret_code >= 0. + + int ret_code = lame_init_params(m_lame_flags); + + if (ret_code < 0) + throw 0; + + int lame_frame_size = lame_get_framesize(m_lame_flags); + int samples_per_frame = 22050 / 12; // AS: (samples/sec) / (frames/sec) = samples/frame + int mp3buffer_size = static_cast<int>(samples_per_frame*1.25 + 7200 + 7200); + + + startTag(TAG_SOUNDSTREAMHEAD2); + + mpTag->addUI8(2<<2 | 1<<1 | 0<<0); // Preferred mixer format ?? + + BitStream bs; + + bs.writeUB(MP3_COMPRESSION,4); + bs.writeUB(2, 2); // AS: Reserved zero bits. + bs.writeUB(1, 1); // AS: 16 Bit + bs.writeUB(0, 1); // AS: Mono. + + mpTag->addBits(bs); + + mpTag->addUI16(samples_per_frame); + endTag(); + + short *sample_buff = new short[static_cast<int>(info.frames)]; + sf_readf_short(sf, sample_buff, info.frames); + + unsigned char* mp3buffer = new unsigned char[mp3buffer_size]; + +// 5. Encode some data. input pcm data, output (maybe) mp3 frames. +// This routine handles all buffering, resampling and filtering for you. +// The required mp3buffer_size can be computed from num_samples, +// samplerate and encoding rate, but here is a worst case estimate: +// mp3buffer_size (in bytes) = 1.25*num_samples + 7200. +// num_samples = the number of PCM samples in each channel. It is +// not the sum of the number of samples in the L and R channels. +// +// The return code = number of bytes output in mp3buffer. This can be 0. +// If it is <0, an error occured. + + + for (int samples_written = 0; samples_written < info.frames; samples_written += samples_per_frame) + { + startTag(TAG_SOUNDSTREAMBLOCK); + + int samples_to_write = std::min((int)info.frames - samples_written, samples_per_frame); + + // AS: Since we're mono, left and right sample buffs are the same + // ie, samplebuff (which is why we pass it twice). + int ret = lame_encode_buffer(m_lame_flags, sample_buff + samples_written, + sample_buff + samples_written, + samples_to_write, mp3buffer, mp3buffer_size); + + if (ret < 0) + throw 0; + +// 6. lame_encode_flush will flush the buffers and may return a +// final few mp3 frames. mp3buffer should be at least 7200 bytes. +// return code = number of bytes output to mp3buffer. This can be 0. + + if (mp3buffer_size - ret < 7200) + throw 0; + + int ret2 = lame_encode_flush(m_lame_flags, mp3buffer + ret, mp3buffer_size - ret); + + if (ret2 < 0) + throw 0; + + + SvMemoryStream strm(mp3buffer, ret + ret2, STREAM_READWRITE); + + mpTag->addUI16(samples_to_write); //lame_frame_size); + mpTag->addUI16(0); + mpTag->addStream(strm); + + endTag(); + + showFrame(); + } + + + delete[] mp3buffer; + + delete[] sample_buff; + int err = sf_close(sf); + + // 8. free the internal data structures. + lame_close(m_lame_flags); + } + + return sal_True; +} +#endif // AUGUSTUS + + +// ----------------------------------------------------------------------------- + +void Writer::stop() +{ + startTag( TAG_DOACTION ); + mpTag->addUI8( 0x07 ); + mpTag->addUI8( 0 ); + endTag(); +} + +// ----------------------------------------------------------------------------- + +void Writer::play() +{ + startTag( TAG_DOACTION ); + mpTag->addUI8( 0x06 ); + mpTag->addUI8( 0 ); + endTag(); +} + +// ----------------------------------------------------------------------------- + +void Writer::waitOnClick( sal_uInt16 nDepth ) +{ + placeShape( _uInt16( mnPageButtonId ), nDepth, 0, 0 ); + stop(); + showFrame(); + removeShape( nDepth ); +} + +// ----------------------------------------------------------------------------- + +/** inserts a doaction tag with an ActionGotoFrame */ +void Writer::gotoFrame( sal_uInt16 nFrame ) +{ + startTag( TAG_DOACTION ); + mpTag->addUI8( 0x81 ); + mpTag->addUI16( 2 ); + mpTag->addUI16( nFrame ); + mpTag->addUI8( 0 ); + endTag(); +} + +// ----------------------------------------------------------------------------- + +sal_uInt16 Writer::getWhiteBackgroundShapeId() +{ + return mnWhiteBackgroundShapeId; +}
\ No newline at end of file diff --git a/filter/source/flash/swfwriter.hxx b/filter/source/flash/swfwriter.hxx new file mode 100644 index 000000000000..3e72c72a69f3 --- /dev/null +++ b/filter/source/flash/swfwriter.hxx @@ -0,0 +1,522 @@ +/************************************************************************* + * + * $RCSfile: swfwriter.hxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: cl $ $Date: 2002-11-21 14:58:03 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Christian Lippka (christian.lippka@sun.com) + * + * + ************************************************************************/ + +#ifndef _SWF_WRITER_HXX_ +#define _SWF_WRITER_HXX_ + +#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_ +#include <com/sun/star/uno/Sequence.hxx> +#endif +#ifndef _COM_SUN_STAR_IO_XOUTPUTSTREAM_HPP_ +#include <com/sun/star/io/XOutputStream.hpp> +#endif + +#ifndef _SV_FONT_HXX +#include <vcl/font.hxx> +#endif +#ifndef _SV_GRADIENT_HXX +#include <vcl/gradient.hxx> +#endif +#ifndef _UNOTOOLS_TEMPFILE_HXX +#include <unotools/tempfile.hxx> +#endif +#ifndef _B2D_MATRIX3D_HXX +#include <goodies/matrix3d.hxx> +#endif +#ifndef _TOOLS_COLOR_HXX +#include <tools/color.hxx> +#endif +#ifndef _SV_POLY_HXX +#include <vcl/poly.hxx> +#endif +#ifndef _SV_GEN_HXX +#include <tools/gen.hxx> +#endif +#ifndef _STREAM_HXX +#include <tools/stream.hxx> +#endif + +#ifndef _OSL_FILE_HXX_ +#include <osl/file.hxx> +#endif + +#include <vector> +#include <stack> +#include <map> + +#ifdef AUGUSTUS +#include "lame.h" +#include "sndfile.h" +#endif + +#include <stdio.h> + +class GDIMetaFile; +class BitmapEx; +class PolyPolygon; +class Gradient; +class SvtGraphicFill; +class SvtGraphicStroke; + +inline sal_uInt16 _uInt16( sal_Int32 nValue ) +{ + OSL_ENSURE( (nValue >= 0) && ((sal_uInt32)nValue <= 0xffff), "overflow while converting sal_Int32 to sal_uInt16" ); + return (sal_uInt16)nValue; +} + +inline sal_Int16 _Int16( sal_Int32 nValue ) +{ + OSL_ENSURE( (nValue >= -32768) && (nValue <= 32767), "overflow while converting sal_Int32 to sal_Int16" ); + return (sal_Int16)nValue; +} + +class VirtualDevice; + +namespace swf { + +const sal_uInt8 TAG_END = 0; +const sal_uInt8 TAG_SHOWFRAME = 1; + +const sal_uInt8 TAG_DEFINEBUTTON = 7; + +const sal_uInt8 TAG_BACKGROUNDCOLOR = 9; + +const sal_uInt8 TAG_DOACTION = 12; +const sal_uInt8 TAG_STARTSOUND = 15; + +const sal_uInt8 TAG_SOUNDSTREAMBLOCK = 19; +const sal_uInt8 TAG_SOUNDSTREAMHEAD = 18; +const sal_uInt8 TAG_SOUNDSTREAMHEAD2 = 45; + +const sal_uInt8 TAG_JPEGTABLES = 8; +const sal_uInt8 TAG_DEFINEBITS = 6; +const sal_uInt8 TAG_DEFINEBITSLOSSLESS = 20; +const sal_uInt8 TAG_DEFINEBITSJPEG2 = 21; +const sal_uInt8 TAG_DEFINEBITSJPEG3 = 35; +const sal_uInt8 TAG_DEFINEBITSLOSSLESS2 = 36; + +const sal_uInt8 TAG_PLACEOBJECT = 4; +const sal_uInt8 TAG_PLACEOBJECT2 = 26; +const sal_uInt8 TAG_REMOVEOBJECT2 = 28; + +const sal_uInt8 TAG_DEFINEFONT = 10; +const sal_uInt8 TAG_DEFINETEXT = 11; +const sal_uInt8 TAG_DEFINESHAPE3 = 32; +const sal_uInt8 TAG_DEFINESPRITE = 39; + +const sal_uInt8 TAG_FRAMELABEL = 43; + +const sal_uInt8 TAG_HEADER = 0xff; + +/////////////////////////////////////////////////////////////////////// + +/** converts a double to a 16.16 flash fixed value */ +sal_uInt32 getFixed( double fValue ); + +/////////////////////////////////////////////////////////////////////// + +typedef ::std::map<sal_uInt32, sal_uInt16> ChecksumCache; + +/** unsigned int 16 compare operation for stl */ +struct ltuint16 +{ + bool operator()(sal_uInt16 s1, sal_uInt16 s2) const + { + return s1 < s2; + } +}; + +/////////////////////////////////////////////////////////////////////// + +/** container class to create bit structures */ +class BitStream +{ +public: + BitStream(); + + void writeUB( sal_uInt32 nValue, sal_uInt16 nBits ); + void writeSB( sal_Int32 nValue, sal_uInt16 nBits ); + void writeFB( sal_uInt32 nValue, sal_uInt16 nBits ); + + void pad(); + void writeTo( SvStream& out ); + + sal_uInt32 getOffset() const; +private: + + std::vector< sal_uInt8 > maData; + sal_uInt8 mnBitPos; + sal_uInt8 mnCurrentByte; +}; + +/////////////////////////////////////////////////////////////////////// + +/** this class collects all used glyphs for a given fonts and maps + characters to glyph ids. +*/ +class FlashFont +{ +public: + FlashFont( const Font& rFont, sal_uInt16 nId ); + ~FlashFont(); + + sal_uInt16 getGlyph( sal_uInt16 nChar, VirtualDevice* pVDev ); + + void write( SvStream& out ); + + sal_uInt16 getID() const { return mnId; } + const Font& getFont() { return maFont; } + +private: + sal_uInt16 mnId; + const Font maFont; + std::map<sal_uInt16, sal_uInt16, ltuint16> maGlyphIndex; + sal_uInt16 mnNextIndex; + BitStream maGlyphData; + std::vector< sal_uInt16 > maGlyphOffsets; +}; + +typedef std::vector<FlashFont*> FontMap; + +/////////////////////////////////////////////////////////////////////// + +/** this class helps creating flash tags */ +class Tag : public SvMemoryStream +{ +public: + Tag( sal_uInt8 nTagId ); + + sal_uInt8 getTagId() const { return mnTagId; } + + void write( SvStream& out ); + + void addUI32( sal_uInt32 nValue ); + void addI32( sal_Int32 nValue ); + void addUI16( sal_uInt16 nValue ); + void addI16( sal_Int16 nValue ); + void addUI8( sal_uInt8 nValue ); + void addBits( BitStream& rIn ); + + void addRGBA( const Color& rColor ); + void addRGB( const Color& rColor ); + void addRect( const Rectangle& rRect ); + void addMatrix( const Matrix3D& rMatrix ); + void addString( const char* pString ); + void addStream( SvStream& rIn ); + + static void writeMatrix( SvStream& rOut, const Matrix3D& rMatrix ); + static void writeRect( SvStream& rOut, const Rectangle& rRect ); + +private: + sal_uInt8 mnTagId; +}; + +/////////////////////////////////////////////////////////////////////// + +/** this class helps to define flash sprites */ +class Sprite +{ +public: + Sprite( sal_uInt16 nId ); + ~Sprite(); + + void write( SvStream& out ); + + sal_uInt16 getId() const { return mnId; } + + void addTag( Tag* pNewTag ); + +private: + std::vector< Tag* > maTags; + sal_uInt16 mnId; + sal_uInt32 mnFrames; +}; + +/////////////////////////////////////////////////////////////////////// + +/** this class stores a flash fill style for shapes */ +class FillStyle +{ +public: + enum FillStyleType { solid = 0x00, linear_gradient = 0x10, radial_gradient = 0x12, tiled_bitmap = 0x40, clipped_bitmap = 0x41 }; + + /** this c'tor creates a solid fill style */ + FillStyle( const Color& rSolidColor ); + + /** this c'tor creates a linear or radial gradient fill style */ + FillStyle( const Rectangle& rBoundRect, const Gradient& rGradient ); + + /** this c'tor creates a tiled or clipped bitmap fill style */ + FillStyle( sal_uInt16 nBitmapId, bool bClipped, const Matrix3D& rMatrix ); + + void addTo( Tag* pTag ) const; + +private: + void Impl_addGradient( Tag* pTag ) const; + + FillStyleType meType; + Matrix3D maMatrix; + sal_uInt16 mnBitmapId; + Color maColor; + Gradient maGradient; + Rectangle maBoundRect; +}; + +/////////////////////////////////////////////////////////////////////// + +/** this class creates a flash movie from vcl geometry */ +class Writer +{ + friend class FlashFont; + +public: + /** creates a writer for a new flash movie. + nDocWidth and nDocHeight are the dimensions of the movie. + They must be in 100th/mm. + + An invisible shape with the size of the document is placed at depth 1 + and it clips all shapes on depth 2 and 3. + */ + Writer( sal_Int32 nDocWidthInput, sal_Int32 nDocHeightInput, sal_Int32 nDocWidth, sal_Int32 nDocHeight, sal_Int32 nJPEGcompressMode = -1 ); + ~Writer(); + + void storeTo( com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > &xOutStream ); + + // geometry + void setClipping( const PolyPolygon* pClipPolyPolygon ); + + /** defines a flash shape from a filled polygon. + The coordinates must be in twips */ + sal_uInt16 defineShape( const Polygon& rPoly, const FillStyle& rFillStyle ); + + /** defines a flash shape from a outlined polygon. + The coordinates must be in twips */ + sal_uInt16 defineShape( const Polygon& rPoly, sal_uInt16 nLineWidth, const Color& rLineColor ); + + /** defines a flash shape from a filled polypolygon. + The coordinates must be in twips */ + sal_uInt16 defineShape( const PolyPolygon& rPolyPoly, const FillStyle& rFillStyle ); + + /** defines a flash shape from a outlined polypolygon. + The coordinates must be in twips */ + sal_uInt16 defineShape( const PolyPolygon& rPolyPoly, sal_uInt16 nLineWidth, const Color& rLineColor ); + + /** defines a flash shape from a vcl metafile. + The mapmode of the metafile is used to map all coordinates to twips. + A character id of a flash sprite is returned that contains all geometry + from the metafile. + */ + sal_uInt16 defineShape( const GDIMetaFile& rMtf, sal_Int16 x = 0, sal_Int16 y = 0 ); + + /** defines a bitmap and returns its flash id. + */ + sal_uInt16 defineBitmap( const BitmapEx& bmpSource, sal_Int32 nJPEGQualityLevel ); + + // control tags + + /** inserts a place shape tag into the movie stream or the current sprite */ + void placeShape( sal_uInt16 nID, sal_uInt16 nDepth, sal_Int32 x, sal_Int32 y, sal_uInt16 nClipDepth = 0, const char* pName = NULL ); + + /** inserts a move shape tag into the movie stream or the current sprite */ + void moveShape( sal_uInt16 nDepth, sal_Int32 x, sal_Int32 y ); + + /** inserts a remove shape tag into the movie stream or the current sprite */ + void removeShape( sal_uInt16 nDepth ); + + /** inserts a show frame tag into the movie stream or the current sprite */ + void showFrame(); + + /** sets the background color in the movie stream */ + void setBackgroundColor( Color& rColor ); + + /** creates a new sprite and sets it as the current sprite for editing. + Only one sprite can be edited at one time */ + sal_uInt16 startSprite(); + + /** ends editing of the curent sprites and adds it to the movie stream */ + void endSprite(); + + /** inserts a doaction tag with an ActionStop */ + void stop(); + + /** inserts a doaction tag with an ActionPlay */ + void play(); + + /** inserts a doaction tag with an ActionStop, place a button on depth nDepth that + continues playback on click */ + void waitOnClick( sal_uInt16 nDepth ); + + /** inserts a doaction tag with an ActionGotoFrame */ + void gotoFrame( sal_uInt16 nFrame ); + + /** returns the character of a white rectangle with the dimensions of the document */ + sal_uInt16 getWhiteBackgroundShapeId(); + +#ifdef AUGUSTUS + /** stream out a sound. Should make it more intelligent so it interleaves with other items.*/ + sal_Bool streamSound( const char * filename ); +#endif + +private: + Point map( const Point& rPoint ) const; + Size map( const Size& rSize ) const; + void map( PolyPolygon& rPolyPolygon ) const; + sal_Int32 mapRelative( sal_Int32 n100thMM ) const; + + void startTag( sal_uInt8 nTagId ); + void endTag(); + sal_uInt16 createID(); + + void Impl_writeBmp( sal_uInt16 nBitmapId, sal_uInt32 width, sal_uInt32 height, sal_uInt8 *pCompressed, sal_uInt32 compressed_size ); + void Impl_writeImage( const BitmapEx& rBmpEx, const Point& rPt, const Size& rSz, const Point& rSrcPt, const Size& rSrcSz, const Rectangle& rClipRect, bool bMap ); + void Impl_writeJPEG(sal_uInt16 nBitmapId, const sal_uInt8* pJpgData, sal_uInt32 nJpgDataLength, sal_uInt8 *pCompressed, sal_uInt32 compressed_size, sal_Bool bStandardCompression ); + void Impl_writeActions( const GDIMetaFile& rMtf ); + void Impl_writePolygon( const Polygon& rPoly, sal_Bool bFilled ); + void Impl_writePolygon( const Polygon& rPoly, sal_Bool bFilled, const Color& rFillColor, const Color& rLineColor ); + void Impl_writePolyPolygon( const PolyPolygon& rPolyPoly, sal_Bool bFilled, sal_uInt8 nTransparence = 0); + void Impl_writePolyPolygon( const PolyPolygon& rPolyPoly, sal_Bool bFilled, const Color& rFillColor, const Color& rLineColor ); + void Impl_writeText( const Point& rPos, const String& rText, const long* pDXArray, long nWidth ); + void Impl_writeGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient ); + void Impl_writeLine( const Point& rPt1, const Point& rPt2, const Color* pLineColor = NULL ); + void Impl_writeRect( const Rectangle& rRect, long nRadX, long nRadY ); + void Impl_writeEllipse( const Point& rCenter, long nRadX, long nRadY ); + bool Impl_writeFilling( SvtGraphicFill& rFilling ); + bool Impl_writeStroke( SvtGraphicStroke& rStroke ); + + FlashFont& Impl_getFont( const Font& rFont ); + + static void Impl_addPolygon( BitStream& rBits, const Polygon& rPoly, sal_Bool bFilled ); + + static void Impl_addShapeRecordChange( BitStream& rBits, sal_Int16 dx, sal_Int16 dy, sal_Bool bFilled ); + static void Impl_addStraightEdgeRecord( BitStream& rBits, sal_Int16 dx, sal_Int16 dy ); + static void Impl_addCurvedEdgeRecord( BitStream& rBits, sal_Int16 control_dx, sal_Int16 control_dy, sal_Int16 anchor_dx, sal_Int16 anchor_dy ); + static void Impl_addEndShapeRecord( BitStream& rBits ); + + static void Impl_addStraightLine( BitStream& rBits, + Point& rLastPoint, + const double P2x, const double P2y ); + static void Impl_addQuadBezier( BitStream& rBits, + Point& rLastPoint, + const double P2x, const double P2y, + const double P3x, const double P3y ); + static void Impl_quadBezierApprox( BitStream& rBits, + Point& rLastPoint, + const double d2, + const double P1x, const double P1y, + const double P2x, const double P2y, + const double P3x, const double P3y, + const double P4x, const double P4y ); + +private: + FontMap maFonts; + + sal_Int32 mnDocWidth; + sal_Int32 mnDocHeight; + + // AS: Scaling factor for output. + double mnDocXScale; + double mnDocYScale; + + sal_uInt16 mnWhiteBackgroundShapeId; + sal_uInt16 mnPageButtonId; + + VirtualDevice* mpVDev; + + const PolyPolygon* mpClipPolyPolygon; + + /** holds the informations of the objects defined in the movie stream + while executing defineShape + */ + typedef std::vector<sal_uInt16> CharacterIdVector; + CharacterIdVector maShapeIds; + + Tag* mpTag; + Sprite* mpSprite; + std::stack<Sprite*> mvSpriteStack; + ChecksumCache mBitmapCache; + + sal_uInt16 mnNextId; + sal_uInt32 mnFrames; + +// com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > mxOutStream; + oslFileHandle mxOutStream; + + utl::TempFile maMovieTempFile; + utl::TempFile maFontsTempFile; + + SvStream* mpMovieStream; + SvStream* mpFontsStream; + +#ifdef AUGUSTUS + lame_global_flags *m_lame_flags; +#endif + + sal_uInt8 mnGlobalTransparency; + sal_Int32 mnJPEGCompressMode; + sal_Bool mbWrittenJPEGTables; +}; + +/////////////////////////////////////////////////////////////////////// + + +}; + +#endif diff --git a/filter/source/flash/swfwriter1.cxx b/filter/source/flash/swfwriter1.cxx new file mode 100644 index 000000000000..6320e243ea6e --- /dev/null +++ b/filter/source/flash/swfwriter1.cxx @@ -0,0 +1,1870 @@ +/************************************************************************* + * + * $RCSfile: swfwriter1.cxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: cl $ $Date: 2002-11-21 14:58:04 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Christian Lippka (christian.lippka@sun.com) + * Thorsten Behrens (thorsten.behrens@sun.com) + * + * + ************************************************************************/ + +#ifndef _SWF_WRITER_HXX_ +#include "swfwriter.hxx" +#endif + +#ifndef _SV_METAACT_HXX +#include <vcl/metaact.hxx> +#endif +#ifndef _SV_GDIMTF_HXX +#include <vcl/gdimtf.hxx> +#endif +#ifndef _SV_BMPACC_HXX +#include <vcl/bmpacc.hxx> +#endif +#ifndef _SV_VIRDEV_HXX +#include <vcl/virdev.hxx> +#endif +#ifndef _SV_METRIC_HXX +#include <vcl/metric.hxx> +#endif + + +#ifndef _FILTER_HXX +#include <svtools/Filter.hxx> +#endif +#ifndef _SVTOOLS_GRAPHICTOOLS_HXX_ +#include <svtools/graphictools.hxx> +#endif + +#include <external/zlib/zlib.h> + +#ifndef _SV_SALBTYPE_HXX +#include <vcl/salbtype.hxx> +#endif + +using namespace ::swf; +using namespace ::std; +using namespace ::rtl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::beans; + +extern sal_uInt16 getMaxBitsUnsigned( sal_uInt32 nValue ); +extern sal_uInt16 getMaxBitsSigned( sal_Int32 nValue ); + +static MapMode aTWIPSMode( MAP_TWIP ); +static MapMode a100thmmMode( MAP_100TH_MM ); + +// ----------------------------------------------------------------------------- + +Point Writer::map( const Point& rPoint ) const +{ + const MapMode& aSourceMapMode = mpVDev->GetMapMode(); + + Point retPoint = mpVDev->LogicToLogic( rPoint, &aSourceMapMode, &aTWIPSMode ); + + // AS: Produces a 'possible loss of data' warning that we can't fix without + // hurting code readability. + retPoint.X() *= mnDocXScale; + retPoint.Y() *= mnDocYScale; + + return retPoint; +} + +// ----------------------------------------------------------------------------- + +Size Writer::map( const Size& rSize ) const +{ + const MapMode& aSourceMapMode = mpVDev->GetMapMode(); + + Size retSize = mpVDev->LogicToLogic( rSize, &aSourceMapMode, &aTWIPSMode ); + + // AS: Produces a 'possible loss of data' warning that we can't fix without + // hurting code readability. + retSize.Width() *= mnDocXScale; + retSize.Height() *= mnDocYScale; + + return retSize; +} + +// ----------------------------------------------------------------------------- + +void Writer::map( PolyPolygon& rPolyPolygon ) const +{ + const sal_uInt16 nPolyCount = rPolyPolygon.Count(); + if( nPolyCount ) + { + sal_uInt16 nPoly, nPoint, nPointCount; + for( nPoly = 0; nPoly < nPolyCount; nPoly++ ) + { + Polygon& rPoly = rPolyPolygon[nPoly]; + nPointCount = rPoly.GetSize(); + + for( nPoint = 0; nPoint < nPointCount; nPoint++ ) + { + rPoly[nPoint] = map( rPoly[nPoint] ); + } + } + } +} + +// ----------------------------------------------------------------------------- + +sal_Int32 Writer::mapRelative( sal_Int32 n100thMM ) const +{ + MapMode aSourceMapMode( mpVDev->GetMapMode() ); + aSourceMapMode.SetOrigin( Point() ); + + sal_Int32 nTwips = mpVDev->LogicToLogic( Point( n100thMM, n100thMM ), &aSourceMapMode, &aTWIPSMode ).X(); + return nTwips; +} + +// ----------------------------------------------------------------------------- + +/** +*/ +void Writer::Impl_addPolygon( BitStream& rBits, const Polygon& rPoly, sal_Bool bFilled ) +{ + Point aLastPoint( rPoly[0] ); + + Impl_addShapeRecordChange( rBits, _Int16(aLastPoint.X()),_Int16(aLastPoint.Y()), bFilled ); + + USHORT i = 0, nSize = rPoly.GetSize(); + + double d = 16.0f; + + // points + while( ( i + 1 ) < nSize ) + { + if( ( i + 3 ) < nSize ) + { + BYTE P1( rPoly.GetFlags( i ) ); + BYTE P4( rPoly.GetFlags( i + 3 ) ); + + if( ( POLY_NORMAL == P1 || POLY_SMOOTH == P1 || POLY_SYMMTR == P1 ) && + ( POLY_CONTROL == rPoly.GetFlags( i + 1 ) ) && + ( POLY_CONTROL == rPoly.GetFlags( i + 2 ) ) && + ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) ) + { + Impl_quadBezierApprox( rBits, aLastPoint, d*d, + rPoly.GetPoint( i ).X(), rPoly.GetPoint( i ).Y(), + rPoly.GetPoint( i+1 ).X(), rPoly.GetPoint( i+1 ).Y(), + rPoly.GetPoint( i+2 ).X(), rPoly.GetPoint( i+2 ).Y(), + rPoly.GetPoint( i+3 ).X(), rPoly.GetPoint( i+3 ).Y() ); + i += 3; + continue; + } + } + + ++i; + + const Point aPolyPoint( rPoly[ i ] ); + if( aPolyPoint != aLastPoint ) + { + Impl_addStraightEdgeRecord( rBits, _Int16(aPolyPoint.X() - aLastPoint.X()),_Int16(aPolyPoint.Y() - aLastPoint.Y())); + aLastPoint = aPolyPoint; + } + } + + if( bFilled && (rPoly[0] != rPoly[nSize-1])) + { + const Point aPolyPoint( rPoly[ 0 ] ); + if( aPolyPoint != aLastPoint ) + { + Impl_addStraightEdgeRecord( rBits, _Int16(aPolyPoint.X() - aLastPoint.X()),_Int16(aPolyPoint.Y() - aLastPoint.Y())); + } + } +} + +// ----------------------------------------------------------------------------- + +/** exports a style change record with a move to (x,y) and depending on bFilled a line style 1 or fill style 1 +*/ +void Writer::Impl_addShapeRecordChange( BitStream& rBits, sal_Int16 dx, sal_Int16 dy, sal_Bool bFilled ) +{ + rBits.writeUB( 0, 1 ); // TypeFlag + rBits.writeUB( 0, 1 ); // StateNewStyles + rBits.writeUB( !bFilled, 1 ); // StateLineStyle + rBits.writeUB( 0, 1 ); // StateFillStyle0 + rBits.writeUB( bFilled, 1 ); // StateFillStyle1 + rBits.writeUB( 1, 1 ); // StateMoveTo + + sal_uInt16 nMoveBits = max( getMaxBitsSigned( dx ), getMaxBitsSigned( dy ) ); + + rBits.writeUB( nMoveBits, 5 ); // Number of bits per value + // TODO: Optimize horizontal and vertical lines + rBits.writeSB( dx, nMoveBits ); // DeltaX + rBits.writeSB( dy, nMoveBits ); // DeltaY + + rBits.writeUB( 1, 1 ); // set FillStyle1 or LineStyle to 1 +} + +// ----------------------------------------------------------------------------- + +/** exports a straight edge record +*/ +void Writer::Impl_addStraightEdgeRecord( BitStream& rBits, sal_Int16 dx, sal_Int16 dy ) +{ + rBits.writeUB( 1, 1 ); // TypeFlag + rBits.writeUB( 1, 1 ); // StraightFlag + + sal_uInt16 nBits = max( getMaxBitsSigned( dx ), getMaxBitsSigned( dy ) ); + + rBits.writeUB( nBits - 2, 4 ); // Number of bits per value + + if( (dx != 0) && (dy != 0) ) + { + rBits.writeUB( 1, 1 ); // GeneralLineFlag + rBits.writeSB( dx, nBits ); // DeltaX + rBits.writeSB( dy, nBits ); // DeltaY + } + else + { + rBits.writeUB( 0, 1 ); + rBits.writeUB( ( dx == 0 ), 1 ); + if( dx == 0 ) + { + rBits.writeSB( dy, nBits ); // DeltaY + } + else + { + rBits.writeSB( dx, nBits ); // DeltaX + } + } +} + +// ----------------------------------------------------------------------------- + +/** exports a curved edge record +*/ +void Writer::Impl_addCurvedEdgeRecord( BitStream& rBits, sal_Int16 control_dx, sal_Int16 control_dy, sal_Int16 anchor_dx, sal_Int16 anchor_dy ) +{ + rBits.writeUB( 1, 1 ); // TypeFlag + rBits.writeUB( 0, 1 ); // CurvedFlag + + sal_uInt8 nBits = static_cast<sal_uInt8>( + max( getMaxBitsSigned( control_dx ), + max( getMaxBitsSigned( control_dy ), + max( getMaxBitsSigned( anchor_dx ), + max( getMaxBitsSigned( anchor_dy ), (sal_uInt16)3 ) ) ) ) ); + + rBits.writeUB( nBits - 2, 4 ); // Number of bits per value + + rBits.writeSB( control_dx, nBits ); // DeltaX + rBits.writeSB( control_dy, nBits ); // DeltaY + rBits.writeSB( anchor_dx, nBits ); // DeltaX + rBits.writeSB( anchor_dy, nBits ); // DeltaY +} + +// ----------------------------------------------------------------------------- + +/** exports a end shape record +*/ +void Writer::Impl_addEndShapeRecord( BitStream& rBits ) +{ + rBits.writeUB( 0, 6 ); +} + +// ----------------------------------------------------------------------------- + +void Writer::Impl_writePolygon( const Polygon& rPoly, sal_Bool bFilled ) +{ + PolyPolygon aPolyPoly( rPoly ); + Impl_writePolyPolygon( aPolyPoly, bFilled ); +} + +// ----------------------------------------------------------------------------- + +void Writer::Impl_writePolygon( const Polygon& rPoly, sal_Bool bFilled, const Color& rFillColor, const Color& rLineColor ) +{ + PolyPolygon aPolyPoly( rPoly ); + Impl_writePolyPolygon( aPolyPoly, bFilled, rFillColor, rLineColor ); +} + +// ----------------------------------------------------------------------------- + +void Writer::Impl_writePolyPolygon( const PolyPolygon& rPolyPoly, sal_Bool bFilled, sal_uInt8 nTransparence /* = 0 */ ) +{ + Color aLineColor( mpVDev->GetLineColor() ); + if( 0 == aLineColor.GetTransparency() ) + aLineColor.SetTransparency( nTransparence ); + Color aFillColor( mpVDev->GetFillColor() ); + if( 0 == aFillColor.GetTransparency() ) + aFillColor.SetTransparency( nTransparence ); + Impl_writePolyPolygon(rPolyPoly, bFilled, aFillColor, aLineColor ); +} + +// ----------------------------------------------------------------------------- + +void Writer::Impl_writePolyPolygon( const PolyPolygon& rPolyPoly, sal_Bool bFilled, const Color& rFillColor, const Color& rLineColor ) +{ + PolyPolygon aPolyPoly( rPolyPoly ); + + if( aPolyPoly.Count() ) + { + map( aPolyPoly ); + + if( mpClipPolyPolygon ) + rPolyPoly.GetIntersection( *mpClipPolyPolygon, aPolyPoly ); + + sal_uInt16 nID; + if( bFilled ) + { + Color aFillColor( rFillColor ); + if( 0 != mnGlobalTransparency ) + aFillColor.SetTransparency( mnGlobalTransparency ); + + FillStyle aStyle( aFillColor ); + nID = defineShape( aPolyPoly, aStyle ); + } + else + { + Color aLineColor( rLineColor ); + if( 0 != mnGlobalTransparency ) + aLineColor.SetTransparency( mnGlobalTransparency ); + + nID = defineShape( aPolyPoly, 1, aLineColor ); + } + maShapeIds.push_back( nID ); + } +} + +// ----------------------------------------------------------------------------- + +/** a gradient is a transition from one color to another, rendered inside a given polypolygon */ +void Writer::Impl_writeGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient ) +{ + if( rPolyPoly.Count() ) + { + PolyPolygon aPolyPolygon( rPolyPoly ); + map( aPolyPolygon ); + + if( (rGradient.GetStyle() == GRADIENT_LINEAR) || (rGradient.GetStyle() == GRADIENT_RADIAL) ) + { + const Rectangle aBoundRect( aPolyPolygon.GetBoundRect() ); + + FillStyle aFillStyle( aBoundRect, rGradient ); + + sal_uInt16 nShapeId = defineShape( aPolyPolygon, aFillStyle ); + maShapeIds.push_back( nShapeId ); + } + else + { + setClipping( &aPolyPolygon ); + + // render the gradient filling to simple polygons + { + GDIMetaFile aTmpMtf; + mpVDev->AddGradientActions( aPolyPolygon.GetBoundRect(), rGradient, aTmpMtf ); + Impl_writeActions( aTmpMtf ); + } + + setClipping( NULL ); + } + } +} + +// ----------------------------------------------------------------------------- + +void Writer::setClipping( const PolyPolygon* pClipPolyPolygon ) +{ + mpClipPolyPolygon = pClipPolyPolygon; +} + +// ----------------------------------------------------------------------------- + +// AS: Just comparing fonts straight up is too literal. There are some +// differences in font that actually require different glyphs to be defined, +// and some that don't. This function is meant to capture all the differences +// that we care about. +bool compare_fonts_for_me(const Font& rFont1, const Font& rFont2) +{ + return rFont1.GetName() == rFont2.GetName() && + rFont1.GetWeight() == rFont2.GetWeight() && + rFont1.GetItalic() == rFont2.GetItalic() && + rFont1.IsOutline() == rFont2.IsOutline() && + rFont1.IsShadow() == rFont2.IsShadow() && + rFont1.GetRelief() == rFont2.GetRelief(); +} + +// ----------------------------------------------------------------------------- + +FlashFont& Writer::Impl_getFont( const Font& rFont ) +{ + FontMap::iterator aIter( maFonts.begin() ); + const FontMap::iterator aEnd( maFonts.end() ); + + while( aIter != aEnd ) + { + const Font tempFont = (*aIter)->getFont(); + if( compare_fonts_for_me(tempFont, rFont) ) + { + return **aIter; + } + + aIter++; + } + + FlashFont* pFont = new FlashFont( rFont, createID() ); + maFonts.push_back( pFont ); + return *pFont; +} + +// ----------------------------------------------------------------------------- + +void Writer::Impl_writeText( const Point& rPos, const String& rText, const long* pDXArray, long nWidth ) +{ + sal_uInt32 nLen = rText.Len(); + + if( nLen ) + { + Size aNormSize; + long* pOwnArray; + long* pDX; + + // get text sizes + if( pDXArray ) + { + pOwnArray = NULL; + aNormSize = Size( mpVDev->GetTextWidth( rText ), 0 ); + pDX = (long*) pDXArray; + } + else + { + pOwnArray = new long[ nLen ]; + aNormSize = Size( mpVDev->GetTextArray( rText, pOwnArray ), 0 ); + pDX = pOwnArray; + } + + if( nLen > 1 ) + { + aNormSize.Width() = pDX[ nLen - 2 ] + mpVDev->GetTextWidth( rText.GetChar( (USHORT) nLen - 1 ) ); + + if( nWidth && aNormSize.Width() && ( nWidth != aNormSize.Width() ) ) + { + const double fFactor = (double) nWidth / aNormSize.Width(); + + sal_uInt32 i; + for( i = 0; i < ( nLen - 1 ); i++ ) + pDX[ i ] = FRound( pDX[ i ] * fFactor ); + } + } + + Font aOldFont( mpVDev->GetFont() ); + Point aBaseLinePos( rPos ); + + Font aFont(aOldFont); + short nOrientation = aFont.GetOrientation(); + aFont.SetOrientation( 0 ); + aFont.SetUnderline(UNDERLINE_NONE); + aFont.SetStrikeout(STRIKEOUT_NONE); + mpVDev->SetFont( aFont ); + + const FontMetric aMetric( mpVDev->GetFontMetric() ); + + FlashFont& rFlashFont = Impl_getFont( aFont ); + + // always adjust text position to match baseline alignment + switch( aOldFont.GetAlign() ) + { + case( ALIGN_TOP ): + aBaseLinePos.Y() += aMetric.GetAscent(); + break; + + case( ALIGN_BOTTOM ): + aBaseLinePos.Y() -= aMetric.GetDescent(); + break; + + default: + break; + } + + // get mapped text position + const Point aPt( map( aBaseLinePos ) ); + + // write text element + +/* test code to create a bound rect, not realy working for rotated text + Size aTextSize( map( Size( mpVDev->GetTextWidth( rText ), mpVDev->GetTextHeight() ) ) ); + Point aMetricPoint( map( Point( aMetric.GetLeading(), aMetric.GetAscent() ) ) ); + + Point aTmpPoint( map( Point( - aMetric.GetLeading(), - aMetric.GetAscent() ) ) ); ; + Rectangle aTmpRectangle(aTmpPoint, aTextSize ); + Polygon aPoly( aTmpRectangle ); + + aPoly.Rotate( aTmpPoint, (USHORT) nOrientation ); + + Rectangle aTextBoundRect( aPoly.GetBoundRect() ); + + aPoly.Move( aPt.X(), aPt.Y() - map( Size( 0, aMetric.GetDescent() ) ).Height() ); + +*/ + +#if 0 // makes the calculated bound rect visible for debuging +{ + Polygon aTmpPoly( aPoly ); + sal_uInt16 nID = FlashGeometryExporter::writePolygonShape( aMovieStream, aTmpPoly, false, Color(COL_MAGENTA), Color(COL_MAGENTA), mpClipPolyPolygon ); + ImplPlaceObject( nID ); +} +#endif + + // CL: This is still a hack until we figure out how to calculate a correct bound rect + // for rotatet text + Rectangle textBounds( 0, 0, static_cast<long>(mnDocWidth*mnDocXScale), static_cast<long>(mnDocHeight*mnDocYScale) ); + + Matrix3D m; + m.Rotate( static_cast<double>(nOrientation) * F_PI1800 ); + m.Translate( double(aPt.X()), double(aPt.Y()) ); + + sal_Int16 nHeight = _Int16( map( Size( 0, aFont.GetHeight() ) ).Height() ); + + startTag( TAG_DEFINETEXT ); + + sal_uInt16 nTextId = createID(); + + mpTag->addUI16( nTextId ); + mpTag->addRect( textBounds ); + mpTag->addMatrix( m ); + + sal_uInt8 nGlyphBits = 16; + sal_uInt8 nAdvanceBits = 16; + + mpTag->addUI8( nGlyphBits ); + mpTag->addUI8( nAdvanceBits ); + + // text style change record + mpTag->addUI8( 0x8c ); + mpTag->addUI16( rFlashFont.getID() ); + mpTag->addRGB( mpVDev->GetTextColor() ); + mpTag->addUI16( _uInt16( nHeight ) ); + + DBG_ASSERT( nLen <= 127, "TODO: handle text with more than 127 characters" ); + + // Glyph record + mpTag->addUI8( (sal_uInt8) nLen ); + + BitStream aBits; + + sal_Int32 nLastDX = 0; + sal_Int32 nAdvance; + sal_uInt32 i; + for( i = 0; i < nLen; i++ ) + { + if( i < (nLen-1) ) + { + nAdvance = pDX[i] - nLastDX; + nLastDX = pDX[i]; + } + else + { + nAdvance = 0; + } + + aBits.writeUB( rFlashFont.getGlyph(rText.GetChar(_uInt16(i)),mpVDev), nGlyphBits ); + aBits.writeSB( _Int16(map( Size( nAdvance, 0 ) ).Width() ), nAdvanceBits ); + } + + mpTag->addBits( aBits ); + mpTag->addUI8( 0 ); + + endTag(); + + maShapeIds.push_back( nTextId ); + + // AS: Write strikeout and underline, if neccessary. This code was originally taken from the SVG + // export facility, although the positioning had to be tweaked a little. I can't explain the + // numbers, but the flash lines up very well with the original OOo document. All of this should + // probably be converted to polygons as part of the meta file, though, as we don't handle any + // fancy lines (like dashes). + if( aOldFont.GetStrikeout() || aOldFont.GetUnderline() ) + { + Polygon aPoly( 4 ); + const long nLineHeight = Max( (long) FRound( aMetric.GetLineHeight() * 0.05 ), (long) 1 ); + + if( aOldFont.GetStrikeout() ) + { + aPoly[ 0 ].X() = aBaseLinePos.X(); + aPoly[ 0 ].Y() = aBaseLinePos.Y() - FRound( aMetric.GetAscent() * 0.26 ) - nLineHeight; + aPoly[ 1 ].X() = aPoly[ 0 ].X() + aNormSize.Width() - 1; + aPoly[ 1 ].Y() = aPoly[ 0 ].Y(); + aPoly[ 2 ].X() = aPoly[ 1 ].X(); + aPoly[ 2 ].Y() = aPoly[ 1 ].Y() + nLineHeight - 1; + aPoly[ 3 ].X() = aPoly[ 0 ].X(); + aPoly[ 3 ].Y() = aPoly[ 2 ].Y(); + + Impl_writePolygon( aPoly, sal_True, aOldFont.GetColor(), aOldFont.GetColor() ); + } + + // AS: The factor of 1.5 on the nLineHeight is a magic number. I'm not sure why it works, + // but it looks good to me. + if( aOldFont.GetUnderline() ) + { + aPoly[ 0 ].X() = aBaseLinePos.X(); + aPoly[ 0 ].Y() = static_cast<long>(aBaseLinePos.Y() + 1.5*nLineHeight); + aPoly[ 1 ].X() = aPoly[ 0 ].X() + aNormSize.Width() - 1; + aPoly[ 1 ].Y() = aPoly[ 0 ].Y(); + aPoly[ 2 ].X() = aPoly[ 1 ].X(); + aPoly[ 2 ].Y() = aPoly[ 1 ].Y() + nLineHeight - 1; + aPoly[ 3 ].X() = aPoly[ 0 ].X(); + aPoly[ 3 ].Y() = aPoly[ 2 ].Y(); + + Impl_writePolygon( aPoly, sal_True, aOldFont.GetColor(), aOldFont.GetColor() ); + } + } + + mpVDev->SetFont( aOldFont ); + delete[] pOwnArray; + } +} + +// ----------------------------------------------------------------------------- +// AS: Because JPEGs require the alpha channel provided seperately (JPEG does not +// natively support alpha channel, but SWF lets you provide it seperately), we +// extract the alpha channel into a seperate array here. +void getBitmapData( const BitmapEx& aBmpEx, sal_uInt8*& tgadata, sal_uInt8*& tgaAlphadata, sal_uInt32& nWidth, sal_uInt32& nHeight ) +{ + if( !aBmpEx.IsEmpty() ) + { + Bitmap aBmp( aBmpEx.GetBitmap() ); + BitmapReadAccess* pRAcc = aBmp.AcquireReadAccess(); + + if( pRAcc ) + { + AlphaMask aAlpha; + nWidth = pRAcc->Width(); + nHeight = pRAcc->Height(); + tgadata = new sal_uInt8[nWidth*nHeight*4]; + tgaAlphadata = new sal_uInt8[nWidth*nHeight]; + sal_uInt8* p = tgadata, *pAlpha = tgaAlphadata; + + + if( aBmpEx.IsAlpha() ) + aAlpha = aBmpEx.GetAlpha(); + else if( aBmpEx.IsTransparent() ) + aAlpha = aBmpEx.GetMask(); + else + { + sal_uInt8 cAlphaVal = 0; + aAlpha = AlphaMask( aBmp.GetSizePixel(), &cAlphaVal ); + } + + BitmapReadAccess* pAAcc = aAlpha.AcquireReadAccess(); + + if( pAAcc ) + { + for( sal_uInt32 nY = 0; nY < nHeight; nY++ ) + { + for( sal_uInt32 nX = 0; nX < nWidth; nX++ ) + { + const sal_uInt8 nAlpha = pAAcc->GetPixel( nY, nX ).GetIndex(); + const BitmapColor aPixelColor( pRAcc->GetColor( nY, nX ) ); + + if( nAlpha == 0xff ) + { + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = 0; + } + else + { + *p++ = 0xff-nAlpha; + *p++ = aPixelColor.GetRed(); + *p++ = aPixelColor.GetGreen(); + *p++ = aPixelColor.GetBlue(); + } + *pAlpha++ = 0xff - nAlpha; + } + } + + aAlpha.ReleaseAccess( pAAcc ); + } + + aBmp.ReleaseAccess( pRAcc ); + } + } +} + +// ----------------------------------------------------------------------------- +sal_uInt16 Writer::defineBitmap( const BitmapEx &bmpSource, sal_Int32 nJPEGQualityLevel ) +{ + ULONG bmpChecksum = bmpSource.GetChecksum(); + + ChecksumCache::iterator it = mBitmapCache.find(bmpChecksum); + + // AS: We already exported this bitmap, so just return its ID. + if (mBitmapCache.end() != it) + return it->second; + + sal_uInt16 nBitmapId = createID(); + mBitmapCache[bmpChecksum] = nBitmapId; + + // AS: OK, we have a good image, so now we decide whether or not to JPEG it or + // or Lossless compress it. + + //Figure out lossless size + sal_uInt8 *pImageData, *pAlphaData; + sal_uInt32 width, height; + + getBitmapData( bmpSource, pImageData, pAlphaData, width, height ); + sal_uInt32 raw_size = width * height * 4; + sal_uInt32 compressed_size = raw_size + (sal_uInt32)(raw_size/100) + 12; + sal_uInt8 *pCompressed = new sal_uInt8[ compressed_size ]; + + if(compress2(pCompressed, &compressed_size, pImageData, raw_size, Z_BEST_COMPRESSION) != Z_OK) + DBG_ASSERT( false, "compress2 failed!" ); + + // AS: SWF files let you provide an Alpha mask for JPEG images, but we have + // to ZLIB compress the alpha channel seperately. + sal_uInt32 alpha_compressed_size = 0; + sal_uInt8 *pAlphaCompressed = NULL; + if (bmpSource.IsAlpha() || bmpSource.IsTransparent()) + { + alpha_compressed_size = width * height + (sal_uInt32)(raw_size/100) + 12; + pAlphaCompressed = new sal_uInt8[ compressed_size ]; + + if(compress2(pAlphaCompressed, &alpha_compressed_size, pAlphaData, width * height, Z_BEST_COMPRESSION) != Z_OK) + DBG_ASSERT( false, "compress2 failed!" ); + } + + //Figure out JPEG size + const sal_uInt8* pJpgData; + sal_uInt32 nJpgDataLength = -1; + + Graphic aGraphic( bmpSource ); + SvMemoryStream aDstStm( 65535, 65535 ); + + GraphicFilter aFilter; + Sequence< PropertyValue > aFilterData(nJPEGQualityLevel != -1); + if( nJPEGQualityLevel != -1 ) + { + aFilterData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM("Quality")); + aFilterData[0].Value <<= nJPEGQualityLevel; + } + + if( aFilter.ExportGraphic( aGraphic, String(), aDstStm, + aFilter.GetExportFormatNumberForShortName( OUString( RTL_CONSTASCII_USTRINGPARAM( JPG_SHORTNAME ) ) ), + false, &aFilterData ) == ERRCODE_NONE ) + { + pJpgData = reinterpret_cast<const sal_uInt8*>(aDstStm.GetData()); + nJpgDataLength = aDstStm.Seek( STREAM_SEEK_TO_END ); + } + + // AS: Ok, now go ahead and use whichever is smaller. If JPEG is smaller, then + // we have to export as TAG_DEFINEBITSJPEG3 in the case that there is alpha + // channel data. + if (nJpgDataLength + alpha_compressed_size < compressed_size) + Impl_writeJPEG(nBitmapId, pJpgData, nJpgDataLength, pAlphaCompressed, alpha_compressed_size, nJPEGQualityLevel == mnJPEGCompressMode); + else + Impl_writeBmp( nBitmapId, width, height, pCompressed, compressed_size ); + + delete[] pCompressed; + delete[] pAlphaCompressed; + delete[] pImageData; + delete[] pAlphaData; + + return nBitmapId; +} + +// ----------------------------------------------------------------------------- + +void Writer::Impl_writeImage( const BitmapEx& rBmpEx, const Point& rPt, const Size& rSz, const Point& rSrcPt, const Size& rSrcSz, const Rectangle& rClipRect, bool bNeedToMapClipRect ) +{ + if( !!rBmpEx ) + { + BitmapEx bmpSource( rBmpEx ); + + Rectangle originalPixelRect(Point(), bmpSource.GetSizePixel()); + + Point srcPt( map(rPt) ); + Size srcSize( map(rSz) ); + Rectangle destRect( srcPt, srcSize ); + + // AS: Christian, my scaling factors are different than yours, and work better for me. + // However, I can't explain why exactly. I got some of this by trial and error. + double XScale = static_cast<double>(originalPixelRect.GetWidth())/destRect.GetWidth(); + double YScale = static_cast<double>(originalPixelRect.GetHeight())/destRect.GetHeight(); + + // AS: If rClipRect has a value set, then we need to crop the bmp appropriately. + // If a map event already occurred in the metafile, then we do not need to map + // the clip rect as it's already been done. + if (!rClipRect.IsEmpty()) + { + // AS: Christian, I also don't understand why bNeedToMapClipRect is necessary, but it + // works like a charm. Sometimes the map event is missing from the metafile, but why? + Size clipSize( bNeedToMapClipRect ? map(rClipRect.GetSize()) : rClipRect.GetSize() ); + Rectangle clipRect(Point(), clipSize); + destRect.Intersection( clipRect ); + + Rectangle cropRect(destRect); + + // AS: The bmp origion is always 0,0 so we have to adjust before we crop. + cropRect.Move(-srcPt.X(), -srcPt.Y()); + // AS: Rectangle has no scale function (?!) so I do it manually... + Rectangle cropPixelRect(static_cast<long>(cropRect.Left()*XScale), + static_cast<long>(cropRect.Top()*YScale), + static_cast<long>(cropRect.Right()*XScale), + static_cast<long>(cropRect.Bottom()*YScale)); + + bmpSource.Crop(cropPixelRect); + } + + if( !!bmpSource ) + { + sal_Int32 nJPEGQuality = mnJPEGCompressMode; + + Size szDestPixel = mpVDev->LogicToPixel(srcSize, aTWIPSMode); + + double pixXScale = static_cast<double>(szDestPixel.Width()) / originalPixelRect.GetWidth(); + double pixYScale = static_cast<double>(szDestPixel.Height()) / originalPixelRect.GetHeight(); + + // AS: If the image has been scaled down, then scale down the quality + // that we use for JPEG compression. + if (pixXScale < 1.0 && pixYScale < 1.0) + { + + double qualityScale = (pixXScale + pixYScale)/2; + + nJPEGQuality *= qualityScale; + + if (nJPEGQuality < 10) + nJPEGQuality += 3; + } + + sal_uInt16 nBitmapId = defineBitmap(bmpSource, nJPEGQuality); + + Polygon aPoly( destRect ); + + // AS: Since images are being cropped now, no translation is normally necessary. + // However, some things like graphical bullet points are still get translated. + Matrix3D m; + m.Scale(1.0/XScale, 1.0/YScale); + if (destRect.Left() || destRect.Top()) + m.Translate(destRect.Left(), destRect.Top()); + + FillStyle aFillStyle( nBitmapId, true, m ); + + sal_uInt16 nShapeId = defineShape( aPoly, aFillStyle ); + + maShapeIds.push_back( nShapeId ); + } + } +} +// ----------------------------------------------------------------------------- + +void Writer::Impl_writeBmp( sal_uInt16 nBitmapId, sal_uInt32 width, sal_uInt32 height, sal_uInt8 *pCompressed, sal_uInt32 compressed_size ) +{ + startTag( TAG_DEFINEBITSLOSSLESS2 ); + + mpTag->addUI16( nBitmapId ); + mpTag->addUI8( 5 ); + mpTag->addUI16( _uInt16(width) ); + mpTag->addUI16( _uInt16(height) ); + + mpTag->Write( pCompressed, compressed_size ); + + endTag(); +} + +// ----------------------------------------------------------------------------- + +void Writer::Impl_writeJPEG(sal_uInt16 nBitmapId, const sal_uInt8* pJpgData, sal_uInt32 nJpgDataLength, sal_uInt8 *pAlphaCompressed, sal_uInt32 alpha_compressed_size, sal_Bool bStandardCompression ) +{ + // AS: Go through the actuall JPEG bits, seperating out the + // header fields from the actual image fields. Fields are + // identifed by 0xFFXX where XX is the field type. Both + // the header and the image need start and stop (D8 and D9), + // so that's why you see those written to both. I don't + // really know what the rest of these are, I got it to work + // kind of by trial and error and by comparing with known + // good SWF files. + sal_uInt8 cType = 0x01; + const sal_uInt8* pJpgSearch = pJpgData; + const sal_uInt8* pLastMark = pJpgData; + + SvMemoryStream EncodingTableStream; + SvMemoryStream ImageBitsStream; + for (;pJpgSearch < pJpgData + nJpgDataLength; pJpgSearch++) + { + if (0xFF == *pJpgSearch) + { + sal_uInt32 nLength = pJpgSearch - pLastMark; + + if (nLength > 0) + { + switch(cType) + { + case 0xD8: + EncodingTableStream.Write( pLastMark, nLength ); + ImageBitsStream.Write( pLastMark, nLength ); + break; + + case 0x01: + case 0x02: + case 0xDB: + case 0xC4: + EncodingTableStream.Write( pLastMark, nLength ); + break; + + case 0xC1: + case 0xE0: + case 0xC0: + case 0xDA: + case 0x03: + case 0x00: + ImageBitsStream.Write( pLastMark, nLength ); + break; + + default: + DBG_ERROR( "JPEG marker I didn't handle!" ); + + } + } + + cType = *(pJpgSearch + 1); + pLastMark = pJpgSearch; + + // AS: The way that I'm checking for markers, we'll miss the + // one at the end, so I special case it :( + if (0xD9 == cType) + { + EncodingTableStream.Write( pLastMark, 2 ); + ImageBitsStream.Write( pLastMark, 2 ); + } + } + } + + EncodingTableStream.Seek( STREAM_SEEK_TO_END ); + sal_uInt32 nEncodingTableSize = EncodingTableStream.Tell(); + EncodingTableStream.Seek( STREAM_SEEK_TO_BEGIN ); + + ImageBitsStream.Seek( STREAM_SEEK_TO_END ); + sal_uInt32 nImageBitsSize = ImageBitsStream.Tell(); + ImageBitsStream.Seek( STREAM_SEEK_TO_BEGIN ); + + // AS: If we need alpha support, use TAG_DEFINEBITSJPEG3. + if (alpha_compressed_size > 0) + { + startTag( TAG_DEFINEBITSJPEG3 ); + + mpTag->addUI16( nBitmapId ); + + mpTag->addUI32( nEncodingTableSize + nImageBitsSize ); + + mpTag->Write(EncodingTableStream.GetData(), nEncodingTableSize); + mpTag->Write(ImageBitsStream.GetData(), nImageBitsSize); + + mpTag->Write( pAlphaCompressed, alpha_compressed_size ); + + endTag(); + } + else if (!bStandardCompression) + { + startTag( TAG_DEFINEBITSJPEG2 ); + + mpTag->addUI16( nBitmapId ); + + mpTag->Write(EncodingTableStream.GetData(), nEncodingTableSize); + mpTag->Write(ImageBitsStream.GetData(), nImageBitsSize); + + endTag(); + } + else + { + if (!mbWrittenJPEGTables) + { + mbWrittenJPEGTables = true; + startTag( TAG_JPEGTABLES ); + + mpTag->Write(EncodingTableStream.GetData(), nEncodingTableSize); + + endTag(); + } + + startTag( TAG_DEFINEBITS ); + + mpTag->addUI16( nBitmapId ); + mpTag->Write(ImageBitsStream.GetData(), nImageBitsSize); + + endTag(); + } +} + +// ----------------------------------------------------------------------------- + +void Writer::Impl_writeLine( const Point& rPt1, const Point& rPt2, const Color* pLineColor ) +{ + Color aOldColor( mpVDev->GetLineColor() ); + if( pLineColor ) + mpVDev->SetLineColor( *pLineColor ); + + const Point aPtAry[2] = { rPt1, rPt2 }; + Polygon aPoly( 2, aPtAry ); + Impl_writePolyPolygon( aPoly, false ); + + mpVDev->SetLineColor( aOldColor ); +} + +// ----------------------------------------------------------------------------- + +void Writer::Impl_writeRect( const Rectangle& rRect, long nRadX, long nRadY ) +{ + if( (rRect.nTop == rRect.nBottom) || (rRect.nLeft == rRect.nRight) ) + { + Color aColor( mpVDev->GetFillColor() ); + Impl_writeLine( rRect.TopLeft(), rRect.BottomRight(), &aColor ); + } + else + { + Polygon aPoly( rRect, nRadX, nRadY ); + Impl_writePolyPolygon( aPoly, true ); + } +} + +// ----------------------------------------------------------------------------- + +void Writer::Impl_writeEllipse( const Point& rCenter, long nRadX, long nRadY ) +{ + Polygon aPoly( rCenter, nRadX, nRadY ); + Impl_writePolyPolygon( aPoly, false ); +} + + +/** writes the stroke defined by SvtGraphicStroke and returns true or it returns + false if it can't handle this stroke. +*/ +bool Writer::Impl_writeStroke( SvtGraphicStroke& rStroke ) +{ + Polygon aPolygon; + rStroke.getPath( aPolygon ); + PolyPolygon aPolyPolygon( aPolygon ); + + Rectangle aOldRect( aPolyPolygon.GetBoundRect() ); + + map( aPolyPolygon ); + + Rectangle aNewRect( aPolyPolygon.GetBoundRect() ); + + PolyPolygon aStartArrow; + rStroke.getStartArrow( aStartArrow ); + if( 0 != aStartArrow.Count() ) + return false; // todo: Implement line ends + + PolyPolygon aEndArrow; + rStroke.getEndArrow( aEndArrow ); + if( 0 != aEndArrow.Count() ) + return false; // todo: Implement line ends + + SvtGraphicStroke::DashArray aDashArray; + rStroke.getDashArray( aDashArray ); + if( 0 != aDashArray.size() ) + return false; // todo: implement dashes + + double fTransparency = rStroke.getTransparency(); + double fStrokeWidth = rStroke.getStrokeWidth(); + + Color aColor( mpVDev->GetLineColor() ); + + if( 0.0 != rStroke.getTransparency() ) + aColor.SetTransparency( MinMax( rStroke.getTransparency() * 0xff, 0, 0xff ) ); + + sal_uInt16 nShapeId = defineShape( aPolyPolygon, mapRelative( rStroke.getStrokeWidth() ), aColor ); + maShapeIds.push_back( nShapeId ); + return true; +} + +// ----------------------------------------------------------------------------- + +/** writes the filling defined by SvtGraphicFill and returns true or it returns + false if it can't handle this filling. +*/ +bool Writer::Impl_writeFilling( SvtGraphicFill& rFilling ) +{ + PolyPolygon aPolyPolygon; + rFilling.getPath( aPolyPolygon ); + + Rectangle aOldRect( aPolyPolygon.GetBoundRect() ); + + map( aPolyPolygon ); + + Rectangle aNewRect( aPolyPolygon.GetBoundRect() ); + + switch( rFilling.getFillType() ) + { + case SvtGraphicFill::FillType::fillSolid: + { + Color aColor( rFilling.getFillColor() ); + + if( 0.0 != rFilling.getTransparency() ) + aColor.SetTransparency( MinMax( rFilling.getTransparency() * 0xff, 0, 0xff ) ); + + FillStyle aFillStyle( aColor ); + + sal_uInt16 nShapeId = defineShape( aPolyPolygon, aFillStyle ); + maShapeIds.push_back( nShapeId ); + } + break; + case SvtGraphicFill::FillType::fillGradient: + return false; + case SvtGraphicFill::FillType::fillHatch: + return false; + case SvtGraphicFill::FillType::fillTexture: + { + Graphic aGraphic; + rFilling.getGraphic( aGraphic ); + + // CL->AS: Should we also scale down the quality here depending on image scale? + sal_uInt16 nBitmapId = defineBitmap( aGraphic.GetBitmapEx(), mnJPEGCompressMode ); + + Matrix3D aMatrix; + + SvtGraphicFill::Transform aTransform; + + rFilling.getTransform( aTransform ); + + int a,b; + for( a = 0; a < 2; a++ ) + { + for( b = 0; b < 3; b++ ) + { + aMatrix[a][b] = aTransform.matrix[a*3+b]; + } + } + aMatrix[2][0] = 0.0; aMatrix[2][1] = 0.0; aMatrix[2][2] = 1.0; + + // scale bitmap + Rectangle originalPixelRect(Point(), aGraphic.GetBitmapEx().GetSizePixel()); + + double XScale = (double)aNewRect.GetWidth()/aOldRect.GetWidth(); + double YScale = (double)aNewRect.GetHeight()/aOldRect.GetHeight(); + + aMatrix.Scale( XScale, YScale ); + + FillStyle aFillStyle( nBitmapId, !rFilling.IsTiling(), aMatrix ); + + sal_uInt16 nShapeId = defineShape( aPolyPolygon, aFillStyle ); + maShapeIds.push_back( nShapeId ); + } + break; + } + return true; +} + +// ----------------------------------------------------------------------------- + +void Writer::Impl_writeActions( const GDIMetaFile& rMtf ) +{ + Rectangle clipRect; + bool bMap = false; + for( ULONG i = 0, nCount = rMtf.GetActionCount(); i < nCount; i++ ) + { + const MetaAction* pAction = rMtf.GetAction( i ); + const USHORT nType = pAction->GetType(); + + switch( nType ) + { + case( META_PIXEL_ACTION ): + { + const MetaPixelAction* pA = (const MetaPixelAction*) pAction; + + Impl_writeLine( pA->GetPoint(), pA->GetPoint(), &pA->GetColor() ); + } + break; + + case( META_POINT_ACTION ): + { + const MetaPointAction* pA = (const MetaPointAction*) pAction; + + Impl_writeLine( pA->GetPoint(), pA->GetPoint() ); + } + break; + + case( META_LINE_ACTION ): + { + const MetaLineAction* pA = (const MetaLineAction*) pAction; + + Impl_writeLine( pA->GetStartPoint(), pA->GetEndPoint() ); + } + break; + + case( META_RECT_ACTION ): + { + Impl_writeRect( ( (const MetaRectAction*) pAction )->GetRect(), 0, 0 ); + } + break; + + case( META_ROUNDRECT_ACTION ): + { + const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pAction; + + Impl_writeRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() ); + } + break; + + case( META_ELLIPSE_ACTION ): + { + const MetaEllipseAction* pA = (const MetaEllipseAction*) pAction; + const Rectangle& rRect = pA->GetRect(); + + Impl_writeEllipse( rRect.Center(), rRect.GetWidth() >> 1, rRect.GetHeight() >> 1 ); + } + break; + + case( META_ARC_ACTION ): + case( META_PIE_ACTION ): + case( META_CHORD_ACTION ): + case( META_POLYGON_ACTION ): + { + Polygon aPoly; + + switch( nType ) + { + case( META_ARC_ACTION ): + { + const MetaArcAction* pA = (const MetaArcAction*) pAction; + aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC ); + } + break; + + case( META_PIE_ACTION ): + { + const MetaPieAction* pA = (const MetaPieAction*) pAction; + aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE ); + } + break; + + case( META_CHORD_ACTION ): + { + const MetaChordAction* pA = (const MetaChordAction*) pAction; + aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD ); + } + break; + + case( META_POLYGON_ACTION ): + aPoly = ( (const MetaPolygonAction*) pAction )->GetPolygon(); + break; + } + + if( aPoly.GetSize() ) + { + Impl_writePolygon( aPoly, sal_True ); + } + } + break; + + case( META_POLYLINE_ACTION ): + { + const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pAction; + const Polygon& rPoly = pA->GetPolygon(); + + if( rPoly.GetSize() ) + Impl_writePolygon( rPoly, sal_False ); + } + break; + + case( META_POLYPOLYGON_ACTION ): + { + const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*) pAction; + const PolyPolygon& rPolyPoly = pA->GetPolyPolygon(); + + if( rPolyPoly.Count() ) + Impl_writePolyPolygon( rPolyPoly, sal_True ); + } + break; + + case( META_GRADIENT_ACTION ): + { + const MetaGradientAction* pA = (const MetaGradientAction*) pAction; + + Polygon aPoly( pA->GetRect() ); + Impl_writeGradientEx( aPoly, pA->GetGradient() ); + } + break; + + case( META_GRADIENTEX_ACTION ): + { + const MetaGradientExAction* pA = (const MetaGradientExAction*) pAction; + Impl_writeGradientEx( pA->GetPolyPolygon(), pA->GetGradient() ); + } + break; + + case META_HATCH_ACTION: + { + const MetaHatchAction* pA = (const MetaHatchAction*) pAction; + GDIMetaFile aTmpMtf; + + mpVDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf ); + Impl_writeActions( aTmpMtf ); + } + break; + + case( META_TRANSPARENT_ACTION ): + { + const MetaTransparentAction* pA = (const MetaTransparentAction*) pAction; + const PolyPolygon& rPolyPoly = pA->GetPolyPolygon(); + + if( rPolyPoly.Count() ) + { + // convert transparence from percent into 0x00 - 0xff + sal_uInt8 nTransparence = (sal_uInt8) MinMax( FRound( pA->GetTransparence() * 2.55 ), 0, 255 ); + Impl_writePolyPolygon( rPolyPoly, sal_True, nTransparence ); + } + } + break; + + case( META_FLOATTRANSPARENT_ACTION ): + { + const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pAction; + GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() ); + Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() ); + const Size aSrcSize( aTmpMtf.GetPrefSize() ); + const Point aDestPt( pA->GetPoint() ); + const Size aDestSize( pA->GetSize() ); + const double fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0; + const double fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0; + long nMoveX, nMoveY; + + if( fScaleX != 1.0 || fScaleY != 1.0 ) + { + aTmpMtf.Scale( fScaleX, fScaleY ); + aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ); + aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY ); + } + + nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y(); + + if( nMoveX || nMoveY ) + aTmpMtf.Move( nMoveX, nMoveY ); + + const Gradient& rGradient = pA->GetGradient(); + sal_uInt32 nLuminance = ((sal_Int32)rGradient.GetStartColor().GetLuminance() + (sal_Int32)rGradient.GetEndColor().GetLuminance() ) >> 1; + + sal_uInt8 nOldGlobalTransparency = mnGlobalTransparency; + mnGlobalTransparency = (sal_uInt8)MinMax( nLuminance, 0, 0xff ); + + mpVDev->Push(); + Impl_writeActions( aTmpMtf ); + mpVDev->Pop(); + + mnGlobalTransparency = nOldGlobalTransparency; + } + break; + + case( META_EPS_ACTION ): + { + const MetaEPSAction* pA = (const MetaEPSAction*) pAction; + const GDIMetaFile aGDIMetaFile( pA->GetSubstitute() ); + sal_Bool bFound = sal_False; + + for( ULONG i = 0, nCount = aGDIMetaFile.GetActionCount(); ( i < nCount ) && !bFound; i++ ) + { + const MetaAction* pSubstAct = aGDIMetaFile.GetAction( i ); + + if( pSubstAct->GetType() == META_BMPSCALE_ACTION ) + { + bFound = sal_True; + const MetaBmpScaleAction* pBmpScaleAction = (const MetaBmpScaleAction*) pSubstAct; + Impl_writeImage( pBmpScaleAction->GetBitmap(), + pA->GetPoint(), pA->GetSize(), + Point(), pBmpScaleAction->GetBitmap().GetSizePixel(), clipRect, !bMap ); + } + } + } + break; + + case( META_COMMENT_ACTION ): + { + const MetaCommentAction* pA = (const MetaCommentAction*) pAction; + const BYTE* pData = pA->GetData(); + String aSkipComment; + + if( pA->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_BEGIN" ) == COMPARE_EQUAL ) + { + const MetaGradientExAction* pGradAction = NULL; + sal_Bool bDone = sal_False; + + while( !bDone && ( ++i < nCount ) ) + { + pAction = rMtf.GetAction( i ); + + if( pAction->GetType() == META_GRADIENTEX_ACTION ) + pGradAction = (const MetaGradientExAction*) pAction; + else if( ( pAction->GetType() == META_COMMENT_ACTION ) && + ( ( (const MetaCommentAction*) pAction )->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_END" ) == COMPARE_EQUAL ) ) + { + bDone = sal_True; + } + } + + if( pGradAction ) + Impl_writeGradientEx( pGradAction->GetPolyPolygon(), pGradAction->GetGradient()); + } + else if( pA->GetComment().CompareIgnoreCaseToAscii( "XPATHFILL_SEQ_BEGIN" ) == COMPARE_EQUAL && + pData ) + { + + // this comment encapsulates all high level information for a filling that caused + // the meta actions between the "XPATHFILL_SEQ_BEGIN" and "XPATHFILL_SEQ_END" comment. + + SvtGraphicFill aFilling; + SvMemoryStream aMemStm( (void*)pData, pA->GetDataSize(), STREAM_READ ); + + // read the fill info + aMemStm >> aFilling; + + // if impl_writeFilling can handle this high level filling, it returns true and we + // skip all meta actions until "XPATHFILL_SEQ_END" + if( Impl_writeFilling( aFilling ) ) + { + bool bDone = sal_False; + + while( !bDone && ( ++i < nCount ) ) + { + pAction = rMtf.GetAction( i ); + + if( ( pAction->GetType() == META_COMMENT_ACTION ) && + ( ( (const MetaCommentAction*) pAction )->GetComment().CompareIgnoreCaseToAscii( "XPATHFILL_SEQ_END" ) == COMPARE_EQUAL ) ) + { + bDone = sal_True; + } + } + } + } + else if( pA->GetComment().CompareIgnoreCaseToAscii( "XPATHSTROKE_SEQ_BEGIN" ) == COMPARE_EQUAL && + pData ) + { + + // this comment encapsulates all high level information for a filling that caused + // the meta actions between the "XPATHFILL_SEQ_BEGIN" and "XPATHFILL_SEQ_END" comment. + + SvtGraphicStroke aStroke; + SvMemoryStream aMemStm( (void*)pData, pA->GetDataSize(), STREAM_READ ); + + // read the fill info + aMemStm >> aStroke; + + // if impl_writeStroke can handle this high level stroke, it returns true and we + // skip all meta actions until "XPATHSTROKE_SEQ_END" + if( Impl_writeStroke( aStroke ) ) + { + bool bDone = sal_False; + + while( !bDone && ( ++i < nCount ) ) + { + pAction = rMtf.GetAction( i ); + + if( ( pAction->GetType() == META_COMMENT_ACTION ) && + ( ( (const MetaCommentAction*) pAction )->GetComment().CompareIgnoreCaseToAscii( "XPATHSTROKE_SEQ_END" ) == COMPARE_EQUAL ) ) + { + bDone = sal_True; + } + } + } + } + } + break; + + case( META_BMPSCALE_ACTION ): + { + const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pAction; + + Impl_writeImage( pA->GetBitmap(), + pA->GetPoint(), pA->GetSize(), + Point(), pA->GetBitmap().GetSizePixel(), clipRect, !bMap ); + } + break; + + case( META_BMP_ACTION ): + { + const MetaBmpAction* pA = (const MetaBmpAction*) pAction; + Impl_writeImage( pA->GetBitmap(), + pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmap().GetSizePixel()), + Point(), pA->GetBitmap().GetSizePixel(), clipRect, !bMap ); + } + break; + + case( META_BMPSCALEPART_ACTION ): + { + const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*) pAction; + Impl_writeImage( pA->GetBitmap(), + pA->GetDestPoint(), pA->GetDestSize(), + pA->GetSrcPoint(), pA->GetSrcSize(), clipRect, !bMap ); + } + break; + + case( META_BMPEX_ACTION ): + { + const MetaBmpExAction* pA = (const MetaBmpExAction*) pAction; + Impl_writeImage( pA->GetBitmapEx(), + pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmapEx().GetSizePixel() ), + Point(), pA->GetBitmapEx().GetSizePixel(), clipRect, !bMap ); + } + break; + + case( META_BMPEXSCALE_ACTION ): + { + const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pAction; + Impl_writeImage( pA->GetBitmapEx(), + pA->GetPoint(), pA->GetSize(), + Point(), pA->GetBitmapEx().GetSizePixel(), clipRect, !bMap ); + } + break; + + case( META_BMPEXSCALEPART_ACTION ): + { + const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pAction; + Impl_writeImage( pA->GetBitmapEx(), + pA->GetDestPoint(), pA->GetDestSize(), + pA->GetSrcPoint(), pA->GetSrcSize(), clipRect, !bMap ); + } + break; + + case( META_TEXT_ACTION ): + { + const MetaTextAction* pA = (const MetaTextAction*) pAction; + Impl_writeText( pA->GetPoint(), String( pA->GetText(), pA->GetIndex(), pA->GetLen() ), NULL, 0); + } + break; + + case( META_TEXTRECT_ACTION ): + { + const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction; + Impl_writeText( pA->GetRect().TopLeft(), pA->GetText(), NULL, 0 ); + } + break; + + case( META_TEXTARRAY_ACTION ): + { + const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pAction; + Impl_writeText( pA->GetPoint(), String( pA->GetText(), pA->GetIndex(), pA->GetLen() ), pA->GetDXArray(), 0 ); + } + break; + + case( META_STRETCHTEXT_ACTION ): + { + const MetaStretchTextAction* pA = (const MetaStretchTextAction*) pAction; + Impl_writeText( pA->GetPoint(), String( pA->GetText(), pA->GetIndex(), pA->GetLen() ), NULL, pA->GetWidth() ); + } + break; + + case( META_ISECTRECTCLIPREGION_ACTION ): + { + const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*) pAction; + clipRect = pA->GetRect(); + } + case( META_CLIPREGION_ACTION ): + case( META_ISECTREGIONCLIPREGION_ACTION ): + case( META_MOVECLIPREGION_ACTION ): + { + ( (MetaAction*) pAction )->Execute( mpVDev ); +// mbClipAttrChanged = sal_True; + } + break; + + case( META_MAPMODE_ACTION ): bMap = true; + case( META_REFPOINT_ACTION ): + case( META_LINECOLOR_ACTION ): + case( META_FILLCOLOR_ACTION ): + case( META_TEXTLINECOLOR_ACTION ): + case( META_TEXTFILLCOLOR_ACTION ): + case( META_TEXTCOLOR_ACTION ): + case( META_TEXTALIGN_ACTION ): + case( META_FONT_ACTION ): + case( META_PUSH_ACTION ): + case( META_POP_ACTION ): + { + ( (MetaAction*) pAction )->Execute( mpVDev ); + } + break; + + case( META_RASTEROP_ACTION ): + case( META_MASK_ACTION ): + case( META_MASKSCALE_ACTION ): + case( META_MASKSCALEPART_ACTION ): + case( META_WALLPAPER_ACTION ): + case( META_TEXTLINE_ACTION ): + case( META_LAYOUTMODE_ACTION ): + { + // !!! >>> we don't want to support these actions + } + break; + + default: + //DBG_ERROR( "FlashActionWriter::ImplWriteActions: unsupported MetaAction #" ); + break; + } + } +} + + +///////////////////////////////////////////////////////////////////////// + + +void Writer::Impl_addStraightLine( BitStream& rBits, Point& rLastPoint, + const double P2x, const double P2y ) +{ + Point aPoint( FRound(P2x), FRound(P2y) ); + + Impl_addStraightEdgeRecord( rBits, _Int16(aPoint.X() - rLastPoint.X()),_Int16(aPoint.Y() - rLastPoint.Y())); + rLastPoint = aPoint; + +} + +// ----------------------------------------------------------------------------- + +void Writer::Impl_addQuadBezier( BitStream& rBits, Point& rLastPoint, + const double P2x, const double P2y, + const double P3x, const double P3y ) +{ + + Point aControlPoint( FRound(P2x), FRound(P2y) ); + Point aAnchorPoint( FRound(P3x), FRound(P3y) ); + + Impl_addCurvedEdgeRecord( rBits, + _Int16(aControlPoint.X() - rLastPoint.X()),_Int16(aControlPoint.Y() - rLastPoint.Y()), + _Int16(aAnchorPoint.X() - aControlPoint.X()),_Int16(aAnchorPoint.Y() - aControlPoint.Y()) ); + rLastPoint = aAnchorPoint; +} + +// ----------------------------------------------------------------------------- + +/* Approximate given cubic bezier curve by quadratic bezier segments */ +void Writer::Impl_quadBezierApprox( BitStream& rBits, + Point& rLastPoint, + const double d2, + const double P1x, const double P1y, + const double P2x, const double P2y, + const double P3x, const double P3y, + const double P4x, const double P4y ) +{ + // Check for degenerate case, where the given cubic bezier curve + // is already quadratic: P4 == 3P3 - 3P2 + P1 + if( P4x == 3.0*P3x - 3.0*P2x + P1x && + P4y == 3.0*P3y - 3.0*P2y + P1y ) + { + Impl_addQuadBezier( rBits, rLastPoint, + 3.0/2.0*P2x - 1.0/2.0*P1x, 3.0/2.0*P2y - 1.0/2.0*P1y, + P4x, P4y); + } + else + { + // Create quadratic segment for given cubic: + // Start and end point must coincide, determine quadratic control + // point in such a way that it lies on the intersection of the + // tangents at start and end point, resp. Thus, both cubic and + // quadratic curve segments will match in 0th and 1st derivative + // at the start and end points + + // Intersection of P2P1 and P4P3 + // (P2y-P4y)(P3x-P4x)-(P2x-P4x)(P3y-P4y) + // lambda = ------------------------------------- + // (P1x-P2x)(P3y-P4y)-(P1y-P2y)(P3x-P4x) + // + // Intersection point IP is now + // IP = P2 + lambda(P1-P2) + // + const double nominator( (P2y-P4y)*(P3x-P4x) - (P2x-P4x)*(P3y-P4y) ); + const double denominator( (P1x-P2x)*(P3y-P4y) - (P1y-P2y)*(P3x-P4x) ); + const double lambda( nominator / denominator ); + + const double IPx( P2x + lambda*( P1x - P2x) ); + const double IPy( P2y + lambda*( P1y - P2y) ); + + // Introduce some alias names: quadratic start point is P1, end + // point is P4, control point is IP + const double QP1x( P1x ); + const double QP1y( P1y ); + const double QP2x( IPx ); + const double QP2y( IPy ); + const double QP3x( P4x ); + const double QP3y( P4y ); + + // Adapted bezier flatness test (lecture notes from R. Schaback, + // Mathematics of Computer-Aided Design, Uni Goettingen, 2000) + // + // ||C(t) - Q(t)|| <= max ||c_j - q_j|| + // 0<=j<=n + // + // In this case, we don't need the distance from the cubic bezier + // to a straight line, but to a quadratic bezier. The c_j's are + // the cubic bezier's bernstein coefficients, the q_j's the + // quadratic bezier's. We have the c_j's given, the q_j's can be + // calculated from QPi like this (sorry, mixed index notation, we + // use [1,n], formulas use [0,n-1]): + // + // q_0 = QP1 = P1 + // q_1 = 1/3 QP1 + 2/3 QP2 + // q_2 = 2/3 QP2 + 1/3 QP3 + // q_3 = QP3 = P4 + // + // We can drop case 0 and 3, since there the curves coincide + // (distance is zero) + + // calculate argument of max for j=1 and j=2 + const double fJ1x( P2x - 1.0/3.0*QP1x - 2.0/3.0*QP2x ); + const double fJ1y( P2y - 1.0/3.0*QP1y - 2.0/3.0*QP2y ); + const double fJ2x( P3x - 2.0/3.0*QP2x - 1.0/3.0*QP3x ); + const double fJ2y( P3y - 2.0/3.0*QP2y - 1.0/3.0*QP3y ); + + // stop if distance from cubic curve is guaranteed to be bounded by d + // Should denominator be 0: then P1P2 and P3P4 are parallel (P1P2^T R[90,P3P4] = 0.0), + // meaning that either we have a straight line or an inflexion point (see else block below) + if( 0.0 != denominator && + ::std::max( fJ1x*fJ1x + fJ1y*fJ1y, + fJ2x*fJ2x + fJ2y*fJ2y) < d2 ) + { + // requested resolution reached. + // Add end points to output file. + // order is preserved, since this is so to say depth first traversal. + Impl_addQuadBezier( rBits, rLastPoint, + QP2x, QP2y, + QP3x, QP3y); + } + else + { + // Maybe subdivide further + + // This is for robustness reasons, since the line intersection + // method below gets instable if the curve gets closer to a + // straight line. If the given cubic bezier does not deviate by + // more than d/4 from a straight line, either: + // - take the line (that's what we do here) + // - express the line by a quadratic bezier + + // Perform bezier flatness test (lecture notes from R. Schaback, + // Mathematics of Computer-Aided Design, Uni Goettingen, 2000) + // + // ||P(t) - L(t)|| <= max ||b_j - b_0 - j/n(b_n - b_0)|| + // 0<=j<=n + // + // What is calculated here is an upper bound to the distance from + // a line through b_0 and b_3 (P1 and P4 in our notation) and the + // curve. We can drop 0 and n from the running indices, since the + // argument of max becomes zero for those cases. + const double fJ1x( P2x - P1x - 1.0/3.0*(P4x - P1x) ); + const double fJ1y( P2y - P1y - 1.0/3.0*(P4y - P1y) ); + const double fJ2x( P3x - P1x - 2.0/3.0*(P4x - P1x) ); + const double fJ2y( P3y - P1y - 2.0/3.0*(P4y - P1y) ); + + // stop if distance from line is guaranteed to be bounded by d/4 + if( ::std::max( fJ1x*fJ1x + fJ1y*fJ1y, + fJ2x*fJ2x + fJ2y*fJ2y) < d2/16.0 ) + { + // do not subdivide further, add straight line instead + Impl_addStraightLine( rBits, rLastPoint, P4x, P4y); + } + else + { + // deCasteljau bezier arc, split at t=0.5 + // Foley/vanDam, p. 508 + const double L1x( P1x ), L1y( P1y ); + const double L2x( (P1x + P2x)*0.5 ), L2y( (P1y + P2y)*0.5 ); + const double Hx ( (P2x + P3x)*0.5 ), Hy ( (P2y + P3y)*0.5 ); + const double L3x( (L2x + Hx)*0.5 ), L3y( (L2y + Hy)*0.5 ); + const double R4x( P4x ), R4y( P4y ); + const double R3x( (P3x + P4x)*0.5 ), R3y( (P3y + P4y)*0.5 ); + const double R2x( (Hx + R3x)*0.5 ), R2y( (Hy + R3y)*0.5 ); + const double R1x( (L3x + R2x)*0.5 ), R1y( (L3y + R2y)*0.5 ); + const double L4x( R1x ), L4y( R1y ); + + // subdivide further + Impl_quadBezierApprox(rBits, rLastPoint, d2, L1x, L1y, L2x, L2y, L3x, L3y, L4x, L4y); + Impl_quadBezierApprox(rBits, rLastPoint, d2, R1x, R1y, R2x, R2y, R3x, R3y, R4x, R4y); + } + } + } +} + +///////////////////////////////////////////////////////////////////////// + +// TODO: Why do I need this? + +extern "C" +{ + +int ZEXPORT compress2 ( Bytef * dest, uLongf * destLen, const Bytef * source, uLong sourceLen, int level) +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +} diff --git a/filter/source/flash/swfwriter2.cxx b/filter/source/flash/swfwriter2.cxx new file mode 100644 index 000000000000..e32bfff6561a --- /dev/null +++ b/filter/source/flash/swfwriter2.cxx @@ -0,0 +1,727 @@ +/************************************************************************* + * + * $RCSfile: swfwriter2.cxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: cl $ $Date: 2002-11-21 14:58:04 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): Christian Lippka (christian.lippka@sun.com) + * + * + ************************************************************************/ + +#ifndef _SWF_WRITER_HXX_ +#include "swfwriter.hxx" +#endif + +#ifndef _SV_VIRDEV_HXX +#include <vcl/virdev.hxx> +#endif + +using namespace ::swf; +using namespace ::std; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using ::rtl::OUString; +using ::rtl::OString; + +// ----------------------------------------------------------------------------- + +sal_uInt16 getMaxBitsUnsigned( sal_uInt32 nValue ) +{ + sal_uInt16 nBits = 0; + + while( nValue ) + { + nBits++; + nValue >>= 1; + } + + return nBits; +} + +// ----------------------------------------------------------------------------- + +sal_uInt16 getMaxBitsSigned( sal_Int32 nValue ) +{ + if( nValue < 0 ) + nValue *= -1; + + return getMaxBitsUnsigned( static_cast< sal_uInt32 >(nValue) ) + 1; +} + +// ----------------------------------------------------------------------------- + +BitStream::BitStream() +{ + mnBitPos = 8; + mnCurrentByte = 0; +} + +// ----------------------------------------------------------------------------- + +void BitStream::writeUB( sal_uInt32 nValue, sal_uInt16 nBits ) +{ + while( nBits != 0 ) + { + mnCurrentByte |= nValue << (32 - nBits) >> (32 - mnBitPos); + + if ( nBits > mnBitPos ) + { + nBits -= mnBitPos; + mnBitPos = 0; + } + else + { + mnBitPos -= nBits; + nBits = 0; + } + + if( 0 == mnBitPos ) + pad(); + } +} + +// ----------------------------------------------------------------------------- + +void BitStream::writeSB( sal_Int32 nValue, sal_uInt16 nBits ) +{ + writeUB( static_cast< sal_uInt32 >(nValue), nBits ); +} + +// ----------------------------------------------------------------------------- + +void BitStream::writeFB( sal_uInt32 nValue, sal_uInt16 nBits ) +{ + writeUB( nValue, nBits ); +} + +// ----------------------------------------------------------------------------- + +void BitStream::pad() +{ + if( 8 != mnBitPos ) + { + maData.push_back( mnCurrentByte ); + mnCurrentByte = 0; + mnBitPos = 8; + } +} + +// ----------------------------------------------------------------------------- + +void BitStream::writeTo( SvStream& out ) +{ + pad(); + + vector< sal_uInt8 >::iterator aIter( maData.begin() ); + const vector< sal_uInt8>::iterator aEnd( maData.end() ); + while(aIter != aEnd) + { + out << (*aIter++); + } +} + +// ----------------------------------------------------------------------------- + +sal_uInt32 BitStream::getOffset() const +{ + return maData.size(); +} + +//////////////////////////////////////////////////////////////////////////////// + +Tag::Tag( sal_uInt8 nTagId ) +{ + mnTagId = nTagId; +} + +// ----------------------------------------------------------------------------- + +void Tag::write( SvStream &out ) +{ + Seek( STREAM_SEEK_TO_END ); + sal_uInt32 nSize = Tell(); + Seek( STREAM_SEEK_TO_BEGIN ); + + if( mnTagId != 0xff ) + { + bool bLarge = nSize > 62; + + sal_uInt16 nCode = ( mnTagId << 6 ) | ( bLarge ? 0x3f : _uInt16(nSize) ); + + out << (sal_uInt8)nCode; + out << (sal_uInt8)(nCode >> 8); + + if( bLarge ) + { + sal_uInt32 nTmp = nSize; + + out << (sal_uInt8)nTmp; + nTmp >>= 8; + out << (sal_uInt8)nTmp; + nTmp >>= 8; + out << (sal_uInt8)nTmp; + nTmp >>= 8; + out << (sal_uInt8)nTmp; + } + } + + out.Write( GetData(), nSize ); +} + +// ----------------------------------------------------------------------------- + +void Tag::addI32( sal_Int32 nValue ) +{ + addUI32( static_cast<sal_uInt32>( nValue ) ); +} + +// ----------------------------------------------------------------------------- + +void Tag::addUI32( sal_uInt32 nValue ) +{ + *this << nValue; +} + +// ----------------------------------------------------------------------------- + +void Tag::addI16( sal_Int16 nValue ) +{ + addUI16( static_cast<sal_uInt16>( nValue ) ); +} + +// ----------------------------------------------------------------------------- + +void Tag::addUI16( sal_uInt16 nValue ) +{ + *this << (sal_uInt8)nValue; + *this << (sal_uInt8)(nValue >> 8); +} + +// ----------------------------------------------------------------------------- + +void Tag::addUI8( sal_uInt8 nValue ) +{ + *this << (sal_uInt8)nValue; +} + +// ----------------------------------------------------------------------------- + +void Tag::addBits( BitStream& rIn ) +{ + rIn.writeTo( *this ); +} + +// ----------------------------------------------------------------------------- + +void Tag::addRGBA( const Color& rColor ) +{ + addUI8( rColor.GetRed() ); + addUI8( rColor.GetGreen() ); + addUI8( rColor.GetBlue() ); + addUI8( 0xff - rColor.GetTransparency() ); +} + +// ----------------------------------------------------------------------------- + +void Tag::addRGB( const Color& rColor ) +{ + addUI8( rColor.GetRed() ); + addUI8( rColor.GetGreen() ); + addUI8( rColor.GetBlue() ); +} + +// ----------------------------------------------------------------------------- + +void Tag::addRect( const Rectangle& rRect ) +{ + writeRect( *this, rRect ); +} + +// ----------------------------------------------------------------------------- + +void Tag::writeRect( SvStream& rOut, const Rectangle& rRect ) +{ + BitStream aBits; + + sal_Int16 minX, minY, maxX, maxY; + + if( rRect.nLeft < rRect.nRight ) + { + minX = _Int16(rRect.nLeft); maxX = _Int16(rRect.nRight); + } + else + { + maxX = _Int16(rRect.nLeft); minX = _Int16(rRect.nRight); + } + + + if( rRect.nTop < rRect.nBottom ) + { + minY = _Int16(rRect.nTop); maxY = _Int16(rRect.nBottom); + } + else + { + maxY = _Int16(rRect.nTop); minY = _Int16(rRect.nBottom); + } + + // AS: Figure out the maximum nubmer of bits required to represent any of the + // rectangle coordinates. Since minX or minY could be negative, they could + // actually require more bits than maxX or maxY. + // AS: Christian, can they be negative, or is that a wasted check? + // CL: I think so, f.e. for shapes that have the top and/or left edge outside + // the page origin + sal_uInt8 nBits1 = max( getMaxBitsSigned( minX ), getMaxBitsSigned( minY ) ); + sal_uInt8 nBits2 = max( getMaxBitsSigned( maxX ), getMaxBitsSigned( maxY ) ); + sal_uInt8 nBitsMax = max( nBits1, nBits2 ); + + aBits.writeUB( nBitsMax, 5 ); + aBits.writeSB( minX, nBitsMax ); + aBits.writeSB( maxX, nBitsMax ); + aBits.writeSB( minY, nBitsMax ); + aBits.writeSB( maxY, nBitsMax ); + + aBits.writeTo( rOut ); +} + +// ----------------------------------------------------------------------------- + +void Tag::addMatrix( const Matrix3D& rMatrix ) +{ + writeMatrix( *this, rMatrix ); +} + +// ----------------------------------------------------------------------------- + +void Tag::writeMatrix( SvStream& rOut, const Matrix3D& rMatrix ) +{ + + BitStream aBits; + + const sal_uInt8 bHasScale = rMatrix[0][0] != 1 || rMatrix[1][1] != 1; + + aBits.writeUB( bHasScale, 1 ); + + if( bHasScale ) + { + sal_uInt8 nScaleBits = 31; + + aBits.writeUB( nScaleBits, 5 ); + aBits.writeFB( getFixed( rMatrix[0][0] ), nScaleBits ); // Scale X + aBits.writeFB( getFixed( rMatrix[1][1] ), nScaleBits ); // Scale Y + } + + const sal_uInt8 bHasRotate = rMatrix[0][1] != 0 || rMatrix[1][0] != 0; + + aBits.writeUB( bHasRotate, 1 ); + + if( bHasRotate ) + { + sal_uInt8 nRotateBits = 31; + + aBits.writeUB( nRotateBits, 5 ); + aBits.writeFB( getFixed( rMatrix[0][1] ), nRotateBits ); // RotateSkew0 + aBits.writeFB( getFixed( rMatrix[1][0] ), nRotateBits ); // RotateSkew1 + } + + sal_uInt8 nTranslateBits = 16; + + aBits.writeUB( nTranslateBits, 5 ); + aBits.writeSB( (sal_Int16)rMatrix[0][2], nTranslateBits ); // Translate X + aBits.writeSB( (sal_Int16)rMatrix[1][2], nTranslateBits ); // Translate Y + + aBits.writeTo( rOut ); +} + +// ----------------------------------------------------------------------------- + +void Tag::addString( const char* pString ) +{ + if( pString ) + { + while( *pString ) + addUI8( *pString++ ); + } + + addUI8( 0 ); +} + +// ----------------------------------------------------------------------------- + +void Tag::addStream( SvStream& rIn ) +{ + *this << rIn; +} + +//////////////////////////////////////////////////////////////////////////////// + +Sprite::Sprite( sal_uInt16 nId ) +: mnId( nId ), mnFrames(0) +{ +} + +// ----------------------------------------------------------------------------- + +Sprite::~Sprite() +{ + for(vector< Tag* >::iterator i = maTags.begin(); i != maTags.end(); i++) + delete *i; +} + +// ----------------------------------------------------------------------------- + +void Sprite::write( SvStream& out ) +{ + SvMemoryStream aTmp; + for(vector< Tag* >::iterator i = maTags.begin(); i != maTags.end(); i++) + (*i)->write( aTmp ); + + aTmp.Seek(0); + + Tag aTag( TAG_DEFINESPRITE ); + aTag.addUI16( mnId ); + aTag.addUI16( _uInt16( mnFrames ) ); + aTag.addStream( aTmp ); + aTag.write( out ); +} + +// ----------------------------------------------------------------------------- + +void Sprite::addTag( Tag* pNewTag ) +{ + if( pNewTag ) + { + if( pNewTag->getTagId() == TAG_SHOWFRAME ) + mnFrames++; + + maTags.push_back( pNewTag ); + } +} + +///////////////////////////////////////////////////////////////////////////////// + +sal_uInt32 swf::getFixed( double fValue ) +{ + sal_Int16 nUpper = (sal_Int16)floor(fValue); + sal_uInt16 nLower = (sal_uInt16)((fValue - floor(fValue))*0x10000); + + sal_uInt32 temp = ((sal_Int32)nUpper)<<16; + temp |= nLower; + + return temp; +} + +///////////////////////////////////////////////////////////////////////////////// + +/** constructs a new flash font for the given VCL Font */ +FlashFont::FlashFont( const Font& rFont, sal_uInt16 nId ) +: maFont( rFont ), mnNextIndex(0), mnId( nId ) +{ +} + +// ----------------------------------------------------------------------------- + +FlashFont::~FlashFont() +{ +} + +// ----------------------------------------------------------------------------- + +/** gets the glyph id for the given character. The glyphs are created on demand */ +sal_uInt16 FlashFont::getGlyph( sal_uInt16 nChar, VirtualDevice* pVDev ) +{ + // see if we already created a glyph for this character + std::map<sal_uInt16, sal_uInt16, ltuint16>::iterator aIter( maGlyphIndex.find(nChar) ); + if( aIter != maGlyphIndex.end() ) + { + return aIter->second; + } + + // if not, we create one now + + maGlyphIndex[nChar] = mnNextIndex; + + Font aOldFont( pVDev->GetFont() ); + Font aNewFont( aOldFont ); + aNewFont.SetAlign( ALIGN_BASELINE ); + pVDev->SetFont( aNewFont ); + aOldFont.SetOrientation(0); + + // let the virtual device convert the character to polygons + PolyPolygon aPolyPoly; + pVDev->GetTextOutline( aPolyPoly, nChar ); + + maGlyphOffsets.push_back( _uInt16( maGlyphData.getOffset() ) ); + + // Number of fill and line index bits set to 1 + maGlyphData.writeUB( 0x11, 8 ); + + const sal_uInt16 nCount = aPolyPoly.Count(); + sal_uInt16 i,n; + for( i = 0; i < nCount; i++ ) + { + Polygon& rPoly = aPolyPoly[ i ]; + + const USHORT nSize = rPoly.GetSize(); + if( nSize ) + { + // convert polygon to flash EM_SQUARE (1024x1024) + for( n = 0; n < nSize; n++ ) + { + Point aPoint( rPoly[n] ); + aPoint.X() = static_cast<long>((double(aPoint.X()) * 1024.0 ) / double(aOldFont.GetHeight())); + aPoint.Y() = static_cast<long>((double(aPoint.Y()) * 1024.0 ) / double(aOldFont.GetHeight())); + rPoly[n] = aPoint; + } + Writer::Impl_addPolygon( maGlyphData, rPoly, true ); + } + } + Writer::Impl_addEndShapeRecord( maGlyphData ); + + maGlyphData.pad(); + + sal_uInt32 nOffset = maGlyphData.getOffset(); + + pVDev->SetFont( aOldFont ); + + return mnNextIndex++; +} + +// ----------------------------------------------------------------------------- + +void FlashFont::write( SvStream& out ) +{ + Tag aTag( TAG_DEFINEFONT ); + + aTag.addUI16( mnId ); + + sal_uInt16 nGlyphs = _uInt16( maGlyphOffsets.size() ); + sal_uInt16 nOffset = nGlyphs * sizeof( sal_uInt16 ); + + for(vector< sal_uInt16 >::iterator i = maGlyphOffsets.begin(); i != maGlyphOffsets.end(); i++) + aTag.addUI16( nOffset + (*i) ); + + aTag.addBits( maGlyphData ); + + aTag.write( out ); +} + +//////////////////////////////////////////////////////////////////////////////// + +/** this c'tor creates a solid fill style */ +FillStyle::FillStyle( const Color& rSolidColor ) +: meType( solid ), + maColor( rSolidColor ) +{ +} + +// ----------------------------------------------------------------------------- + +/** this c'tor creates a tiled or clipped bitmap fill style */ +FillStyle::FillStyle( sal_uInt16 nBitmapId, bool bClipped, const Matrix3D& rMatrix ) +: meType( bClipped ? clipped_bitmap : tiled_bitmap ), + maMatrix( rMatrix ), + mnBitmapId( nBitmapId ) +{ +} + +// ----------------------------------------------------------------------------- + +FillStyle::FillStyleType Impl_getFillStyleType( const Gradient& rGradient ) +{ + switch( rGradient.GetStyle() ) + { + case GradientStyle_ELLIPTICAL: + case GradientStyle_RADIAL: + return FillStyle::radial_gradient; +// case GradientStyle_AXIAL: +// case GradientStyle_SQUARE: +// case GradientStyle_RECT: +// case GradientStyle_LINEAR: + default: + return FillStyle::linear_gradient; + } +} + +// ----------------------------------------------------------------------------- + +/** this c'tor creates a linear or radial gradient fill style */ +FillStyle::FillStyle( const Rectangle& rBoundRect, const Gradient& rGradient ) +: meType( Impl_getFillStyleType( rGradient ) ), + maGradient( rGradient ), + maBoundRect( rBoundRect ) +{ +} + +// ----------------------------------------------------------------------------- + +void FillStyle::addTo( Tag* pTag ) const +{ + pTag->addUI8( meType ); + switch( meType ) + { + case solid: + pTag->addRGBA( maColor ); + break; + case linear_gradient: + case radial_gradient: + Impl_addGradient( pTag ); + break; + case tiled_bitmap: + case clipped_bitmap: + pTag->addUI16( mnBitmapId ); + pTag->addMatrix( maMatrix ); + break; + } +} + +// ----------------------------------------------------------------------------- + +struct GradRecord +{ + sal_uInt8 mnRatio; + Color maColor; + + GradRecord( sal_uInt8 nRatio, const Color& rColor ) : mnRatio( nRatio ), maColor( rColor ) {} +}; + +// TODO: better emulation of our gradients +void FillStyle::Impl_addGradient( Tag* pTag ) const +{ + vector< struct GradRecord > aGradientRecords; + + Matrix3D m; + + m.Rotate( (maGradient.GetAngle() - 900) * F_PI1800 ); + + switch( maGradient.GetStyle() ) + { + case GradientStyle_ELLIPTICAL: + case GradientStyle_RADIAL: + { + aGradientRecords.push_back( GradRecord( 0x00, maGradient.GetEndColor() ) ); + aGradientRecords.push_back( GradRecord( 0xff, maGradient.GetStartColor() ) ); + + double tx = ( maGradient.GetOfsX() * 32768.0 ) / 100.0; + double ty = ( maGradient.GetOfsY() * 32768.0 ) / 100.0; + double scalex = (double)maBoundRect.GetWidth() / 32768.0; + double scaley = (double)maBoundRect.GetHeight() / 32768.0; + + m.Scale( 1.2, 1.2 ); + + if( scalex > scaley ) + { + double scale_move = scaley / scalex; + + m.Translate( tx, scale_move * ty ); + + + m.Scale( scalex, scalex ); + } + else + { + double scale_move = scalex / scaley; + + m.Translate( scale_move * tx, ty ); + + + m.Scale( scaley, scaley ); + } + + } + break; + case GradientStyle_AXIAL: + { + aGradientRecords.push_back( GradRecord( 0x00, maGradient.GetEndColor() ) ); + aGradientRecords.push_back( GradRecord( 0x80, maGradient.GetStartColor() ) ); + aGradientRecords.push_back( GradRecord( 0xff, maGradient.GetEndColor() ) ); + double tx = ( 32768.0 / 2.0 ); + double ty = ( 32768.0 / 2.0 ); + double scalex = (double)maBoundRect.GetWidth() / 32768.0; + double scaley = (double)maBoundRect.GetHeight() / 32768.0; + + m.Translate( tx, ty ); + m.Scale( scalex, scaley ); + } + break; + case GradientStyle_SQUARE: + case GradientStyle_RECT: + case GradientStyle_LINEAR: + { + aGradientRecords.push_back( GradRecord( 0x00, maGradient.GetStartColor() ) ); + aGradientRecords.push_back( GradRecord( 0xff, maGradient.GetEndColor() ) ); + double scalex = (double)maBoundRect.GetWidth() / 32768.0; + double scaley = (double)maBoundRect.GetHeight() / 32768.0; + + m.Scale( scalex, scaley ); + + m.Translate( maBoundRect.GetWidth() / 2.0, maBoundRect.GetHeight() / 2.0 ); + } + break; + } + + m.Translate( maBoundRect.nLeft, maBoundRect.nTop ); + + pTag->addMatrix( m ); + + DBG_ASSERT( aGradientRecords.size() < 8, "Illegal FlashGradient!" ); + + pTag->addUI8( static_cast<sal_uInt8>( aGradientRecords.size() ) ); + + for(std::vector< GradRecord >::iterator i = aGradientRecords.begin(); i != aGradientRecords.end(); i++) + { + pTag->addUI8( (*i).mnRatio ); + pTag->addRGBA( (*i).maColor ); + } +} + |