summaryrefslogtreecommitdiffstats
path: root/sd/source/filter/eppt
diff options
context:
space:
mode:
Diffstat (limited to 'sd/source/filter/eppt')
-rw-r--r--sd/source/filter/eppt/eppt.cxx1464
-rw-r--r--sd/source/filter/eppt/eppt.hxx232
-rw-r--r--sd/source/filter/eppt/epptbase.hxx412
-rw-r--r--sd/source/filter/eppt/epptdef.hxx145
-rw-r--r--sd/source/filter/eppt/epptooxml.hxx189
-rw-r--r--sd/source/filter/eppt/epptso.cxx3361
-rw-r--r--sd/source/filter/eppt/escherex.cxx266
-rw-r--r--sd/source/filter/eppt/escherex.hxx64
-rw-r--r--sd/source/filter/eppt/grouptable.hxx69
-rw-r--r--sd/source/filter/eppt/pptexanimations.cxx2150
-rw-r--r--sd/source/filter/eppt/pptexanimations.hxx134
-rw-r--r--sd/source/filter/eppt/pptexsoundcollection.cxx213
-rw-r--r--sd/source/filter/eppt/pptexsoundcollection.hxx71
-rw-r--r--sd/source/filter/eppt/pptx-animations.cxx1539
-rw-r--r--sd/source/filter/eppt/pptx-animations.hxx25
-rw-r--r--sd/source/filter/eppt/pptx-epptbase.cxx1000
-rw-r--r--sd/source/filter/eppt/pptx-epptooxml.cxx2594
-rw-r--r--sd/source/filter/eppt/pptx-grouptable.cxx85
-rw-r--r--sd/source/filter/eppt/pptx-stylesheet.cxx489
-rw-r--r--sd/source/filter/eppt/pptx-text.cxx1400
-rw-r--r--sd/source/filter/eppt/text.hxx254
21 files changed, 16156 insertions, 0 deletions
diff --git a/sd/source/filter/eppt/eppt.cxx b/sd/source/filter/eppt/eppt.cxx
new file mode 100644
index 000000000..6f58d919e
--- /dev/null
+++ b/sd/source/filter/eppt/eppt.cxx
@@ -0,0 +1,1464 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "eppt.hxx"
+#include "epptdef.hxx"
+#include "pptexanimations.hxx"
+#include <o3tl/any.hxx>
+#include <tools/globname.hxx>
+#include <rtl/ustring.hxx>
+#include <tools/stream.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdoole2.hxx>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/office/XAnnotation.hpp>
+#include <com/sun/star/office/XAnnotationAccess.hpp>
+#include <com/sun/star/office/XAnnotationEnumeration.hpp>
+#include <com/sun/star/presentation/AnimationSpeed.hpp>
+#include <com/sun/star/presentation/XPresentationSupplier.hpp>
+#include <com/sun/star/presentation/XCustomPresentationSupplier.hpp>
+#include <com/sun/star/geometry/RealPoint2D.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <comphelper/sequence.hxx>
+#include <tools/zcodec.hxx>
+#include <filter/msfilter/classids.hxx>
+#include <filter/msfilter/msoleexp.hxx>
+#include <filter/msfilter/msdffimp.hxx>
+#include <filter/msfilter/svxmsbas.hxx>
+#include <editeng/flditem.hxx>
+#include <sfx2/docinf.hxx>
+#include <oox/export/utils.hxx>
+#include <oox/ole/olehelper.hxx>
+#include <memory>
+
+class SfxObjectShell;
+ // complete SfxObjectShell for SaveVBA under -fsanitize=function
+
+using namespace com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::presentation;
+
+using ::com::sun::star::beans::XPropertySet;
+
+//============================ PPTWriter ==================================
+
+PPTWriter::PPTWriter( tools::SvRef<SotStorage> const & rSvStorage,
+ css::uno::Reference< css::frame::XModel > const & rXModel,
+ css::uno::Reference< css::task::XStatusIndicator > const & rXStatInd,
+ SvMemoryStream* pVBA, sal_uInt32 nCnvrtFlags ) :
+ PPTWriterBase ( rXModel, rXStatInd ),
+ mnCnvrtFlags ( nCnvrtFlags ),
+ mbStatus ( false ),
+ mnStatMaxValue ( 0 ),
+ mnLatestStatValue ( 0 ),
+ mnTextStyle( 0 ),
+ mbFontIndependentLineSpacing( false ),
+ mnTextSize( 0 ),
+ mrStg ( rSvStorage ),
+ mnVBAOleOfs ( 0 ),
+ mpVBA ( pVBA ),
+ mnExEmbed ( 0 ),
+ mpExEmbed ( new SvMemoryStream ),
+ mnPagesWritten ( 0 ),
+ mnTxId ( 0x7a2f64 ),
+ mnDiaMode ( 0 ),
+ mnShapeMasterTitle ( 0 ),
+ mnShapeMasterBody ( 0 )
+{
+}
+
+void PPTWriter::exportPPTPre( const std::vector< css::beans::PropertyValue >& rMediaData )
+{
+ if ( !mrStg.is() )
+ return;
+
+ if ( mXStatusIndicator.is() )
+ {
+ mbStatusIndicator = true;
+ mnStatMaxValue = ( mnPages + mnMasterPages ) * 5;
+ mXStatusIndicator->start( "PowerPoint Export", mnStatMaxValue + ( mnStatMaxValue >> 3 ) );
+ }
+
+ SvGlobalName aGName(MSO_PPT8_CLASSID);
+ mrStg->SetClass( aGName, SotClipboardFormatId::NONE, "MS PowerPoint 97" );
+
+ if ( !ImplCreateCurrentUserStream() )
+ return;
+
+ mpStrm = mrStg->OpenSotStream( "PowerPoint Document" );
+ if ( !mpStrm )
+ return;
+
+ if ( !mpPicStrm )
+ mpPicStrm = mrStg->OpenSotStream( "Pictures" );
+
+ auto aIter = std::find_if(rMediaData.begin(), rMediaData.end(),
+ [](const css::beans::PropertyValue& rProp) { return rProp.Name == "BaseURI"; });
+ if (aIter != rMediaData.end())
+ (*aIter).Value >>= maBaseURI;
+ mpPptEscherEx.reset( new PptEscherEx( *mpStrm, maBaseURI ) );
+}
+
+void PPTWriter::exportPPTPost( )
+{
+ if ( !ImplCloseDocument() )
+ return;
+
+ if ( mbStatusIndicator )
+ {
+ mXStatusIndicator->setText( "PowerPoint Export" );
+ sal_uInt32 nValue = mnStatMaxValue + ( mnStatMaxValue >> 3 );
+ if ( nValue > mnLatestStatValue )
+ {
+ mXStatusIndicator->setValue( nValue );
+ mnLatestStatValue = nValue;
+ }
+ }
+
+ ImplWriteOLE();
+
+ ImplWriteVBA();
+
+ ImplWriteAtomEnding();
+
+ ImplCreateDocumentSummaryInformation();
+
+ mbStatus = true;
+};
+
+static void ImplExportComments( const uno::Reference< drawing::XDrawPage >& xPage, SvMemoryStream& rBinaryTagData10Atom );
+
+void PPTWriter::ImplWriteSlide( sal_uInt32 nPageNum, sal_uInt32 nMasterNum, sal_uInt16 nMode,
+ bool bHasBackground, Reference< XPropertySet > const & aXBackgroundPropSet )
+{
+ Any aAny;
+
+ const PHLayout& rLayout = GetLayout( mXPagePropSet );
+ mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_Slide | nPageNum, mpStrm->Tell() );
+ mpPptEscherEx->OpenContainer( EPP_Slide );
+ mpPptEscherEx->AddAtom( 24, EPP_SlideAtom, 2 );
+ mpStrm->WriteInt32( static_cast<sal_Int32>(rLayout.nLayout) );
+ mpStrm->WriteBytes(rLayout.nPlaceHolder, 8); // placeholderIDs (8 parts)
+ mpStrm->WriteUInt32( nMasterNum | 0x80000000 ) // master ID (equals 0x80000000 on a master page)
+ .WriteUInt32( nPageNum + 0x100 ) // notes ID (equals null if no notes are present)
+ .WriteUInt16( nMode )
+ .WriteUInt16( 0 ); // padword
+
+ mnDiaMode = 0;
+ bool bVisible = true;
+ css::presentation::FadeEffect eFe = css::presentation::FadeEffect_NONE;
+
+ if ( GetPropertyValue( aAny, mXPagePropSet, "Visible" ) )
+ aAny >>= bVisible;
+ if ( GetPropertyValue( aAny, mXPagePropSet, "Change" ) )
+ {
+ switch ( *o3tl::doAccess<sal_Int32>(aAny) )
+ {
+ case 1 : // automatic
+ mnDiaMode++;
+ [[fallthrough]];
+ case 2 : // semi-automatic
+ mnDiaMode++;
+ break;
+ default :
+ case 0 : // manual
+ break;
+ }
+ }
+ if ( GetPropertyValue( aAny, mXPagePropSet, "Effect" ) )
+ aAny >>= eFe;
+
+ sal_uInt32 nSoundRef = 0;
+ bool bIsSound = false;
+ bool bStopSound = false;
+ bool bLoopSound = false;
+
+ if ( GetPropertyValue( aAny, mXPagePropSet, "Sound" ) )
+ {
+ OUString aSoundURL;
+ if ( aAny >>= aSoundURL )
+ {
+ nSoundRef = maSoundCollection.GetId( aSoundURL );
+ bIsSound = true;
+ }
+ else
+ aAny >>= bStopSound;
+ }
+ if ( GetPropertyValue( aAny, mXPagePropSet, "LoopSound" ) )
+ aAny >>= bLoopSound;
+
+ bool bNeedsSSSlideInfoAtom = !bVisible
+ || ( mnDiaMode == 2 )
+ || bIsSound
+ || bStopSound
+ || ( eFe != css::presentation::FadeEffect_NONE );
+ if ( bNeedsSSSlideInfoAtom )
+ {
+ sal_uInt8 nDirection = 0;
+ sal_uInt8 nTransitionType = 0;
+ sal_uInt16 nBuildFlags = 1; // advance by mouseclick
+ sal_Int32 nSlideTime = 0; // still has to !!!
+ sal_uInt8 nSpeed = 1;
+
+ if ( GetPropertyValue( aAny, mXPagePropSet, "TransitionDuration" ) )
+ {
+ css::presentation::AnimationSpeed aAs;
+ double fTransitionDuration = -1.0;
+ aAny >>= fTransitionDuration;
+
+ if (fTransitionDuration >= 0)
+ {
+ if (fTransitionDuration <= 0.5)
+ {
+ aAs = css::presentation::AnimationSpeed::AnimationSpeed_FAST;
+ }
+ else if (fTransitionDuration >= 1.0)
+ {
+ aAs = css::presentation::AnimationSpeed::AnimationSpeed_SLOW;
+ }
+ else
+ {
+ aAs = css::presentation::AnimationSpeed::AnimationSpeed_MEDIUM;
+ }
+ }
+ else
+ aAs = css::presentation::AnimationSpeed::AnimationSpeed_MEDIUM;
+
+ nSpeed = static_cast<sal_uInt8>(aAs);
+ }
+ sal_Int16 nTT = 0;
+ if ( GetPropertyValue( aAny, mXPagePropSet, "TransitionType" )
+ && ( aAny >>= nTT ) )
+ {
+ sal_Int16 nTST = 0;
+ if ( GetPropertyValue( aAny, mXPagePropSet, "TransitionSubtype" )
+ && ( aAny >>= nTST ) )
+ nTransitionType = GetTransition( nTT, nTST, eFe, 0, nDirection );
+
+ }
+ if ( !nTransitionType )
+ nTransitionType = GetTransition( eFe, nDirection );
+ if ( mnDiaMode == 2 ) // automatic ?
+ nBuildFlags |= 0x400;
+ if ( !bVisible )
+ nBuildFlags |= 4;
+ if ( bIsSound )
+ nBuildFlags |= 16;
+ if ( bLoopSound )
+ nBuildFlags |= 64;
+ if ( bStopSound )
+ nBuildFlags |= 256;
+
+ if ( GetPropertyValue( aAny, mXPagePropSet, "Duration" ) )// duration of this slide
+ nSlideTime = *o3tl::doAccess<sal_Int32>(aAny) << 10; // in ticks
+
+ mpPptEscherEx->AddAtom( 16, EPP_SSSlideInfoAtom );
+ mpStrm->WriteInt32( nSlideTime ) // standtime in ticks
+ .WriteUInt32( nSoundRef )
+ .WriteUChar( nDirection )
+ .WriteUChar( nTransitionType )
+ .WriteUInt16( nBuildFlags )
+ .WriteUChar( nSpeed )
+ .WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 );
+ }
+
+ ImplCreateHeaderFooters( mXPagePropSet );
+
+ EscherSolverContainer aSolverContainer;
+ mpPptEscherEx->OpenContainer( EPP_PPDrawing );
+ mpPptEscherEx->OpenContainer( ESCHER_DgContainer );
+ mpPptEscherEx->EnterGroup(nullptr,nullptr);
+ ImplWritePage( rLayout, aSolverContainer, NORMAL, false, nPageNum ); // the shapes of the pages are created in the PPT document
+ mpPptEscherEx->LeaveGroup();
+
+ if ( bHasBackground )
+ ImplWriteBackground( aXBackgroundPropSet );
+ else
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::Background | ShapeFlag::HaveShapeProperty );
+ EscherPropertyContainer aPropOpt;
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, PPTtoEMU( maDestPageSize.Width ) );
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, PPTtoEMU( maDestPageSize.Width ) );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
+ aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_wDontShow );
+ aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 ); // if true, this is the background shape
+ aPropOpt.Commit( *mpStrm );
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+ }
+
+ aSolverContainer.WriteSolver( *mpStrm );
+
+ mpPptEscherEx->CloseContainer(); // ESCHER_DgContainer
+ mpPptEscherEx->CloseContainer(); // EPP_Drawing
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
+
+ SvMemoryStream aBinaryTagData10Atom;
+ ImplExportComments( mXDrawPage, aBinaryTagData10Atom );
+ SvMemoryStream amsofbtAnimGroup;
+ ppt::AnimationExporter aExporter( aSolverContainer, maSoundCollection );
+ aExporter.doexport( mXDrawPage, amsofbtAnimGroup );
+ sal_uInt32 nmsofbtAnimGroupSize = amsofbtAnimGroup.Tell();
+ if ( nmsofbtAnimGroupSize )
+ {
+ {
+ EscherExAtom aMagic2( aBinaryTagData10Atom, 0x2eeb );
+ aBinaryTagData10Atom.WriteUInt32( 0x01c45df9 )
+ .WriteUInt32( 0xe1471b30 );
+ }
+ {
+ EscherExAtom aMagic( aBinaryTagData10Atom, 0x2b00 );
+ aBinaryTagData10Atom.WriteUInt32( 0 );
+ }
+ aBinaryTagData10Atom.WriteBytes(amsofbtAnimGroup.GetData(), amsofbtAnimGroup.Tell());
+ {
+ EscherExContainer aMagic2( aBinaryTagData10Atom, 0x2b02 );
+ }
+ }
+ if ( aBinaryTagData10Atom.Tell() )
+ {
+ EscherExContainer aProgTags ( *mpStrm, EPP_ProgTags );
+ EscherExContainer aProgBinaryTag( *mpStrm, EPP_ProgBinaryTag );
+ {
+ EscherExAtom aCString( *mpStrm, EPP_CString );
+ mpStrm->WriteUInt32( 0x5f005f )
+ .WriteUInt32( 0x50005f )
+ .WriteUInt32( 0x540050 )
+ .WriteUInt16( 0x31 )
+ .WriteUInt16( 0x30 );
+ }
+ {
+ EscherExAtom aBinaryTagData( *mpStrm, EPP_BinaryTagData );
+ mpStrm->WriteBytes(aBinaryTagData10Atom.GetData(), aBinaryTagData10Atom.Tell());
+ }
+ }
+ mpPptEscherEx->CloseContainer(); // EPP_Slide
+}
+
+void PPTWriter::ImplWriteSlideMaster( sal_uInt32 nPageNum, Reference< XPropertySet > const & aXBackgroundPropSet )
+{
+ if (!aXBackgroundPropSet)
+ return;
+ mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_MainMaster | nPageNum, mpStrm->Tell() );
+ mpPptEscherEx->OpenContainer( EPP_MainMaster );
+ mpPptEscherEx->AddAtom( 24, EPP_SlideAtom, 2 );
+ mpStrm->WriteInt32( static_cast<sal_Int32>(EppLayout::TITLEANDBODYSLIDE) ) // slide layout -> title and body slide
+ .WriteUChar( 1 ).WriteUChar( 2 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 ) // placeholderID
+ .WriteUInt32( 0 ) // master ID (equals null at a master page)
+ .WriteUInt32( 0 ) // notes ID (equals null if no notes are present)
+ .WriteUInt16( 0 ) // Bit 1: Follow master objects, Bit 2: Follow master scheme, Bit 3: Follow master background
+ .WriteUInt16( 0 ); // padword
+
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
+ mpStrm->WriteUInt32( 0xff0000 ).WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x00ffff ).WriteUInt32( 0x0099ff ).WriteUInt32( 0xffff00 ).WriteUInt32( 0x0000ff ).WriteUInt32( 0x969696 );
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
+ mpStrm->WriteUInt32( 0xccffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x336666 ).WriteUInt32( 0x008080 ).WriteUInt32( 0x339933 ).WriteUInt32( 0x000080 ).WriteUInt32( 0xcc3300 ).WriteUInt32( 0x66ccff );
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x333333 ).WriteUInt32( 0x000000 ).WriteUInt32( 0xdddddd ).WriteUInt32( 0x808080 ).WriteUInt32( 0x4d4d4d ).WriteUInt32( 0xeaeaea );
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x66ccff ).WriteUInt32( 0xff0000 ).WriteUInt32( 0xcc00cc ).WriteUInt32( 0xc0c0c0 );
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0xc0c0c0 ).WriteUInt32( 0xff6600 ).WriteUInt32( 0x0000ff ).WriteUInt32( 0x009900 );
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 6 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0xff9933 ).WriteUInt32( 0xccff99 ).WriteUInt32( 0xcc00cc ).WriteUInt32( 0xb2b2b2 );
+
+ for ( int nInstance = EPP_TEXTTYPE_Title; nInstance <= EPP_TEXTTYPE_QuarterBody; nInstance++ )
+ {
+ if ( nInstance == EPP_TEXTTYPE_notUsed )
+ continue;
+
+ // the auto color is dependent to the page background,so we have to set a page that is in the right context
+ if ( nInstance == EPP_TEXTTYPE_Notes )
+ (void)GetPageByIndex(0, NOTICE);
+ else
+ (void)GetPageByIndex(0, MASTER);
+
+ mpPptEscherEx->BeginAtom();
+
+ bool bSimpleText = false;
+
+ mpStrm->WriteUInt16( 5 ); // paragraph count
+
+ for ( sal_uInt16 nLev = 0; nLev < 5; nLev++ )
+ {
+ if ( nInstance >= EPP_TEXTTYPE_CenterBody )
+ {
+ bSimpleText = true;
+ mpStrm->WriteUInt16( nLev );
+ }
+ mpStyleSheet->mpParaSheet[ nInstance ]->Write( *mpStrm, nLev, bSimpleText, mXPagePropSet );
+ mpStyleSheet->mpCharSheet[ nInstance ]->Write( *mpStrm, nLev, bSimpleText, mXPagePropSet );
+ }
+ mpPptEscherEx->EndAtom( EPP_TxMasterStyleAtom, 0, nInstance );
+ }
+ GetPageByIndex( nPageNum, MASTER );
+
+ EscherSolverContainer aSolverContainer;
+
+ mpPptEscherEx->OpenContainer( EPP_PPDrawing );
+ mpPptEscherEx->OpenContainer( ESCHER_DgContainer );
+
+ mpPptEscherEx->EnterGroup(nullptr,nullptr);
+ ImplWritePage( GetLayout( 0 ), aSolverContainer, MASTER, true ); // the shapes of the pages are created in the PPT document
+ mpPptEscherEx->LeaveGroup();
+
+ ImplWriteBackground( aXBackgroundPropSet );
+
+ aSolverContainer.WriteSolver( *mpStrm );
+
+ mpPptEscherEx->CloseContainer(); // ESCHER_DgContainer
+ mpPptEscherEx->CloseContainer(); // EPP_Drawing
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
+
+ if ( aBuExMasterStream.Tell() )
+ {
+ ImplProgTagContainer( mpStrm.get(), &aBuExMasterStream );
+ }
+ mpPptEscherEx->CloseContainer(); // EPP_MainMaster
+};
+
+PPTWriter::~PPTWriter()
+{
+ mpExEmbed.reset();
+ mpPptEscherEx.reset();
+ mpCurUserStrm.clear();
+ mpPicStrm.clear();
+ mpStrm.clear();
+ maStyleSheetList.clear();
+ maExOleObj.clear();
+ if ( mbStatusIndicator )
+ mXStatusIndicator->end();
+}
+
+bool PPTWriter::ImplCreateCurrentUserStream()
+{
+ mpCurUserStrm = mrStg->OpenSotStream( "Current User" );
+ if ( !mpCurUserStrm )
+ return false;
+ char pUserName[] = "Current User";
+ sal_uInt32 nLenOfUserName = strlen( pUserName );
+ sal_uInt32 nSizeOfRecord = 0x14 + ( ( nLenOfUserName + 4 ) & ~ 3 );
+
+ mpCurUserStrm->WriteUInt16( 0 ).WriteUInt16( EPP_CurrentUserAtom ).WriteUInt32( nSizeOfRecord );
+ mpCurUserStrm->WriteUInt32( 0x14 ) // Len
+ .WriteUInt32( 0xe391c05f ); // Magic
+
+ sal_uInt32 nEditPos = mpCurUserStrm->Tell();
+ mpCurUserStrm->WriteUInt32( 0x0 ) // OffsetToCurrentEdit;
+ .WriteUInt16( nLenOfUserName )
+ .WriteUInt16( 0x3f4 ) // DocFileVersion
+ .WriteUChar( 3 ) // MajorVersion
+ .WriteUChar( 0 ) // MinorVersion
+ .WriteUInt16( 0 ); // Pad Word
+ pUserName[ nLenOfUserName ] = 8;
+ mpCurUserStrm->WriteBytes(pUserName, nLenOfUserName + 1);
+ for ( sal_uInt32 i = 0x15 + nLenOfUserName; i < nSizeOfRecord; i++ )
+ {
+ mpCurUserStrm->WriteUChar( 0 ); // pad bytes
+ }
+ mpCurUserStrm->Seek( nEditPos );
+ return true;
+};
+
+void PPTWriter::ImplCreateDocumentSummaryInformation()
+{
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
+ mXModel, uno::UNO_QUERY_THROW);
+ uno::Reference<document::XDocumentProperties> xDocProps(
+ xDPS->getDocumentProperties());
+
+ if (!xDocProps.is())
+ return;
+
+ // no idea what this is...
+ static const sal_Int8 aGuid[ 0x52 ] =
+ {
+ 0x4e, 0x00, 0x00, 0x00,
+ '{',0,'D',0,'B',0,'1',0,'A',0,'C',0,'9',0,'6',0,'4',0,'-',0,
+ 'E',0,'3',0,'9',0,'C',0,'-',0,'1',0,'1',0,'D',0,'2',0,'-',0,
+ 'A',0,'1',0,'E',0,'F',0,'-',0,'0',0,'0',0,'6',0,'0',0,'9',0,
+ '7',0,'D',0,'A',0,'5',0,'6',0,'8',0,'9',0,'}',0
+ };
+ // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence
+ uno::Sequence<sal_Int8> aGuidSeq(aGuid, 0x52);
+
+ SvMemoryStream aHyperBlob;
+ ImplCreateHyperBlob( aHyperBlob );
+
+ auto nHyperLength = static_cast<sal_Int32>(aHyperBlob.Tell());
+ const sal_Int8* pBlob(
+ static_cast<const sal_Int8*>(aHyperBlob.GetData()));
+ auto aHyperSeq = comphelper::arrayToSequence<sal_Int8>(pBlob, nHyperLength);
+
+ if ( mnCnvrtFlags & 0x8000 )
+ {
+ uno::Sequence<sal_Int8> aThumbSeq;
+ if ( GetPageByIndex( 0, NORMAL ) && ImplGetPropertyValue( mXPagePropSet, "PreviewBitmap" ) )
+ {
+ aThumbSeq = *o3tl::doAccess<uno::Sequence<sal_Int8>>(mAny);
+ }
+ sfx2::SaveOlePropertySet( xDocProps, mrStg.get(),
+ &aThumbSeq, &aGuidSeq, &aHyperSeq);
+ }
+ else
+ {
+ sfx2::SaveOlePropertySet( xDocProps, mrStg.get(),
+ nullptr, &aGuidSeq, &aHyperSeq );
+ }
+}
+
+void PPTWriter::ImplWriteExtParaHeader( SvMemoryStream& rSt, sal_uInt32 nRef, sal_uInt32 nInstance, sal_uInt32 nSlideId )
+{
+ if ( rSt.Tell() )
+ {
+ aBuExOutlineStream.WriteUInt32( ( EPP_PST_ExtendedParagraphHeaderAtom << 16 )
+ | ( nRef << 4 ) )
+ .WriteUInt32( 8 )
+ .WriteUInt32( nSlideId )
+ .WriteUInt32( nInstance );
+ aBuExOutlineStream.WriteBytes(rSt.GetData(), rSt.Tell());
+ }
+}
+
+void PPTWriter::ImplCreateHeaderFooterStrings( SvStream& rStrm, css::uno::Reference< css::beans::XPropertySet > const & rXPagePropSet )
+{
+ if ( !rXPagePropSet.is() )
+ return;
+
+ OUString aString;
+ css::uno::Any aAny;
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "HeaderText", true ) )
+ {
+ if ( aAny >>= aString )
+ PPTWriter::WriteCString( rStrm, aString, 1 );
+ }
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "FooterText", true ) )
+ {
+ if ( aAny >>= aString )
+ PPTWriter::WriteCString( rStrm, aString, 2 );
+ }
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "DateTimeText", true ) )
+ {
+ if ( aAny >>= aString )
+ PPTWriter::WriteCString( rStrm, aString );
+ }
+}
+
+void PPTWriter::ImplCreateHeaderFooters( css::uno::Reference< css::beans::XPropertySet > const & rXPagePropSet )
+{
+ if ( !rXPagePropSet.is() )
+ return;
+
+ bool bVal = false;
+ sal_uInt32 nVal = 0;
+ css::uno::Any aAny;
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsHeaderVisible", true ) )
+ {
+ if ( ( aAny >>= bVal ) && bVal )
+ nVal |= 0x100000;
+ }
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsFooterVisible", true ) )
+ {
+ if ( ( aAny >>= bVal ) && bVal )
+ nVal |= 0x200000;
+ }
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsDateTimeVisible", true ) )
+ {
+ if ( ( aAny >>= bVal ) && bVal )
+ nVal |= 0x010000;
+ }
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsPageNumberVisible", true ) )
+ {
+ if ( ( aAny >>= bVal ) && bVal )
+ nVal |= 0x080000;
+ }
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "IsDateTimeFixed", true ) )
+ {
+ if ( ( aAny >>= bVal ) && !bVal )
+ nVal |= 0x20000;
+ else
+ nVal |= 0x40000;
+ }
+ if ( PropValue::GetPropertyValue( aAny, rXPagePropSet, "DateTimeFormat", true ) )
+ {
+ sal_Int32 nFormat = *o3tl::doAccess<sal_Int32>(aAny);
+ SvxDateFormat eDateFormat = static_cast<SvxDateFormat>( nFormat & 0xf );
+ SvxTimeFormat eTimeFormat = static_cast<SvxTimeFormat>( ( nFormat >> 4 ) & 0xf );
+ switch( eDateFormat )
+ {
+ case SvxDateFormat::F :
+ nFormat = 1;
+ break;
+ case SvxDateFormat::D :
+ nFormat = 2;
+ break;
+ case SvxDateFormat::C :
+ nFormat = 4;
+ break;
+ default:
+ case SvxDateFormat::A :
+ nFormat = 0;
+ }
+ switch( eTimeFormat )
+ {
+ case SvxTimeFormat::HH24_MM :
+ nFormat = 9;
+ break;
+ case SvxTimeFormat::HH12_MM :
+ nFormat = 11;
+ break;
+ case SvxTimeFormat::HH24_MM_SS :
+ nFormat = 10;
+ break;
+ case SvxTimeFormat::HH12_MM_SS :
+ nFormat = 12;
+ break;
+ default:
+ break;
+ }
+ nVal |= nFormat;
+ }
+
+ mpPptEscherEx->OpenContainer( EPP_HeadersFooters );
+ mpPptEscherEx->AddAtom( 4, EPP_HeadersFootersAtom );
+ mpStrm->WriteUInt32( nVal );
+ ImplCreateHeaderFooterStrings( *mpStrm, rXPagePropSet );
+ mpPptEscherEx->CloseContainer();
+}
+
+bool PPTWriter::ImplCreateDocument()
+{
+ sal_uInt32 i;
+ sal_uInt16 nSlideType = EPP_SLIDESIZE_TYPECUSTOM;
+
+ sal_uInt32 nWidth = maDestPageSize.Width;
+ sal_uInt32 nHeight = maDestPageSize.Height;
+
+ if ( ( nWidth == 0x1680 ) && ( nHeight == 0x10e0 ) )
+ nSlideType = EPP_SLIDESIZE_TYPEONSCREEN;
+ else if ( ( nWidth == 0x1200 ) && ( nHeight == 0x240 ) )
+ nSlideType = EPP_SLIDESIZE_TYPEBANNER;
+ else if ( ( nWidth == 0x1950 ) && ( nHeight == 0x10e0 ) )
+ nSlideType = EPP_SLIDESIZE_TYPE35MM;
+ else if ( ( nWidth == 0x1860 ) && ( nHeight == 0x10e0 ) )
+ nSlideType = EPP_SLIDESIZE_TYPEA4PAPER;
+
+ mpPptEscherEx->OpenContainer( EPP_Document );
+ // CREATE DOCUMENT ATOM
+ mpPptEscherEx->AddAtom( 40, EPP_DocumentAtom, 1 );
+ mpStrm->WriteUInt32( nWidth ) // Slide Size in Master coordinates X
+ .WriteUInt32( nHeight ) // " " " " " Y
+ .WriteInt32( maNotesPageSize.Width ) // Notes Page Size X
+ .WriteInt32( maNotesPageSize.Height ) // " " " Y
+ .WriteInt32( 1 ).WriteInt32( 2 ); // the scale used when the Powerpoint document is embedded. the default is 1:2
+ mpPptEscherEx->InsertPersistOffset( EPP_MAINNOTESMASTER_PERSIST_KEY, mpStrm->Tell() );
+ mpStrm->WriteUInt32( 0 ) // Reference to NotesMaster ( 0 if none );
+ .WriteUInt32( 0 ) // Reference to HandoutMaster ( 0 if none );
+ .WriteInt16( 1 ) // Number of the first slide;
+ .WriteUInt16( nSlideType ) // Size of the document slides ( default: EPP_SLIDESIZETYPEONSCREEN )
+ .WriteUChar( 0 ) // bool1 indicates if document was saved with embedded true type fonts
+ .WriteUChar( 0 ) // bool1 indicates if the placeholders on the title slide are omitted
+ .WriteUChar( 0 ) // bool1 right to left ( flag for Bidi version )
+ .WriteUChar( 1 ); // bool1 visibility of comments shapes
+
+ mpPptEscherEx->PtInsert( EPP_Persist_Document, mpStrm->Tell() );
+
+ mpPptEscherEx->OpenContainer( EPP_HeadersFooters, 3 ); //Master footer (default)
+ mpPptEscherEx->AddAtom( 4, EPP_HeadersFootersAtom );
+ mpStrm->WriteUInt32( 0x25000d );
+ if ( GetPageByIndex( 0, MASTER ) )
+ ImplCreateHeaderFooterStrings( *mpStrm, mXPagePropSet );
+ mpPptEscherEx->CloseContainer();
+ mpPptEscherEx->OpenContainer( EPP_HeadersFooters, 4 ); //NotesMaster footer (default)
+ mpPptEscherEx->AddAtom( 4, EPP_HeadersFootersAtom );
+ mpStrm->WriteUInt32( 0x3d000d );
+ if ( GetPageByIndex( 0, NOTICE ) )
+ ImplCreateHeaderFooterStrings( *mpStrm, mXPagePropSet );
+ mpPptEscherEx->CloseContainer();
+
+ mpPptEscherEx->OpenContainer( EPP_SlideListWithText ); // animation information for the slides
+
+ for ( i = 0; i < mnPages; i++ )
+ {
+ mpPptEscherEx->AddAtom( 20, EPP_SlidePersistAtom );
+ mpPptEscherEx->InsertPersistOffset( EPP_MAINSLIDE_PERSIST_KEY | i, mpStrm->Tell() );
+ mpStrm->WriteUInt32( 0 ) // psrReference - logical reference to the slide persist object ( EPP_MAINSLIDE_PERSIST_KEY )
+ .WriteUInt32( 4 ) // flags - only bit 3 used, if set then slide contains shapes other than placeholders
+ .WriteInt32( 0 ) // numberTexts - number of placeholder texts stored with the persist object. Allows to display outline view without loading the slide persist objects
+ .WriteInt32( i + 0x100 ) // slideId - Unique slide identifier, used for OLE link monikers for example
+ .WriteUInt32( 0 ); // reserved, usually 0
+
+ if ( !GetPageByIndex( i, NORMAL ) ) // very exciting: once again through all pages
+ return false;
+ SetCurrentStyleSheet( GetMasterIndex( NORMAL ) );
+
+ css::uno::Reference< css::container::XNamed >
+ aXName( mXDrawPage, css::uno::UNO_QUERY );
+
+ if ( aXName.is() )
+ maSlideNameList.push_back( aXName->getName() );
+ else
+ maSlideNameList.emplace_back( );
+ }
+ mpPptEscherEx->CloseContainer(); // EPP_SlideListWithText
+
+ mpPptEscherEx->OpenContainer( EPP_SlideListWithText, 2 ); // animation information for the notes
+ for( i = 0; i < mnPages; i++ )
+ {
+ mpPptEscherEx->AddAtom( 20, EPP_SlidePersistAtom );
+ mpPptEscherEx->InsertPersistOffset( EPP_MAINNOTES_PERSIST_KEY | i, mpStrm->Tell() );
+ mpStrm->WriteUInt32( 0 )
+ .WriteUInt32( 4 )
+ .WriteInt32( 0 )
+ .WriteInt32( i + 0x100 )
+ .WriteUInt32( 0 );
+ }
+ mpPptEscherEx->CloseContainer(); // EPP_SlideListWithText
+
+ css::uno::Reference< css::presentation::XPresentationSupplier >
+ aXPresSupplier( mXModel, css::uno::UNO_QUERY );
+ if ( aXPresSupplier.is() )
+ {
+ css::uno::Reference< css::presentation::XPresentation > aXPresentation( aXPresSupplier->getPresentation() );
+ if ( aXPresentation.is() )
+ {
+ mXPropSet.set( aXPresentation, css::uno::UNO_QUERY );
+ if ( mXPropSet.is() )
+ {
+ OUString aCustomShow;
+ sal_uInt32 const nPenColor = 0x1000000;
+ sal_Int32 const nRestartTime = 0x7fffffff;
+ sal_Int16 nStartSlide = 0;
+ sal_Int16 nEndSlide = 0;
+ sal_uInt32 nFlags = 0; // Bit 0: Auto advance
+ // Bit 1 Skip builds ( do not allow slide effects )
+ // Bit 2 Use slide range
+ // Bit 3 Use named show
+ // Bit 4 Browse mode on
+ // Bit 5 Kiosk mode on
+ // Bit 6 Skip narration
+ // Bit 7 loop continuously
+ // Bit 8 show scrollbar
+
+ if ( ImplGetPropertyValue( "CustomShow" ) )
+ {
+ aCustomShow = *o3tl::doAccess<OUString>(mAny);
+ if ( !aCustomShow.isEmpty() )
+ {
+ nFlags |= 8;
+ }
+ }
+ if ( ( nFlags & 8 ) == 0 )
+ {
+ if ( ImplGetPropertyValue( "FirstPage" ) )
+ {
+ auto aSlideName = o3tl::doAccess<OUString>(mAny);
+
+ std::vector<OUString>::const_iterator pIter = std::find(
+ maSlideNameList.begin(),maSlideNameList.end(), *aSlideName);
+
+ if (pIter != maSlideNameList.end())
+ {
+ nStartSlide = pIter - maSlideNameList.begin() + 1;
+ nFlags |= 4;
+ nEndSlide = static_cast<sal_uInt16>(mnPages);
+ }
+ }
+ }
+
+ if ( ImplGetPropertyValue( "IsAutomatic" ) )
+ {
+ bool bBool = false;
+ mAny >>= bBool;
+ if ( !bBool )
+ nFlags |= 1;
+ }
+
+ if ( ImplGetPropertyValue( "IsEndless" ) )
+ {
+ bool bBool = false;
+ mAny >>= bBool;
+ if ( bBool )
+ nFlags |= 0x80;
+ }
+ if ( ImplGetPropertyValue( "IsFullScreen" ) )
+ {
+ bool bBool = false;
+ mAny >>= bBool;
+ if ( !bBool )
+ nFlags |= 0x11;
+ }
+
+ mpPptEscherEx->AddAtom( 80, EPP_SSDocInfoAtom, 1 );
+ mpStrm->WriteUInt32( nPenColor ).WriteInt32( nRestartTime ).WriteInt16( nStartSlide ).WriteInt16( nEndSlide );
+
+ sal_uInt32 nCustomShowNameLen = aCustomShow.getLength();
+ if ( nCustomShowNameLen > 31 )
+ nCustomShowNameLen = 31;
+ if ( nCustomShowNameLen ) // named show identifier
+ {
+ const sal_Unicode* pCustomShow = aCustomShow.getStr();
+ for ( i = 0; i < nCustomShowNameLen; i++ )
+ {
+ mpStrm->WriteUInt16( pCustomShow[ i ] );
+ }
+ }
+ for ( i = nCustomShowNameLen; i < 32; i++, mpStrm->WriteUInt16( 0 ) ) ;
+
+ mpStrm->WriteUInt32( nFlags );
+ css::uno::Reference< css::presentation::XCustomPresentationSupplier > aXCPSup( mXModel, css::uno::UNO_QUERY );
+ if ( aXCPSup.is() )
+ {
+ css::uno::Reference< css::container::XNameContainer > aXCont( aXCPSup->getCustomPresentations() );
+ if ( aXCont.is() )
+ {
+ const css::uno::Sequence< OUString> aNameSeq( aXCont->getElementNames() );
+ if ( aNameSeq.hasElements() )
+ {
+ mpPptEscherEx->OpenContainer( EPP_NamedShows );
+ sal_uInt32 nCustomShowIndex = 0;
+ for( OUString const & customShowName : aNameSeq )
+ {
+ if ( !customShowName.isEmpty() )
+ {
+ mpPptEscherEx->OpenContainer( EPP_NamedShow, nCustomShowIndex++ );
+
+ sal_uInt32 nNamedShowLen = customShowName.getLength();
+ if ( nNamedShowLen > 31 )
+ nNamedShowLen = 31;
+ mpPptEscherEx->AddAtom( nNamedShowLen << 1, EPP_CString );
+ const sal_Unicode* pCustomShowName = customShowName.getStr();
+ for ( sal_uInt32 k = 0; k < nNamedShowLen; ++k )
+ mpStrm->WriteUInt16( pCustomShowName[ k ] );
+ mAny = aXCont->getByName( customShowName );
+ css::uno::Reference< css::container::XIndexContainer > aXIC;
+ if ( mAny >>= aXIC )
+ {
+ mpPptEscherEx->BeginAtom();
+
+ sal_Int32 nSlideCount = aXIC->getCount();
+ for ( sal_Int32 j = 0; j < nSlideCount; j++ ) // number of slides
+ {
+ mAny = aXIC->getByIndex( j );
+ css::uno::Reference< css::drawing::XDrawPage > aXDrawPage;
+ if ( mAny >>= aXDrawPage )
+ {
+ css::uno::Reference< css::container::XNamed > aXName( aXDrawPage, css::uno::UNO_QUERY );
+ if ( aXName.is() )
+ {
+ OUString aSlideName( aXName->getName() );
+ std::vector<OUString>::const_iterator pIter = std::find(
+ maSlideNameList.begin(),maSlideNameList.end(),aSlideName);
+
+ if (pIter != maSlideNameList.end())
+ {
+ sal_uInt32 nPageNumber = pIter - maSlideNameList.begin();
+ mpStrm->WriteUInt32( nPageNumber + 0x100 ); // unique slide id
+ }
+ }
+ }
+ }
+ mpPptEscherEx->EndAtom( EPP_NamedShowSlides );
+ }
+ mpPptEscherEx->CloseContainer(); // EPP_NamedShow
+ }
+ }
+ mpPptEscherEx->CloseContainer(); // EPP_NamedShows
+ }
+ }
+ }
+ }
+ }
+ }
+ mpPptEscherEx->AddAtom( 0, EPP_EndDocument );
+ mpPptEscherEx->CloseContainer(); // EPP_Document
+ return true;
+};
+
+void PPTWriter::ImplCreateHyperBlob( SvMemoryStream& rStrm )
+{
+ sal_uInt32 nCurrentOfs, nParaOfs, nParaCount = 0;
+
+ nParaOfs = rStrm.Tell();
+ rStrm.WriteUInt32( 0 ); // property size
+ rStrm.WriteUInt32( 0 ); // property count
+
+ for ( const auto& rHyperlink : maHyperlink )
+ {
+ nParaCount += 6;
+ rStrm .WriteUInt32( 3 ) // Type VT_I4
+ .WriteUInt32( 7 ) // (VTI4 - Private1)
+ .WriteUInt32( 3 ) // Type VT_I4
+ .WriteUInt32( 6 ) // (VTI4 - Private2)
+ .WriteUInt32( 3 ) // Type VT_I4
+ .WriteUInt32( 0 ); // (VTI4 - Private3)
+
+ // INFO
+ // HIWORD: = 0 : do not change anything
+ // = 1 : replace the hyperlink with the target and subaddress in the following two VTLPWSTR
+ // = 2 : delete the hyperlink
+ // LOWORD: = 0 : graphic shown as background (link)
+ // = 1 : graphic shown as shape (link)
+ // = 2 : graphic is used to fill a shape
+ // = 3 : graphic used to fill a shape outline (future use)
+ // = 4 : hyperlink attached to a shape
+ // = 5 : " " " " (Word) field
+ // = 6 : " " " " (Excel) range
+ // = 7 : " " " " (PPT) text range
+ // = 8 : " " " " (Project) task
+
+ sal_Int32 nUrlLen = rHyperlink.aURL.getLength();
+ const OUString& rUrl = rHyperlink.aURL;
+
+ sal_uInt32 const nInfo = 7;
+
+ rStrm .WriteUInt32( 3 ) // Type VT_I4
+ .WriteUInt32( nInfo ); // Info
+
+ switch( rHyperlink.nType & 0xff )
+ {
+ case 1 : // click action to slidenumber
+ {
+ rStrm.WriteUInt32( 0x1f ).WriteUInt32( 1 ).WriteUInt32( 0 ); // path
+ rStrm.WriteUInt32( 0x1f ).WriteUInt32( nUrlLen + 1 );
+ for ( sal_Int32 i = 0; i < nUrlLen; i++ )
+ {
+ rStrm.WriteUInt16( rUrl[ i ] );
+ }
+ rStrm.WriteUInt16( 0 );
+ }
+ break;
+ case 2 :
+ {
+ sal_Int32 i;
+
+ rStrm .WriteUInt32( 0x1f )
+ .WriteUInt32( nUrlLen + 1 );
+ for ( i = 0; i < nUrlLen; i++ )
+ {
+ rStrm.WriteUInt16( rUrl[ i ] );
+ }
+ if ( ! ( i & 1 ) )
+ rStrm.WriteUInt16( 0 );
+ rStrm .WriteUInt16( 0 )
+ .WriteUInt32( 0x1f )
+ .WriteUInt32( 1 )
+ .WriteUInt32( 0 );
+ }
+ break;
+ }
+ }
+ nCurrentOfs = rStrm.Tell();
+ rStrm.Seek( nParaOfs );
+ rStrm.WriteUInt32( nCurrentOfs - ( nParaOfs + 4 ) );
+ rStrm.WriteUInt32( nParaCount );
+ rStrm.Seek( nCurrentOfs );
+}
+
+bool PPTWriter::ImplCreateMainNotes()
+{
+ EscherSolverContainer aSolverContainer;
+
+ mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_MainNotes, mpStrm->Tell() );
+ mpPptEscherEx->OpenContainer( EPP_Notes );
+ mpPptEscherEx->AddAtom( 8, EPP_NotesAtom, 1 );
+ mpStrm->WriteUInt32( 0x80000001 ) // Number that identifies this slide
+ .WriteUInt32( 0 ); // follow nothing
+ mpPptEscherEx->OpenContainer( EPP_PPDrawing );
+ mpPptEscherEx->OpenContainer( ESCHER_DgContainer );
+ mpPptEscherEx->EnterGroup(nullptr,nullptr);
+
+ ImplWritePage( GetLayout( 20 ), aSolverContainer, NOTICE, true );
+
+ mpPptEscherEx->LeaveGroup();
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty );
+ EscherPropertyContainer aPropOpt;
+ aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0xffffff ); // stock valued fill color
+ aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0 );
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, 0x68bdde );
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, 0x8b9f8e );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0 );
+ aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_wDontShow );
+ aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 ); // if true, this is the background shape
+ aPropOpt.Commit( *mpStrm );
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+
+ aSolverContainer.WriteSolver( *mpStrm );
+
+ mpPptEscherEx->CloseContainer(); // ESCHER_DgContainer
+ mpPptEscherEx->CloseContainer(); // EPP_Drawing
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
+ mpPptEscherEx->CloseContainer(); // EPP_Notes
+ return true;
+}
+
+static OUString getInitials( const OUString& rName )
+{
+ OUStringBuffer sInitials;
+
+ const sal_Unicode * pStr = rName.getStr();
+ sal_Int32 nLength = rName.getLength();
+
+ while( nLength )
+ {
+ // skip whitespace
+ while( nLength && (*pStr <= ' ') )
+ {
+ nLength--; pStr++;
+ }
+
+ // take letter
+ if( nLength )
+ {
+ sInitials.append( *pStr );
+ nLength--; pStr++;
+ }
+
+ // skip letters until whitespace
+ while( nLength && (*pStr > ' ') )
+ {
+ nLength--; pStr++;
+ }
+ }
+
+ return sInitials.makeStringAndClear();
+}
+
+void ImplExportComments( const uno::Reference< drawing::XDrawPage >& xPage, SvMemoryStream& rBinaryTagData10Atom )
+{
+ try
+ {
+ uno::Reference< office::XAnnotationAccess > xAnnotationAccess( xPage, uno::UNO_QUERY_THROW );
+ uno::Reference< office::XAnnotationEnumeration > xAnnotationEnumeration( xAnnotationAccess->createAnnotationEnumeration() );
+
+ sal_Int32 nIndex = 1;
+
+ while( xAnnotationEnumeration->hasMoreElements() )
+ {
+ EscherExContainer aComment10( rBinaryTagData10Atom, EPP_Comment10 );
+ {
+ uno::Reference< office::XAnnotation > xAnnotation( xAnnotationEnumeration->nextElement() );
+
+ geometry::RealPoint2D aRealPoint2D( xAnnotation->getPosition() );
+ Point aPoint(o3tl::convert(aRealPoint2D.X, o3tl::Length::mm, o3tl::Length::master),
+ o3tl::convert(aRealPoint2D.Y, o3tl::Length::mm, o3tl::Length::master));
+
+ OUString sAuthor( xAnnotation->getAuthor() );
+ uno::Reference< text::XText > xText( xAnnotation->getTextRange() );
+ OUString sText( xText->getString() );
+ OUString sInitials( getInitials( sAuthor ) );
+ util::DateTime aDateTime( xAnnotation->getDateTime() );
+ if ( !sAuthor.isEmpty() )
+ PPTWriter::WriteCString( rBinaryTagData10Atom, sAuthor );
+ if ( !sText.isEmpty() )
+ PPTWriter::WriteCString( rBinaryTagData10Atom, sText, 1 );
+ if ( !sInitials.isEmpty() )
+ PPTWriter::WriteCString( rBinaryTagData10Atom, sInitials, 2 );
+
+ sal_Int16 nMilliSeconds = static_cast<sal_Int16>(::rtl::math::round(static_cast<double>(aDateTime.NanoSeconds) / 1000000000.0));
+ EscherExAtom aCommentAtom10( rBinaryTagData10Atom, EPP_CommentAtom10 );
+ rBinaryTagData10Atom.WriteInt32( nIndex++ )
+ .WriteInt16( aDateTime.Year )
+ .WriteUInt16( aDateTime.Month )
+ .WriteUInt16( aDateTime.Day ) // todo: day of week
+ .WriteUInt16( aDateTime.Day )
+ .WriteUInt16( aDateTime.Hours )
+ .WriteUInt16( aDateTime.Minutes )
+ .WriteUInt16( aDateTime.Seconds )
+ .WriteInt16( nMilliSeconds )
+ .WriteInt32( aPoint.X() )
+ .WriteInt32( aPoint.Y() );
+ }
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ }
+}
+
+void PPTWriter::ImplWriteNotes( sal_uInt32 nPageNum )
+{
+ mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_Notes | nPageNum, mpStrm->Tell() );
+ mpPptEscherEx->OpenContainer( EPP_Notes );
+ mpPptEscherEx->AddAtom( 8, EPP_NotesAtom, 1 );
+ mpStrm->WriteUInt32( nPageNum + 0x100 )
+ .WriteUInt16( 3 ) // follow master...
+ .WriteUInt16( 0 );
+
+ ImplCreateHeaderFooters( mXPagePropSet );
+
+ EscherSolverContainer aSolverContainer;
+
+ mpPptEscherEx->OpenContainer( EPP_PPDrawing );
+ mpPptEscherEx->OpenContainer( ESCHER_DgContainer );
+ mpPptEscherEx->EnterGroup(nullptr,nullptr);
+
+ ImplWritePage( GetLayout( 20 ), aSolverContainer, NOTICE, false ); // the shapes of the pages are created in the PPT document
+
+ mpPptEscherEx->LeaveGroup();
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty );
+ EscherPropertyContainer aPropOpt;
+ aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0xffffff ); // stock valued fill color
+ aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0 );
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, 0x8b9f8e );
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, 0x68bdde );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
+ aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_wDontShow );
+ aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 );
+ aPropOpt.Commit( *mpStrm );
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+
+ aSolverContainer.WriteSolver( *mpStrm );
+
+ mpPptEscherEx->CloseContainer(); // ESCHER_DgContainer
+ mpPptEscherEx->CloseContainer(); // EPP_Drawing
+ mpPptEscherEx->AddAtom( 32, EPP_ColorSchemeAtom, 0, 1 );
+ mpStrm->WriteUInt32( 0xffffff ).WriteUInt32( 0x000000 ).WriteUInt32( 0x808080 ).WriteUInt32( 0x000000 ).WriteUInt32( 0x99cc00 ).WriteUInt32( 0xcc3333 ).WriteUInt32( 0xffcccc ).WriteUInt32( 0xb2b2b2 );
+ mpPptEscherEx->CloseContainer(); // EPP_Notes
+};
+
+void PPTWriter::ImplWriteBackground( css::uno::Reference< css::beans::XPropertySet > const & rXPropSet )
+{
+ //************************ ******
+ //** DEFAULT BACKGROUND SHAPE **
+
+ sal_uInt32 nFillColor = 0xffffff;
+ sal_uInt32 nFillBackColor = 0;
+
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::Background | ShapeFlag::HaveShapeProperty );
+
+ // #i121183# Use real PageSize in 100th mm
+ ::tools::Rectangle aRect(Point(0, 0), Size(maPageSize.Width, maPageSize.Height));
+
+ EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect );
+ aPropOpt.AddOpt( ESCHER_Prop_fillType, ESCHER_FillSolid );
+ css::drawing::FillStyle aFS( css::drawing::FillStyle_NONE );
+ if ( ImplGetPropertyValue( rXPropSet, "FillStyle" ) )
+ mAny >>= aFS;
+
+ switch( aFS )
+ {
+ case css::drawing::FillStyle_GRADIENT :
+ {
+ aPropOpt.CreateGradientProperties( rXPropSet );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x1f001e );
+ aPropOpt.GetOpt( ESCHER_Prop_fillColor, nFillColor );
+ aPropOpt.GetOpt( ESCHER_Prop_fillBackColor, nFillBackColor );
+ }
+ break;
+
+ case css::drawing::FillStyle_BITMAP :
+ aPropOpt.CreateGraphicProperties( rXPropSet, "FillBitmap", true );
+ break;
+
+ case css::drawing::FillStyle_HATCH :
+ aPropOpt.CreateGraphicProperties( rXPropSet, "FillHatch", true );
+ break;
+
+ case css::drawing::FillStyle_SOLID :
+ {
+ if ( ImplGetPropertyValue( rXPropSet, "FillColor" ) )
+ {
+ nFillColor = EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(mAny) );
+ nFillBackColor = nFillColor ^ 0xffffff;
+ }
+ [[fallthrough]];
+ }
+ case css::drawing::FillStyle_NONE :
+ default:
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x120012 );
+ break;
+ }
+ aPropOpt.AddOpt( ESCHER_Prop_fillColor, nFillColor );
+ aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, nFillBackColor );
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectRight, PPTtoEMU( maDestPageSize.Width ) );
+ aPropOpt.AddOpt( ESCHER_Prop_fillRectBottom, PPTtoEMU( maDestPageSize.Height ) );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
+ aPropOpt.AddOpt( ESCHER_Prop_bWMode, ESCHER_bwWhite );
+ aPropOpt.AddOpt( ESCHER_Prop_fBackground, 0x10001 );
+ aPropOpt.Commit( *mpStrm );
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+}
+
+void PPTWriter::ImplWriteVBA()
+{
+ if ( mpVBA )
+ {
+ sal_uInt32 nLen = mpVBA->TellEnd();
+ if ( nLen > 8 )
+ {
+ nLen -= 8;
+ mnVBAOleOfs = mpStrm->Tell();
+ mpPptEscherEx->BeginAtom();
+ mpStrm->WriteBytes(static_cast<sal_Int8 const *>(mpVBA->GetData()) + 8, nLen);
+ mpPptEscherEx->EndAtom( EPP_ExOleObjStg, 0, 1 );
+ }
+ }
+}
+
+void PPTWriter::ImplWriteOLE( )
+{
+
+ SvxMSExportOLEObjects aOleExport( mnCnvrtFlags );
+
+ for ( const auto& rxExOleObjEntry : maExOleObj )
+ {
+ PPTExOleObjEntry* pPtr = rxExOleObjEntry.get();
+ std::unique_ptr<SvMemoryStream> pStrm;
+ pPtr->nOfsB = mpStrm->Tell();
+ switch ( pPtr->eType )
+ {
+ case NORMAL_OLE_OBJECT :
+ {
+ SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape(pPtr->xShape);
+ if ( auto pSdrOle2Obj = dynamic_cast< SdrOle2Obj* >(pSdrObj) )
+ {
+ const ::uno::Reference < embed::XEmbeddedObject >& xObj( pSdrOle2Obj->GetObjRef() );
+ if( xObj.is() )
+ {
+ tools::SvRef<SotStorage> xTempStorage( new SotStorage( new SvMemoryStream(), true ) );
+ aOleExport.ExportOLEObject( xObj, *xTempStorage );
+
+ //TODO/MBA: testing
+ SvMemoryStream aStream;
+ tools::SvRef<SotStorage> xCleanStorage( new SotStorage( false, aStream ) );
+ xTempStorage->CopyTo( xCleanStorage.get() );
+ // create a dummy content stream, the dummy content is necessary for ppt, but not for
+ // doc files, so we can't share code.
+ tools::SvRef<SotStorageStream> xStm = xCleanStorage->OpenSotStream( SVEXT_PERSIST_STREAM );
+ xStm->WriteUInt32( 0 ) // no ClipboardId
+ .WriteUInt32( 4 ) // no target device
+ .WriteUInt32( 1 ) // aspect ratio
+ .WriteInt32( -1 ) // L-Index
+ .WriteUInt32( 0 ) // Advanced Flags
+ .WriteUInt32( 0 ) // compression
+ .WriteUInt32( 0 ) // Size
+ .WriteUInt32( 0 ) // "
+ .WriteUInt32( 0 );
+ pStrm = xCleanStorage->CreateMemoryStream();
+ }
+ }
+ }
+ break;
+
+ case OCX_CONTROL :
+ {
+ if ( pPtr->xControlModel.is() )
+ {
+ OUString aName;
+ //Initialize the graphic size which will be used on export
+ css::awt::Size aSize( pPtr->xShape->getSize() );
+ tools::SvRef<SotStorage> xDest( new SotStorage( new SvMemoryStream(), true ) );
+ bool bOk = oox::ole::MSConvertOCXControls::WriteOCXStream( mXModel, xDest, pPtr->xControlModel, aSize, aName );
+ if ( bOk )
+ pStrm = xDest->CreateMemoryStream();
+ }
+ }
+ }
+ if ( pStrm )
+ {
+ mpPptEscherEx->BeginAtom();
+ pStrm->Seek( STREAM_SEEK_TO_END );
+ sal_uInt32 npStrmSize = pStrm->Tell();
+ mpStrm->WriteUInt32( npStrmSize ); // uncompressed size
+
+ pStrm->Seek( 0 );
+ ZCodec aZCodec( 0x8000, 0x8000 );
+ aZCodec.BeginCompression();
+ aZCodec.Compress( *pStrm, *mpStrm );
+ aZCodec.EndCompression();
+ pStrm.reset();
+ mpPptEscherEx->EndAtom( EPP_ExOleObjStg, 0, 1 );
+ }
+ }
+}
+
+// write PersistantTable and UserEditAtom
+
+void PPTWriter::ImplWriteAtomEnding()
+{
+
+#define EPP_LastViewTypeSlideView 1
+
+ sal_uInt32 i, nPos, nOfs, nPersistOfs = mpStrm->Tell();
+ sal_uInt32 nPersistEntrys = 0;
+ mpStrm->WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ); // skip record header and first entry
+
+ // write document persist
+ nPersistEntrys++;
+ mpStrm->WriteUInt32( 0 );
+ // write MasterPages persists
+ for ( i = 0; i < mnMasterPages; i++ )
+ {
+ nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_MainMaster | i );
+ if ( nOfs )
+ {
+ mpStrm->WriteUInt32( nOfs );
+ mpPptEscherEx->InsertAtPersistOffset( EPP_MAINMASTER_PERSIST_KEY | i, ++nPersistEntrys );
+ }
+ }
+ // write MainNotesMaster persist
+ nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_MainNotes );
+ if ( nOfs )
+ {
+ mpStrm->WriteUInt32( nOfs );
+ mpPptEscherEx->InsertAtPersistOffset( EPP_MAINNOTESMASTER_PERSIST_KEY, ++nPersistEntrys );
+ }
+ // write slide persists -> we have to write a valid value into EPP_SlidePersistAtome too
+ for ( i = 0; i < mnPages; i++ )
+ {
+ nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_Slide | i );
+ if ( nOfs )
+ {
+ mpStrm->WriteUInt32( nOfs );
+ mpPptEscherEx->InsertAtPersistOffset( EPP_MAINSLIDE_PERSIST_KEY | i, ++nPersistEntrys );
+ }
+ }
+ // write Notes persists
+ for ( i = 0; i < mnPages; i++ )
+ {
+ nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_Notes | i );
+ if ( nOfs )
+ {
+ mpStrm->WriteUInt32( nOfs );
+ mpPptEscherEx->InsertAtPersistOffset( EPP_MAINNOTES_PERSIST_KEY | i, ++nPersistEntrys );
+ }
+ }
+ // Ole persists
+ for ( const auto& rxExOleObjEntry : maExOleObj )
+ {
+ PPTExOleObjEntry* pPtr = rxExOleObjEntry.get();
+ nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_ExObj );
+ if ( nOfs )
+ {
+ nPersistEntrys++;
+ mpStrm->WriteUInt32( pPtr->nOfsB );
+ sal_uInt32 nOldPos, nPersOfs = nOfs + pPtr->nOfsA + 16 + 8; // 8 bytes atom header, +16 to the persist entry
+ nOldPos = mpStrm->Tell();
+ mpStrm->Seek( nPersOfs );
+ mpStrm->WriteUInt32( nPersistEntrys );
+ mpStrm->Seek( nOldPos );
+ }
+ }
+ // VB persist
+ if ( mnVBAOleOfs && mpVBA )
+ {
+ nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_VBAInfoAtom );
+ if ( nOfs )
+ {
+ nPersistEntrys++;
+ sal_uInt32 n1, n2;
+
+ mpVBA->Seek( 0 );
+ mpVBA->ReadUInt32( n1 )
+ .ReadUInt32( n2 );
+
+ mpStrm->WriteUInt32( mnVBAOleOfs );
+ sal_uInt32 nOldPos = mpStrm->Tell();
+ mpStrm->Seek( nOfs ); // Fill the VBAInfoAtom with the correct index to the persisttable
+ mpStrm->WriteUInt32( nPersistEntrys )
+ .WriteUInt32( n1 )
+ .WriteInt32( 2 );
+ mpStrm->Seek( nOldPos );
+
+ }
+ }
+ nPos = mpStrm->Tell();
+ mpStrm->Seek( nPersistOfs );
+ mpPptEscherEx->AddAtom( ( nPersistEntrys + 1 ) << 2, EPP_PersistPtrIncrementalBlock ); // insert Record Header
+ mpStrm->WriteUInt32( ( nPersistEntrys << 20 ) | 1 );
+ mpStrm->Seek( nPos );
+
+ mpCurUserStrm->WriteUInt32( nPos ); // set offset to current edit
+ mpPptEscherEx->AddAtom( 28, EPP_UserEditAtom );
+ mpStrm->WriteInt32( 0x100 ) // last slide ID
+ .WriteUInt32( 0x03000dbc ) // minor and major app version that did the save
+ .WriteUInt32( 0 ) // offset last save, 0 after a full save
+ .WriteUInt32( nPersistOfs ) // File offset to persist pointers for this save operation
+ .WriteUInt32( 1 ) // Persist reference to the document persist object
+ .WriteUInt32( nPersistEntrys ) // max persists written, Seed value for persist object id management
+ .WriteInt16( EPP_LastViewTypeSlideView ) // last view type
+ .WriteInt16( 0x12 ); // padword
+}
+
+// - exported function -
+
+extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool ExportPPT( const std::vector< css::beans::PropertyValue >& rMediaData,
+ tools::SvRef<SotStorage> const & rSvStorage,
+ css::uno::Reference< css::frame::XModel > const & rXModel,
+ css::uno::Reference< css::task::XStatusIndicator > const & rXStatInd,
+ SvMemoryStream* pVBA,
+ sal_uInt32 nCnvrtFlags )
+{
+ PPTWriter aPPTWriter( rSvStorage, rXModel, rXStatInd, pVBA, nCnvrtFlags );
+ aPPTWriter.exportPPT(rMediaData);
+ bool bStatus = aPPTWriter.IsValid();
+ return bStatus;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool SaveVBA( SfxObjectShell& rDocShell, SvMemoryStream*& pBas )
+{
+ tools::SvRef<SotStorage> xDest( new SotStorage( new SvMemoryStream(), true ) );
+ SvxImportMSVBasic aMSVBas( rDocShell, *xDest );
+ aMSVBas.SaveOrDelMSVBAStorage( true, "_MS_VBA_Overhead" );
+
+ tools::SvRef<SotStorage> xOverhead = xDest->OpenSotStorage( "_MS_VBA_Overhead" );
+ if ( xOverhead.is() && ( xOverhead->GetError() == ERRCODE_NONE ) )
+ {
+ tools::SvRef<SotStorage> xOverhead2 = xOverhead->OpenSotStorage( "_MS_VBA_Overhead" );
+ if ( xOverhead2.is() && ( xOverhead2->GetError() == ERRCODE_NONE ) )
+ {
+ tools::SvRef<SotStorageStream> xTemp = xOverhead2->OpenSotStream( "_MS_VBA_Overhead2" );
+ if ( xTemp.is() && ( xTemp->GetError() == ERRCODE_NONE ) )
+ {
+ sal_uInt32 nLen = xTemp->GetSize();
+ if ( nLen )
+ {
+ char* pTemp = new char[ nLen ];
+ xTemp->Seek( STREAM_SEEK_TO_BEGIN );
+ xTemp->ReadBytes(pTemp, nLen);
+ pBas = new SvMemoryStream( pTemp, nLen, StreamMode::READ );
+ pBas->ObjectOwnsMemory( true );
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/eppt.hxx b/sd/source/filter/eppt/eppt.hxx
new file mode 100644
index 000000000..eec839290
--- /dev/null
+++ b/sd/source/filter/eppt/eppt.hxx
@@ -0,0 +1,232 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+#include <memory>
+#include <vector>
+#include "escherex.hxx"
+#include <sal/types.h>
+#include <sot/storage.hxx>
+#include "pptexsoundcollection.hxx"
+
+#include "text.hxx"
+
+#include <com/sun/star/presentation/AnimationEffect.hpp>
+#include <com/sun/star/presentation/ClickAction.hpp>
+
+#include "epptbase.hxx"
+
+namespace com::sun::star::awt { class XControlModel; }
+namespace com::sun::star::beans { class XPropertySet; }
+namespace com::sun::star::beans { struct PropertyValue; }
+namespace com::sun::star::drawing { class XShape; }
+namespace com::sun::star::frame { class XModel; }
+namespace com::sun::star::task { class XStatusIndicator; }
+namespace com::sun::star::text { class XSimpleText; }
+
+class SotStorage;
+
+#define EPP_MAINMASTER_PERSIST_KEY 0x80010000
+#define EPP_MAINNOTESMASTER_PERSIST_KEY 0x80020000
+#define EPP_MAINSLIDE_PERSIST_KEY 0x80030000
+#define EPP_MAINNOTES_PERSIST_KEY 0x80040000
+
+#define EPP_Persist_Document 0x80080000
+#define EPP_Persist_MainMaster 0x80100000
+#define EPP_Persist_MainNotes 0x80200000
+#define EPP_Persist_Slide 0x80400000
+#define EPP_Persist_Notes 0x80800000
+#define EPP_Persist_CurrentPos 0x81000000
+#define EPP_Persist_VBAInfoAtom 0x84000000
+#define EPP_Persist_ExObj 0x88000000
+
+#define EPP_TEXTSTYLE_NORMAL 0x00000001
+#define EPP_TEXTSTYLE_TITLE 0x00000010
+#define EPP_TEXTSTYLE_BODY 0x00000100
+#define EPP_TEXTSTYLE_TEXT 0x00001000
+
+struct EPPTHyperlink
+{
+ OUString aURL;
+ sal_uInt32 nType; // bit 0-7 : type ( 1: click action to a slide )
+ // ( 2: hyperlink url )
+ // bit 8-23: index
+ // bit 31 : hyperlink is attached to a shape
+
+ EPPTHyperlink( const OUString& rURL, sal_uInt32 nT ) :
+ aURL ( rURL ),
+ nType ( nT ){};
+};
+
+enum PPTExOleObjEntryType
+{
+ NORMAL_OLE_OBJECT, OCX_CONTROL
+};
+
+struct PPTExOleObjEntry
+{
+ PPTExOleObjEntryType eType;
+ sal_uInt32 nOfsA; ///< offset to the EPP_ExOleObjAtom in mpExEmbed (set at creation)
+ sal_uInt32 nOfsB; ///< offset to the EPP_ExOleObjStg
+
+ css::uno::Reference< css::awt::XControlModel > xControlModel;
+ css::uno::Reference< css::drawing::XShape > xShape;
+
+ PPTExOleObjEntry(PPTExOleObjEntryType eT, sal_uInt32 nOfs)
+ : eType(eT)
+ , nOfsA(nOfs)
+ , nOfsB(0)
+ {}
+};
+
+struct TextRuleEntry
+{
+ std::unique_ptr<SvMemoryStream> pOut;
+};
+
+class TextObjBinary : public TextObj
+{
+public:
+ TextObjBinary( css::uno::Reference< css::text::XSimpleText > const & rXText,
+ int nInstance, FontCollection& rFontCollection, PPTExBulletProvider& rBuProv ) : TextObj( rXText, nInstance, rFontCollection, rBuProv ) {}
+ void Write( SvStream* pStrm );
+ void WriteTextSpecInfo( SvStream* pStrm );
+};
+
+struct CellBorder;
+class PPTWriter final : public PPTWriterBase, public PPTExBulletProvider
+{
+ sal_uInt32 mnCnvrtFlags;
+ bool mbStatus;
+ sal_uInt32 mnStatMaxValue;
+ sal_uInt32 mnLatestStatValue;
+
+ std::vector<OUString> maSlideNameList;
+ OUString maBaseURI;
+
+ css::uno::Reference< css::text::XSimpleText > mXText; // TextRef of the global text
+ sal_uInt32 mnTextStyle;
+
+ bool mbFontIndependentLineSpacing;
+ sal_uInt32 mnTextSize;
+
+ tools::SvRef<SotStorage> mrStg;
+ tools::SvRef<SotStorageStream> mpCurUserStrm;
+ tools::SvRef<SotStorageStream> mpStrm;
+ tools::SvRef<SotStorageStream> mpPicStrm;
+ std::unique_ptr<PptEscherEx> mpPptEscherEx;
+
+ std::vector<std::unique_ptr<PPTExOleObjEntry>> maExOleObj;
+ sal_uInt32 mnVBAOleOfs;
+ SvMemoryStream* mpVBA;
+ sal_uInt32 mnExEmbed;
+ std::unique_ptr<SvMemoryStream> mpExEmbed;
+
+ sal_uInt32 mnPagesWritten;
+ sal_uInt32 mnTxId; // Identifier determined by the HOST (PP) ????
+ sal_uInt32 mnDiaMode; // 0 -> manual
+ // 1 -> semi-automatic
+ // 2 -> automatic
+
+ sal_uInt32 mnShapeMasterTitle;
+ sal_uInt32 mnShapeMasterBody;
+
+ std::vector<EPPTHyperlink> maHyperlink;
+
+ ppt::ExSoundCollection maSoundCollection;
+
+ void ImplWriteExtParaHeader( SvMemoryStream& rSt, sal_uInt32 nRef, sal_uInt32 nInstance, sal_uInt32 nSlideId );
+
+ sal_uInt32 ImplProgBinaryTag( SvStream* pOutStrm );
+ sal_uInt32 ImplProgBinaryTagContainer( SvStream* pOutStrm, SvMemoryStream* pBinTag );
+ sal_uInt32 ImplProgTagContainer( SvStream* pOutStrm, SvMemoryStream* pBinTag = nullptr );
+ static sal_uInt32 ImplOutlineViewInfoContainer( SvStream* pOutStrm );
+ static sal_uInt32 ImplSlideViewInfoContainer( sal_uInt32 nInstance, SvStream* pOutStrm );
+ sal_uInt32 ImplVBAInfoContainer( SvStream* pOutStrm );
+ sal_uInt32 ImplDocumentListContainer( SvStream* pOutStrm );
+ sal_uInt32 ImplMasterSlideListContainer( SvStream* pOutStrm );
+
+ public:
+ static void WriteCString( SvStream&, const OUString&, sal_uInt32 nInstance = 0 );
+
+ private:
+
+ void ImplCreateDocumentSummaryInformation();
+ bool ImplCreateCurrentUserStream();
+ static void ImplCreateHeaderFooterStrings( SvStream& rOut,
+ css::uno::Reference< css::beans::XPropertySet > const & rXPagePropSet );
+ void ImplCreateHeaderFooters( css::uno::Reference< css::beans::XPropertySet > const & rXPagePropSet );
+ virtual bool ImplCreateDocument() override;
+ void ImplCreateHyperBlob( SvMemoryStream& rStream );
+ sal_uInt32 ImplInsertBookmarkURL( const OUString& rBookmark, const sal_uInt32 nType,
+ const OUString& rStringVer0, const OUString& rStringVer1, const OUString& rStringVer2, const OUString& rStringVer3 );
+ virtual bool ImplCreateMainNotes() override;
+ void ImplWriteBackground( css::uno::Reference< css::beans::XPropertySet > const & rXBackgroundPropSet );
+ void ImplWriteVBA();
+ void ImplWriteOLE();
+ void ImplWriteAtomEnding();
+
+ void ImplFlipBoundingBox( EscherPropertyContainer& rPropOpt );
+ bool ImplGetText();
+ bool ImplCreatePresentationPlaceholder( const bool bMaster,
+ const sal_uInt32 StyleInstance, const sal_uInt8 PlaceHolderId );
+ static bool ImplGetEffect( const css::uno::Reference< css::beans::XPropertySet > &,
+ css::presentation::AnimationEffect& eEffect,
+ css::presentation::AnimationEffect& eTextEffect,
+ bool& bHasSound );
+ void ImplWriteClickAction( SvStream& rSt, css::presentation::ClickAction eAction, bool bMediaClickAction );
+ void ImplWriteParagraphs( SvStream& rOutStrm, TextObj& rTextObj );
+ void ImplWritePortions( SvStream& rOutStrm, TextObj& rTextObj );
+ void ImplWriteTextStyleAtom( SvStream& rOut, int nTextInstance, sal_uInt32 nAtomInstance,
+ TextRuleEntry* pTextRule, SvStream& rExtBu, EscherPropertyContainer* );
+ void ImplAdjustFirstLineLineSpacing( TextObj& rTextObj, EscherPropertyContainer& rPropOpt );
+ void ImplCreateShape( sal_uInt32 nType, ShapeFlag nFlags, EscherSolverContainer& );
+ void ImplCreateTextShape( EscherPropertyContainer&, EscherSolverContainer&, bool bFill );
+
+ void ImplWritePage( const PHLayout& rLayout,
+ EscherSolverContainer& rSolver,
+ PageType ePageType,
+ bool bMaster,
+ int nPageNumber = 0 );
+ bool ImplCreateCellBorder( const CellBorder* pCellBorder, sal_Int32 nX1, sal_Int32 nY1, sal_Int32 nX2, sal_Int32 nY2 );
+ void ImplCreateTable( css::uno::Reference< css::drawing::XShape > const & rXShape, EscherSolverContainer& aSolverContainer,
+ EscherPropertyContainer& aPropOpt );
+
+ bool ImplCloseDocument(); // we write the font, hyper and sound list
+
+ virtual void ImplWriteSlide( sal_uInt32 nPageNum, sal_uInt32 nMasterID, sal_uInt16 nMode,
+ bool bHasBackground, css::uno::Reference< css::beans::XPropertySet > const & aXBackgroundPropSet ) override;
+ virtual void ImplWriteNotes( sal_uInt32 nPageNum ) override;
+ virtual void ImplWriteSlideMaster( sal_uInt32 nPageNum, css::uno::Reference< css::beans::XPropertySet > const & aXBackgroundPropSet ) override;
+
+ public:
+ PPTWriter( tools::SvRef<SotStorage> const & rSvStorage,
+ css::uno::Reference< css::frame::XModel > const & rModel,
+ css::uno::Reference< css::task::XStatusIndicator > const & rStatInd,
+ SvMemoryStream* pVBA, sal_uInt32 nCnvrtFlags );
+
+ virtual ~PPTWriter() override;
+
+ bool IsValid() const { return mbStatus; };
+
+ virtual void exportPPTPre( const std::vector< css::beans::PropertyValue >& ) override;
+ virtual void exportPPTPost( ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/epptbase.hxx b/sd/source/filter/eppt/epptbase.hxx
new file mode 100644
index 000000000..e8ac992e3
--- /dev/null
+++ b/sd/source/filter/eppt/epptbase.hxx
@@ -0,0 +1,412 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <vcl/mapmod.hxx>
+#include <tools/stream.hxx>
+#include <tools/fract.hxx>
+#include <tools/gen.hxx>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/presentation/FadeEffect.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <vcl/vclptr.hxx>
+#include <vcl/graph.hxx>
+
+#include "grouptable.hxx"
+
+namespace com::sun::star::task { class XStatusIndicator; }
+namespace com::sun::star::frame { class XModel; }
+namespace com::sun::star::awt { struct Rectangle; }
+namespace com::sun::star::drawing { class XMasterPagesSupplier; }
+namespace com::sun::star::drawing { class XDrawPage; }
+namespace com::sun::star::drawing { class XDrawPages; }
+namespace com::sun::star::drawing { class XDrawPagesSupplier; }
+namespace com::sun::star::beans { struct PropertyValue; }
+namespace com::sun::star::beans { class XPropertySet; }
+namespace com::sun::star::drawing { class XShape; }
+namespace com::sun::star::drawing { class XShapes; }
+
+class VirtualDevice;
+
+// PLACEMENT_ID
+enum class EppLayout
+{
+ TITLESLIDE = 0, /* The slide is a title slide */
+ TITLEANDBODYSLIDE = 1, /* Title and body slide */
+ TITLEMASTERSLIDE = 2, /* Title master slide */
+ MASTERSLIDE = 3, /* Master slide layout */
+ MASTERNOTES = 4, /* Master notes layout */
+ NOTESTITLEBODY = 5, /* Notes title/body layout */
+ HANDOUTLAYOUT = 6, /* Handout layout, therefore it doesn't have placeholders except header, footer, and date */
+ ONLYTITLE = 7, /* Only title placeholder */
+ TWOCOLUMNSANDTITLE = 8, /* Body of the slide has 2 columns and a title */
+ TWOROWSANDTITLE = 9, /* Slide's body has 2 rows and a title */
+ RIGHTCOLUMN2ROWS = 10, /* Body contains 2 columns, right column has 2 rows */
+ LEFTCOLUMN2ROWS = 11, /* Body contains 2 columns, left column has 2 rows */
+ BOTTOMROW2COLUMNS = 12, /* Body contains 2 rows, bottom row has 2 columns */
+ TOPROW2COLUMN = 13, /* Body contains 2 rows, top row has 2 columns */
+ FOUROBJECTS = 14, /* 4 objects */
+ BIGOBJECT = 15, /* Big object */
+ BLANKSLIDE = 16, /* Blank slide */
+ TITLERIGHTBODYLEFT = 17, /* Vertical title on the right, body on the left */
+ TITLERIGHT2BODIESLEFT = 18 /* Vertical title on the right, body on the left split into 2 rows */
+};
+
+#define EPP_LAYOUT_SIZE 25
+
+struct PHLayout
+{
+ EppLayout nLayout;
+ sal_uInt8 nPlaceHolder[ 8 ];
+
+ sal_uInt8 nUsedObjectPlaceHolder;
+ sal_uInt8 nTypeOfTitle;
+ sal_uInt8 nTypeOfOutliner;
+
+ bool bTitlePossible;
+ bool bOutlinerPossible;
+ bool bSecOutlinerPossible;
+};
+
+enum PageType { NORMAL = 0, MASTER = 1, NOTICE = 2, UNDEFINED = 3, LAYOUT = 4 };
+
+class PropValue
+{
+ protected:
+
+ css::uno::Any mAny;
+ css::uno::Reference< css::beans::XPropertySet > mXPropSet;
+
+ bool ImplGetPropertyValue( const OUString& rString );
+ bool ImplGetPropertyValue( const css::uno::Reference
+ < css::beans::XPropertySet > &, const OUString& );
+
+ public:
+
+ PropValue() {}
+
+ static bool GetPropertyValue(
+ css::uno::Any& rAny,
+ const css::uno::Reference< css::beans::XPropertySet > &,
+ const OUString& rPropertyName,
+ bool bTestPropertyAvailability = false );
+
+ static css::beans::PropertyState GetPropertyState(
+ const css::uno::Reference < css::beans::XPropertySet > &,
+ const OUString& rPropertyName );
+};
+
+class EscherGraphicProvider;
+class PPTExBulletProvider
+{
+ friend struct PPTExParaSheet;
+
+ protected:
+
+ SvMemoryStream aBuExPictureStream;
+ SvMemoryStream aBuExOutlineStream;
+ SvMemoryStream aBuExMasterStream;
+
+ std::unique_ptr<EscherGraphicProvider>
+ pGraphicProv;
+
+ public:
+
+ sal_uInt16 GetId(Graphic const & rGraphic, Size& rGraphicSize);
+
+ PPTExBulletProvider();
+ ~PPTExBulletProvider();
+};
+
+struct FontCollectionEntry
+{
+ OUString Name;
+ double Scaling;
+ sal_Int16 Family;
+ sal_Int16 Pitch;
+ sal_Int16 CharSet;
+
+ OUString Original;
+
+ FontCollectionEntry( const OUString& rName, sal_Int16 nFamily, sal_Int16 nPitch, sal_Int16 nCharSet ) :
+ Scaling ( 1.0 ),
+ Family ( nFamily ),
+ Pitch ( nPitch ),
+ CharSet ( nCharSet ),
+ Original( rName )
+ {
+ ImplInit( rName );
+ };
+
+ explicit FontCollectionEntry( const OUString& rName ) :
+ Scaling ( 1.0 ),
+ Family ( 0 ),
+ Pitch ( 0 ),
+ CharSet ( 0 ),
+ Original( rName )
+ {
+ ImplInit( rName );
+ };
+
+ private:
+
+ void ImplInit( const OUString& rName );
+};
+
+class FontCollection
+{
+public:
+
+ FontCollection();
+
+ ~FontCollection();
+
+ static short GetScriptDirection( std::u16string_view rText );
+
+ sal_uInt32 GetId( FontCollectionEntry& rFontDescriptor );
+
+ sal_uInt32 GetCount() const { return maFonts.size(); };
+
+ const FontCollectionEntry* GetById( sal_uInt32 nId );
+
+ FontCollectionEntry& GetLast() { return *(maFonts.rbegin()); };
+
+private:
+
+ VclPtr<VirtualDevice> pVDev;
+ std::vector<FontCollectionEntry> maFonts;
+};
+
+#define PPTEX_STYLESHEETENTRIES 9
+
+enum PPTExTextAttr
+{
+ ParaAttr_BulletOn,
+ ParaAttr_BuHardFont,
+ ParaAttr_BuHardColor,
+ ParaAttr_BuHardHeight,
+ ParaAttr_BulletChar,
+ ParaAttr_BulletFont,
+ ParaAttr_BulletHeight,
+ ParaAttr_BulletColor,
+ ParaAttr_Adjust,
+ ParaAttr_LineFeed,
+ ParaAttr_UpperDist,
+ ParaAttr_LowerDist,
+ ParaAttr_TextOfs,
+ ParaAttr_BulletOfs,
+ ParaAttr_DefaultTab,
+ ParaAttr_BiDi,
+ CharAttr_Bold,
+ CharAttr_Italic,
+ CharAttr_Underline,
+ CharAttr_Shadow,
+ CharAttr_Strikeout,
+ CharAttr_Embossed,
+ CharAttr_Font,
+ CharAttr_AsianOrComplexFont,
+ CharAttr_Symbol,
+ CharAttr_FontHeight,
+ CharAttr_FontColor,
+ CharAttr_Escapement
+};
+
+struct PPTExCharLevel
+{
+ sal_uInt16 mnFlags;
+ sal_uInt16 mnFont;
+ sal_uInt16 mnAsianOrComplexFont;
+ sal_uInt16 mnFontHeight;
+ sal_uInt16 mnEscapement;
+ Color mnFontColor;
+};
+
+struct PPTExCharSheet
+{
+ PPTExCharLevel maCharLevel[ 5 ];
+
+ explicit PPTExCharSheet( int nInstance );
+
+ void SetStyleSheet( const css::uno::Reference< css::beans::XPropertySet > &,
+ FontCollection& rFontCollection, int nLevel );
+ void Write( SvStream& rSt, sal_uInt16 nLev, bool bSimpleText,
+ const css::uno::Reference< css::beans::XPropertySet > & rPagePropSet );
+
+};
+
+struct PPTExParaLevel
+{
+ bool mbIsBullet;
+ sal_uInt16 mnBulletChar;
+ sal_uInt16 mnBulletFont;
+ sal_uInt16 mnBulletHeight;
+ sal_uInt32 mnBulletColor;
+
+ sal_uInt16 mnAdjust;
+ sal_uInt16 mnLineFeed;
+ sal_uInt16 mnUpperDist;
+ sal_uInt16 mnLowerDist;
+ sal_uInt16 mnTextOfs;
+ sal_uInt16 mnBulletOfs;
+ sal_uInt16 mnDefaultTab;
+
+ bool mbExtendedBulletsUsed;
+ sal_uInt16 mnBulletId;
+ sal_uInt16 mnBulletStart;
+ sal_uInt32 mnMappedNumType;
+ sal_uInt32 mnNumberingType;
+ sal_uInt16 mnAsianSettings;
+ sal_uInt16 mnBiDi;
+};
+
+struct PPTExParaSheet
+{
+ PPTExBulletProvider* pBuProv;
+
+ sal_uInt32 mnInstance;
+
+ PPTExParaLevel maParaLevel[ 5 ];
+ PPTExParaSheet( int nInstance, sal_uInt16 nDefaultTab, PPTExBulletProvider* pProv );
+
+ void SetStyleSheet( const css::uno::Reference< css::beans::XPropertySet > &,
+ FontCollection& rFontCollection, int nLevel, const PPTExCharLevel& rCharLevel );
+ void Write( SvStream& rSt, sal_uInt16 nLev, bool bSimpleText,
+ const css::uno::Reference< css::beans::XPropertySet > & rPagePropSet );
+};
+
+class PPTExStyleSheet
+{
+
+ public:
+
+ std::unique_ptr<PPTExCharSheet> mpCharSheet[ PPTEX_STYLESHEETENTRIES ];
+ std::unique_ptr<PPTExParaSheet> mpParaSheet[ PPTEX_STYLESHEETENTRIES ];
+
+ PPTExStyleSheet( sal_uInt16 nDefaultTab, PPTExBulletProvider* pBuProv );
+ ~PPTExStyleSheet();
+
+ PPTExParaSheet& GetParaSheet( int nInstance ) { return *mpParaSheet[ nInstance ]; };
+
+ void SetStyleSheet( const css::uno::Reference< css::beans::XPropertySet > &,
+ FontCollection& rFontCollection, int nInstance, int nLevel );
+ bool IsHardAttribute( sal_uInt32 nInstance, sal_uInt32 nLevel, PPTExTextAttr eAttr, sal_uInt32 nValue );
+
+ static sal_uInt32 SizeOfTxCFStyleAtom() { return 24; }
+ void WriteTxCFStyleAtom( SvStream& rSt );
+};
+
+class PPTWriterBase : public PropValue, public GroupTable
+{
+protected:
+ css::uno::Reference< css::frame::XModel > mXModel;
+ css::uno::Reference< css::task::XStatusIndicator > mXStatusIndicator;
+
+ bool mbStatusIndicator;
+
+ css::uno::Reference< css::drawing::XDrawPagesSupplier > mXDrawPagesSupplier;
+ css::uno::Reference< css::drawing::XMasterPagesSupplier > mXMasterPagesSupplier;
+ css::uno::Reference< css::drawing::XDrawPages > mXDrawPages;
+ css::uno::Reference< css::drawing::XDrawPage > mXDrawPage;
+ css::uno::Reference< css::beans::XPropertySet > mXPagePropSet;
+ css::uno::Reference< css::beans::XPropertySet > mXBackgroundPropSet;
+ css::uno::Reference< css::drawing::XShapes > mXShapes;
+ css::uno::Reference< css::drawing::XShape > mXShape;
+ css::awt::Size maSize;
+ css::awt::Point maPosition;
+ ::tools::Rectangle maRect;
+ OString mType;
+ bool mbPresObj;
+ bool mbEmptyPresObj;
+ bool mbIsBackgroundDark;
+ sal_Int32 mnAngle;
+
+ sal_uInt32 mnPages; ///< number of Slides ( w/o master pages & notes & handout )
+ sal_uInt32 mnMasterPages;
+
+ Fraction maFraction;
+ MapMode maMapModeSrc;
+ MapMode maMapModeDest;
+ css::awt::Size maDestPageSize;
+ css::awt::Size maPageSize; // #i121183# Keep size in logic coordinates (100th mm)
+ css::awt::Size maNotesPageSize;
+
+ PageType meLatestPageType;
+ std::vector< std::unique_ptr<PPTExStyleSheet> > maStyleSheetList;
+ PPTExStyleSheet* mpStyleSheet;
+
+ FontCollection maFontCollection;
+
+ virtual void ImplWriteSlide( sal_uInt32 /* nPageNum */, sal_uInt32 /* nMasterNum */, sal_uInt16 /* nMode */,
+ bool /* bHasBackground */, css::uno::Reference< css::beans::XPropertySet > const & /* aXBackgroundPropSet */ ) {}
+ virtual void ImplWriteNotes( sal_uInt32 nPageNum ) = 0;
+ virtual void ImplWriteSlideMaster( sal_uInt32 /* nPageNum */, css::uno::Reference< css::beans::XPropertySet > const & /* aXBackgroundPropSet */ ) {}
+
+ virtual void exportPPTPre( const std::vector< css::beans::PropertyValue >& ) {}
+ virtual void exportPPTPost() {}
+
+ virtual bool ImplCreateDocument()=0;
+ virtual bool ImplCreateMainNotes()=0;
+
+ bool GetStyleSheets();
+ bool GetShapeByIndex( sal_uInt32 nIndex, bool bGroup );
+
+ bool CreateMainNotes();
+
+ css::awt::Size MapSize( const css::awt::Size& );
+ css::awt::Point MapPoint( const css::awt::Point& );
+ ::tools::Rectangle MapRectangle( const css::awt::Rectangle& );
+
+ bool ContainsOtherShapeThanPlaceholders();
+
+public:
+ PPTWriterBase();
+ PPTWriterBase( const css::uno::Reference< css::frame::XModel > & rModel,
+ const css::uno::Reference< css::task::XStatusIndicator > & rStatInd );
+
+ virtual ~PPTWriterBase();
+
+ void exportPPT(const std::vector< css::beans::PropertyValue >&);
+
+ bool InitSOIface();
+ bool GetPageByIndex( sal_uInt32 nIndex, PageType );
+ sal_uInt32 GetMasterIndex( PageType ePageType );
+ void SetCurrentStyleSheet( sal_uInt32 nPageNum );
+
+ bool GetPresObj() const { return mbPresObj; }
+
+ static PHLayout const & GetLayout( const css::uno::Reference< css::beans::XPropertySet >& rXPropSet );
+ static PHLayout const & GetLayout( sal_Int32 nOffset );
+ static sal_Int32 GetLayoutOffset( const css::uno::Reference< css::beans::XPropertySet >& rXPropSet );
+ static sal_Int32 GetLayoutOffsetFixed( const css::uno::Reference< css::beans::XPropertySet >& rXPropSet );
+
+ bool CreateSlide( sal_uInt32 nPageNum );
+ bool CreateSlideMaster( sal_uInt32 nPageNum );
+ bool CreateNotes( sal_uInt32 nPageNum );
+
+ static sal_Int8 GetTransition( sal_Int16 nTransitionType, sal_Int16 nTransitionSubtype, css::presentation::FadeEffect eEffect,
+ sal_Int32 nTransitionFadeColor, sal_uInt8& nDirection );
+ static sal_Int8 GetTransition( css::presentation::FadeEffect eEffect, sal_uInt8& nDirection );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/epptdef.hxx b/sd/source/filter/eppt/epptdef.hxx
new file mode 100644
index 000000000..f5059681c
--- /dev/null
+++ b/sd/source/filter/eppt/epptdef.hxx
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#define EPP_Document 1000
+#define EPP_DocumentAtom 1001
+#define EPP_EndDocument 1002
+#define EPP_Slide 1006
+#define EPP_SlideAtom 1007
+#define EPP_Notes 1008
+#define EPP_NotesAtom 1009
+#define EPP_Environment 1010
+#define EPP_SlidePersistAtom 1011 //0x03F3
+#define EPP_MainMaster 1016
+#define EPP_SSSlideInfoAtom 1017
+#define EPP_SlideViewInfo 1018
+#define EPP_GuideAtom 1019
+#define EPP_ViewInfoAtom 1021
+#define EPP_SlideViewInfoAtom 1022
+#define EPP_VBAInfo 1023
+#define EPP_VBAInfoAtom 1024
+#define EPP_SSDocInfoAtom 1025
+#define EPP_OutlineViewInfo 1031
+#define EPP_ExObjList 1033
+#define EPP_ExObjListAtom 1034
+#define EPP_PPDrawingGroup 1035
+#define EPP_PPDrawing 1036
+#define EPP_NamedShows 1040
+#define EPP_NamedShow 1041
+#define EPP_NamedShowSlides 1042
+#define EPP_List 2000
+#define EPP_FontCollection 2005
+#define EPP_SoundCollection 2020
+#define EPP_SoundCollAtom 2021
+#define EPP_Sound 2022
+#define EPP_SoundData 2023
+#define EPP_ColorSchemeAtom 2032
+
+// these atoms first was seen in ppt2000 in a private Tag atom
+#define EPP_PST_ExtendedBuGraContainer 2040 // consist of 4041
+
+#define EPP_ExObjRefAtom 3009
+#define EPP_OEPlaceholderAtom 3011
+#define EPP_TextHeaderAtom 3999
+#define EPP_TextCharsAtom 4000
+#define EPP_StyleTextPropAtom 4001
+#define EPP_BaseTextPropAtom 4002
+#define EPP_TxMasterStyleAtom 4003
+#define EPP_TxCFStyleAtom 4004
+#define EPP_TextRulerAtom 4006
+#define EPP_TxSIStyleAtom 4009
+#define EPP_TextSpecInfoAtom 4010
+
+// these atoms first was seen in ppt2000 in a private Tag atom
+#define EPP_PST_ExtendedParagraphAtom 4012
+#define EPP_PST_ExtendedParagraphMasterAtom 4013
+#define EPP_PST_ExtendedPresRuleContainer 4014 // consist of 4012, 4015,
+#define EPP_PST_ExtendedParagraphHeaderAtom 4015 // the instance of this atom indices the current presobj
+ // the first sal_uInt32 in this atom indices the current slideId
+
+#define EPP_FontEnityAtom 4023
+#define EPP_CString 4026
+#define EPP_ExOleObjAtom 4035
+#define EPP_SrKinsoku 4040
+#define EPP_ExEmbed 4044
+#define EPP_ExEmbedAtom 4045
+#define EPP_SrKinsokuAtom 4050
+#define EPP_ExHyperlinkAtom 4051
+#define EPP_ExHyperlink 4055
+#define EPP_SlideNumberMCAtom 4056
+#define EPP_HeadersFooters 4057
+#define EPP_HeadersFootersAtom 4058
+#define EPP_TxInteractiveInfoAtom 4063
+#define EPP_ExControl 4078
+#define EPP_ExControlAtom 4091
+#define EPP_SlideListWithText 4080 // 0x0FF0
+#define EPP_AnimationInfoAtom 4081
+#define EPP_InteractiveInfo 4082
+#define EPP_InteractiveInfoAtom 4083
+#define EPP_UserEditAtom 4085
+#define EPP_CurrentUserAtom 4086
+#define EPP_DateTimeMCAtom 4087
+#define EPP_GenericDateMCAtom 4088
+#define EPP_HeaderMCAtom 4089
+#define EPP_FooterMCAtom 4090
+#define EPP_ExMediaAtom 4100
+#define EPP_ExVideo 4101
+#define EPP_ExMCIMovie 4103
+#define EPP_ExOleObjStg 4113
+#define EPP_AnimationInfo 4116
+#define EPP_ProgTags 5000
+#define EPP_ProgBinaryTag 5002
+#define EPP_BinaryTagData 5003
+#define EPP_PersistPtrIncrementalBlock 6002
+#define EPP_Comment10 12000
+#define EPP_CommentAtom10 12001
+
+#define EPP_PLACEHOLDER_NONE 0 // 0 None
+#define EPP_PLACEHOLDER_MASTERTITLE 1 // 1 Master title
+#define EPP_PLACEHOLDER_MASTERBODY 2 // 2 Master body
+#define EPP_PLACEHOLDER_MASTERSUBTITLE 4 // 10 Master subtitle
+#define EPP_PLACEHOLDER_MASTERNOTESSLIDEIMAGE 5 // 4 Master notes slide image
+#define EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE 6 // 5 Master notes body image
+#define EPP_PLACEHOLDER_MASTERDATE 7 // 6 Master date
+#define EPP_PLACEHOLDER_MASTERSLIDENUMBER 8 // 7 Master slide number
+#define EPP_PLACEHOLDER_MASTERFOOTER 9 // 8 Master footer
+#define EPP_PLACEHOLDER_MASTERHEADER 10 // 9 Master header
+#define EPP_PLACEHOLDER_GENERICTEXTOBJECT // 11 Generic text object
+#define EPP_PLACEHOLDER_NOTESBODY 12 // 14 Notes body
+#define EPP_PLACEHOLDER_NOTESSLIDEIMAGE 11 // 19 Notes slide image
+
+#define EPP_TEXTTYPE_Title 0
+#define EPP_TEXTTYPE_Body 1
+#define EPP_TEXTTYPE_Notes 2
+#define EPP_TEXTTYPE_notUsed 3
+#define EPP_TEXTTYPE_Other 4 // ( Text in a shape )
+#define EPP_TEXTTYPE_CenterBody 5 // ( subtitle in title slide )
+#define EPP_TEXTTYPE_CenterTitle 6 // ( title in title slide )
+#define EPP_TEXTTYPE_HalfBody 7 // ( body in two-column slide )
+#define EPP_TEXTTYPE_QuarterBody 8 // ( body in four-body slide )
+
+#define EPP_SLIDESIZE_TYPEONSCREEN 0
+#define EPP_SLIDESIZE_TYPEA4PAPER 2
+#define EPP_SLIDESIZE_TYPE35MM 3
+#define EPP_SLIDESIZE_TYPEBANNER 5
+#define EPP_SLIDESIZE_TYPECUSTOM 6
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/epptooxml.hxx b/sd/source/filter/eppt/epptooxml.hxx
new file mode 100644
index 000000000..5ee3248ec
--- /dev/null
+++ b/sd/source/filter/eppt/epptooxml.hxx
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <oox/core/xmlfilterbase.hxx>
+#include <oox/vml/vmldrawing.hxx>
+#include <oox/export/shapes.hxx>
+#include "epptbase.hxx"
+
+using ::sax_fastparser::FSHelperPtr;
+
+namespace svx
+{
+class Theme;
+}
+
+namespace oox::core {
+
+struct LayoutInfo
+{
+ std::vector< sal_Int32 > mnFileIdArray;
+};
+
+enum PlaceholderType
+{
+ None,
+ SlideImage,
+ Notes,
+ Header,
+ Footer,
+ SlideNumber,
+ DateAndTime,
+ Outliner,
+ Title,
+ Subtitle
+};
+
+class PowerPointShapeExport;
+
+class PowerPointExport final : public XmlFilterBase, public PPTWriterBase
+{
+ friend class PowerPointShapeExport;
+public:
+
+ PowerPointExport(const css::uno::Reference<css::uno::XComponentContext> & rContext, const css::uno::Sequence<css::uno::Any>& rArguments);
+
+ virtual ~PowerPointExport() override;
+
+ // from FilterBase
+ virtual bool importDocument() noexcept override;
+ virtual bool exportDocument() override;
+
+ // only needed for import, leave them empty, refactor later XmlFilterBase to export and import base?
+ virtual oox::vml::Drawing* getVmlDrawing() override { return nullptr; }
+ virtual const oox::drawingml::Theme* getCurrentTheme() const override { return nullptr; }
+ virtual oox::drawingml::table::TableStyleListPtr getTableStyles() override { return oox::drawingml::table::TableStyleListPtr(); }
+ virtual oox::drawingml::chart::ChartConverter* getChartConverter() override { return nullptr; }
+
+ static const char* GetSideDirection( sal_uInt8 nDirection );
+ static const char* GetCornerDirection( sal_uInt8 nDirection );
+ static const char* Get8Direction( sal_uInt8 nDirection );
+ static int GetPPTXLayoutId( int nOffset );
+
+ sal_Int32 GetShapeID(const css::uno::Reference<css::drawing::XShape>& rXShape);
+ sal_Int32 GetNextAnimationNodeID();
+
+ void embedEffectAudio(const FSHelperPtr& pFS, const OUString& sUrl, OUString& sRelId, OUString& sName);
+
+private:
+
+ virtual void ImplWriteSlide( sal_uInt32 nPageNum, sal_uInt32 nMasterNum, sal_uInt16 nMode,
+ bool bHasBackground, css::uno::Reference< css::beans::XPropertySet > const & aXBackgroundPropSet ) override;
+ virtual void ImplWriteNotes( sal_uInt32 nPageNum ) override;
+ virtual void ImplWriteSlideMaster( sal_uInt32 nPageNum, css::uno::Reference< css::beans::XPropertySet > const & aXBackgroundPropSet ) override;
+ void ImplWritePPTXLayout( sal_Int32 nOffset, sal_uInt32 nMasterNum );
+
+ /// Export the color set part of a theme.
+ static bool WriteColorSets(const FSHelperPtr& pFS, svx::Theme* pTheme);
+
+ /// Same as WriteColorSets(), but works from a grab-bag.
+ bool WriteColorSchemes(const FSHelperPtr& pFS, const OUString& rThemePath);
+
+ static void WriteDefaultColorSchemes(const FSHelperPtr& pFS);
+ void WriteTheme( sal_Int32 nThemeNum, svx::Theme* pTheme );
+
+ virtual bool ImplCreateDocument() override;
+ virtual bool ImplCreateMainNotes() override;
+ virtual ::oox::ole::VbaProject* implCreateVbaProject() const override;
+ void WriteNotesMaster();
+
+ bool WriteComments( sal_uInt32 nPageNum );
+ void ImplWriteBackground( const ::sax_fastparser::FSHelperPtr& pFS, const css::uno::Reference< css::beans::XPropertySet >& aXBackgroundPropSet );
+ void WriteTransition( const ::sax_fastparser::FSHelperPtr& pFS );
+
+ sal_Int32 GetLayoutFileId( sal_Int32 nOffset, sal_uInt32 nMasterNum );
+
+ // shapes
+ void WriteShapeTree( const ::sax_fastparser::FSHelperPtr& pFS, PageType ePageType, bool bMaster );
+
+ sal_uInt32 GetNewSlideId() { return mnSlideIdMax ++; }
+ sal_uInt32 GetNewSlideMasterId() { return mnSlideMasterIdMax ++; }
+ sal_Int32 GetAuthorIdAndLastIndex( const OUString& sAuthor, sal_Int32& nLastIndex );
+
+ // Write docProps/core.xml and docprops/custom.xml and docprops/app.xml
+ void writeDocumentProperties();
+
+ void WriteCustomSlideShow();
+
+ void AddLayoutIdAndRelation( const ::sax_fastparser::FSHelperPtr& pFS, sal_Int32 nLayoutFileId );
+
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ static void WriteDiagram(const FSHelperPtr& pFS, PowerPointShapeExport& rDML, const css::uno::Reference<css::drawing::XShape>& rXShape, int nDiagramId);
+
+ /** Create a new placeholder index for a master placeholder shape
+
+ @param rXShape Master placeholder shape
+ @returns Placeholder index
+ */
+ sal_Int32 CreateNewPlaceholderIndex(const css::uno::Reference<css::drawing::XShape>& rXShape);
+ css::uno::Reference<css::drawing::XShape> GetReferencedPlaceholderXShape(const PlaceholderType eType, PageType ePageType) const;
+ void WritePlaceholderReferenceShapes(PowerPointShapeExport& rDML, PageType ePageType);
+
+ /// Should we export as .pptm, ie. do we contain macros?
+ bool mbPptm;
+
+ // Export as a template
+ bool mbExportTemplate;
+
+ ::sax_fastparser::FSHelperPtr mPresentationFS;
+
+ LayoutInfo mLayoutInfo[EPP_LAYOUT_SIZE];
+ std::vector< ::sax_fastparser::FSHelperPtr > mpSlidesFSArray;
+ sal_Int32 mnLayoutFileIdMax;
+
+ sal_uInt32 mnSlideIdMax;
+ sal_uInt32 mnSlideMasterIdMax;
+ sal_uInt32 mnAnimationNodeIdMax;
+
+ sal_uInt32 mnDiagramId;
+
+ std::vector<OUString> maRelId;
+
+ bool mbCreateNotes;
+
+ ::oox::drawingml::ShapeExport::ShapeHashMap maShapeMap;
+
+ sal_Int32 mnPlaceholderIndexMax; ///< Last used placeholder index
+ /// Map of placeholder indexes for Master placeholders
+ std::unordered_map< css::uno::Reference<css::drawing::XShape>, sal_Int32 > maPlaceholderShapeToIndexMap;
+
+ struct AuthorComments {
+ sal_Int32 nId;
+ sal_Int32 nLastIndex;
+ };
+ typedef std::unordered_map< OUString, struct AuthorComments > AuthorsMap;
+ AuthorsMap maAuthors;
+
+ void WriteAuthors();
+
+ void WritePresentationProps();
+
+ /// If this is PPTM, output the VBA stream.
+ void WriteVBA();
+
+ void WriteModifyVerifier();
+};
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/epptso.cxx b/sd/source/filter/eppt/epptso.cxx
new file mode 100644
index 000000000..41126aedf
--- /dev/null
+++ b/sd/source/filter/eppt/epptso.cxx
@@ -0,0 +1,3361 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <sal/config.h>
+
+#include <basegfx/numeric/ftools.hxx>
+#include <o3tl/any.hxx>
+#include "eppt.hxx"
+#include "text.hxx"
+#include "epptdef.hxx"
+#include "escherex.hxx"
+#include <tools/poly.hxx>
+#include <tools/stream.hxx>
+#include <tools/fontenum.hxx>
+#include <tools/UnitConversion.hxx>
+#include <sot/storage.hxx>
+#include <vcl/graph.hxx>
+#include <editeng/svxenum.hxx>
+#include <svx/svdobj.hxx>
+#include <com/sun/star/awt/FontFamily.hpp>
+#include <com/sun/star/awt/FontPitch.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/style/TabStop.hpp>
+#include <com/sun/star/drawing/CircleKind.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <tools/urlobj.hxx>
+#include <com/sun/star/text/XSimpleText.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/table/XTable.hpp>
+#include <com/sun/star/table/XMergeableCell.hpp>
+#include <com/sun/star/table/BorderLine.hpp>
+#include <com/sun/star/table/XColumnRowRange.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <oox/ole/olehelper.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+using namespace ::com::sun::star;
+
+#define ANSI_CHARSET 0
+#define SYMBOL_CHARSET 2
+
+/* Font Families */
+#define FF_ROMAN 0x10
+#define FF_SWISS 0x20
+#define FF_MODERN 0x30
+#define FF_SCRIPT 0x40
+#define FF_DECORATIVE 0x50
+
+#define DEFAULT_PITCH 0x00
+#define FIXED_PITCH 0x01
+
+PPTExBulletProvider::PPTExBulletProvider()
+ : pGraphicProv( new EscherGraphicProvider( EscherGraphicProviderFlags::UseInstances ) )
+{
+}
+
+PPTExBulletProvider::~PPTExBulletProvider()
+{
+}
+
+sal_uInt16 PPTExBulletProvider::GetId(Graphic const & rGraphic, Size& rGraphicSize )
+{
+ sal_uInt16 nRetValue = 0xffff;
+
+ if (!rGraphic.IsNone())
+ {
+ Graphic aMappedGraphic, aGraphic(rGraphic);
+ GraphicObject aGraphicObject(aGraphic);
+ Size aPrefSize( aGraphic.GetPrefSize() );
+ BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
+
+ if ( rGraphicSize.Width() && rGraphicSize.Height() )
+ {
+ if (aPrefSize.IsEmpty())
+ {
+ aBmpEx.Scale(aPrefSize);
+ }
+ else
+ {
+ double fQ1 = static_cast<double>(aPrefSize.Width()) / static_cast<double>(aPrefSize.Height());
+ double fQ2 = static_cast<double>(rGraphicSize.Width()) / static_cast<double>(rGraphicSize.Height());
+ double fXScale = 1;
+ double fYScale = 1;
+
+ if ( fQ1 > fQ2 )
+ fYScale = fQ1 / fQ2;
+ else if ( fQ1 < fQ2 )
+ fXScale = fQ2 / fQ1;
+
+ if ( ( fXScale != 1.0 ) || ( fYScale != 1.0 ) )
+ {
+ aBmpEx.Scale( fXScale, fYScale );
+ rGraphicSize = Size( static_cast<sal_Int32>(static_cast<double>(rGraphicSize.Width()) / fXScale + 0.5 ),
+ static_cast<sal_Int32>(static_cast<double>(rGraphicSize.Height()) / fYScale + 0.5 ) );
+
+ aMappedGraphic = Graphic( aBmpEx );
+ aGraphicObject.SetGraphic(aMappedGraphic);
+ }
+ }
+ }
+ sal_uInt32 nId = pGraphicProv->GetBlibID(aBuExPictureStream, aGraphicObject);
+
+ if ( nId && ( nId < 0x10000 ) )
+ nRetValue = static_cast<sal_uInt16>(nId) - 1;
+ }
+ return nRetValue;
+}
+
+sal_uInt32 PPTWriter::ImplVBAInfoContainer( SvStream* pStrm )
+{
+ sal_uInt32 nSize = 28;
+ if ( pStrm )
+ {
+ pStrm->WriteUInt32( 0x1f | ( EPP_VBAInfo << 16 ) )
+ .WriteUInt32( nSize - 8 )
+ .WriteUInt32( 2 | ( EPP_VBAInfoAtom << 16 ) )
+ .WriteUInt32( 12 );
+ mpPptEscherEx->InsertPersistOffset( EPP_Persist_VBAInfoAtom, pStrm->Tell() );
+ pStrm->WriteUInt32( 0 )
+ .WriteUInt32( 0 )
+ .WriteUInt32( 1 );
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplSlideViewInfoContainer( sal_uInt32 nInstance, SvStream* pStrm )
+{
+ sal_uInt32 nSize = 111;
+ if ( pStrm )
+ {
+ sal_uInt8 bShowGuides = 0;
+ sal_uInt8 const bSnapToGrid = 1;
+ sal_uInt8 const bSnapToShape = 0;
+
+ sal_Int32 nScaling = 85;
+ sal_Int32 nMasterCoordinate = 0xdda;
+ sal_Int32 nXOrigin = -780;
+ sal_Int32 nYOrigin = -84;
+
+ sal_Int32 nPosition1 = 0x870;
+ sal_Int32 nPosition2 = 0xb40;
+
+ if ( nInstance )
+ {
+ bShowGuides = 1;
+ nScaling = 0x3b;
+ nMasterCoordinate = 0xf0c;
+ nXOrigin = -1752;
+ nYOrigin = -72;
+ nPosition1 = 0xb40;
+ nPosition2 = 0x870;
+ }
+ pStrm->WriteUInt32( 0xf | ( EPP_SlideViewInfo << 16 ) | ( nInstance << 4 ) )
+ .WriteUInt32( nSize - 8 )
+ .WriteUInt32( EPP_SlideViewInfoAtom << 16 ).WriteUInt32( 3 )
+ .WriteUChar( bShowGuides ).WriteUChar( bSnapToGrid ).WriteUChar( bSnapToShape )
+ .WriteUInt32( EPP_ViewInfoAtom << 16 ).WriteUInt32( 52 )
+ .WriteInt32( nScaling ).WriteInt32( 100 ).WriteInt32( nScaling ).WriteInt32( 100 ) // scaling atom - Keeps the current scale
+ .WriteInt32( nScaling ).WriteInt32( 100 ).WriteInt32( nScaling ).WriteInt32( 100 ) // scaling atom - Keeps the previous scale
+ .WriteInt32( 0x17ac ).WriteInt32( nMasterCoordinate )// Origin - Keeps the origin in master coordinates
+ .WriteInt32( nXOrigin ).WriteInt32( nYOrigin ) // Origin
+ .WriteUChar( 1 ) // Bool1 varScale - Set if zoom to fit is set
+ .WriteUChar( 0 ) // bool1 draftMode - Not used
+ .WriteUInt16( 0 ) // padword
+ .WriteUInt32( ( 7 << 4 ) | ( EPP_GuideAtom << 16 ) ).WriteUInt32( 8 )
+ .WriteUInt32( 0 ) // Type of the guide. If the guide is horizontal this value is zero. If it's vertical, it's one.
+ .WriteInt32( nPosition1 ) // Position of the guide in master coordinates. X coordinate if it's vertical, and Y coordinate if it's horizontal.
+ .WriteUInt32( ( 7 << 4 ) | ( EPP_GuideAtom << 16 ) ).WriteUInt32( 8 )
+ .WriteInt32( 1 ) // Type of the guide. If the guide is horizontal this value is zero. If it's vertical, it's one.
+ .WriteInt32( nPosition2 ); // Position of the guide in master coordinates. X coordinate if it's vertical, and Y coordinate if it's horizontal.
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplOutlineViewInfoContainer( SvStream* pStrm )
+{
+ sal_uInt32 nSize = 68;
+ if ( pStrm )
+ {
+ pStrm->WriteUInt32( 0xf | ( EPP_OutlineViewInfo << 16 ) ).WriteUInt32( nSize - 8 )
+ .WriteUInt32( EPP_ViewInfoAtom << 16 ).WriteUInt32( 52 )
+ .WriteInt32( 170 ).WriteInt32( 200 ).WriteInt32( 170 ).WriteInt32( 200 ) // scaling atom - Keeps the current scale
+ .WriteInt32( 170 ).WriteInt32( 200 ).WriteInt32( 170 ).WriteInt32( 200 ) // scaling atom - Keeps the previous scale
+ .WriteInt32( 0x17ac ).WriteInt32( 0xdda ) // Origin - Keeps the origin in master coordinates
+ .WriteInt32( -780 ).WriteInt32( -84 ) // Origin
+ .WriteUChar( 1 ) // bool1 varScale - Set if zoom to fit is set
+ .WriteUChar( 0 ) // bool1 draftMode - Not used
+ .WriteUInt16( 0 ); // padword
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplProgBinaryTag( SvStream* pStrm )
+{
+ sal_uInt32 nPictureStreamSize, nOutlineStreamSize, nSize = 8;
+
+ nPictureStreamSize = aBuExPictureStream.Tell();
+ if ( nPictureStreamSize )
+ nSize += nPictureStreamSize + 8;
+
+ nOutlineStreamSize = aBuExOutlineStream.Tell();
+ if ( nOutlineStreamSize )
+ nSize += nOutlineStreamSize + 8;
+
+ if ( pStrm )
+ {
+ pStrm->WriteUInt32( EPP_BinaryTagData << 16 ).WriteUInt32( nSize - 8 );
+ if ( nPictureStreamSize )
+ {
+ pStrm->WriteUInt32( 0xf | ( EPP_PST_ExtendedBuGraContainer << 16 ) ).WriteUInt32( nPictureStreamSize );
+ pStrm->WriteBytes(aBuExPictureStream.GetData(), nPictureStreamSize);
+ }
+ if ( nOutlineStreamSize )
+ {
+ pStrm->WriteUInt32( 0xf | ( EPP_PST_ExtendedPresRuleContainer << 16 ) ).WriteUInt32( nOutlineStreamSize );
+ pStrm->WriteBytes(aBuExOutlineStream.GetData(), nOutlineStreamSize);
+ }
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplProgBinaryTagContainer( SvStream* pStrm, SvMemoryStream* pBinTagStrm )
+{
+ sal_uInt32 nSize = 8 + 8 + 14;
+ if ( pStrm )
+ {
+ pStrm->WriteUInt32( 0xf | ( EPP_ProgBinaryTag << 16 ) ).WriteUInt32( 0 )
+ .WriteUInt32( EPP_CString << 16 ).WriteUInt32( 14 )
+ .WriteUInt32( 0x5f005f ).WriteUInt32( 0x50005f )
+ .WriteUInt32( 0x540050 ).WriteUInt16( 0x39 );
+ }
+ if ( pStrm && pBinTagStrm )
+ {
+ sal_uInt32 nLen = pBinTagStrm->Tell();
+ nSize += nLen + 8;
+ pStrm->WriteUInt32( EPP_BinaryTagData << 16 ).WriteUInt32( nLen );
+ pStrm->WriteBytes(pBinTagStrm->GetData(), nLen);
+ }
+ else
+ nSize += ImplProgBinaryTag( pStrm );
+
+ if ( pStrm )
+ {
+ pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
+ pStrm->WriteUInt32( nSize - 8 );
+ pStrm->SeekRel( nSize - 8 );
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplProgTagContainer( SvStream* pStrm, SvMemoryStream* pBinTagStrm )
+{
+ sal_uInt32 nSize = 0;
+ if ( aBuExPictureStream.Tell() || aBuExOutlineStream.Tell() || pBinTagStrm )
+ {
+ nSize = 8;
+ if ( pStrm )
+ {
+ pStrm->WriteUInt32( 0xf | ( EPP_ProgTags << 16 ) ).WriteUInt32( 0 );
+ }
+ nSize += ImplProgBinaryTagContainer( pStrm, pBinTagStrm );
+ if ( pStrm )
+ {
+ pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
+ pStrm->WriteUInt32( nSize - 8 );
+ pStrm->SeekRel( nSize - 8 );
+ }
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplDocumentListContainer( SvStream* pStrm )
+{
+ sal_uInt32 nSize = 8;
+ if ( pStrm )
+ {
+ pStrm->WriteUInt32( ( EPP_List << 16 ) | 0xf ).WriteUInt32( 0 );
+ }
+
+ nSize += ImplVBAInfoContainer( pStrm );
+ nSize += ImplSlideViewInfoContainer( 0, pStrm );
+ nSize += ImplOutlineViewInfoContainer( pStrm );
+ nSize += ImplSlideViewInfoContainer( 1, pStrm );
+ nSize += ImplProgTagContainer( pStrm );
+
+ if ( pStrm )
+ {
+ pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
+ pStrm->WriteUInt32( nSize - 8 );
+ pStrm->SeekRel( nSize - 8 );
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplMasterSlideListContainer( SvStream* pStrm )
+{
+ sal_uInt32 i, nSize = 28 * mnMasterPages + 8;
+ if ( pStrm )
+ {
+ pStrm->WriteUInt32( 0x1f | ( EPP_SlideListWithText << 16 ) ).WriteUInt32( nSize - 8 );
+
+ for ( i = 0; i < mnMasterPages; i++ )
+ {
+ pStrm->WriteUInt32( EPP_SlidePersistAtom << 16 ).WriteUInt32( 20 );
+ mpPptEscherEx->InsertPersistOffset( EPP_MAINMASTER_PERSIST_KEY | i, pStrm->Tell() );
+ pStrm->WriteUInt32( 0 ) // psrReference - logical reference to the slide persist object ( EPP_MAINMASTER_PERSIST_KEY )
+ .WriteUInt32( 0 ) // flags - only bit 3 used, if set then slide contains shapes other than placeholders
+ .WriteInt32( 0 ) // numberTexts - number of placeholder texts stored with the persist object. Allows to display outline view without loading the slide persist objects
+ .WriteInt32( 0x80000000 | i ) // slideId - Unique slide identifier, used for OLE link monikers for example
+ .WriteUInt32( 0 ); // reserved, usually 0
+ }
+ }
+ return nSize;
+}
+
+sal_uInt32 PPTWriter::ImplInsertBookmarkURL( const OUString& rBookmarkURL, const sal_uInt32 nType,
+ const OUString& rStringVer0, const OUString& rStringVer1, const OUString& rStringVer2, const OUString& rStringVer3 )
+{
+ sal_uInt32 nHyperId = ++mnExEmbed;
+
+ OUString sBookmarkURL( rBookmarkURL );
+ INetURLObject aBaseURI( maBaseURI );
+ INetURLObject aBookmarkURI( rBookmarkURL );
+ if( aBaseURI.GetProtocol() == aBookmarkURI.GetProtocol() )
+ {
+ OUString aRelUrl( INetURLObject::GetRelURL( maBaseURI, rBookmarkURL ) );
+ if ( !aRelUrl.isEmpty() )
+ sBookmarkURL = aRelUrl;
+ }
+ maHyperlink.emplace_back( sBookmarkURL, nType );
+
+ mpExEmbed->WriteUInt16( 0xf )
+ .WriteUInt16( EPP_ExHyperlink )
+ .WriteUInt32( 0 );
+ sal_uInt32 nHyperSize, nHyperStart = mpExEmbed->Tell();
+ mpExEmbed->WriteUInt16( 0 )
+ .WriteUInt16( EPP_ExHyperlinkAtom )
+ .WriteUInt32( 4 )
+ .WriteUInt32( nHyperId );
+
+ PPTWriter::WriteCString( *mpExEmbed, rStringVer0 );
+ PPTWriter::WriteCString( *mpExEmbed, rStringVer1, 1 );
+ PPTWriter::WriteCString( *mpExEmbed, rStringVer2, 2 );
+ PPTWriter::WriteCString( *mpExEmbed, rStringVer3, 3 );
+
+ nHyperSize = mpExEmbed->Tell() - nHyperStart;
+ mpExEmbed->SeekRel( - ( static_cast<sal_Int32>(nHyperSize) + 4 ) );
+ mpExEmbed->WriteUInt32( nHyperSize );
+ mpExEmbed->SeekRel( nHyperSize );
+ return nHyperId;
+}
+
+bool PPTWriter::ImplCloseDocument()
+{
+ sal_uInt32 nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_Document );
+ if ( nOfs )
+ {
+ mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_CurrentPos, mpStrm->Tell() );
+ mpStrm->Seek( nOfs );
+
+ // creating the TxMasterStyleAtom
+ SvMemoryStream aTxMasterStyleAtomStrm( 0x200, 0x200 );
+ {
+ EscherExAtom aTxMasterStyleAtom( aTxMasterStyleAtomStrm, EPP_TxMasterStyleAtom, EPP_TEXTTYPE_Other );
+ aTxMasterStyleAtomStrm.WriteUInt16( 5 ); // paragraph count
+ sal_uInt16 nLev;
+ for ( nLev = 0; nLev < 5; nLev++ )
+ {
+ mpStyleSheet->mpParaSheet[ EPP_TEXTTYPE_Other ]->Write( aTxMasterStyleAtomStrm, nLev, false, mXPagePropSet );
+ mpStyleSheet->mpCharSheet[ EPP_TEXTTYPE_Other ]->Write( aTxMasterStyleAtomStrm, nLev, false, mXPagePropSet );
+ }
+ }
+
+ sal_uInt32 nExEmbedSize = mpExEmbed->TellEnd();
+
+ // nEnvironment : whole size of the environment container
+ sal_uInt32 nEnvironment = maFontCollection.GetCount() * 76 // 68 bytes per Fontenityatom and 8 Bytes per header
+ + 8 // 1 FontCollection container
+ + 20 // SrKinsoku container
+ + 18 // 1 TxSiStyleAtom
+ + aTxMasterStyleAtomStrm.Tell() // 1 TxMasterStyleAtom;
+ + PPTExStyleSheet::SizeOfTxCFStyleAtom();
+
+ sal_uInt32 nBytesToInsert = nEnvironment + 8;
+
+ if ( nExEmbedSize )
+ nBytesToInsert += nExEmbedSize + 8 + 12;
+
+ nBytesToInsert += maSoundCollection.GetSize();
+ nBytesToInsert += mpPptEscherEx->DrawingGroupContainerSize();
+ nBytesToInsert += ImplMasterSlideListContainer(nullptr);
+ nBytesToInsert += ImplDocumentListContainer(nullptr);
+
+ // insert nBytes into stream and adjust depending container
+ mpPptEscherEx->InsertAtCurrentPos( nBytesToInsert );
+
+ // CREATE HYPERLINK CONTAINER
+ if ( nExEmbedSize )
+ {
+ mpStrm->WriteUInt16( 0xf )
+ .WriteUInt16( EPP_ExObjList )
+ .WriteUInt32( nExEmbedSize + 12 )
+ .WriteUInt16( 0 )
+ .WriteUInt16( EPP_ExObjListAtom )
+ .WriteUInt32( 4 )
+ .WriteUInt32( mnExEmbed );
+ mpPptEscherEx->InsertPersistOffset( EPP_Persist_ExObj, mpStrm->Tell() );
+ mpStrm->WriteBytes(mpExEmbed->GetData(), nExEmbedSize);
+ }
+
+ // CREATE ENVIRONMENT
+ mpStrm->WriteUInt16( 0xf ).WriteUInt16( EPP_Environment ).WriteUInt32( nEnvironment );
+
+ // Open Container ( EPP_SrKinsoku )
+ mpStrm->WriteUInt16( 0x2f ).WriteUInt16( EPP_SrKinsoku ).WriteUInt32( 12 );
+ mpPptEscherEx->AddAtom( 4, EPP_SrKinsokuAtom, 0, 3 );
+ mpStrm->WriteInt32( 0 ); // SrKinsoku Level 0
+
+ // Open Container ( EPP_FontCollection )
+ mpStrm->WriteUInt16( 0xf ).WriteUInt16( EPP_FontCollection ).WriteUInt32( maFontCollection.GetCount() * 76 );
+
+ for ( sal_uInt32 i = 0; i < maFontCollection.GetCount(); i++ )
+ {
+ mpPptEscherEx->AddAtom( 68, EPP_FontEnityAtom, 0, i );
+ const FontCollectionEntry* pDesc = maFontCollection.GetById( i );
+ sal_Int32 nFontLen = pDesc->Name.getLength();
+ if ( nFontLen > 31 )
+ nFontLen = 31;
+ for ( sal_Int32 n = 0; n < 32; n++ )
+ {
+ sal_Unicode nUniCode = 0;
+ if ( n < nFontLen )
+ nUniCode = pDesc->Name[n];
+ mpStrm->WriteUInt16( nUniCode );
+ }
+ sal_uInt8 lfCharSet = ANSI_CHARSET;
+ sal_uInt8 const lfClipPrecision = 0;
+ sal_uInt8 const lfQuality = 6;
+ sal_uInt8 lfPitchAndFamily = 0;
+
+ if ( pDesc->CharSet == RTL_TEXTENCODING_SYMBOL )
+ lfCharSet = SYMBOL_CHARSET;
+
+ switch( pDesc->Family )
+ {
+ case css::awt::FontFamily::ROMAN :
+ lfPitchAndFamily |= FF_ROMAN;
+ break;
+
+ case css::awt::FontFamily::SWISS :
+ lfPitchAndFamily |= FF_SWISS;
+ break;
+
+ case css::awt::FontFamily::MODERN :
+ lfPitchAndFamily |= FF_MODERN;
+ break;
+
+ case css::awt::FontFamily::SCRIPT:
+ lfPitchAndFamily |= FF_SCRIPT;
+ break;
+
+ case css::awt::FontFamily::DECORATIVE:
+ lfPitchAndFamily |= FF_DECORATIVE;
+ break;
+
+ default:
+ lfPitchAndFamily |= FAMILY_DONTKNOW;
+ break;
+ }
+ switch( pDesc->Pitch )
+ {
+ case css::awt::FontPitch::FIXED:
+ lfPitchAndFamily |= FIXED_PITCH;
+ break;
+
+ default:
+ lfPitchAndFamily |= DEFAULT_PITCH;
+ break;
+ }
+ mpStrm->WriteUChar( lfCharSet )
+ .WriteUChar( lfClipPrecision )
+ .WriteUChar( lfQuality )
+ .WriteUChar( lfPitchAndFamily );
+ }
+ mpStyleSheet->WriteTxCFStyleAtom( *mpStrm ); // create style that is used for new standard objects
+ mpPptEscherEx->AddAtom( 10, EPP_TxSIStyleAtom );
+ mpStrm->WriteUInt32( 7 ) // ?
+ .WriteInt16( 2 ) // ?
+ .WriteUChar( 9 ) // ?
+ .WriteUChar( 8 ) // ?
+ .WriteInt16( 0 ); // ?
+
+ mpStrm->WriteBytes(aTxMasterStyleAtomStrm.GetData(), aTxMasterStyleAtomStrm.Tell());
+ maSoundCollection.Write( *mpStrm );
+ mpPptEscherEx->WriteDrawingGroupContainer( *mpStrm );
+ ImplMasterSlideListContainer( mpStrm.get() );
+ ImplDocumentListContainer( mpStrm.get() );
+
+ sal_uInt32 nOldPos = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_CurrentPos );
+ if ( nOldPos )
+ {
+ mpStrm->Seek( nOldPos );
+ return true;
+ }
+ }
+ return false;
+}
+
+bool PropValue::GetPropertyValue(
+ css::uno::Any& rAny,
+ const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
+ const OUString& rString,
+ bool bTestPropertyAvailability )
+{
+ bool bRetValue = true;
+ if ( bTestPropertyAvailability )
+ {
+ bRetValue = false;
+ try
+ {
+ css::uno::Reference< css::beans::XPropertySetInfo > aXPropSetInfo( rXPropSet->getPropertySetInfo() );
+ if ( aXPropSetInfo.is() )
+ bRetValue = aXPropSetInfo->hasPropertyByName( rString );
+ }
+ catch( css::uno::Exception& )
+ {
+ bRetValue = false;
+ }
+ }
+ if ( bRetValue )
+ {
+ try
+ {
+ rAny = rXPropSet->getPropertyValue( rString );
+ if ( !rAny.hasValue() )
+ bRetValue = false;
+ }
+ catch( css::uno::Exception& )
+ {
+ bRetValue = false;
+ }
+ }
+ return bRetValue;
+}
+
+css::beans::PropertyState PropValue::GetPropertyState(
+ const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
+ const OUString& rPropertyName )
+{
+ css::beans::PropertyState eRetValue = css::beans::PropertyState_AMBIGUOUS_VALUE;
+ try
+ {
+ css::uno::Reference< css::beans::XPropertyState > aXPropState( rXPropSet, css::uno::UNO_QUERY );
+ if ( aXPropState.is() )
+ eRetValue = aXPropState->getPropertyState( rPropertyName );
+ }
+ catch( css::uno::Exception& )
+ {
+
+ }
+ return eRetValue;
+}
+
+bool PropValue::ImplGetPropertyValue( const OUString& rString )
+{
+ return GetPropertyValue( mAny, mXPropSet, rString );
+}
+
+bool PropValue::ImplGetPropertyValue( const css::uno::Reference< css::beans::XPropertySet > & aXPropSet, const OUString& rString )
+{
+ return GetPropertyValue( mAny, aXPropSet, rString );
+}
+
+bool PropStateValue::ImplGetPropertyValue( const OUString& rString, bool bGetPropertyState )
+{
+ ePropState = css::beans::PropertyState_AMBIGUOUS_VALUE;
+ bool bRetValue = true;
+#ifdef UNX
+ css::uno::Reference< css::beans::XPropertySetInfo >
+ aXPropSetInfo( mXPropSet->getPropertySetInfo() );
+ if ( !aXPropSetInfo.is() )
+ return false;
+#endif
+ try
+ {
+ mAny = mXPropSet->getPropertyValue( rString );
+ if ( !mAny.hasValue() )
+ bRetValue = false;
+ else if ( bGetPropertyState )
+ ePropState = mXPropState->getPropertyState( rString );
+ else
+ ePropState = css::beans::PropertyState_DIRECT_VALUE;
+ }
+ catch( css::uno::Exception& )
+ {
+ bRetValue = false;
+ }
+ return bRetValue;
+}
+
+void PPTWriter::ImplWriteParagraphs( SvStream& rOut, TextObj& rTextObj )
+{
+ bool bFirstParagraph = true;
+ sal_uInt32 nCharCount;
+ sal_uInt32 nPropertyFlags = 0;
+ sal_Int16 nLineSpacing;
+ int nInstance = rTextObj.GetInstance();
+
+ for ( sal_uInt32 i = 0; i < rTextObj.ParagraphCount(); ++i, bFirstParagraph = false )
+ {
+ ParagraphObj* pPara = rTextObj.GetParagraph(i);
+ const PortionObj& rPortion = pPara->front();
+ nCharCount = pPara->CharacterCount();
+
+ if ( ( pPara->meTextAdjust == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_Adjust, pPara->mnTextAdjust ) ) )
+ nPropertyFlags |= 0x00000800;
+ nLineSpacing = pPara->mnLineSpacing;
+
+ const FontCollectionEntry* pDesc = maFontCollection.GetById( rPortion.mnFont );
+ sal_Int16 nNormalSpacing = 100;
+ if ( !mbFontIndependentLineSpacing && pDesc )
+ {
+ double fN = 100.0;
+ fN *= pDesc->Scaling;
+ nNormalSpacing = static_cast<sal_Int16>( fN + 0.5 );
+ }
+ if ( !mbFontIndependentLineSpacing && bFirstParagraph && ( nLineSpacing > nNormalSpacing ) ) // sj: i28747, no replacement for fixed linespacing
+ {
+ nLineSpacing = nNormalSpacing;
+ nPropertyFlags |= 0x00001000;
+ }
+ else
+ {
+ if ( nLineSpacing > 0 )
+ {
+ if ( !mbFontIndependentLineSpacing && pDesc )
+ nLineSpacing = static_cast<sal_Int16>( static_cast<double>(nLineSpacing) * pDesc->Scaling + 0.5 );
+ }
+ else
+ {
+ if ( !pPara->mbFixedLineSpacing && rPortion.mnCharHeight > static_cast<sal_uInt16>( static_cast<double>(-nLineSpacing) * 0.001 * 72.0 / 2.54 ) ) // 1/100mm to point
+ nLineSpacing = nNormalSpacing;
+ else
+ nLineSpacing = static_cast<sal_Int16>( convertMm100ToMasterUnit(nLineSpacing) );
+ }
+ if ( ( pPara->meLineSpacing == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_LineFeed, nLineSpacing ) ) )
+ nPropertyFlags |= 0x00001000;
+ }
+ if ( ( pPara->meLineSpacingTop == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_UpperDist, pPara->mnLineSpacingTop ) ) )
+ nPropertyFlags |= 0x00002000;
+ if ( ( pPara->meLineSpacingBottom == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_LowerDist, pPara->mnLineSpacingBottom ) ) )
+ nPropertyFlags |= 0x00004000;
+ if ( ( pPara->meForbiddenRules == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_UpperDist, pPara->mbForbiddenRules ? 1 : 0 ) ) )
+ nPropertyFlags |= 0x00020000;
+ if ( ( pPara->meParagraphPunctation == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_UpperDist, pPara->mbParagraphPunctation ? 1 : 0 ) ) )
+ nPropertyFlags |= 0x00080000;
+ if ( ( pPara->meBiDi == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_BiDi, pPara->mnBiDi ) ) )
+ nPropertyFlags |= 0x00200000;
+
+ sal_Int32 nBuRealSize = pPara->nBulletRealSize;
+ sal_Int16 nBulletFlags = pPara->nBulletFlags;
+
+ if ( pPara->bExtendedParameters )
+ nPropertyFlags |= pPara->nParaFlags;
+ else
+ {
+ nPropertyFlags |= 1; // turn off bullet explicit
+ nBulletFlags = 0;
+ }
+
+ // Write nTextOfs and nBullets
+ if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_TextOfs, pPara->nTextOfs ) )
+ nPropertyFlags |= 0x100;
+ if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_BulletOfs, pPara->nBulletOfs ))
+ nPropertyFlags |= 0x400;
+
+ FontCollectionEntry aFontDescEntry( pPara->aFontDesc.Name, pPara->aFontDesc.Family, pPara->aFontDesc.Pitch, pPara->aFontDesc.CharSet );
+ sal_uInt16 nFontId = static_cast<sal_uInt16>(maFontCollection.GetId( aFontDescEntry ));
+
+ rOut.WriteUInt32( nCharCount )
+ .WriteUInt16( pPara->nDepth ) // Level
+ .WriteUInt32( nPropertyFlags ); // Paragraph Attribute Set
+
+ if ( nPropertyFlags & 0xf )
+ rOut.WriteInt16( nBulletFlags );
+ if ( nPropertyFlags & 0x80 )
+ rOut.WriteUInt16( pPara->cBulletId );
+ if ( nPropertyFlags & 0x10 )
+ rOut.WriteUInt16( nFontId );
+ if ( nPropertyFlags & 0x40 )
+ rOut.WriteInt16( nBuRealSize );
+ if ( nPropertyFlags & 0x20 )
+ {
+ sal_uInt32 nBulletColor = pPara->nBulletColor;
+ if ( nBulletColor == sal_uInt32(COL_AUTO) )
+ {
+ bool bIsDark = false;
+ css::uno::Any aAny;
+ if ( PropValue::GetPropertyValue( aAny, mXPagePropSet, "IsBackgroundDark", true ) )
+ aAny >>= bIsDark;
+ nBulletColor = bIsDark ? 0xffffff : 0x000000;
+ }
+ nBulletColor &= 0xffffff;
+ nBulletColor |= 0xfe000000;
+ rOut.WriteUInt32( nBulletColor );
+ }
+ if ( nPropertyFlags & 0x00000800 )
+ rOut.WriteUInt16( pPara->mnTextAdjust );
+ if ( nPropertyFlags & 0x00001000 )
+ rOut.WriteUInt16( nLineSpacing );
+ if ( nPropertyFlags & 0x00002000 )
+ rOut.WriteUInt16( pPara->mnLineSpacingTop );
+ if ( nPropertyFlags & 0x00004000 )
+ rOut.WriteUInt16( pPara->mnLineSpacingBottom );
+ if ( nPropertyFlags & 0x100 )
+ rOut.WriteUInt16( pPara->nTextOfs );
+ if ( nPropertyFlags & 0x400 )
+ rOut.WriteUInt16( pPara->nBulletOfs );
+ if ( nPropertyFlags & 0x000e0000 )
+ {
+ sal_uInt16 nAsianSettings = 0;
+ if ( pPara->mbForbiddenRules )
+ nAsianSettings |= 1;
+ if ( pPara->mbParagraphPunctation )
+ nAsianSettings |= 4;
+ rOut.WriteUInt16( nAsianSettings );
+ }
+ if ( nPropertyFlags & 0x200000 )
+ rOut.WriteUInt16( pPara->mnBiDi );
+ }
+}
+
+void PPTWriter::ImplWritePortions( SvStream& rOut, TextObj& rTextObj )
+{
+ sal_uInt32 nPropertyFlags;
+ int nInstance = rTextObj.GetInstance();
+
+ for ( sal_uInt32 i = 0; i < rTextObj.ParagraphCount(); ++i )
+ {
+ ParagraphObj* pPara = rTextObj.GetParagraph(i);
+ for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = pPara->begin(); it != pPara->end(); ++it )
+ {
+ const PortionObj& rPortion = **it;
+ nPropertyFlags = 0;
+ sal_uInt32 nCharAttr = rPortion.mnCharAttr;
+ sal_uInt32 nCharColor = rPortion.mnCharColor;
+
+ if ( nCharColor == sal_uInt32(COL_AUTO) ) // nCharColor depends to the background color
+ {
+ bool bIsDark = false;
+ css::uno::Any aAny;
+ if ( PropValue::GetPropertyValue( aAny, mXPagePropSet, "IsBackgroundDark", true ) )
+ aAny >>= bIsDark;
+ nCharColor = bIsDark ? 0xffffff : 0x000000;
+ }
+
+ nCharColor &= 0xffffff;
+
+ /* the portion is using the embossed or engraved attribute, which we want to map to the relief feature of PPT.
+ Because the relief feature of PPT is dependent to the background color, such a mapping can not always be used. */
+ if ( nCharAttr & 0x200 )
+ {
+ sal_uInt32 nBackgroundColor = 0xffffff;
+
+ if ( !nCharColor ) // special treatment for
+ nCharColor = 0xffffff; // black fontcolor
+
+ css::uno::Any aAny;
+ css::drawing::FillStyle aFS( css::drawing::FillStyle_NONE );
+ if ( PropValue::GetPropertyValue( aAny, mXPropSet, "FillStyle" ) )
+ aAny >>= aFS;
+ switch( aFS )
+ {
+ case css::drawing::FillStyle_GRADIENT :
+ {
+ ::tools::Rectangle aRect( Point(), Size( 28000, 21000 ) );
+ EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect );
+ aPropOpt.CreateGradientProperties( mXPropSet );
+ aPropOpt.GetOpt( ESCHER_Prop_fillColor, nBackgroundColor );
+ }
+ break;
+ case css::drawing::FillStyle_SOLID :
+ {
+ if ( PropValue::GetPropertyValue( aAny, mXPropSet, "FillColor" ) )
+ nBackgroundColor = EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(aAny) );
+ }
+ break;
+ case css::drawing::FillStyle_NONE :
+ {
+ css::uno::Any aBackAny;
+ css::drawing::FillStyle aBackFS( css::drawing::FillStyle_NONE );
+ if ( PropValue::GetPropertyValue( aBackAny, mXBackgroundPropSet, "FillStyle" ) )
+ aBackAny >>= aBackFS;
+ switch( aBackFS )
+ {
+ case css::drawing::FillStyle_GRADIENT :
+ {
+ ::tools::Rectangle aRect( Point(), Size( 28000, 21000 ) );
+ EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect );
+ aPropOpt.CreateGradientProperties( mXBackgroundPropSet );
+ aPropOpt.GetOpt( ESCHER_Prop_fillColor, nBackgroundColor );
+ }
+ break;
+ case css::drawing::FillStyle_SOLID :
+ {
+ if ( PropValue::GetPropertyValue( aAny, mXBackgroundPropSet, "FillColor" ) )
+ nBackgroundColor = EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(aAny) );
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ sal_Int32 nB = nBackgroundColor & 0xff;
+ nB += static_cast<sal_uInt8>( nBackgroundColor >> 8 );
+ nB += static_cast<sal_uInt8>( nBackgroundColor >> 16 );
+ // if the background color is nearly black, relief can't been used, because the text would not be visible
+ if ( nB < 0x60 || ( nBackgroundColor != nCharColor ) )
+ {
+ nCharAttr &=~ 0x200;
+
+ // now check if the text is part of a group, and if the previous object has the same color than the fontcolor
+ // ( and if fillcolor is not available the background color ), it is sometimes
+ // not possible to export the 'embossed' flag
+ if ( ( GetCurrentGroupLevel() > 0 ) && ( GetCurrentGroupIndex() >= 1 ) )
+ {
+ css::uno::Reference< css::drawing::XShape > aGroupedShape( GetCurrentGroupAccess()->getByIndex( GetCurrentGroupIndex() - 1 ), uno::UNO_QUERY );
+ if( aGroupedShape.is() )
+ {
+ css::uno::Reference< css::beans::XPropertySet > aPropSetOfNextShape
+ ( aGroupedShape, css::uno::UNO_QUERY );
+ if ( aPropSetOfNextShape.is() )
+ {
+ if ( PropValue::GetPropertyValue( aAny, aPropSetOfNextShape,
+ "FillColor", true ) )
+ {
+ if ( nCharColor == EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(aAny) ) )
+ {
+ nCharAttr |= 0x200;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ nCharColor |= 0xfe000000;
+ if ( nInstance == 4 ) // special handling for normal textobjects:
+ nPropertyFlags |= nCharAttr & 0x217; // not all attributes are inherited
+ else
+ {
+ if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Bold, nCharAttr ) )
+ nPropertyFlags |= 1;
+ if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Italic, nCharAttr ) )
+ nPropertyFlags |= 2;
+ if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Underline, nCharAttr ) )
+ nPropertyFlags |= 4;
+ if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Shadow, nCharAttr ) )
+ nPropertyFlags |= 0x10;
+ if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Embossed, nCharAttr ) )
+ nPropertyFlags |= 512;
+ }
+ if ( rTextObj.HasExtendedBullets() )
+ {
+ nPropertyFlags |= ( i & 0x3f ) << 10 ;
+ nCharAttr |= ( i & 0x3f ) << 10;
+ }
+ if ( ( rPortion.meFontName == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Font, rPortion.mnFont ) ) )
+ nPropertyFlags |= 0x00010000;
+ if ( ( rPortion.meAsianOrComplexFont == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_AsianOrComplexFont, rPortion.mnAsianOrComplexFont ) ) )
+ nPropertyFlags |= 0x00200000;
+ if ( ( rPortion.meCharHeight == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_FontHeight, rPortion.mnCharHeight ) ) )
+ nPropertyFlags |= 0x00020000;
+ if ( ( rPortion.meCharColor == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_FontColor, nCharColor & 0xffffff ) ) )
+ nPropertyFlags |= 0x00040000;
+ if ( ( rPortion.meCharEscapement == css::beans::PropertyState_DIRECT_VALUE ) ||
+ ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Escapement, rPortion.mnCharEscapement ) ) )
+ nPropertyFlags |= 0x00080000;
+
+ sal_uInt32 nCharCount = rPortion.Count();
+
+ rOut.WriteUInt32( nCharCount )
+ .WriteUInt32( nPropertyFlags ); //PropertyFlags
+
+ if ( nPropertyFlags & 0xffff )
+ rOut.WriteUInt16( nCharAttr );
+ if ( nPropertyFlags & 0x00010000 )
+ rOut.WriteUInt16( rPortion.mnFont );
+ if ( nPropertyFlags & 0x00200000 )
+ rOut.WriteUInt16( rPortion.mnAsianOrComplexFont );
+ if ( nPropertyFlags & 0x00020000 )
+ rOut.WriteUInt16( rPortion.mnCharHeight );
+ if ( nPropertyFlags & 0x00040000 )
+ rOut.WriteUInt32( nCharColor );
+ if ( nPropertyFlags & 0x00080000 )
+ rOut.WriteInt16( rPortion.mnCharEscapement );
+ }
+ }
+}
+
+/**
+ * Loads and converts text from shape, value is stored in mnTextSize.
+ */
+bool PPTWriter::ImplGetText()
+{
+ mnTextSize = 0;
+ mbFontIndependentLineSpacing = false;
+ mXText.set( mXShape, css::uno::UNO_QUERY );
+
+ if ( mXText.is() )
+ {
+ mnTextSize = mXText->getString().getLength();
+ css::uno::Any aAny;
+ if ( GetPropertyValue( aAny, mXPropSet, "FontIndependentLineSpacing", true ) )
+ aAny >>= mbFontIndependentLineSpacing;
+ }
+ return ( mnTextSize != 0 );
+}
+
+void PPTWriter::ImplFlipBoundingBox( EscherPropertyContainer& rPropOpt )
+{
+ if ( mnAngle < 0 )
+ mnAngle = ( 36000 + mnAngle ) % 36000;
+ else
+ mnAngle = ( 36000 - ( mnAngle % 36000 ) );
+
+ double fCos = cos( basegfx::deg2rad<100>(mnAngle) );
+ double fSin = sin( basegfx::deg2rad<100>(mnAngle) );
+
+ double fWidthHalf = maRect.GetWidth() / 2.0;
+ double fHeightHalf = maRect.GetHeight() / 2.0;
+
+ double fXDiff = fCos * fWidthHalf + fSin * (-fHeightHalf);
+ double fYDiff = - ( fSin * fWidthHalf - fCos * ( -fHeightHalf ) );
+
+ maRect.Move( static_cast<sal_Int32>( -( fWidthHalf - fXDiff ) ), static_cast<sal_Int32>( - ( fHeightHalf + fYDiff ) ) );
+ mnAngle *= 655;
+ mnAngle += 0x8000;
+ mnAngle &=~0xffff; // round nAngle to full grads
+ rPropOpt.AddOpt( ESCHER_Prop_Rotation, mnAngle );
+
+ if ( ( mnAngle >= ( 45 << 16 ) && mnAngle < ( 135 << 16 ) ) ||
+ ( mnAngle >= ( 225 << 16 ) && mnAngle < ( 315 << 16 ) ) )
+ {
+ // Maddeningly, in those two areas of PPT is the BoundingBox already
+ // vertical. Therefore, we need to put down it BEFORE THE ROTATION.
+ css::awt::Point aTopLeft( static_cast<sal_Int32>( maRect.Left() + fWidthHalf - fHeightHalf ), static_cast<sal_Int32>( maRect.Top() + fHeightHalf - fWidthHalf ) );
+ const tools::Long nRotatedWidth(maRect.GetHeight());
+ const tools::Long nRotatedHeight(maRect.GetWidth());
+ const Size aNewSize(nRotatedWidth, nRotatedHeight);
+ maRect = ::tools::Rectangle( Point( aTopLeft.X, aTopLeft.Y ), aNewSize );
+ }
+}
+
+void PPTWriter::ImplAdjustFirstLineLineSpacing( TextObj& rTextObj, EscherPropertyContainer& rPropOpt )
+{
+ if ( mbFontIndependentLineSpacing )
+ return;
+
+ if ( !rTextObj.ParagraphCount() )
+ return;
+
+ ParagraphObj* pPara = rTextObj.GetParagraph(0);
+ if ( pPara->empty() )
+ return;
+
+ const PortionObj& rPortion = pPara->front();
+ sal_Int16 nLineSpacing = pPara->mnLineSpacing;
+ const FontCollectionEntry* pDesc = maFontCollection.GetById( rPortion.mnFont );
+ if ( pDesc )
+ nLineSpacing = static_cast<sal_Int16>( static_cast<double>(nLineSpacing) * pDesc->Scaling + 0.5 );
+
+ if ( ( nLineSpacing > 0 ) && ( nLineSpacing < 100 ) )
+ {
+ double fCharHeight = convertPointToMm100<double>(rPortion.mnCharHeight);
+ fCharHeight *= 100 - nLineSpacing;
+ fCharHeight /= 100;
+
+ sal_uInt32 nUpperDistance = 0;
+ rPropOpt.GetOpt( ESCHER_Prop_dyTextTop, nUpperDistance );
+ nUpperDistance += static_cast< sal_uInt32 >( fCharHeight * 360.0 );
+ rPropOpt.AddOpt( ESCHER_Prop_dyTextTop, nUpperDistance );
+ }
+}
+
+void PPTWriter::ImplWriteTextStyleAtom( SvStream& rOut, int nTextInstance, sal_uInt32 nAtomInstance,
+ TextRuleEntry* pTextRule, SvStream& rExtBuStr, EscherPropertyContainer* pPropOpt )
+{
+ PPTExParaSheet& rParaSheet = mpStyleSheet->GetParaSheet( nTextInstance );
+
+ rOut.WriteUInt32( ( EPP_TextHeaderAtom << 16 ) | ( nAtomInstance << 4 ) ).WriteUInt32( 4 )
+ .WriteInt32( nTextInstance );
+
+ if ( mbEmptyPresObj )
+ mnTextSize = 0;
+ if ( mbEmptyPresObj )
+ return;
+
+ ParagraphObj* pPara;
+ TextObjBinary aTextObj( mXText, nTextInstance, maFontCollection, static_cast<PPTExBulletProvider&>(*this) );
+
+ // leaving out EPP_TextCharsAtom w/o text - still write out
+ // attribute info though
+ if ( mnTextSize )
+ aTextObj.Write( &rOut );
+
+ if ( pPropOpt && mType != "drawing.Table" )
+ ImplAdjustFirstLineLineSpacing( aTextObj, *pPropOpt );
+
+ sal_uInt32 nSize, nPos = rOut.Tell();
+
+ rOut.WriteUInt32( EPP_StyleTextPropAtom << 16 ).WriteUInt32( 0 );
+ ImplWriteParagraphs( rOut, aTextObj );
+ ImplWritePortions( rOut, aTextObj );
+ nSize = rOut.Tell() - nPos;
+ rOut.SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
+ rOut.WriteUInt32( nSize - 8 );
+ rOut.SeekRel( nSize - 8 );
+
+ for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount(); ++i )
+ {
+ pPara = aTextObj.GetParagraph(i);
+ for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = pPara->begin(); it != pPara->end(); ++it )
+ {
+ const PortionObj& rPortion = **it;
+ if ( rPortion.mpFieldEntry )
+ {
+ const FieldEntry* pFieldEntry = rPortion.mpFieldEntry.get();
+
+ switch ( pFieldEntry->nFieldType >> 28 )
+ {
+ case 1 :
+ case 2 :
+ {
+ rOut.WriteUInt32( EPP_DateTimeMCAtom << 16 ).WriteUInt32( 8 )
+ .WriteUInt32( pFieldEntry->nFieldStartPos ) // TxtOffset to TxtField;
+ .WriteUChar( pFieldEntry->nFieldType & 0xff ) // Type
+ .WriteUChar( 0 ).WriteUInt16( 0 ); // PadBytes
+ }
+ break;
+ case 3 :
+ {
+ rOut.WriteUInt32( EPP_SlideNumberMCAtom << 16 ).WriteUInt32( 4 )
+ .WriteUInt32( pFieldEntry->nFieldStartPos );
+ }
+ break;
+ case 4 :
+ {
+ sal_uInt32 nPageIndex = 0;
+ OUString aPageUrl;
+ OUString aFile( pFieldEntry->aFieldUrl );
+ OUString aTarget( pFieldEntry->aFieldUrl );
+ INetURLObject aUrl( pFieldEntry->aFieldUrl );
+ if ( INetProtocol::File == aUrl.GetProtocol() )
+ aFile = aUrl.PathToFileName();
+ else if ( INetProtocol::Smb == aUrl.GetProtocol() )
+ {
+ // Convert smb notation to '\\' and skip the 'smb:' part
+ aFile = aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE).copy(4);
+ aFile = aFile.replaceAll( "/", "\\" );
+ aTarget = aFile;
+ }
+ else if ( pFieldEntry->aFieldUrl.startsWith("#") )
+ {
+ OUString aPage( INetURLObject::decode( pFieldEntry->aFieldUrl, INetURLObject::DecodeMechanism::WithCharset ) );
+ aPage = aPage.copy( 1 );
+
+ std::vector<OUString>::const_iterator pIter = std::find(
+ maSlideNameList.begin(),maSlideNameList.end(),aPage);
+
+ if ( pIter != maSlideNameList.end() )
+ {
+ nPageIndex = pIter - maSlideNameList.begin();
+ aPageUrl = OUString::number(256 + nPageIndex) +
+ "," +
+ OUString::number(nPageIndex + 1) +
+ ",Slide " +
+ OUString::number(nPageIndex + 1);
+ }
+ }
+ sal_uInt32 nHyperId(0);
+ if ( !aPageUrl.isEmpty() )
+ nHyperId = ImplInsertBookmarkURL( aPageUrl, 1 | ( nPageIndex << 8 ) | ( 1U << 31 ), pFieldEntry->aRepresentation, "", "", aPageUrl );
+ else
+ nHyperId = ImplInsertBookmarkURL( pFieldEntry->aFieldUrl, 2 | ( nHyperId << 8 ), aFile, aTarget, "", "" );
+
+ rOut.WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0xf ).WriteUInt32( 24 )
+ .WriteUInt32( EPP_InteractiveInfoAtom << 16 ).WriteUInt32( 16 )
+ .WriteUInt32( 0 ) // soundref
+ .WriteUInt32( nHyperId ) // hyperlink id
+ .WriteUChar( 4 ) // hyperlink action
+ .WriteUChar( 0 ) // ole verb
+ .WriteUChar( 0 ) // jump
+ .WriteUChar( 0 ) // flags
+ .WriteUChar( 8 ) // hyperlink type ?
+ .WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 )
+ .WriteUInt32( EPP_TxInteractiveInfoAtom << 16 ).WriteUInt32( 8 )
+ .WriteUInt32( pFieldEntry->nFieldStartPos )
+ .WriteUInt32( pFieldEntry->nFieldEndPos );
+ }
+ break;
+ case 5 :
+ {
+ rOut.WriteUInt32( EPP_GenericDateMCAtom << 16 ).WriteUInt32( 4 )
+ .WriteUInt32( pFieldEntry->nFieldStartPos );
+ }
+ break;
+ case 6 :
+ {
+ rOut.WriteUInt32( EPP_HeaderMCAtom << 16 ).WriteUInt32( 4 )
+ .WriteUInt32( pFieldEntry->nFieldStartPos );
+ }
+ break;
+ case 7 :
+ {
+ rOut.WriteUInt32( EPP_FooterMCAtom << 16 ).WriteUInt32( 4 )
+ .WriteUInt32( pFieldEntry->nFieldStartPos );
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ aTextObj.WriteTextSpecInfo( &rOut );
+
+ // write Star Office Default TabSizes (if necessary)
+ if ( aTextObj.ParagraphCount() )
+ {
+ pPara = aTextObj.GetParagraph(0);
+ sal_uInt32 nParaFlags = 0x1f;
+ sal_Int16 nMask, nNumberingRule[ 10 ];
+ const sal_uInt32 nTabs = pPara->maTabStop.getLength();
+ const auto& rTabStops = pPara->maTabStop;
+
+ for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount(); ++i )
+ {
+ pPara = aTextObj.GetParagraph(i);
+ if ( pPara->bExtendedParameters )
+ {
+ nMask = 1 << pPara->nDepth;
+ if ( nParaFlags & nMask )
+ {
+ nParaFlags &=~ nMask;
+ if ( ( rParaSheet.maParaLevel[ pPara->nDepth ].mnTextOfs != pPara->nTextOfs ) ||
+ ( rParaSheet.maParaLevel[ pPara->nDepth ].mnBulletOfs != pPara->nBulletOfs ) )
+ {
+ nParaFlags |= nMask << 16;
+ nNumberingRule[ pPara->nDepth << 1 ] = pPara->nTextOfs;
+ nNumberingRule[ ( pPara->nDepth << 1 ) + 1 ] = static_cast<sal_Int16>(pPara->nBulletOfs);
+ }
+ }
+ }
+ }
+ nParaFlags >>= 16;
+
+ sal_Int32 nDefaultTabSizeSrc = 2011; // I've no idea where this number came from, honestly
+ const uno::Reference< beans::XPropertySet > xPropSet( mXModel, uno::UNO_QUERY );
+ if ( xPropSet.is() )
+ {
+ if(ImplGetPropertyValue( xPropSet, "TabStop" ))
+ {
+ sal_Int32 nTabStop( 0 );
+ if ( mAny >>= nTabStop )
+ nDefaultTabSizeSrc = nTabStop;
+ }
+ }
+ const sal_uInt32 nDefaultTabSize = MapSize( awt::Size( nDefaultTabSizeSrc, 1 ) ).Width;
+ sal_uInt32 nDefaultTabs = std::abs( maRect.GetWidth() ) / nDefaultTabSize;
+ if ( nTabs )
+ nDefaultTabs -= static_cast<sal_Int32>( convertMm100ToMasterUnit(rTabStops[ nTabs - 1 ].Position) / nDefaultTabSize );
+ if ( static_cast<sal_Int32>(nDefaultTabs) < 0 )
+ nDefaultTabs = 0;
+
+ sal_uInt32 nTabCount = nTabs + nDefaultTabs;
+ sal_uInt32 i, nTextRulerAtomFlags = 0;
+
+ if ( nTabCount )
+ nTextRulerAtomFlags |= 4;
+ if ( nParaFlags )
+ nTextRulerAtomFlags |= ( ( nParaFlags << 3 ) | ( nParaFlags << 8 ) );
+
+ if ( nTextRulerAtomFlags )
+ {
+ SvStream* pRuleOut = &rOut;
+ if ( pTextRule )
+ {
+ pTextRule->pOut.reset( new SvMemoryStream( 0x100, 0x100 ) );
+ pRuleOut = pTextRule->pOut.get();
+ }
+
+ sal_uInt32 nRulePos = pRuleOut->Tell();
+ pRuleOut->WriteUInt32( EPP_TextRulerAtom << 16 ).WriteUInt32( 0 );
+ pRuleOut->WriteUInt32( nTextRulerAtomFlags );
+ if ( nTextRulerAtomFlags & 4 )
+ {
+ pRuleOut->WriteUInt16( nTabCount );
+ for ( const css::style::TabStop& rTabStop : rTabStops )
+ {
+ sal_uInt16 nPosition = static_cast<sal_uInt16>( convertMm100ToMasterUnit(rTabStop.Position) );
+ sal_uInt16 nType;
+ switch ( rTabStop.Alignment )
+ {
+ case css::style::TabAlign_DECIMAL : nType = 3; break;
+ case css::style::TabAlign_RIGHT : nType = 2; break;
+ case css::style::TabAlign_CENTER : nType = 1; break;
+
+ case css::style::TabAlign_LEFT :
+ default: nType = 0;
+ }
+ pRuleOut->WriteUInt16( nPosition )
+ .WriteUInt16( nType );
+ }
+
+ sal_uInt32 nWidth = 1;
+ if ( nTabs )
+ nWidth += static_cast<sal_Int32>( convertMm100ToMasterUnit(rTabStops[ nTabs - 1 ].Position) / nDefaultTabSize );
+ nWidth *= nDefaultTabSize;
+ for ( i = 0; i < nDefaultTabs; i++, nWidth += nDefaultTabSize )
+ pRuleOut->WriteUInt32( nWidth );
+ }
+ for ( i = 0; i < 5; i++ )
+ {
+ if ( nTextRulerAtomFlags & ( 8 << i ) )
+ pRuleOut->WriteInt16( nNumberingRule[ i << 1 ] );
+ if ( nTextRulerAtomFlags & ( 256 << i ) )
+ pRuleOut->WriteInt16( nNumberingRule[ ( i << 1 ) + 1 ] );
+ }
+ sal_uInt32 nBufSize = pRuleOut->Tell() - nRulePos;
+ pRuleOut->SeekRel( - ( static_cast<sal_Int32>(nBufSize) - 4 ) );
+ pRuleOut->WriteUInt32( nBufSize - 8 );
+ pRuleOut->SeekRel( nBufSize - 8 );
+ }
+ }
+ if ( !aTextObj.HasExtendedBullets() )
+ return;
+
+ if ( !aTextObj.ParagraphCount() )
+ return;
+
+ sal_uInt32 nNumberingType = 0, nPos2 = rExtBuStr.Tell();
+
+ rExtBuStr.WriteUInt32( EPP_PST_ExtendedParagraphAtom << 16 ).WriteUInt32( 0 );
+
+ for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount(); ++i )
+ {
+ ParagraphObj* pBulletPara = aTextObj.GetParagraph(i);
+ sal_uInt32 nBulletFlags = 0;
+ sal_uInt16 nBulletId = pBulletPara->nBulletId;
+
+ if ( pBulletPara->bExtendedBulletsUsed )
+ {
+ nBulletFlags = 0x800000;
+ if ( pBulletPara->nNumberingType != SVX_NUM_BITMAP )
+ nBulletFlags = 0x3000000;
+ }
+ rExtBuStr.WriteUInt32( nBulletFlags );
+
+ if ( nBulletFlags & 0x800000 )
+ rExtBuStr.WriteUInt16( nBulletId );
+ if ( nBulletFlags & 0x1000000 )
+ {
+ switch( pBulletPara->nNumberingType )
+ {
+ case SVX_NUM_NUMBER_NONE :
+ case SVX_NUM_CHAR_SPECIAL :
+ nNumberingType = 0;
+ break;
+ case SVX_NUM_CHARS_UPPER_LETTER :
+ case SVX_NUM_CHARS_UPPER_LETTER_N :
+ case SVX_NUM_CHARS_LOWER_LETTER :
+ case SVX_NUM_CHARS_LOWER_LETTER_N :
+ case SVX_NUM_ROMAN_UPPER :
+ case SVX_NUM_ROMAN_LOWER :
+ case SVX_NUM_ARABIC :
+ case SVX_NUM_NUMBER_UPPER_ZH:
+ case SVX_NUM_CIRCLE_NUMBER:
+ case SVX_NUM_NUMBER_UPPER_ZH_TW:
+ case SVX_NUM_NUMBER_LOWER_ZH:
+ case SVX_NUM_FULL_WIDTH_ARABIC:
+ nNumberingType = pBulletPara->nMappedNumType;
+ break;
+
+ case SVX_NUM_BITMAP :
+ nNumberingType = 0;
+ break;
+ default: break;
+ }
+ rExtBuStr.WriteUInt32( nNumberingType );
+ }
+ if ( nBulletFlags & 0x2000000 )
+ rExtBuStr.WriteUInt16( pBulletPara->nStartWith );
+ rExtBuStr.WriteUInt32( 0 ).WriteUInt32( 0 );
+ }
+ sal_uInt32 nBulletSize = ( rExtBuStr.Tell() - nPos2 ) - 8;
+ rExtBuStr.SeekRel( - ( static_cast<sal_Int32>(nBulletSize) + 4 ) );
+ rExtBuStr.WriteUInt32( nBulletSize );
+ rExtBuStr.SeekRel( nBulletSize );
+}
+
+void PPTWriter::ImplWriteClickAction( SvStream& rSt, css::presentation::ClickAction eCa, bool bMediaClickAction )
+{
+ sal_uInt32 nSoundRef = 0; // a reference to a sound in the sound collection, or NULL.
+ sal_uInt32 nHyperLinkID = 0;// a persistent unique identifier to an external hyperlink object (only valid when action == HyperlinkAction).
+ sal_uInt8 nAction = 0; // Action See Action Table
+ sal_uInt8 const nOleVerb = 0; // OleVerb Only valid when action == OLEAction. OLE verb to use, 0 = first verb, 1 = second verb, etc.
+ sal_uInt8 nJump = 0; // Jump See Jump Table
+ sal_uInt8 const nFlags = 0; // Bit 1: Animated. If 1, then button is animated
+ // Bit 2: Stop sound. If 1, then stop current sound when button is pressed.
+ // Bit 3: CustomShowReturn. If 1, and this is a jump to custom show, then return to this slide after custom show.
+ sal_uInt8 nHyperLinkType = 0;// HyperlinkType a value from the LinkTo enum, such as LT_URL (only valid when action == HyperlinkAction).
+
+ OUString aFile;
+
+ /*
+ Action Table: Action Value
+ NoAction 0
+ MacroAction 1
+ RunProgramAction 2
+ JumpAction 3
+ HyperlinkAction 4
+ OLEAction 5
+ MediaAction 6
+ CustomShowAction 7
+
+ Jump Table: Jump Value
+ NoJump 0
+ NextSlide, 1
+ PreviousSlide, 2
+ FirstSlide, 3
+ LastSlide, 4
+ LastSlideViewed 5
+ EndShow 6
+ */
+
+ if ( bMediaClickAction )
+ nAction = 6;
+ else switch( eCa )
+ {
+ case css::presentation::ClickAction_STOPPRESENTATION :
+ nJump += 2;
+ [[fallthrough]];
+ case css::presentation::ClickAction_LASTPAGE :
+ nJump++;
+ [[fallthrough]];
+ case css::presentation::ClickAction_FIRSTPAGE :
+ nJump++;
+ [[fallthrough]];
+ case css::presentation::ClickAction_PREVPAGE :
+ nJump++;
+ [[fallthrough]];
+ case css::presentation::ClickAction_NEXTPAGE :
+ {
+ nJump++;
+ nAction = 3;
+ }
+ break;
+ case css::presentation::ClickAction_SOUND :
+ {
+ if ( ImplGetPropertyValue( "Bookmark" ) )
+ nSoundRef = maSoundCollection.GetId( *o3tl::doAccess<OUString>(mAny) );
+ }
+ break;
+ case css::presentation::ClickAction_PROGRAM :
+ {
+ if ( ImplGetPropertyValue( "Bookmark" ) )
+ {
+ INetURLObject aUrl( *o3tl::doAccess<OUString>(mAny) );
+ if ( INetProtocol::File == aUrl.GetProtocol() )
+ {
+ aFile = aUrl.PathToFileName();
+ nAction = 2;
+ }
+ }
+ }
+ break;
+
+ case css::presentation::ClickAction_BOOKMARK :
+ {
+ if ( ImplGetPropertyValue( "Bookmark" ) )
+ {
+ OUString aBookmark( *o3tl::doAccess<OUString>(mAny) );
+ sal_uInt32 nIndex = 0;
+ for ( const auto& rSlideName : maSlideNameList )
+ {
+ if ( rSlideName == aBookmark )
+ {
+ // Bookmark is a link to a document page
+ nAction = 4;
+ nHyperLinkType = 7;
+
+ OUString aHyperString = OUString::number(256 + nIndex) +
+ "," +
+ OUString::number(nIndex + 1) +
+ ",Slide " +
+ OUString::number(nIndex + 1);
+ nHyperLinkID = ImplInsertBookmarkURL( aHyperString, 1 | ( nIndex << 8 ) | ( 1U << 31 ), aBookmark, "", "", aHyperString );
+ }
+ nIndex++;
+ }
+ }
+ }
+ break;
+
+ case css::presentation::ClickAction_DOCUMENT :
+ {
+ if ( ImplGetPropertyValue( "Bookmark" ) )
+ {
+ OUString aBookmark( *o3tl::doAccess<OUString>(mAny) );
+ if ( !aBookmark.isEmpty() )
+ {
+ nAction = 4;
+ nHyperLinkType = 8;
+
+ OUString aBookmarkFile( aBookmark );
+ INetURLObject aUrl( aBookmark );
+ if ( INetProtocol::File == aUrl.GetProtocol() )
+ aBookmarkFile = aUrl.PathToFileName();
+ nHyperLinkID = ImplInsertBookmarkURL( aBookmark, sal_uInt32(2 | ( 1U << 31 )), aBookmarkFile, aBookmark, "", "" );
+ }
+ }
+ }
+ break;
+
+ case css::presentation::ClickAction_INVISIBLE :
+ case css::presentation::ClickAction_VERB :
+ case css::presentation::ClickAction_VANISH :
+ case css::presentation::ClickAction_MACRO :
+ default :
+ break;
+ }
+
+ sal_uInt32 nContainerSize = 24;
+ if ( nAction == 2 )
+ nContainerSize += ( aFile.getLength() * 2 ) + 8;
+ rSt.WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0xf ).WriteUInt32( nContainerSize )
+ .WriteUInt32( EPP_InteractiveInfoAtom << 16 ).WriteUInt32( 16 )
+ .WriteUInt32( nSoundRef )
+ .WriteUInt32( nHyperLinkID )
+ .WriteUChar( nAction )
+ .WriteUChar( nOleVerb )
+ .WriteUChar( nJump )
+ .WriteUChar( nFlags )
+ .WriteUInt32( nHyperLinkType );
+
+ if ( nAction == 2 ) // run program Action
+ {
+ sal_Int32 nLen = aFile.getLength();
+ rSt.WriteUInt32( ( EPP_CString << 16 ) | 0x20 ).WriteUInt32( nLen * 2 );
+ for ( sal_Int32 i = 0; i < nLen; i++ )
+ rSt.WriteUInt16( aFile[i] );
+ }
+
+ rSt.WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0x1f ).WriteUInt32( 24 ) // Mouse Over Action
+ .WriteUInt32( EPP_InteractiveInfo << 16 ).WriteUInt32( 16 );
+ for ( int i = 0; i < 4; i++, rSt.WriteUInt32( 0 ) ) ;
+}
+
+bool PPTWriter::ImplGetEffect( const css::uno::Reference< css::beans::XPropertySet > & rPropSet,
+ css::presentation::AnimationEffect& eEffect,
+ css::presentation::AnimationEffect& eTextEffect,
+ bool& bIsSound )
+{
+ css::uno::Any aAny;
+ if ( GetPropertyValue( aAny, rPropSet, "Effect" ) )
+ aAny >>= eEffect;
+ else
+ eEffect = css::presentation::AnimationEffect_NONE;
+
+ if ( GetPropertyValue( aAny, rPropSet, "TextEffect" ) )
+ aAny >>= eTextEffect;
+ else
+ eTextEffect = css::presentation::AnimationEffect_NONE;
+ if ( GetPropertyValue( aAny, rPropSet, "SoundOn" ) )
+ aAny >>= bIsSound;
+ else
+ bIsSound = false;
+
+ bool bHasEffect = ( ( eEffect != css::presentation::AnimationEffect_NONE )
+ || ( eTextEffect != css::presentation::AnimationEffect_NONE )
+ || bIsSound );
+ return bHasEffect;
+};
+
+bool PPTWriter::ImplCreatePresentationPlaceholder( const bool bMasterPage,
+ const sal_uInt32 nStyleInstance, const sal_uInt8 nPlaceHolderId )
+{
+ bool bRet = ImplGetText();
+ if ( bRet && bMasterPage )
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ sal_uInt32 nPresShapeID = mpPptEscherEx->GenerateShapeId();
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty, nPresShapeID );
+ EscherPropertyContainer aPropOpt;
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x50001 );
+ mnTxId += 0x60;
+ aPropOpt.AddOpt( ESCHER_Prop_lTxid, mnTxId );
+ aPropOpt.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110001 );
+ aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x8000001 );
+ aPropOpt.AddOpt( ESCHER_Prop_shadowColor, 0x8000002 );
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ sal_uInt32 nLineFlags = 0x90001;
+ if ( aPropOpt.GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ) )
+ nLineFlags |= 0x10001; // draw dashed line if no line
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
+
+ SvMemoryStream aExtBu( 0x200, 0x200 );
+ SvMemoryStream aClientTextBox( 0x200, 0x200 );
+ ImplWriteTextStyleAtom( aClientTextBox, nStyleInstance, 0, nullptr, aExtBu, &aPropOpt );
+
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId );
+ aPropOpt.CreateShapeProperties( mXShape );
+ aPropOpt.Commit( *mpStrm );
+ mpPptEscherEx->AddAtom( 8, ESCHER_ClientAnchor );
+ mpStrm->WriteInt16( maRect.Top() ).WriteInt16( maRect.Left() ).WriteInt16( maRect.Right() ).WriteInt16( maRect.Bottom() ); // top, left, right, bottom ????
+ mpPptEscherEx->OpenContainer( ESCHER_ClientData );
+ mpPptEscherEx->AddAtom( 8, EPP_OEPlaceholderAtom );
+ mpStrm->WriteUInt32( 0 ) // PlacementID
+ .WriteUChar( nPlaceHolderId ) // PlaceHolderID
+ .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
+ .WriteUInt16( 0 ); // padword
+ mpPptEscherEx->CloseContainer(); // ESCHER_ClientData
+
+ if ( aClientTextBox.Tell() )
+ {
+ mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
+ .WriteUInt32( aClientTextBox.Tell() );
+
+ mpStrm->WriteBytes(aClientTextBox.GetData(), aClientTextBox.Tell());
+ }
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+ }
+ else
+ bRet = false;
+ return bRet;
+}
+
+void PPTWriter::ImplCreateShape( sal_uInt32 nType, ShapeFlag nFlags, EscherSolverContainer& rSolver )
+{
+ sal_uInt32 nId = mpPptEscherEx->GenerateShapeId();
+ mpPptEscherEx->AddShape( nType, nFlags, nId );
+ rSolver.AddShape( mXShape, nId );
+}
+
+void PPTWriter::ImplCreateTextShape( EscherPropertyContainer& rPropOpt, EscherSolverContainer& rSolver, bool bFill )
+{
+ mnTextStyle = EPP_TEXTSTYLE_TEXT;
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_TextBox, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty, rSolver );
+ if ( bFill )
+ rPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ if ( ImplGetText() )
+ {
+ mnTxId += 0x60;
+ rPropOpt.CreateTextProperties( mXPropSet, mnTxId );
+ }
+}
+
+void PPTWriter::ImplWritePage( const PHLayout& rLayout, EscherSolverContainer& aSolverContainer, PageType ePageType, bool bMasterPage, int nPageNumber )
+{
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // sal_uInt32 nGroupLevel = 0;
+
+ sal_uInt32 nGroups, nShapes, nShapeCount, nPer, nLastPer, nIndices, nOlePictureId;
+ css::awt::Point aTextRefPoint;
+
+ nShapes = mXShapes->getCount();
+ ResetGroupTable( nShapes );
+
+ nIndices = nLastPer = nShapeCount = 0;
+
+ bool bIsTitlePossible = true; // powerpoint is not able to handle more than one title
+
+ sal_uInt32 nOutlinerCount = 0; // the outline objects have to conform to the layout,
+ sal_uInt32 nPrevTextStyle = 0; // there are no more than two allowed
+
+ nOlePictureId = 0;
+
+ bool bAdditionalText = false;
+
+ bool bSecOutl = false;
+ sal_uInt32 nPObjects = 0;
+
+ std::unique_ptr<SvMemoryStream> pClientTextBox;
+ std::unique_ptr<SvMemoryStream> pClientData;
+
+ while( GetNextGroupEntry() )
+ {
+ nShapeCount++;
+
+ nPer = ( 5 * nShapeCount ) / nShapes;
+ if ( nPer != nLastPer )
+ {
+ nLastPer = nPer;
+ sal_uInt32 nValue = mnPagesWritten * 5 + nPer;
+ if ( nValue > mnStatMaxValue )
+ nValue = mnStatMaxValue;
+ if ( mbStatusIndicator && ( nValue > mnLatestStatValue ) )
+ {
+ mXStatusIndicator->setValue( nValue );
+ mnLatestStatValue = nValue;
+ }
+ }
+ nGroups = GetGroupsClosed();
+ for ( sal_uInt32 i = 0; i < nGroups; i++, mpPptEscherEx->LeaveGroup() ) ;
+
+ if ( GetShapeByIndex( GetCurrentGroupIndex(), true ) )
+ {
+ bool bIsSound;
+ bool bMediaClickAction = false;
+ css::presentation::AnimationEffect eAe;
+ css::presentation::AnimationEffect eTe;
+
+ bool bEffect = ImplGetEffect( mXPropSet, eAe, eTe, bIsSound );
+ css::presentation::ClickAction eCa = css::presentation::ClickAction_NONE;
+ if ( ImplGetPropertyValue( "OnClick" ) )
+ mAny >>= eCa;
+
+ bool bGroup = mType == "drawing.Group";
+ bool bOpenBezier = mType == "drawing.OpenBezier";
+ bool bClosedBezier = mType == "drawing.ClosedBezier";
+ bool bPolyPolygon = mType == "drawing.PolyPolygon";
+ bool bPolyLine = mType == "drawing.PolyLine";
+ OUString aGraphicPropertyName("Graphic");
+
+ const css::awt::Size aSize100thmm( mXShape->getSize() );
+ const css::awt::Point aPoint100thmm( mXShape->getPosition() );
+ ::tools::Rectangle aRect100thmm( Point( aPoint100thmm.X, aPoint100thmm.Y ), Size( aSize100thmm.Width, aSize100thmm.Height ) );
+ EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect100thmm );
+
+ if ( bGroup )
+ {
+ css::uno::Reference< css::container::XIndexAccess >
+ aXIndexAccess( mXShape, css::uno::UNO_QUERY );
+ if ( EnterGroup( aXIndexAccess ) )
+ {
+ std::unique_ptr<SvMemoryStream> pTmp;
+ if ( eCa != css::presentation::ClickAction_NONE )
+ {
+ pTmp.reset(new SvMemoryStream(0x200, 0x200));
+ ImplWriteClickAction( *pTmp, eCa, bMediaClickAction );
+ }
+ sal_uInt32 nShapeId = mpPptEscherEx->EnterGroup(&maRect, pTmp.get());
+ aSolverContainer.AddShape( mXShape, nShapeId );
+ }
+ }
+ else
+ {
+ bool bIsFontwork = false;
+ bool bIsHatching = false;
+ css::uno::Any aAny;
+ if ( GetPropertyValue( aAny, mXPropSet, "IsFontwork", true ) )
+ aAny >>= bIsFontwork;
+ if ( GetPropertyValue( aAny, mXPropSet, "FillStyle", true ) )
+ {
+ css::drawing::FillStyle eFS;
+ aAny >>= eFS;
+ bIsHatching = eFS == css::drawing::FillStyle_HATCH;
+ if (mType == "drawing.Custom" && eFS == drawing::FillStyle_BITMAP)
+ {
+ ShapeFlag nMirrorFlags;
+ OUString sCustomShapeType;
+ MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType(
+ mXShape, nMirrorFlags, sCustomShapeType);
+ if (eShapeType == mso_sptMax)
+ {
+ // We can't map this custom shape to a PPT preset and it has a bitmap
+ // fill. Make sure that at least the bitmap fill is not lost.
+ mType = "drawing.GraphicObject";
+ aGraphicPropertyName = "Bitmap";
+ }
+ }
+ }
+ if ( bIsHatching || bIsFontwork || ( mType == "drawing.Measure" ) || ( mType == "drawing.Caption" ) )
+ {
+ if ( ImplGetPropertyValue( "BoundRect" ) )
+ {
+ auto aRect = o3tl::doAccess<css::awt::Rectangle>(mAny);
+ maPosition = MapPoint( css::awt::Point( aRect->X, aRect->Y ) );
+ maSize = MapSize( css::awt::Size( aRect->Width, aRect->Height ) );
+ maRect = ::tools::Rectangle( Point( maPosition.X, maPosition.Y ), Size( maSize.Width, maSize.Height ) );
+ }
+ mType = "drawing.dontknow";
+ }
+ }
+ sal_uInt8 nPlaceHolderAtom = EPP_PLACEHOLDER_NONE;
+
+ mnTextSize = 0;
+ mnTextStyle = EPP_TEXTSTYLE_NORMAL;
+
+ if ( mType == "drawing.Custom" )
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ShapeFlag nMirrorFlags;
+ OUString sCustomShapeType;
+ MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType( mXShape, nMirrorFlags, sCustomShapeType );
+ if ( sCustomShapeType == "col-502ad400" || sCustomShapeType == "col-60da8460" )
+ { // sj: creating metafile for customshapes that can't be saved to ms format properly
+ ImplCreateShape( ESCHER_ShpInst_PictureFrame,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ if ( aPropOpt.CreateGraphicProperties( mXPropSet, "MetaFile", false ) )
+ {
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mXShape);
+ if ( pObj )
+ {
+ ::tools::Rectangle aBound = pObj->GetCurrentBoundRect();
+ maPosition = MapPoint( css::awt::Point( aBound.Left(), aBound.Top() ) );
+ maSize = MapSize( css::awt::Size ( aBound.GetWidth(), aBound.GetHeight() ) );
+ maRect = ::tools::Rectangle( Point( maPosition.X, maPosition.Y ), Size( maSize.Width, maSize.Height ) );
+ mnAngle = 0;
+ }
+ }
+ }
+ else
+ {
+ ImplCreateShape( eShapeType,
+ nMirrorFlags | ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ aPropOpt.CreateCustomShapeProperties( eShapeType, mXShape );
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape);
+ if ( ImplGetText() )
+ {
+ if ( !aPropOpt.IsFontWork() )
+ {
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId, true );
+ }
+ }
+ }
+ }
+ else if ( mType == "drawing.Rectangle" )
+ {
+ sal_Int32 nRadius = 0;
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ if ( ImplGetPropertyValue( "CornerRadius" ) )
+ {
+ mAny >>= nRadius;
+ nRadius = MapSize( css::awt::Size( nRadius, 0 ) ).Width;
+ }
+ if ( nRadius )
+ {
+ ImplCreateShape( ESCHER_ShpInst_RoundRectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ sal_Int32 nLength = maRect.GetWidth();
+ if ( nLength > maRect.GetHeight() )
+ nLength = maRect.GetHeight();
+ nLength >>= 1;
+ if ( nRadius >= nLength )
+ nRadius = 0x2a30; // 0x2a30 is PPTs maximum radius
+ else
+ {
+ if (nLength != 0)
+ nRadius = ( 0x2a30 * nRadius ) / nLength;
+ else
+ nRadius = 0x2a30; // 0x2a30 is PPTs maximum radius
+ }
+ aPropOpt.AddOpt( ESCHER_Prop_adjustValue, nRadius );
+ }
+ else
+ {
+ ImplCreateShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ }
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ if ( ImplGetText() )
+ {
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
+ }
+ }
+ else if ( mType == "drawing.Ellipse" )
+ {
+ css::drawing::CircleKind eCircleKind( css::drawing::CircleKind_FULL );
+ PolyStyle ePolyKind = PolyStyle::Chord;
+ if ( ImplGetPropertyValue( "CircleKind" ) )
+ {
+ mAny >>= eCircleKind;
+ switch ( eCircleKind )
+ {
+ case css::drawing::CircleKind_SECTION :
+ {
+ ePolyKind = PolyStyle::Pie;
+ }
+ break;
+ case css::drawing::CircleKind_ARC :
+ {
+ ePolyKind = PolyStyle::Arc;
+ }
+ break;
+
+ case css::drawing::CircleKind_CUT :
+ {
+ ePolyKind = PolyStyle::Chord;
+ }
+ break;
+
+ default:
+ eCircleKind = css::drawing::CircleKind_FULL;
+ }
+ }
+ if ( eCircleKind == css::drawing::CircleKind_FULL )
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_Ellipse,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ if ( ImplGetText() )
+ {
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
+ }
+ }
+ else
+ {
+ sal_Int32 nStartAngle, nEndAngle;
+ if ( !ImplGetPropertyValue( "CircleStartAngle" ) )
+ continue;
+ nStartAngle = *o3tl::doAccess<sal_Int32>(mAny);
+ if( !ImplGetPropertyValue( "CircleEndAngle" ) )
+ continue;
+ nEndAngle = *o3tl::doAccess<sal_Int32>(mAny);
+ css::awt::Point aPoint( mXShape->getPosition() );
+ css::awt::Size aSize( mXShape->getSize() );
+ css::awt::Point aStart, aEnd, aCenter;
+ ::tools::Rectangle aRect( Point( aPoint.X, aPoint.Y ), Size( aSize.Width, aSize.Height ) );
+ aStart.X = static_cast<sal_Int32>( cos( basegfx::deg2rad<100>(nStartAngle) ) * 100.0 );
+ aStart.Y = - static_cast<sal_Int32>( sin( basegfx::deg2rad<100>(nStartAngle) ) * 100.0 );
+ aEnd.X = static_cast<sal_Int32>( cos( basegfx::deg2rad<100>(nEndAngle) ) * 100.0 );
+ aEnd.Y = - static_cast<sal_Int32>( sin( basegfx::deg2rad<100>(nEndAngle) ) * 100.0 );
+ aCenter.X = aPoint.X + ( aSize.Width / 2 );
+ aCenter.Y = aPoint.Y + ( aSize.Height / 2 );
+ aStart.X += aCenter.X;
+ aStart.Y += aCenter.Y;
+ aEnd.X += aCenter.X;
+ aEnd.Y += aCenter.Y;
+ tools::Polygon aPolygon( aRect, Point( aStart.X, aStart.Y ), Point( aEnd.X, aEnd.Y ), ePolyKind );
+ bool bNeedText = true;
+ if ( mnAngle )
+ {
+ aPolygon.Rotate( aRect.TopLeft(), Degree10(static_cast<sal_Int16>( mnAngle / 10 )) );
+ if ( ImplGetText() )
+ {
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->EnterGroup( 0,0 );
+ // nGroupLevel = mpPptEscherEx->GetGroupLevel();
+ bNeedText = false;
+ bAdditionalText = true;
+ mnTextSize = 0;
+ }
+ mnAngle = 0;
+ }
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ css::awt::Rectangle aNewRect;
+ switch ( ePolyKind )
+ {
+ case PolyStyle::Pie :
+ case PolyStyle::Chord :
+ {
+ if ( aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect, &aPolygon ) )
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ }
+ break;
+
+ case PolyStyle::Arc :
+ {
+ if ( aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect, &aPolygon ) )
+ aPropOpt.CreateLineProperties( mXPropSet, false );
+ }
+ break;
+ }
+ maRect = MapRectangle( aNewRect );
+ maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
+ maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
+ if ( bNeedText && ImplGetText() )
+ {
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
+ }
+ }
+ }
+ else if ( mType == "drawing.Control" )
+ {
+ css::uno::Reference< css::drawing::XControlShape > aXControlShape( mXShape, css::uno::UNO_QUERY );
+ if ( !aXControlShape.is() )
+ continue;
+ css::uno::Reference< css::awt::XControlModel > aXControlModel( aXControlShape->getControl() );
+ if ( !aXControlModel.is() )
+ continue;
+
+ sal_Int64 nAspect = css::embed::Aspects::MSOLE_CONTENT;
+ try
+ {
+ // try to get the aspect when available
+ css::uno::Reference< css::beans::XPropertySet > xShapeProps( mXShape, css::uno::UNO_QUERY_THROW );
+ xShapeProps->getPropertyValue("Aspect") >>= nAspect;
+ }
+ catch( css::uno::Exception& )
+ {}
+
+ mpExEmbed->WriteUInt32( 0xf | ( EPP_ExControl << 16 ) )
+ .WriteUInt32( 0 ); // Size of this container
+
+ sal_uInt32 nSize, nOldPos = mpExEmbed->Tell();
+
+ sal_uInt32 nPageId = nPageNumber;
+ if ( ePageType == MASTER )
+ nPageId |= 0x80000000;
+ else
+ nPageId += 0x100;
+ mpExEmbed->WriteUInt32( EPP_ExControlAtom << 16 )
+ .WriteUInt32( 4 )
+ .WriteUInt32( nPageId );
+ std::unique_ptr<PPTExOleObjEntry> pEntry( new PPTExOleObjEntry( OCX_CONTROL, mpExEmbed->Tell() ) );
+ pEntry->xControlModel = aXControlModel;
+ pEntry->xShape = mXShape;
+ maExOleObj.push_back( std::move(pEntry) );
+
+ mnExEmbed++;
+
+ mpExEmbed->WriteUInt32( 1 | ( EPP_ExOleObjAtom << 16 ) )
+ .WriteUInt32( 24 )
+ .WriteUInt32( nAspect )
+ .WriteUInt32( 2 )
+ .WriteUInt32( mnExEmbed )
+ .WriteUInt32( 0 )
+ .WriteUInt32( 4 ) // index to the persist table
+ .WriteUInt32( 0x0012de00 );
+
+ css::awt::Size aSize;
+ OUString aControlName;
+ tools::SvRef<SotStorage> xTemp( new SotStorage( new SvMemoryStream(), true ) );
+ if ( oox::ole::MSConvertOCXControls::WriteOCXStream( mXModel, xTemp, aXControlModel, aSize, aControlName ) )
+ {
+ OUString aUserName( xTemp->GetUserName() );
+ OUString aOleIdentifier;
+ if ( !aUserName.isEmpty() )
+ {
+ tools::SvRef<SotStorageStream> xCompObj = xTemp->OpenSotStream(
+ "\1CompObj",
+ StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYALL );
+ sal_uInt32 const nStreamLen = xCompObj->remainingSize();
+ sal_Int16 nVersion, nByteOrder;
+ sal_Int32 nWinVersion, nVal, nStringLen;
+ xCompObj->ReadInt16( nVersion )
+ .ReadInt16( nByteOrder )
+ .ReadInt32( nWinVersion )
+ .ReadInt32( nVal );
+ xCompObj->SeekRel( 16 ); // skipping clsid
+ xCompObj->ReadInt32( nStringLen );
+ if ( ( xCompObj->Tell() + nStringLen ) < nStreamLen )
+ {
+ xCompObj->SeekRel( nStringLen ); // now skipping the UserName;
+ xCompObj->ReadInt32( nStringLen );
+ if ( ( xCompObj->Tell() + nStringLen ) < nStreamLen )
+ {
+ xCompObj->SeekRel( nStringLen ); // now skipping the clipboard formatname
+ xCompObj->ReadInt32( nStringLen );
+ if ( ( nStringLen > 1 ) && ( ( xCompObj->Tell() + nStringLen ) < nStreamLen ) )
+ { // i think that the OleIdentifier will follow
+ OString aTemp = read_uInt8s_ToOString(*xCompObj, nStringLen - 1);
+ aOleIdentifier = OStringToOUString(aTemp, RTL_TEXTENCODING_MS_1252);
+ }
+ }
+ }
+ }
+
+ PPTWriter::WriteCString( *mpExEmbed, aControlName, 1 );
+ PPTWriter::WriteCString( *mpExEmbed, aOleIdentifier, 2 );
+ PPTWriter::WriteCString( *mpExEmbed, aUserName, 3 );
+ }
+ nSize = mpExEmbed->Tell() - nOldPos;
+ mpExEmbed->Seek( nOldPos - 4 );
+ mpExEmbed->WriteUInt32( nSize );
+ mpExEmbed->Seek( STREAM_SEEK_TO_END );
+ nOlePictureId = mnExEmbed;
+
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ShapeFlag const nSpFlags = ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor | ShapeFlag::OLEShape;
+ ImplCreateShape( ESCHER_ShpInst_HostControl, nSpFlags, aSolverContainer );
+ if ( aPropOpt.CreateGraphicProperties( mXPropSet, "MetaFile", false ) )
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ //export form control graphic
+ else if ( aPropOpt.CreateBlipPropertiesforOLEControl(mXPropSet,mXShape))
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ aPropOpt.AddOpt( ESCHER_Prop_pictureId, mnExEmbed );
+ aPropOpt.AddOpt( ESCHER_Prop_pictureActive, 0x10000 );
+
+ if ( !aControlName.isEmpty() )
+ {
+ aPropOpt.AddOpt(ESCHER_Prop_wzName, aControlName);
+ }
+ }
+ else if ( mType == "drawing.Connector" )
+ {
+ sal_uInt16 nSpType;
+ ShapeFlag nSpFlags;
+ css::awt::Rectangle aNewRect;
+ if ( !aPropOpt.CreateConnectorProperties( mXShape, aSolverContainer, aNewRect, nSpType, nSpFlags ) )
+ continue;
+
+ maRect = MapRectangle( aNewRect );
+ maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
+ maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
+
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( nSpType, nSpFlags, aSolverContainer );
+
+ // #119459# for connector shape, the start point and end point is fixed, and should not be rotated.
+ mnAngle = 0;
+ }
+ else if ( mType == "drawing.Measure" )
+ {
+ continue;
+ }
+ else if ( mType == "drawing.Line" )
+ {
+ css::awt::Rectangle aNewRect;
+ aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_LINE, false, aNewRect );
+ maRect = MapRectangle( aNewRect );
+ maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
+ maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
+ if ( ImplGetText() )
+ {
+ aTextRefPoint = css::awt::Point( maRect.Left(), maRect.Top() );
+ mnTextSize = 0;
+ bAdditionalText = true;
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->EnterGroup( &maRect,0 );
+ }
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ShapeFlag nFlags = ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty;
+
+ if ( maRect.Top() > maRect.Bottom() )
+ nFlags |= ShapeFlag::FlipV;
+ if ( maRect.Left() > maRect.Right() )
+ nFlags |= ShapeFlag::FlipH;
+
+ ImplCreateShape( ESCHER_ShpInst_Line, nFlags, aSolverContainer );
+ aPropOpt.AddOpt( ESCHER_Prop_shapePath, ESCHER_ShapeComplex );
+ aPropOpt.CreateLineProperties( mXPropSet, false );
+ mnAngle = 0;
+ }
+ else if ( bPolyPolygon )
+ {
+ if ( ImplGetText() )
+ {
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->EnterGroup( 0,0 );
+ // nGroupLevel = mpPptEscherEx->GetGroupLevel();
+ bAdditionalText = true;
+ mnTextSize = 0;
+ }
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ css::awt::Rectangle aNewRect;
+ aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect );
+ maRect = MapRectangle( aNewRect );
+ maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
+ maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ mnAngle = 0;
+ }
+ else if ( bPolyLine )
+ {
+ if ( ImplGetText() )
+ {
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->EnterGroup( 0,0 );
+ // nGroupLevel = mpPptEscherEx->GetGroupLevel();
+ bAdditionalText = true;
+ mnTextSize = 0;
+ }
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ css::awt::Rectangle aNewRect;
+ aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect );
+ maRect = MapRectangle( aNewRect );
+ maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
+ maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
+ aPropOpt.CreateLineProperties( mXPropSet, false );
+ mnAngle = 0;
+ }
+ else if ( bOpenBezier )
+ {
+ if ( ImplGetText() )
+ {
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->EnterGroup( 0,0 );
+ // nGroupLevel = mpPptEscherEx->GetGroupLevel();
+ bAdditionalText = true;
+ mnTextSize = 0;
+ }
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ css::awt::Rectangle aNewRect;
+ aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, true, aNewRect );
+ maRect = MapRectangle( aNewRect );
+ maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
+ maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
+ aPropOpt.CreateLineProperties( mXPropSet, false );
+ mnAngle = 0;
+ }
+ else if ( bClosedBezier )
+ {
+ if ( ImplGetText() )
+ {
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->EnterGroup( 0,0 );
+ // nGroupLevel = mpPptEscherEx->GetGroupLevel();
+ bAdditionalText = true;
+ mnTextSize = 0;
+ }
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ css::awt::Rectangle aNewRect;
+ aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, true, aNewRect );
+ maRect = MapRectangle( aNewRect );
+ maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
+ maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ mnAngle = 0;
+ }
+ else if ( ( mType == "drawing.GraphicObject" ) || ( mType == "presentation.GraphicObject" ) )
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+
+ // a GraphicObject can also be a ClickMe element
+ if ( mbEmptyPresObj && ( ePageType == NORMAL ) )
+ {
+ nPlaceHolderAtom = rLayout.nUsedObjectPlaceHolder;
+ ImplCreateShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster, aSolverContainer );
+ mnTxId += 0x60;
+ aPropOpt.AddOpt( ESCHER_Prop_lTxid, mnTxId );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 );
+ aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
+ }
+ else
+ {
+ mXText.set( mXShape, css::uno::UNO_QUERY );
+
+ if ( mXText.is() )
+ mnTextSize = mXText->getString().getLength();
+
+ if ( mnTextSize ) // graphic object or area fill
+ {
+ /* SJ #i34951#: because M. documents are not allowing GraphicObjects containing text, we
+ have to create a simple Rectangle with fill bitmap instead (while not allowing BitmapMode_Repeat).
+ */
+ ImplCreateShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ if ( aPropOpt.CreateGraphicProperties( mXPropSet, "Graphic", true, true, false ) )
+ {
+ aPropOpt.AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapNone );
+ aPropOpt.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x140014 );
+ aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x8000000 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
+ if ( ImplGetText() )
+ {
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
+ }
+ }
+ }
+ else
+ {
+ ImplCreateShape( ESCHER_ShpInst_PictureFrame,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+
+ if (aPropOpt.CreateGraphicProperties(mXPropSet, aGraphicPropertyName, false,
+ true))
+ {
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ }
+ }
+ }
+ }
+ else if ( ( mType == "drawing.Text" ) || ( mType == "presentation.Notes" ) )
+ {
+ if ( ( ePageType == NOTICE ) && mbPresObj )
+ {
+ if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Notes, EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE ) )
+ continue;
+ else
+ nPlaceHolderAtom = EPP_PLACEHOLDER_NOTESBODY;
+ }
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ else if ( mType == "presentation.TitleText" )
+ {
+ if ( mbPresObj )
+ {
+ if ( ( ePageType == NOTICE ) && mbEmptyPresObj )
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ nPlaceHolderAtom = EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE;
+ ImplCreateShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveAnchor, aSolverContainer );
+ aPropOpt.CreateLineProperties( mXPropSet, false );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
+ }
+ else if ( rLayout.bTitlePossible && bIsTitlePossible )
+ {
+ bIsTitlePossible = false;
+
+ ImplGetText();
+ TextObjBinary aTextObj( mXText, EPP_TEXTTYPE_Title, maFontCollection, static_cast<PPTExBulletProvider&>(*this) );
+ if ( ePageType == MASTER )
+ {
+ if ( mnTextSize )
+ {
+ OUString aUString( mXText->getString() );
+ sal_uInt16 nChar;
+
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ mnShapeMasterTitle = mpPptEscherEx->GenerateShapeId();
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ mnShapeMasterTitle );
+ EscherPropertyContainer aPropertyOptions;
+ aPropertyOptions.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x50001 );
+ mnTxId += 0x60;
+ aPropertyOptions.AddOpt( ESCHER_Prop_lTxid, mnTxId );
+ aPropertyOptions.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
+ aPropertyOptions.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110001 );
+ aPropertyOptions.AddOpt( ESCHER_Prop_lineColor, 0x8000001 );
+ aPropertyOptions.AddOpt( ESCHER_Prop_shadowColor, 0x8000002 );
+ aPropertyOptions.CreateFillProperties( mXPropSet, true, mXShape );
+ sal_uInt32 nLineFlags = 0x90001;
+ if ( aPropertyOptions.GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ) )
+ nLineFlags |= 0x10001; // draw dashed line if no line
+ aPropertyOptions.AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
+ mnTxId += 0x60;
+ aPropertyOptions.CreateTextProperties( mXPropSet, mnTxId );
+ ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt );
+ aPropertyOptions.Commit( *mpStrm );
+ mpPptEscherEx->AddAtom( 8, ESCHER_ClientAnchor );
+ mpStrm->WriteInt16( maRect.Top() ).WriteInt16( maRect.Left() ).WriteInt16( maRect.Right() ).WriteInt16( maRect.Bottom() ); // top, left, right, bottom ????
+ mpPptEscherEx->OpenContainer( ESCHER_ClientData );
+ mpPptEscherEx->AddAtom( 8, EPP_OEPlaceholderAtom );
+ mpStrm->WriteUInt32( 0 ) // PlacementID
+ .WriteUChar( EPP_PLACEHOLDER_MASTERTITLE ) // PlaceHolderID
+ .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
+ .WriteUInt16( 0 ); // padword
+ mpPptEscherEx->CloseContainer(); // ESCHER_ClientData
+ mpPptEscherEx->OpenContainer( ESCHER_ClientTextbox );
+ mpPptEscherEx->AddAtom( 4, EPP_TextHeaderAtom );
+ mpStrm->WriteUInt32( EPP_TEXTTYPE_Title );
+ mpPptEscherEx->AddAtom( mnTextSize << 1, EPP_TextCharsAtom );
+ const sal_Unicode* pString = aUString.getStr();
+ for ( sal_uInt32 i = 0; i < mnTextSize; i++ )
+ {
+ nChar = pString[ i ]; // 0xa -> 0xb soft newline
+ if ( nChar == 0xa )
+ nChar++; // 0xd -> 0xd hard newline
+ mpStrm->WriteUInt16( nChar );
+ }
+ mpPptEscherEx->AddAtom( 6, EPP_BaseTextPropAtom );
+ mpStrm->WriteUInt32( mnTextSize + 1 ).WriteUInt16( 0 );
+ mpPptEscherEx->AddAtom( 10, EPP_TextSpecInfoAtom );
+ mpStrm->WriteUInt32( mnTextSize + 1 ).WriteUInt32( 1 ).WriteUInt16( 0 );
+ mpPptEscherEx->CloseContainer(); // ESCHER_ClientTextBox
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+ }
+ continue;
+ }
+ else
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ mnTextStyle = EPP_TEXTSTYLE_TITLE;
+ nPlaceHolderAtom = rLayout.nTypeOfTitle;
+ ImplCreateShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster,
+ aSolverContainer );
+ aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterTitle );
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId );
+ ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt );
+ if ( mbEmptyPresObj )
+ {
+ sal_uInt32 nNoLineDrawDash = 0;
+ aPropOpt.GetOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
+ nNoLineDrawDash |= 0x10001;
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
+ }
+ }
+ }
+ else
+ mbPresObj = false;
+ }
+ if ( !mbPresObj )
+ {
+ mType = "drawing.Text";
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ }
+ else if ( ( mType == "presentation.Outliner" ) || ( mType == "presentation.Subtitle" ) )
+ {
+ if ( mbPresObj )
+ {
+ nOutlinerCount++;
+ if ( (rLayout.bOutlinerPossible && ( nOutlinerCount == 1 )) ||
+ (( rLayout.bSecOutlinerPossible && ( nOutlinerCount == 2 ) ) && ( nPrevTextStyle == EPP_TEXTSTYLE_BODY ))
+ )
+ {
+ ImplGetText();
+ TextObjBinary aTextObj( mXText, EPP_TEXTTYPE_Body, maFontCollection, static_cast<PPTExBulletProvider&>(*this) );
+ if ( ePageType == MASTER )
+ {
+ nPrevTextStyle = EPP_TEXTSTYLE_TITLE;
+ if ( mnTextSize )
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ mnShapeMasterBody = mpPptEscherEx->GenerateShapeId();
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ mnShapeMasterBody );
+ EscherPropertyContainer aPropOpt2;
+ aPropOpt2.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x50001 );
+ mnTxId += 0x60;
+ aPropOpt2.AddOpt( ESCHER_Prop_lTxid, mnTxId );
+ aPropOpt2.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110001 );
+ aPropOpt2.AddOpt( ESCHER_Prop_lineColor, 0x8000001 );
+ aPropOpt2.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90001 );
+ aPropOpt2.AddOpt( ESCHER_Prop_shadowColor, 0x8000002 );
+ aPropOpt2.CreateFillProperties( mXPropSet, true, mXShape );
+ sal_uInt32 nLineFlags = 0x90001;
+ if ( aPropOpt2.GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ) )
+ nLineFlags |= 0x10001; // draw dashed line if no line
+ aPropOpt2.AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
+ mnTxId += 0x60;
+ aPropOpt2.CreateTextProperties( mXPropSet, mnTxId );
+ ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt2 );
+ aPropOpt2.Commit( *mpStrm );
+ mpPptEscherEx->AddAtom( 8, ESCHER_ClientAnchor );
+ mpStrm->WriteInt16( maRect.Top() ).WriteInt16( maRect.Left() ).WriteInt16( maRect.Right() ).WriteInt16( maRect.Bottom() ); // top, left, right, bottom ????
+ mpPptEscherEx->OpenContainer( ESCHER_ClientData );
+ mpPptEscherEx->AddAtom( 8, EPP_OEPlaceholderAtom );
+ sal_uInt8 PlaceHolderID = ( mType == "presentation.Subtitle") ? EPP_PLACEHOLDER_MASTERSUBTITLE:EPP_PLACEHOLDER_MASTERBODY;
+ mpStrm->WriteUInt32( 1 ) // PlacementID
+ .WriteUChar( PlaceHolderID )/*(sal_uInt8)EPP_PLACEHOLDER_MASTERBODY */ // PlaceHolderID
+ .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
+ .WriteUInt16( 0 ); // padword
+ mpPptEscherEx->CloseContainer(); // ESCHER_ClientData
+ mpPptEscherEx->OpenContainer( ESCHER_ClientTextbox ); // printf
+ mpPptEscherEx->AddAtom( 4, EPP_TextHeaderAtom );
+ if ( mType == "presentation.Subtitle")
+ mpStrm->WriteUInt32( EPP_TEXTTYPE_CenterBody );
+ else
+ mpStrm->WriteUInt32( EPP_TEXTTYPE_Body );
+ mnTextSize = aTextObj.Count();
+ aTextObj.Write( mpStrm.get() );
+ mpPptEscherEx->BeginAtom();
+ for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount() ; ++i )
+ {
+ ParagraphObj* pPara = aTextObj.GetParagraph(i);
+ mpStrm->WriteUInt32( pPara->CharacterCount() )
+ .WriteUInt16( pPara->nDepth );
+ }
+ mpPptEscherEx->EndAtom( EPP_BaseTextPropAtom );
+ mpPptEscherEx->AddAtom( 10, EPP_TextSpecInfoAtom );
+ mpStrm->WriteUInt32( mnTextSize ).WriteUInt32( 1 ).WriteUInt16( 0 );
+
+ mpPptEscherEx->CloseContainer(); // ESCHER_ClientTextBox
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+ }
+ continue;
+ }
+ else
+ {
+ mnTextStyle = EPP_TEXTSTYLE_BODY;
+ nPlaceHolderAtom = rLayout.nTypeOfOutliner;
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster,
+ aSolverContainer );
+ aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
+ aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
+ mnTxId += 0x60;
+ aPropOpt.CreateTextProperties( mXPropSet, mnTxId );
+ ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt );
+ if ( mbEmptyPresObj )
+ {
+ sal_uInt32 nNoLineDrawDash = 0;
+ aPropOpt.GetOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
+ nNoLineDrawDash |= 0x10001;
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
+ }
+ }
+ }
+ else
+ mbPresObj = false;
+ }
+ if ( !mbPresObj )
+ {
+ if (ePageType == MASTER )
+ {
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mXShape);
+ if (pObj && pObj->IsNotVisibleAsMaster())
+ continue;
+ }
+
+ mType = "drawing.Text";
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ }
+ else if ( ( mType == "drawing.Page" ) || ( mType == "presentation.Page" ) )
+ {
+ if ( ( ePageType == NOTICE ) && mbPresObj )
+ {
+ if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Notes, EPP_PLACEHOLDER_MASTERNOTESSLIDEIMAGE ) )
+ continue;
+ else
+ nPlaceHolderAtom = EPP_PLACEHOLDER_NOTESSLIDEIMAGE;
+ }
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ else if ( mType == "drawing.Frame" )
+ {
+ continue;
+ }
+ else if ( ( mType == "drawing.OLE2" ) || ( mType == "presentation.OLE2" )
+ || ( mType == "presentation.Chart" ) || ( mType == "presentation.Calc" )
+ || ( mType == "presentation.OrgChart" ) )
+ {
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ if ( mbEmptyPresObj && ( ePageType == NORMAL ) )
+ {
+ nPlaceHolderAtom = rLayout.nUsedObjectPlaceHolder;
+ ImplCreateShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster,
+ aSolverContainer );
+ mnTxId += 0x60;
+ aPropOpt.AddOpt( ESCHER_Prop_lTxid, mnTxId );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 );
+ aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
+ }
+ else
+ {
+ mpExEmbed->WriteUInt32( 0xf | ( EPP_ExEmbed << 16 ) )
+ .WriteUInt32( 0 ); // Size of this container
+
+ sal_uInt32 nSize, nOldPos = mpExEmbed->Tell();
+
+ mpExEmbed->WriteUInt32( EPP_ExEmbedAtom << 16 )
+ .WriteUInt32( 8 )
+ .WriteUInt32( 0 ) // follow colorscheme : 0->do not follow
+ // 1->follow colorscheme
+ // 2->follow text and background scheme
+ .WriteUChar( 1 ) // (bool)set if embedded server can not be locked
+ .WriteUChar( 0 ) // (bool)do not need to send dimension
+ .WriteUChar( 0 ) // (bool)is object a world table
+ .WriteUChar( 0 ); // pad byte
+
+ std::unique_ptr<PPTExOleObjEntry> pE( new PPTExOleObjEntry( NORMAL_OLE_OBJECT, mpExEmbed->Tell() ) );
+ pE->xShape = mXShape;
+ maExOleObj.push_back( std::move(pE) );
+
+ mnExEmbed++;
+
+ sal_Int64 nAspect = css::embed::Aspects::MSOLE_CONTENT;
+ try
+ {
+ // try to get the aspect when available
+ css::uno::Reference< css::beans::XPropertySet > xShapeProps( mXShape, css::uno::UNO_QUERY_THROW );
+ xShapeProps->getPropertyValue("Aspect") >>= nAspect;
+ }
+ catch( css::uno::Exception& )
+ {}
+
+ mpExEmbed->WriteUInt32( 1 | ( EPP_ExOleObjAtom << 16 ) )
+ .WriteUInt32( 24 )
+ .WriteUInt32( nAspect ) // Aspect
+ .WriteUInt32( 0 )
+ .WriteUInt32( mnExEmbed ) // index to the persist table
+ .WriteUInt32( 0 ) // subtype
+ .WriteUInt32( 0 )
+ .WriteUInt32( 0x0012b600 );
+
+ nSize = mpExEmbed->Tell() - nOldPos;
+ mpExEmbed->Seek( nOldPos - 4 );
+ mpExEmbed->WriteUInt32( nSize );
+ mpExEmbed->Seek( STREAM_SEEK_TO_END );
+ nOlePictureId = mnExEmbed;
+
+ ShapeFlag nSpFlags = ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty;
+ if ( nOlePictureId )
+ nSpFlags |= ShapeFlag::OLEShape;
+ ImplCreateShape( ESCHER_ShpInst_PictureFrame, nSpFlags, aSolverContainer );
+ if ( aPropOpt.CreateOLEGraphicProperties( mXShape ) )
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ if ( nOlePictureId )
+ aPropOpt.AddOpt( ESCHER_Prop_pictureId, nOlePictureId );
+ }
+ }
+ else if ( mType == "presentation.Header" )
+ {
+ if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERHEADER ) )
+ continue;
+ else
+ {
+ mbPresObj = false;
+ mType = "drawing.Text";
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ }
+ else if ( mType == "presentation.Footer" )
+ {
+ if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERFOOTER ) )
+ continue;
+ else
+ {
+ mbPresObj = false;
+ mType = "drawing.Text";
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ }
+ else if ( mType == "presentation.DateTime" )
+ {
+ if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERDATE ) )
+ continue;
+ else
+ {
+ mbPresObj = false;
+ mType = "drawing.Text";
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ }
+ else if ( mType == "presentation.SlideNumber" )
+ {
+ if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERSLIDENUMBER ) )
+ continue;
+ else
+ {
+ mbPresObj = false;
+ mType = "drawing.Text";
+ ImplCreateTextShape( aPropOpt, aSolverContainer, true );
+ }
+ }
+ else if ( (mType.getLength() > 9) && (mType[8] == '3') && (mType[9] == 'D') ) // drawing.3D
+ {
+ // SceneObject, CubeObject, SphereObject, LatheObject, ExtrudeObject, PolygonObject
+ if ( !ImplGetPropertyValue( "Bitmap" ) )
+ continue;
+
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_PictureFrame,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+
+ if ( aPropOpt.CreateGraphicProperties( mXPropSet, "Bitmap", false ) )
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ }
+ else if ( mType == "drawing.Media" )
+ {
+ mnAngle = 0;
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_PictureFrame,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ if ( aPropOpt.CreateMediaGraphicProperties( mXShape ) )
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ css::uno::Any aAny;
+ if ( PropValue::GetPropertyValue( aAny, mXPropSet, "MediaURL", true ) )
+ {
+ OUString aMediaURL;
+ if ( (aAny >>= aMediaURL ) && !aMediaURL.isEmpty() )
+ {
+ // SJ: creating the Media RefObj
+ sal_uInt32 nRefId = ++mnExEmbed;
+
+ mpExEmbed->WriteUInt16( 0xf )
+ .WriteUInt16( EPP_ExMCIMovie ) // PPT_PST_ExAviMovie
+ .WriteUInt32( 0 );
+ sal_uInt32 nSize, nStart = mpExEmbed->Tell();
+ mpExEmbed->WriteUInt16( 0 )
+ .WriteUInt16( EPP_ExObjRefAtom )
+ .WriteUInt32( 4 )
+ .WriteUInt32( nRefId );
+ mpExEmbed->WriteUInt16( 0xf )
+ .WriteUInt16( EPP_ExVideo )
+ .WriteUInt32( 0 );
+
+ mpExEmbed->WriteUInt16( 0 )
+ .WriteUInt16( EPP_ExMediaAtom )
+ .WriteUInt32( 8 )
+ .WriteUInt32( nRefId )
+ .WriteUInt16( 0 )
+ .WriteUInt16( 0x435 );
+
+ sal_uInt16 i, nStringLen = static_cast<sal_uInt16>(aMediaURL.getLength());
+ mpExEmbed->WriteUInt32( EPP_CString << 16 ).WriteUInt32( nStringLen * 2 );
+ for ( i = 0; i < nStringLen; i++ )
+ {
+ sal_Unicode nChar = aMediaURL[ i ];
+ mpExEmbed->WriteUInt16( nChar );
+ }
+ nSize = mpExEmbed->Tell() - nStart;
+ mpExEmbed->SeekRel( - ( static_cast<sal_Int32>(nSize) + 4 ) );
+ mpExEmbed->WriteUInt32( nSize ); // size of PPT_PST_ExMCIMovie
+ mpExEmbed->SeekRel( 0x10 );
+ nSize -= 20;
+ mpExEmbed->WriteUInt32( nSize ); // PPT_PST_ExMediaAtom
+ mpExEmbed->SeekRel( nSize );
+
+ if ( !pClientData )
+ pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
+ pClientData->WriteUInt16( 0 )
+ .WriteUInt16( EPP_ExObjRefAtom )
+ .WriteUInt32( 4 )
+ .WriteUInt32( nRefId );
+ // write EPP_InteractiveInfo container for no_action
+ pClientData->WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0xf ).WriteUInt32( 24 );
+ pClientData->WriteUInt16( 0 )
+ .WriteUInt16( EPP_InteractiveInfoAtom )
+ .WriteUInt32( 16 )
+ .WriteUInt32( 0 )
+ .WriteUInt32( 0 )
+ .WriteUChar( 6 )
+ .WriteUChar( 0 )
+ .WriteUChar( 0 )
+ .WriteUChar( 0 )
+ .WriteUInt32( 0 );
+ }
+ }
+ }
+ else if ( (mType == "drawing.Table") || (mType == "presentation.Table") )
+ {
+ if ( eCa != css::presentation::ClickAction_NONE )
+ {
+ SvMemoryStream aTmp(0x200, 0x200);
+ ImplWriteClickAction( aTmp, eCa, bMediaClickAction );
+ }
+ ImplCreateTable( mXShape, aSolverContainer, aPropOpt );
+ continue;
+ }
+ else if ( mType == "drawing.dontknow" )
+ {
+ mnAngle = 0;
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ ImplCreateShape( ESCHER_ShpInst_PictureFrame,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
+ aSolverContainer );
+ if ( aPropOpt.CreateGraphicProperties( mXPropSet, "MetaFile", false ) )
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
+ }
+ else
+ {
+ continue;
+ }
+
+ bool bClientData = ( bEffect || ( eCa != css::presentation::ClickAction_NONE ) ||
+ nPlaceHolderAtom || nOlePictureId );
+ if ( bClientData )
+ {
+ if ( nPlaceHolderAtom )
+ {
+ sal_Int32 nPlacementID = -1;
+ if ( ( mnTextStyle == EPP_TEXTSTYLE_TITLE ) || ( mnTextStyle == EPP_TEXTSTYLE_BODY ) )
+ nPlacementID = nIndices++;
+ else
+ {
+ switch ( nPlaceHolderAtom )
+ {
+ default :
+ {
+ if ( nPlaceHolderAtom < 19 )
+ break;
+ [[fallthrough]];
+ }
+ case EPP_PLACEHOLDER_NOTESBODY :
+ case EPP_PLACEHOLDER_MASTERDATE :
+ case EPP_PLACEHOLDER_NOTESSLIDEIMAGE :
+ case EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE :
+ nPlacementID = nIndices++;
+ }
+ }
+ if ( !pClientData )
+ pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
+
+ pClientData->WriteUInt32( EPP_OEPlaceholderAtom << 16 ).WriteUInt32( 8 )
+ .WriteInt32( nPlacementID ) // PlacementID
+ .WriteUChar( nPlaceHolderAtom ) // PlaceHolderID
+ .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
+ .WriteUInt16( 0 ); // padword
+ }
+ if ( nOlePictureId )
+ {
+ if ( !pClientData )
+ pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
+
+ pClientData->WriteUInt32( EPP_ExObjRefAtom << 16 ).WriteUInt32( 4 )
+ .WriteUInt32( nOlePictureId );
+ nOlePictureId = 0;
+ }
+ if ( bEffect && !pClientData )
+ {
+ pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
+ }
+
+ if ( eCa != css::presentation::ClickAction_NONE )
+ {
+ if ( !pClientData )
+ pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
+ ImplWriteClickAction( *pClientData, eCa, bMediaClickAction );
+ }
+ }
+ if ( ( mnTextStyle == EPP_TEXTSTYLE_TITLE ) || ( mnTextStyle == EPP_TEXTSTYLE_BODY ) )
+ {
+ if ( !pClientTextBox )
+ pClientTextBox.reset(new SvMemoryStream( 0x200, 0x200 ));
+
+ if ( !mbEmptyPresObj )
+ {
+ if ( ( ePageType == NORMAL ) && !bMasterPage )
+ {
+ sal_uInt32 nTextType = EPP_TEXTTYPE_Body;
+ if ( mnTextStyle == EPP_TEXTSTYLE_BODY )
+ {
+ if ( bSecOutl )
+ nTextType = EPP_TEXTTYPE_HalfBody;
+ else if ( mType == "presentation.Subtitle" )
+ nTextType = EPP_TEXTTYPE_CenterBody;
+ bSecOutl = true;
+ }
+ else
+ nTextType = EPP_TEXTTYPE_Title;
+
+ TextRuleEntry aTextRule;
+ SvMemoryStream aExtBu( 0x200, 0x200 );
+ ImplGetText();
+ ImplWriteTextStyleAtom( *pClientTextBox, nTextType, nPObjects, &aTextRule, aExtBu, nullptr );
+ ImplWriteExtParaHeader( aExtBu, nPObjects++, nTextType, nPageNumber + 0x100 );
+ SvMemoryStream* pOut = aTextRule.pOut.get();
+ if ( pOut )
+ {
+ pClientTextBox->WriteBytes(pOut->GetData(), pOut->Tell());
+ aTextRule.pOut.reset();
+ }
+ if ( aExtBu.Tell() )
+ {
+ if ( !pClientData )
+ pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
+ ImplProgTagContainer( pClientData.get(), &aExtBu );
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( !aPropOpt.IsFontWork() )
+ {
+ if ( mnTextSize || ( nPlaceHolderAtom == EPP_PLACEHOLDER_MASTERDATE ) || ( nPlaceHolderAtom == EPP_PLACEHOLDER_NOTESBODY ) )
+ {
+ int nInstance2;
+ if ( ( nPlaceHolderAtom == EPP_PLACEHOLDER_MASTERDATE ) || ( nPlaceHolderAtom == EPP_PLACEHOLDER_NOTESBODY ) )
+ nInstance2 = 2;
+ else
+ nInstance2 = EPP_TEXTTYPE_Other; // Text in a Shape
+
+ if ( !pClientTextBox )
+ pClientTextBox.reset(new SvMemoryStream( 0x200, 0x200 ));
+
+ SvMemoryStream aExtBu( 0x200, 0x200 );
+ ImplWriteTextStyleAtom( *pClientTextBox, nInstance2, 0, nullptr, aExtBu, &aPropOpt );
+ if ( aExtBu.Tell() )
+ {
+ if ( !pClientData )
+ pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
+ ImplProgTagContainer( pClientData.get(), &aExtBu );
+ }
+ }
+ else if ( nPlaceHolderAtom >= 19 )
+ {
+ if ( !pClientTextBox )
+ pClientTextBox.reset(new SvMemoryStream( 12 ));
+
+ pClientTextBox->WriteUInt32( EPP_TextHeaderAtom << 16 ).WriteUInt32( 4 )
+ .WriteUInt32( 7 );
+ }
+ }
+ }
+
+ aPropOpt.CreateShadowProperties( mXPropSet );
+ maRect.Justify();
+ if ( mnAngle )
+ ImplFlipBoundingBox( aPropOpt );
+ aPropOpt.CreateShapeProperties( mXShape );
+ aPropOpt.Commit( *mpStrm );
+ if ( GetCurrentGroupLevel() > 0 )
+ mpPptEscherEx->AddChildAnchor( maRect );
+ else
+ mpPptEscherEx->AddClientAnchor( maRect );
+
+ if ( pClientData )
+ {
+ mpStrm->WriteUInt32( ( ESCHER_ClientData << 16 ) | 0xf )
+ .WriteUInt32( pClientData->Tell() );
+
+ mpStrm->WriteBytes(pClientData->GetData(), pClientData->Tell());
+ pClientData.reset();
+ }
+ if ( pClientTextBox )
+ {
+ mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
+ .WriteUInt32( pClientTextBox->Tell() );
+
+ mpStrm->WriteBytes(pClientTextBox->GetData(), pClientTextBox->Tell());
+ pClientTextBox.reset();
+ }
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+ }
+ nPrevTextStyle = mnTextStyle;
+
+ if ( bAdditionalText )
+ {
+ bAdditionalText = false;
+
+ css::uno::Any aAny;
+ EscherPropertyContainer aPropOpt;
+ mnAngle = ( PropValue::GetPropertyValue( aAny,
+ mXPropSet, "RotateAngle", true ) )
+ ? *o3tl::doAccess<sal_Int32>(aAny)
+ : 0;
+
+ aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 );
+ aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 );
+ if ( mType == "drawing.Line" )
+ {
+ double fDist = hypot( maRect.GetWidth(), maRect.GetHeight() );
+ maRect = ::tools::Rectangle( Point( aTextRefPoint.X, aTextRefPoint.Y ),
+ Point( static_cast<sal_Int32>( aTextRefPoint.X + fDist ), aTextRefPoint.Y - 1 ) );
+ ImplCreateTextShape( aPropOpt, aSolverContainer, false );
+ aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x60006 ); // Size Shape To Fit Text
+ if ( mnAngle < 0 )
+ mnAngle = ( 36000 + mnAngle ) % 36000;
+ if ( mnAngle )
+ ImplFlipBoundingBox( aPropOpt );
+ }
+ else
+ {
+ ImplCreateTextShape( aPropOpt, aSolverContainer, false );
+ if ( mnAngle < 0 )
+ mnAngle = ( 36000 + mnAngle ) % 36000;
+ else
+ mnAngle = ( 36000 - ( mnAngle % 36000 ) );
+
+ mnAngle *= 655;
+ mnAngle += 0x8000;
+ mnAngle &=~0xffff; // round nAngle to full grad
+ aPropOpt.AddOpt( ESCHER_Prop_Rotation, mnAngle );
+
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->SetGroupSnapRect( nGroupLevel, maRect );
+ // mpPptEscherEx->SetGroupLogicRect( nGroupLevel, maRect );
+ }
+ if ( !pClientTextBox )
+ pClientTextBox.reset(new SvMemoryStream( 0x200, 0x200 ));
+
+ SvMemoryStream aExtBu( 0x200, 0x200 );
+ ImplWriteTextStyleAtom( *pClientTextBox, EPP_TEXTTYPE_Other, 0, nullptr, aExtBu, &aPropOpt );
+
+ aPropOpt.CreateShapeProperties( mXShape );
+ aPropOpt.Commit( *mpStrm );
+ if ( GetCurrentGroupLevel() > 0 )
+ mpPptEscherEx->AddChildAnchor( maRect );
+ else
+ mpPptEscherEx->AddClientAnchor( maRect );
+
+ mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
+ .WriteUInt32( pClientTextBox->Tell() );
+
+ mpStrm->WriteBytes(pClientTextBox->GetData(), pClientTextBox->Tell());
+ pClientTextBox.reset();
+
+ mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
+
+ // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
+ // mpPptEscherEx->LeaveGroup();
+ }
+ }
+ ClearGroupTable(); // storing groups if any are still open, which should not be the case
+ nGroups = GetGroupsClosed();
+ for ( sal_uInt32 i = 0; i < nGroups; i++, mpPptEscherEx->LeaveGroup() ) ;
+ mnPagesWritten++;
+}
+
+struct CellBorder
+{
+ sal_Int32 mnPos; // specifies the distance to the top/left position of the table
+ table::BorderLine maCellBorder;
+
+ CellBorder() : mnPos ( 0 ) {};
+};
+
+bool PPTWriter::ImplCreateCellBorder( const CellBorder* pCellBorder, sal_Int32 nX1, sal_Int32 nY1, sal_Int32 nX2, sal_Int32 nY2)
+{
+ sal_Int32 nLineWidth = pCellBorder->maCellBorder.OuterLineWidth + pCellBorder->maCellBorder.InnerLineWidth;
+ if ( nLineWidth )
+ {
+ nLineWidth *= 2;
+ mnAngle = 0;
+ mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
+ EscherPropertyContainer aPropOptSp;
+
+ sal_uInt32 nId = mpPptEscherEx->GenerateShapeId();
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Line,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty | ShapeFlag::Child,
+ nId );
+ aPropOptSp.AddOpt( ESCHER_Prop_shapePath, ESCHER_ShapeComplex );
+ aPropOptSp.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0xa0008 );
+ aPropOptSp.AddOpt( ESCHER_Prop_fshadowObscured, 0x20000 );
+
+ sal_uInt32 nBorderColor = pCellBorder->maCellBorder.Color & 0xff00; // green
+ nBorderColor |= static_cast< sal_uInt8 >( pCellBorder->maCellBorder.Color ) << 16; // red
+ nBorderColor |= static_cast< sal_uInt8 >( pCellBorder->maCellBorder.Color >> 16 ); // blue
+ aPropOptSp.AddOpt( ESCHER_Prop_lineColor, nBorderColor );
+
+ aPropOptSp.AddOpt( ESCHER_Prop_lineWidth, nLineWidth * 360 );
+ aPropOptSp.AddOpt( ESCHER_Prop_fc3DLightFace, 0x80000 );
+ aPropOptSp.Commit( *mpStrm );
+ mpPptEscherEx->AddAtom( 16, ESCHER_ChildAnchor );
+ mpStrm ->WriteInt32( nX1 )
+ .WriteInt32( nY1 )
+ .WriteInt32( nX2 )
+ .WriteInt32( nY2 );
+ mpPptEscherEx->CloseContainer();
+ return true;
+ }
+ return false;
+}
+
+//get merged cell's width
+static sal_Int32 GetCellRight( sal_Int32 nColumn,
+ ::tools::Rectangle const & rect,
+ std::vector< std::pair< sal_Int32, sal_Int32 > >& aColumns,
+ uno::Reference< table::XMergeableCell > const & xCell )
+{
+ sal_Int32 nRight = aColumns[ nColumn ].first + aColumns[ nColumn ].second;
+ for ( sal_Int32 nColumnSpan = 1; nColumnSpan < xCell->getColumnSpan(); nColumnSpan++ )
+ {
+ sal_uInt32 nC = nColumnSpan + nColumn;
+ if ( nC < aColumns.size() )
+ nRight += aColumns[ nC ].second;
+ else
+ nRight = rect.Right();
+ }
+ return nRight;
+}
+//get merged cell's height
+static sal_Int32 GetCellBottom( sal_Int32 nRow,
+ ::tools::Rectangle const & rect,
+ std::vector< std::pair< sal_Int32, sal_Int32 > >& aRows,
+ uno::Reference< table::XMergeableCell > const & xCell )
+{
+ sal_Int32 nBottom = aRows[nRow].first + aRows[nRow].second;
+ for ( sal_Int32 nRowSpan = 1; nRowSpan < xCell->getRowSpan(); nRowSpan++ )
+ {
+ sal_uInt32 nR = nRowSpan + nRow;
+ if ( nR < aRows.size() )
+ nBottom += aRows[ nR ].second;
+ else
+ nBottom = rect.Bottom();
+ }
+ return nBottom;
+}
+
+void PPTWriter::WriteCString( SvStream& rSt, const OUString& rString, sal_uInt32 nInstance )
+{
+ sal_Int32 nLen = rString.getLength();
+ if ( nLen )
+ {
+ rSt.WriteUInt32( ( nInstance << 4 ) | ( EPP_CString << 16 ) )
+ .WriteUInt32( nLen << 1 );
+ for ( sal_Int32 i = 0; i < nLen; i++ )
+ rSt.WriteUInt16( rString[i] );
+ }
+}
+
+namespace {
+
+class ContainerGuard
+{
+private:
+ PptEscherEx* m_pPptEscherEx;
+public:
+ ContainerGuard(PptEscherEx* pPptEscherEx, sal_uInt16 nRecord)
+ : m_pPptEscherEx(pPptEscherEx)
+ {
+ m_pPptEscherEx->OpenContainer(nRecord);
+ }
+ ~ContainerGuard()
+ {
+ m_pPptEscherEx->CloseContainer();
+ }
+};
+
+}
+
+void PPTWriter::ImplCreateTable( uno::Reference< drawing::XShape > const & rXShape, EscherSolverContainer& aSolverContainer,
+ EscherPropertyContainer& aPropOpt )
+{
+ try
+ {
+ uno::Reference< table::XTable > xTable;
+ if ( mXPropSet->getPropertyValue( "Model" ) >>= xTable )
+ {
+ uno::Reference< table::XColumnRowRange > xColumnRowRange( xTable, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xColumns( xColumnRowRange->getColumns(), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xRows( xColumnRowRange->getRows(), uno::UNO_QUERY_THROW );
+ sal_uInt16 nRowCount = static_cast< sal_uInt16 >( xRows->getCount() );
+ sal_uInt16 nColumnCount = static_cast< sal_uInt16 >( xColumns->getCount() );
+
+ std::vector< std::pair< sal_Int32, sal_Int32 > > aColumns;
+ std::vector< std::pair< sal_Int32, sal_Int32 > > aRows;
+
+ awt::Point aPosition( MapPoint( rXShape->getPosition() ) );
+ sal_Int32 nPosition = aPosition.X;
+ for ( sal_Int32 x = 0; x < nColumnCount; x++ )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xColumns->getByIndex( x ), uno::UNO_QUERY_THROW );
+ awt::Size aS( 0, 0 );
+ xPropSet->getPropertyValue( "Width" ) >>= aS.Width;
+ awt::Size aM( MapSize( aS ) );
+ aColumns.emplace_back( nPosition, aM.Width );
+ nPosition += aM.Width;
+ if ( x == nColumnCount - 1 && nPosition != maRect.Right() )
+ maRect.SetRight( nPosition );
+ }
+
+ nPosition = aPosition.Y;
+ for ( sal_Int32 y = 0; y < nRowCount; y++ )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xRows->getByIndex( y ), uno::UNO_QUERY_THROW );
+ awt::Size aS( 0, 0 );
+ xPropSet->getPropertyValue( "Height" ) >>= aS.Height;
+ awt::Size aM( MapSize( aS ) );
+ aRows.emplace_back( nPosition, aM.Height );
+ nPosition += aM.Height;
+ if ( y == nRowCount - 1 && nPosition != maRect.Bottom())
+ maRect.SetBottom( nPosition );
+ }
+ std::optional<ContainerGuard> xSpgrContainer(std::in_place, mpPptEscherEx.get(), ESCHER_SpgrContainer);
+ std::optional<ContainerGuard> xSpContainer(std::in_place, mpPptEscherEx.get(), ESCHER_SpContainer);
+ mpPptEscherEx->AddAtom( 16, ESCHER_Spgr, 1 );
+ mpStrm ->WriteInt32( maRect.Left() ) // Bounding box for the grouped shapes to which they are attached
+ .WriteInt32( maRect.Top() )
+ .WriteInt32( maRect.Right() )
+ .WriteInt32( maRect.Bottom() );
+
+ sal_uInt32 nShapeId = mpPptEscherEx->GenerateShapeId();
+ mpPptEscherEx->AddShape( ESCHER_ShpInst_Min, ShapeFlag::HaveAnchor | ShapeFlag::Group, nShapeId );
+ // TODO: check flags, comment does not match code // Flags: Group | Patriarch
+ aSolverContainer.AddShape( rXShape, nShapeId );
+ EscherPropertyContainer aPropOpt2;
+
+ SvMemoryStream aMemStrm;
+ aMemStrm.WriteUInt16( nRowCount )
+ .WriteUInt16( nRowCount )
+ .WriteUInt16( 4 );
+
+ for( const auto& rRow : aRows )
+ aMemStrm.WriteInt32( rRow.second );
+
+ aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x1000100 );
+ aPropOpt2.AddOpt( ESCHER_Prop_tableProperties, 1 );
+ aPropOpt2.AddOpt(ESCHER_Prop_tableRowProperties, true, 0, aMemStrm);
+ aPropOpt.CreateShapeProperties( rXShape );
+ aPropOpt.Commit( *mpStrm );
+ aPropOpt2.Commit( *mpStrm, 3, ESCHER_UDefProp );
+ if ( GetCurrentGroupLevel() > 0 )
+ mpPptEscherEx->AddChildAnchor( maRect );
+ else
+ mpPptEscherEx->AddClientAnchor( maRect );
+ xSpContainer.reset(); //ESCHER_SpContainer
+
+ uno::Reference< table::XCellRange > xCellRange( xTable, uno::UNO_QUERY_THROW );
+ for( sal_Int32 nRow = 0; nRow < xRows->getCount(); nRow++ )
+ {
+ for( sal_Int32 nColumn = 0; nColumn < xColumns->getCount(); nColumn++ )
+ {
+ uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn, nRow ), uno::UNO_QUERY_THROW );
+ if ( !xCell->isMerged() )
+ {
+ sal_Int32 nLeft = aColumns[ nColumn ].first;
+ sal_Int32 nTop = aRows[ nRow ].first;
+ sal_Int32 nRight = GetCellRight( nColumn, maRect,aColumns,xCell );
+ sal_Int32 nBottom = GetCellBottom( nRow, maRect,aRows,xCell );
+
+ mbFontIndependentLineSpacing = false;
+ mXPropSet.set( xCell, uno::UNO_QUERY_THROW );
+ mXText.set( xCell, uno::UNO_QUERY_THROW );
+ mnTextSize = mXText->getString().getLength();
+
+ css::uno::Any aAny;
+ if ( GetPropertyValue( aAny, mXPropSet, "FontIndependentLineSpacing", true ) )
+ aAny >>= mbFontIndependentLineSpacing;
+
+ EscherPropertyContainer aPropOptSp;
+ std::optional<ContainerGuard> xCellContainer(std::in_place, mpPptEscherEx.get(), ESCHER_SpContainer);
+ ImplCreateShape( ESCHER_ShpInst_Rectangle,
+ ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty | ShapeFlag::Child,
+ aSolverContainer );
+ aPropOptSp.CreateFillProperties( mXPropSet, true );
+ aPropOptSp.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 );
+ mnTxId += 0x60;
+ aPropOptSp.CreateTextProperties( mXPropSet, mnTxId );
+ aPropOptSp.AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapSquare );
+
+ SvMemoryStream aClientTextBox( 0x200, 0x200 );
+ SvMemoryStream aExtBu( 0x200, 0x200 );
+
+ ImplWriteTextStyleAtom( aClientTextBox, EPP_TEXTTYPE_Other, 0, nullptr, aExtBu, &aPropOptSp );
+
+ // need write client data for extend bullet
+ if ( aExtBu.Tell() )
+ {
+ SvMemoryStream aClientData( 0x200, 0x200 );
+ ImplProgTagContainer( &aClientData, &aExtBu );
+ mpStrm->WriteUInt32( ( ESCHER_ClientData << 16 ) | 0xf )
+ .WriteUInt32( aClientData.Tell() );
+
+ mpStrm->WriteBytes(aClientData.GetData(), aClientData.Tell());
+ }
+
+ aPropOptSp.Commit( *mpStrm );
+ mpPptEscherEx->AddAtom( 16, ESCHER_ChildAnchor );
+ mpStrm ->WriteInt32( nLeft )
+ .WriteInt32( nTop )
+ .WriteInt32( nRight )
+ .WriteInt32( nBottom );
+
+ mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
+ .WriteUInt32( aClientTextBox.Tell() );
+
+ mpStrm->WriteBytes(aClientTextBox.GetData(), aClientTextBox.Tell());
+ xCellContainer.reset();
+ }
+ }
+ }
+
+ // creating horz lines
+ for( sal_Int32 nLine = 0; nLine < ( xRows->getCount() + 1 ); nLine++ )
+ {
+ for( sal_Int32 nColumn = 0; nColumn < xColumns->getCount(); nColumn++ )
+ {
+ CellBorder aCellBorder;
+ aCellBorder.mnPos = aColumns[ nColumn ].first;
+ bool bTop = false;
+ //write nLine*nColumn cell's top border
+ if ( nLine < xRows->getCount() )
+ { // top border
+ uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn, nLine ), uno::UNO_QUERY_THROW );
+ if ( !xCell->isMerged() )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet2( xCell, uno::UNO_QUERY_THROW );
+ table::BorderLine aBorderLine;
+ if ( xPropSet2->getPropertyValue( "TopBorder" ) >>= aBorderLine )
+ aCellBorder.maCellBorder = aBorderLine;
+ sal_Int32 nRight = GetCellRight( nColumn, maRect,aColumns,xCell );
+ bTop = ImplCreateCellBorder( &aCellBorder, aCellBorder.mnPos,
+ aRows[ nLine ].first, nRight, aRows[ nLine ].first );
+ }
+ }
+
+ //if nLine*nColumn cell's top border is empty, check (nLine-1)*nColumn cell's bottom border
+ //and write the last row's bottom border
+ if (( nLine && !bTop ) || (nLine == xRows->getCount()))
+ { // bottom border
+ sal_Int32 nRow = nLine;
+
+ while( nRow )
+ { //find last no merged cell
+ uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn, nRow - 1 ), uno::UNO_QUERY_THROW );
+ if ( !xCell->isMerged() )
+ {
+ sal_Int32 nRight = GetCellRight( nColumn, maRect,aColumns,xCell );
+ sal_Int32 nBottom = GetCellBottom( nRow - 1, maRect,aRows,xCell );
+ if ( nBottom == ( aRows[ nLine-1 ].first + aRows[ nLine-1 ].second ) )
+ {
+ uno::Reference< table::XMergeableCell > xCellOwn( xCellRange->getCellByPosition( nColumn, nRow - 1 ), uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xPropSet2( xCellOwn, uno::UNO_QUERY_THROW );
+ table::BorderLine aBorderLine;
+ if ( xPropSet2->getPropertyValue( "BottomBorder" ) >>= aBorderLine )
+ aCellBorder.maCellBorder = aBorderLine;
+ ImplCreateCellBorder( &aCellBorder, aCellBorder.mnPos,
+ nBottom, nRight, nBottom);
+ }
+ nRow=0;
+ }
+ else
+ nRow--;
+ }
+ }
+ }
+ }
+
+ // creating vertical lines
+ for( sal_Int32 nLine = 0; nLine < ( xColumns->getCount() + 1 ); nLine++ )
+ {
+ for( sal_Int32 nRow = 0; nRow < xRows->getCount(); nRow++ )
+ {
+
+ CellBorder aCellBorder;
+ aCellBorder.mnPos = aRows[ nRow].first;
+ bool bLeft = false;
+ if ( nLine < xColumns->getCount() )
+ { // left border
+ uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nLine, nRow ), uno::UNO_QUERY_THROW );
+ if (!xCell->isMerged() )
+ {
+ uno::Reference< beans::XPropertySet > xCellSet( xCell, uno::UNO_QUERY_THROW );
+ table::BorderLine aBorderLine;
+ if ( xCellSet->getPropertyValue( "LeftBorder" ) >>= aBorderLine )
+ aCellBorder.maCellBorder = aBorderLine;
+ sal_Int32 nBottom = GetCellBottom( nRow, maRect, aRows,xCell );
+ bLeft = ImplCreateCellBorder( &aCellBorder, aColumns[nLine].first, aCellBorder.mnPos,
+ aColumns[nLine].first, nBottom );
+ }
+ }
+ if ( ( nLine && !bLeft )||(nLine == xColumns->getCount()))
+ { // right border
+ sal_Int32 nColumn = nLine;
+ while ( nColumn )
+ {
+ uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn - 1, nRow ), uno::UNO_QUERY_THROW );
+ if (!xCell->isMerged() )
+ {
+ sal_Int32 nRight = GetCellRight( nColumn-1, maRect, aColumns,xCell );
+ sal_Int32 nBottom = GetCellBottom( nRow, maRect, aRows, xCell );
+ if ( nRight == (aColumns[nLine-1].first + aColumns[nLine-1].second) )
+ {
+ uno::Reference< table::XMergeableCell > xCellOwn( xCellRange->getCellByPosition( nColumn - 1, nRow ), uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xCellSet( xCellOwn, uno::UNO_QUERY_THROW );
+ table::BorderLine aBorderLine;
+ if ( xCellSet->getPropertyValue( "RightBorder" ) >>= aBorderLine )
+ aCellBorder.maCellBorder = aBorderLine;
+ ImplCreateCellBorder( &aCellBorder, nRight, aCellBorder.mnPos,
+ nRight, nBottom );
+ }
+ nColumn = 0;
+ }
+ else
+ nColumn --;
+ }
+ }
+ }
+ }
+
+ xSpgrContainer.reset(); //ESCHER_SpgrContainer
+ }
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+void TextObjBinary::Write( SvStream* pStrm )
+{
+ sal_uInt32 nSize, nPos = pStrm->Tell();
+ pStrm->WriteUInt32( EPP_TextCharsAtom << 16 ).WriteUInt32( 0 );
+ for ( sal_uInt32 i = 0; i < ParagraphCount(); ++i )
+ GetParagraph(i)->Write( pStrm );
+ nSize = pStrm->Tell() - nPos;
+ pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
+ pStrm->WriteUInt32( nSize - 8 );
+ pStrm->SeekRel( nSize - 8 );
+}
+
+void TextObjBinary::WriteTextSpecInfo( SvStream* pStrm )
+{
+ sal_uInt32 nCharactersLeft( Count() );
+ if ( nCharactersLeft < 1 )
+ return;
+
+ EscherExAtom aAnimationInfoAtom( *pStrm, EPP_TextSpecInfoAtom, 0, 0 );
+ for ( sal_uInt32 i = 0; nCharactersLeft && i < ParagraphCount(); ++i )
+ {
+ ParagraphObj* pPtr = GetParagraph(i);
+ for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = pPtr->begin(); nCharactersLeft && it != pPtr->end(); ++it )
+ {
+ const PortionObj& rPortion = **it;
+ sal_Int32 nPortionSize = rPortion.mnTextSize >= nCharactersLeft ? nCharactersLeft : rPortion.mnTextSize;
+ sal_Int32 const nFlags = 7;
+ nCharactersLeft -= nPortionSize;
+ pStrm ->WriteUInt32( nPortionSize )
+ .WriteInt32( nFlags )
+ .WriteInt16( 1 ) // spellinfo -> needs rechecking
+ .WriteInt16( static_cast<sal_uInt16>(LanguageTag( rPortion.meCharLocale ).makeFallback().getLanguageType()) )
+ .WriteInt16( 0 ); // alt language
+ }
+ }
+ if ( nCharactersLeft )
+ pStrm->WriteUInt32( nCharactersLeft ).WriteInt32( 1 ).WriteInt16( 1 );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/escherex.cxx b/sd/source/filter/eppt/escherex.cxx
new file mode 100644
index 000000000..5032c2721
--- /dev/null
+++ b/sd/source/filter/eppt/escherex.cxx
@@ -0,0 +1,266 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "escherex.hxx"
+
+PptEscherEx::PptEscherEx( SvStream& rOutStrm, const OUString& rBaseURI ) :
+ EscherEx( std::make_shared<EscherExGlobal>( ), &rOutStrm )
+{
+ mxGlobal->SetBaseURI( rBaseURI );
+ mnCurrentDg = 0;
+}
+
+sal_uInt32 PptEscherEx::DrawingGroupContainerSize()
+{
+ return ImplDggContainerSize() + 8;
+}
+
+void PptEscherEx::WriteDrawingGroupContainer( SvStream& rSt )
+{
+ sal_uInt32 nSize = DrawingGroupContainerSize();
+ rSt.WriteUInt32( 0xf | ( 1035 << 16 ) ) // EPP_PPDrawingGroup
+ .WriteUInt32( nSize - 8 );
+
+ ImplWriteDggContainer( rSt );
+}
+
+sal_uInt32 PptEscherEx::ImplDggContainerSize()
+{
+ sal_uInt32 nSize;
+
+ nSize = mxGlobal->GetDggAtomSize();
+ nSize += mxGlobal->GetBlibStoreContainerSize();
+ nSize += ImplOptAtomSize();
+ nSize += ImplSplitMenuColorsAtomSize();
+
+ return nSize + 8;
+}
+
+void PptEscherEx::ImplWriteDggContainer( SvStream& rSt )
+{
+ sal_uInt32 nSize = ImplDggContainerSize();
+ if ( nSize )
+ {
+ rSt.WriteUInt32( 0xf | ( ESCHER_DggContainer << 16 ) )
+ .WriteUInt32( nSize - 8 );
+
+ mxGlobal->SetDggContainer();
+ mxGlobal->WriteDggAtom( rSt );
+ mxGlobal->WriteBlibStoreContainer( rSt );
+ ImplWriteOptAtom( rSt );
+ ImplWriteSplitMenuColorsAtom( rSt );
+ }
+}
+
+#define ESCHER_OPT_COUNT 6
+
+sal_uInt32 PptEscherEx::ImplOptAtomSize()
+{
+ sal_uInt32 nSize = 0;
+ if ( ESCHER_OPT_COUNT != 0 )
+ nSize = ( ESCHER_OPT_COUNT * 6 ) + 8;
+ return nSize;
+}
+
+void PptEscherEx::ImplWriteOptAtom( SvStream& rSt )
+{
+ sal_uInt32 nSize = ImplOptAtomSize();
+ if ( nSize )
+ {
+ rSt.WriteUInt32( ( ESCHER_OPT << 16 ) | ( ESCHER_OPT_COUNT << 4 ) | 0x3 )
+ .WriteUInt32( nSize - 8 )
+ .WriteUInt16( ESCHER_Prop_fillColor ) .WriteUInt32( 0xffb800 )
+ .WriteUInt16( ESCHER_Prop_fillBackColor ) .WriteUInt32( 0 )
+ .WriteUInt16( ESCHER_Prop_fNoFillHitTest ) .WriteUInt32( 0x00100010 )
+ .WriteUInt16( ESCHER_Prop_lineColor ) .WriteUInt32( 0x8000001 )
+ .WriteUInt16( ESCHER_Prop_fNoLineDrawDash ) .WriteUInt32( 0x00080008 )
+ .WriteUInt16( ESCHER_Prop_shadowColor ) .WriteUInt32( 0x8000002 );
+ }
+}
+
+#define ESCHER_SPLIT_MENU_COLORS_COUNT 4
+
+sal_uInt32 PptEscherEx::ImplSplitMenuColorsAtomSize()
+{
+ sal_uInt32 nSize = 0;
+ if ( ESCHER_SPLIT_MENU_COLORS_COUNT != 0 )
+ nSize = ( ESCHER_SPLIT_MENU_COLORS_COUNT << 2 ) + 8;
+ return nSize;
+}
+
+void PptEscherEx::ImplWriteSplitMenuColorsAtom( SvStream& rSt )
+{
+ sal_uInt32 nSize = ImplSplitMenuColorsAtomSize();
+ if ( nSize )
+ {
+ rSt.WriteUInt32( ( ESCHER_SplitMenuColors << 16 ) | ( ESCHER_SPLIT_MENU_COLORS_COUNT << 4 ) )
+ .WriteUInt32( nSize - 8 )
+ .WriteUInt32( 0x08000004 )
+ .WriteUInt32( 0x08000001 )
+ .WriteUInt32( 0x08000002 )
+ .WriteUInt32( 0x100000f7 );
+ }
+
+}
+
+PptEscherEx::~PptEscherEx()
+{
+}
+
+void PptEscherEx::OpenContainer( sal_uInt16 n_EscherContainer, int nRecInstance )
+{
+ mpOutStrm->WriteUInt16( ( nRecInstance << 4 ) | 0xf ).WriteUInt16( n_EscherContainer ).WriteUInt32( 0 );
+ mOffsets.push_back( mpOutStrm->Tell() - 4 );
+ mRecTypes.push_back( n_EscherContainer );
+
+ switch( n_EscherContainer )
+ {
+ case ESCHER_DgContainer :
+ {
+ if ( !mbEscherDg )
+ {
+ mbEscherDg = true;
+ mnCurrentDg = mxGlobal->GenerateDrawingId();
+ AddAtom( 8, ESCHER_Dg, 0, mnCurrentDg );
+ PtReplaceOrInsert( ESCHER_Persist_Dg | mnCurrentDg, mpOutStrm->Tell() );
+ mpOutStrm->WriteUInt32( 0 ) // The number of shapes in this drawing
+ .WriteUInt32( 0 ); // The last MSOSPID given to an SP in this DG
+ }
+ }
+ break;
+
+ case ESCHER_SpgrContainer :
+ {
+ if ( mbEscherDg )
+ {
+ mbEscherSpgr = true;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void PptEscherEx::CloseContainer()
+{
+ /* SJ: #Issue 26747#
+ not creating group objects with a depth higher than 16, because then
+ PPT is having a big performance problem when starting a slide show
+ */
+ if ( ( mRecTypes.back() == ESCHER_SpgrContainer ) && ( mnGroupLevel >= 12 ) )
+ return;
+
+ sal_uInt32 nSize, nPos = mpOutStrm->Tell();
+ nSize = ( nPos - mOffsets.back() ) - 4;
+ mpOutStrm->Seek( mOffsets.back() );
+ mpOutStrm->WriteUInt32( nSize );
+
+ switch( mRecTypes.back() )
+ {
+ case ESCHER_DgContainer :
+ {
+ if ( mbEscherDg )
+ {
+ mbEscherDg = false;
+ if ( DoSeek( ESCHER_Persist_Dg | mnCurrentDg ) )
+ mpOutStrm->WriteUInt32( mxGlobal->GetDrawingShapeCount( mnCurrentDg ) ).WriteUInt32( mxGlobal->GetLastShapeId( mnCurrentDg ) );
+ }
+ }
+ break;
+
+ case ESCHER_SpgrContainer :
+ {
+ if ( mbEscherSpgr )
+ {
+ mbEscherSpgr = false;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ mOffsets.pop_back();
+ mRecTypes.pop_back();
+ mpOutStrm->Seek( nPos );
+}
+
+sal_uInt32 PptEscherEx::EnterGroup( ::tools::Rectangle const * pBoundRect, SvMemoryStream* pClientData )
+{
+ sal_uInt32 nShapeId = 0;
+ /* SJ: #Issue 26747#
+ not creating group objects with a depth higher than 16, because then
+ PPT is having a big performance problem when starting a slide show
+ */
+ if ( mnGroupLevel < 12 )
+ {
+ ::tools::Rectangle aRect;
+ if ( pBoundRect )
+ aRect = *pBoundRect;
+
+ OpenContainer( ESCHER_SpgrContainer );
+ OpenContainer( ESCHER_SpContainer );
+ AddAtom( 16, ESCHER_Spgr, 1 );
+ PtReplaceOrInsert( ESCHER_Persist_Grouping_Snap | mnGroupLevel, mpOutStrm->Tell() );
+ mpOutStrm ->WriteInt32( aRect.Left() ) // bounding box for the grouped shapes to which they are attached
+ .WriteInt32( aRect.Top() )
+ .WriteInt32( aRect.Right() )
+ .WriteInt32( aRect.Bottom() );
+
+ nShapeId = GenerateShapeId();
+ if ( !mnGroupLevel )
+ AddShape( ESCHER_ShpInst_Min, ShapeFlag::Group | ShapeFlag::Patriarch, nShapeId );
+ else
+ {
+ AddShape( ESCHER_ShpInst_Min, ShapeFlag::HaveAnchor | ShapeFlag::Group, nShapeId );
+ if ( mnGroupLevel == 1 )
+ {
+ AddAtom( 8, ESCHER_ClientAnchor );
+ PtReplaceOrInsert( ESCHER_Persist_Grouping_Logic | mnGroupLevel, mpOutStrm->Tell() );
+ mpOutStrm->WriteInt16( aRect.Top() ).WriteInt16( aRect.Left() ).WriteInt16( aRect.Right() ).WriteInt16( aRect.Bottom() );
+ }
+ else
+ {
+ AddAtom( 16, ESCHER_ChildAnchor );
+ PtReplaceOrInsert( ESCHER_Persist_Grouping_Snap | mnGroupLevel, mpOutStrm->Tell() );
+ mpOutStrm ->WriteInt32( aRect.Left() )
+ .WriteInt32( aRect.Top() )
+ .WriteInt32( aRect.Right() )
+ .WriteInt32( aRect.Bottom() );
+ }
+ }
+ if ( pClientData )
+ {
+ sal_uInt32 nSize = pClientData->TellEnd();
+ if ( nSize )
+ {
+ mpOutStrm->WriteUInt32( ( ESCHER_ClientData << 16 ) | 0xf )
+ .WriteUInt32( nSize );
+ mpOutStrm->WriteBytes(pClientData->GetData(), nSize);
+ }
+ }
+ CloseContainer(); // ESCHER_SpContainer
+ }
+ mnGroupLevel++;
+ return nShapeId;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/escherex.hxx b/sd/source/filter/eppt/escherex.hxx
new file mode 100644
index 000000000..8f64419f4
--- /dev/null
+++ b/sd/source/filter/eppt/escherex.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+#include <filter/msfilter/escherex.hxx>
+
+/// Values for the sal_uLong in PPT_PST_TextHeaderAtom.
+enum PPT_TextHeader
+{
+ PPTTH_TITLE,
+ PPTTH_BODY,
+ PPTTH_NOTES,
+ PPTTH_NOTUSED,
+ PPTTH_OTHER, ///< Text in a Shape
+ PPTTH_CENTERBODY, ///< Subtitle in Title-Slide
+ PPTTH_CENTERTITLE, ///< Title in Title-Slide
+ PPTTH_HALFBODY, ///< Body in two-column slide
+ PPTTH_QUARTERBODY ///< Body in four-body slide
+};
+
+class PptEscherEx : public EscherEx
+{
+ sal_uInt32 ImplDggContainerSize();
+ void ImplWriteDggContainer( SvStream& rSt );
+
+ static sal_uInt32 ImplOptAtomSize();
+ static void ImplWriteOptAtom( SvStream& rSt );
+
+ static sal_uInt32 ImplSplitMenuColorsAtomSize();
+ static void ImplWriteSplitMenuColorsAtom( SvStream& rSt );
+
+ public:
+
+ PptEscherEx( SvStream& rOut, const OUString& );
+ virtual ~PptEscherEx() override;
+
+ void OpenContainer( sal_uInt16 n_EscherContainer, int nRecInstance = 0 ) override;
+ void CloseContainer() override;
+
+ sal_uInt32 EnterGroup( ::tools::Rectangle const * pBoundRect, SvMemoryStream* pClientData );
+
+ sal_uInt32 DrawingGroupContainerSize();
+ void WriteDrawingGroupContainer( SvStream& rSt );
+
+ using EscherEx::EnterGroup;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/grouptable.hxx b/sd/source/filter/eppt/grouptable.hxx
new file mode 100644
index 000000000..885f95741
--- /dev/null
+++ b/sd/source/filter/eppt/grouptable.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <memory>
+#include <vector>
+
+struct GroupEntry
+{
+ sal_uInt32 mnCurrentPos;
+ sal_uInt32 mnCount;
+ css::uno::Reference< css::container::XIndexAccess > mXIndexAccess;
+
+ explicit GroupEntry( css::uno::Reference< css::container::XIndexAccess > const & rIndex )
+ : mnCurrentPos(0),
+ mnCount(rIndex->getCount()),
+ mXIndexAccess(rIndex)
+ {
+ };
+
+ explicit GroupEntry( sal_uInt32 nCount )
+ : mnCurrentPos(0),
+ mnCount(nCount)
+ {
+ };
+};
+
+class GroupTable
+{
+ protected:
+
+ sal_uInt32 mnIndex;
+ sal_uInt32 mnGroupsClosed;
+ std::vector<GroupEntry> mvGroupEntry;
+
+ public:
+
+ sal_uInt32 GetCurrentGroupIndex() const { return mnIndex; };
+ sal_Int32 GetCurrentGroupLevel() const { return mvGroupEntry.size() - 1; };
+ const css::uno::Reference< css::container::XIndexAccess > &
+ GetCurrentGroupAccess() const { return mvGroupEntry.back().mXIndexAccess; };
+ sal_uInt32 GetGroupsClosed();
+ void ResetGroupTable( sal_uInt32 nCount );
+ void ClearGroupTable();
+ bool EnterGroup( css::uno::Reference< css::container::XIndexAccess > const & rIndex );
+ bool GetNextGroupEntry();
+ GroupTable();
+ ~GroupTable();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptexanimations.cxx b/sd/source/filter/eppt/pptexanimations.cxx
new file mode 100644
index 000000000..99fe0b443
--- /dev/null
+++ b/sd/source/filter/eppt/pptexanimations.cxx
@@ -0,0 +1,2150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
+#include <com/sun/star/animations/AnimationFill.hpp>
+#include <com/sun/star/animations/AnimationRestart.hpp>
+#include <com/sun/star/animations/Timing.hpp>
+#include <com/sun/star/animations/Event.hpp>
+#include <com/sun/star/animations/AnimationEndSync.hpp>
+#include <com/sun/star/animations/EventTrigger.hpp>
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/presentation/EffectPresetClass.hpp>
+#include <com/sun/star/animations/AnimationNodeType.hpp>
+#include <com/sun/star/animations/AnimationTransformType.hpp>
+#include <com/sun/star/animations/AnimationCalcMode.hpp>
+#include <com/sun/star/util/XCloneable.hpp>
+#include <com/sun/star/animations/AnimationAdditiveMode.hpp>
+#include <com/sun/star/animations/XAnimateSet.hpp>
+#include <com/sun/star/animations/XAudio.hpp>
+#include <com/sun/star/animations/XTransitionFilter.hpp>
+#include <com/sun/star/animations/XAnimateColor.hpp>
+#include <com/sun/star/animations/XAnimateMotion.hpp>
+#include <com/sun/star/animations/XAnimateTransform.hpp>
+#include <com/sun/star/animations/ValuePair.hpp>
+#include <com/sun/star/animations/AnimationColorSpace.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/text/XSimpleText.hpp>
+#include <com/sun/star/animations/XIterateContainer.hpp>
+#include <com/sun/star/presentation/TextAnimationType.hpp>
+
+#include <oox/ppt/pptfilterhelpers.hxx>
+#include "pptexanimations.hxx"
+#include "pptexsoundcollection.hxx"
+#include "../ppt/pptanimations.hxx"
+#include <filter/msfilter/escherex.hxx>
+#include <osl/diagnose.h>
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <o3tl/string_view.hxx>
+
+#include <algorithm>
+
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::util::XCloneable;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::beans::NamedValue;
+using ::com::sun::star::container::XEnumerationAccess;
+using ::com::sun::star::container::XEnumeration;
+
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::presentation;
+
+namespace ppt
+{
+
+static void ImplTranslateAttribute( OUString& rString, const TranslateMode eTranslateMode )
+{
+ if ( eTranslateMode == TRANSLATE_NONE )
+ return;
+
+ if ( ( eTranslateMode & TRANSLATE_VALUE ) || ( eTranslateMode & TRANSLATE_ATTRIBUTE ) )
+ {
+ const oox::ppt::ImplAttributeNameConversion* p = oox::ppt::getAttributeConversionList();
+ while( p->mpAPIName )
+ {
+ if( rString.equalsAscii( p->mpAPIName ) )
+ break;
+ p++;
+ }
+ if( p->mpMSName )
+ {
+ if ( eTranslateMode & TRANSLATE_VALUE )
+ {
+ rString = "#";
+ rString += OUString::createFromAscii( p->mpMSName );
+ }
+ else
+ rString = OUString::createFromAscii( p->mpMSName );
+ }
+ }
+ else if ( eTranslateMode & TRANSLATE_MEASURE )
+ {
+ const char* pDest[] = { "#ppt_x", "#ppt_y", "#ppt_w", "#ppt_h", nullptr };
+ const char* pSource[] = { "x", "y", "width", "height", nullptr };
+ sal_Int32 nIndex = 0;
+
+ const char** ps = pSource;
+ const char** pd = pDest;
+
+ while( *ps )
+ {
+ const OUString aSearch( OUString::createFromAscii( *ps ) );
+ while( (nIndex = rString.indexOf( aSearch, nIndex )) != -1 )
+ {
+ sal_Int32 nLength = aSearch.getLength();
+ if( nIndex && ( rString[nIndex-1] == '#' ) )
+ {
+ nIndex--;
+ nLength++;
+ }
+
+ const OUString aNew( OUString::createFromAscii( *pd ) );
+ rString = rString.replaceAt( nIndex, nLength, aNew );
+ nIndex += aNew.getLength();
+ }
+ ps++;
+ pd++;
+ }
+ }
+}
+
+sal_uInt32 AnimationExporter::TranslatePresetSubType( const sal_uInt32 nPresetClass, const sal_uInt32 nPresetId, std::u16string_view rPresetSubType )
+{
+ sal_uInt32 nPresetSubType = 0;
+ bool bTranslated = false;
+
+ if ( ( nPresetClass == sal_uInt32(EffectPresetClass::ENTRANCE) ) || ( nPresetClass == sal_uInt32(EffectPresetClass::EXIT) ) )
+ {
+ if ( nPresetId != 21 )
+ {
+ switch( nPresetId )
+ {
+ case 5 :
+ {
+ if ( rPresetSubType == u"downward" )
+ {
+ nPresetSubType = 5;
+ bTranslated = true;
+ }
+ else if ( rPresetSubType == u"across" )
+ {
+ nPresetSubType = 10;
+ bTranslated = true;
+ }
+ }
+ break;
+ case 17 :
+ {
+ if ( rPresetSubType == u"across" )
+ {
+ nPresetSubType = 10;
+ bTranslated = true;
+ }
+ }
+ break;
+ case 18 :
+ {
+ if ( rPresetSubType == u"right-to-top" )
+ {
+ nPresetSubType = 3;
+ bTranslated = true;
+ }
+ else if ( rPresetSubType == u"right-to-bottom" )
+ {
+ nPresetSubType = 6;
+ bTranslated = true;
+ }
+ else if ( rPresetSubType == u"left-to-top" )
+ {
+ nPresetSubType = 9;
+ bTranslated = true;
+ }
+ else if ( rPresetSubType == u"left-to-bottom" )
+ {
+ nPresetSubType = 12;
+ bTranslated = true;
+ }
+ }
+ break;
+ }
+ }
+ if ( !bTranslated )
+ {
+ const oox::ppt::convert_subtype* p = oox::ppt::convert_subtype::getList();
+ while( p->mpStrSubType )
+ {
+ if ( o3tl::equalsAscii( rPresetSubType, p->mpStrSubType ) )
+ {
+ nPresetSubType = p->mnID;
+ bTranslated = true;
+ break;
+ }
+ p++;
+ }
+ }
+ }
+ if ( !bTranslated )
+ nPresetSubType = o3tl::toUInt32(rPresetSubType);
+ return nPresetSubType;
+}
+
+const char* AnimationExporter::FindTransitionName( const sal_Int16 nType, const sal_Int16 nSubType, const bool bDirection )
+{
+ const char* pRet = nullptr;
+ int nFit = 0;
+
+ const oox::ppt::transition* p = oox::ppt::transition::getList();
+ while( p->mpName )
+ {
+ int nF = 0;
+ if ( nType == p->mnType )
+ nF += 4;
+ if ( nSubType == p->mnSubType )
+ nF += 2;
+ if ( bDirection == p->mbDirection )
+ nF += 1;
+ if ( nF > nFit )
+ {
+ pRet = p->mpName;
+ nFit = nF;
+ }
+ if ( nFit == 7 ) // maximum
+ break;
+ p++;
+ }
+ return pRet;
+}
+
+SvStream& WriteAnimationNode(SvStream& rOut, AnimationNode const & rNode )
+{
+ rOut.WriteInt32( rNode.mnU1 );
+ rOut.WriteInt32( rNode.mnRestart );
+ rOut.WriteInt32( rNode.mnGroupType );
+ rOut.WriteInt32( rNode.mnFill );
+ rOut.WriteInt32( rNode.mnU3 );
+ rOut.WriteInt32( rNode.mnU4 );
+ rOut.WriteInt32( rNode.mnDuration );
+ rOut.WriteInt32( rNode.mnNodeType );
+
+ return rOut;
+}
+
+AnimationExporter::AnimationExporter( const EscherSolverContainer& rSolverContainer, ppt::ExSoundCollection& rExSoundCollection ) :
+ mrSolverContainer ( rSolverContainer ),
+ mrExSoundCollection ( rExSoundCollection ),
+ mnCurrentGroup(0)
+{
+}
+
+sal_Int16 AnimationExporter::GetFillMode( const Reference< XAnimationNode >& xNode, const sal_Int16 nFillDefault )
+{
+ sal_Int16 nFill = xNode->getFill();
+ //#i119699 <Animation> The animation effect "Emphasis->FlashBulb" play incorrectly in Aoo saves a .ppt to another .ppt and plays the saved one.
+ //#i119740 <Animation> The animation effect "Entrance->Flash Once" fails to play in Aoo while Aoo saves a .ppt to another .ppt and plays the saved one.
+ if ((xNode->getType() == AnimationNodeType::ANIMATE)
+ ||(xNode->getType() == AnimationNodeType::SET)
+ ||(xNode->getType() == AnimationNodeType::TRANSITIONFILTER))
+ {
+ if ( nFill == AnimationFill::DEFAULT )
+ return nFill;
+ }
+
+ if ( nFill == AnimationFill::DEFAULT )
+ {
+ nFill = nFillDefault;
+ }
+ if( nFill == AnimationFill::AUTO )
+ {
+ nFill = AnimationFill::REMOVE;
+ bool bIsIndefiniteTiming = true;
+ Any aAny = xNode->getDuration();
+ if( aAny.hasValue() )
+ {
+ Timing eTiming;
+ if( aAny >>= eTiming )
+ bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
+ }
+ if ( bIsIndefiniteTiming )
+ {
+ aAny = xNode->getEnd();
+ if( aAny.hasValue() )
+ {
+ Timing eTiming;
+ if( aAny >>= eTiming )
+ bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
+ }
+ if ( bIsIndefiniteTiming )
+ {
+ if ( !xNode->getRepeatCount().hasValue() )
+ {
+ aAny = xNode->getRepeatDuration();
+ if( aAny.hasValue() )
+ {
+ Timing eTiming;
+ if( aAny >>= eTiming )
+ bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
+ }
+ if ( bIsIndefiniteTiming )
+ nFill = AnimationFill::FREEZE;
+ }
+ }
+ }
+ }
+ return nFill;
+}
+
+void AnimationExporter::doexport( const Reference< XDrawPage >& xPage, SvStream& rStrm )
+{
+ Reference< XAnimationNodeSupplier > xNodeSupplier( xPage, UNO_QUERY );
+ if( xNodeSupplier.is() )
+ {
+ const Reference< XAnimationNode > xRootNode( xNodeSupplier->getAnimationNode() );
+ if( xRootNode.is() )
+ {
+ processAfterEffectNodes( xRootNode );
+ exportNode( rStrm, xRootNode, DFF_msofbtAnimGroup, 1, 0, false, AnimationFill::AUTO );
+ }
+ }
+}
+
+void AnimationExporter::processAfterEffectNodes( const Reference< XAnimationNode >& xRootNode )
+{
+ try
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW );
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
+
+ Reference< XEnumerationAccess > xEnumerationAccess2( xNode, UNO_QUERY );
+ if ( xEnumerationAccess2.is() )
+ {
+ Reference< XEnumeration > xEnumeration2( xEnumerationAccess2->createEnumeration(), css::uno::UNO_SET_THROW );
+ while( xEnumeration2->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration2->nextElement(), UNO_QUERY_THROW );
+
+ Reference< XEnumerationAccess > xEnumerationAccess3( xChildNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration3( xEnumerationAccess3->createEnumeration(), css::uno::UNO_SET_THROW );
+ while( xEnumeration3->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode2( xEnumeration3->nextElement(), UNO_QUERY_THROW );
+
+ Reference< XEnumerationAccess > xEnumerationAccess4( xChildNode2, UNO_QUERY_THROW );
+ Reference< XEnumeration > xEnumeration4( xEnumerationAccess4->createEnumeration(), css::uno::UNO_SET_THROW );
+ while( xEnumeration4->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode3( xEnumeration4->nextElement(), UNO_QUERY_THROW );
+
+ switch( xChildNode3->getType() )
+ {
+ // found an after effect
+ case AnimationNodeType::SET:
+ case AnimationNodeType::ANIMATECOLOR:
+ {
+ Reference< XAnimationNode > xMaster;
+
+ const Sequence< NamedValue > aUserData( xChildNode3->getUserData() );
+ const NamedValue* p = std::find_if(aUserData.begin(), aUserData.end(),
+ [](const NamedValue& rProp) { return rProp.Name == "master-element"; });
+
+ if (p != aUserData.end())
+ p->Value >>= xMaster;
+
+ AfterEffectNodePtr pAfterEffectNode = std::make_shared<AfterEffectNode>( xChildNode3, xMaster );
+ maAfterEffectNodes.push_back( pAfterEffectNode );
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sd", "(@CL)AnimationExporter::processAfterEffectNodes()" );
+ }
+}
+
+bool AnimationExporter::isAfterEffectNode( const Reference< XAnimationNode >& xNode ) const
+{
+ return std::any_of(maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
+ [&xNode](const AfterEffectNodePtr& rxNode) { return rxNode->mxNode == xNode; });
+}
+
+bool AnimationExporter::hasAfterEffectNode( const Reference< XAnimationNode >& xNode, Reference< XAnimationNode >& xAfterEffectNode ) const
+{
+ auto aIter = std::find_if(maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
+ [&xNode](const AfterEffectNodePtr& rxNode) { return rxNode->mxMaster == xNode; });
+ if (aIter != maAfterEffectNodes.end())
+ {
+ xAfterEffectNode = (*aIter)->mxNode;
+ return true;
+ }
+
+ return false;
+}
+
+// check if this group only contain empty groups. this may happen when
+// after effect nodes are not exported at their original position
+bool AnimationExporter::isEmptyNode( const Reference< XAnimationNode >& xNode ) const
+{
+ if( xNode.is() ) switch( xNode->getType() )
+ {
+ case AnimationNodeType::PAR :
+ case AnimationNodeType::SEQ :
+ case AnimationNodeType::ITERATE :
+ {
+ Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
+ if( xChildNode.is() && !isEmptyNode( xChildNode ) )
+ return false;
+ }
+ }
+ }
+ }
+ break;
+
+ case AnimationNodeType::SET :
+ case AnimationNodeType::ANIMATECOLOR :
+ return isAfterEffectNode( xNode );
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+void AnimationExporter::exportNode( SvStream& rStrm, Reference< XAnimationNode > const & xNode_in, const sal_uInt16 nContainerRecType,
+ const sal_uInt16 nInstance, const sal_Int32 nGroupLevel, const bool bTakeBackInteractiveSequenceTiming, const sal_Int16 nFDef )
+{
+ auto xNode = xNode_in;
+
+ if( (nGroupLevel == 4) && isEmptyNode( xNode ) )
+ return;
+
+ if ( ( nContainerRecType == DFF_msofbtAnimGroup ) && ( nGroupLevel == 2 ) && isEmptyNode( xNode ) )
+ return;
+
+ if( nContainerRecType == DFF_msofbtAnimGroup )
+ mnCurrentGroup++;
+
+ bool bTakeBackInteractiveSequenceTimingForChild = false;
+ sal_Int16 nFillDefault = GetFillMode( xNode, nFDef );
+
+ Reference< XAnimationNode > xAudioNode;
+ static sal_uInt32 nAudioGroup;
+
+ {
+ bool bSkipChildren = false;
+ EscherExContainer aContainer( rStrm, nContainerRecType, nInstance );
+ switch( xNode->getType() )
+ {
+ case AnimationNodeType::CUSTOM :
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ }
+ break;
+
+ case AnimationNodeType::PAR :
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ sal_Int32 nFlags = nGroupLevel == 2 ? 0x10 : 0;
+ if ( bTakeBackInteractiveSequenceTiming )
+ nFlags |= 0x40;
+ exportAnimEvent( rStrm, xNode, nFlags );
+ exportAnimValue( rStrm, xNode, nGroupLevel == 4 );
+ }
+ break;
+
+ case AnimationNodeType::SEQ :
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ sal_Int16 nNodeType = exportAnimPropertySet( rStrm, xNode );
+ sal_Int32 nFlags = 12;
+ if ( ( nGroupLevel == 1 ) && ( nNodeType == css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE ) )
+ {
+ nFlags |= 0x20;
+ bTakeBackInteractiveSequenceTimingForChild = true;
+ }
+ exportAnimAction( rStrm, xNode );
+ exportAnimEvent( rStrm, xNode, nFlags );
+ exportAnimValue( rStrm, xNode, false );
+ }
+ break;
+
+ case AnimationNodeType::ITERATE :
+ {
+ {
+ EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode );
+ AnimationNode aAnim;
+ aAnim.mnGroupType = mso_Anim_GroupType_PAR;
+ aAnim.mnNodeType = 1;
+ // attribute Restart
+ switch( xNode->getRestart() )
+ {
+ default:
+ case AnimationRestart::DEFAULT : aAnim.mnRestart = 0; break;
+ case AnimationRestart::ALWAYS : aAnim.mnRestart = 1; break;
+ case AnimationRestart::WHEN_NOT_ACTIVE : aAnim.mnRestart = 2; break;
+ case AnimationRestart::NEVER : aAnim.mnRestart = 3; break;
+ }
+ // attribute Fill
+ switch( xNode->getFill() )
+ {
+ default:
+ case AnimationFill::DEFAULT : aAnim.mnFill = 0; break;
+ case AnimationFill::REMOVE : aAnim.mnFill = 1; break;
+ case AnimationFill::FREEZE : aAnim.mnFill = 2; break;
+ case AnimationFill::HOLD : aAnim.mnFill = 3; break;
+ case AnimationFill::TRANSITION : aAnim.mnFill = 4; break;
+ }
+ WriteAnimationNode( rStrm, aAnim );
+ }
+ exportIterate( rStrm, xNode );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ }
+ break;
+
+ case AnimationNodeType::ANIMATE :
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ exportAnimate( rStrm, xNode );
+ }
+ break;
+
+ case AnimationNodeType::SET :
+ {
+ bool bIsAfterEffectNode( isAfterEffectNode( xNode ) );
+ if( (nGroupLevel != 4) || !bIsAfterEffectNode )
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimateSet( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_SET : AFTEREFFECT_NONE );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ }
+ else
+ {
+ bSkipChildren = true;
+ }
+ }
+ break;
+
+ case AnimationNodeType::ANIMATEMOTION :
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimateMotion( rStrm, xNode );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ }
+ break;
+
+ case AnimationNodeType::ANIMATECOLOR :
+ {
+ bool bIsAfterEffectNode( isAfterEffectNode( xNode ) );
+ if( (nGroupLevel != 4) || !bIsAfterEffectNode )
+ {
+ if( bIsAfterEffectNode )
+ xNode = createAfterEffectNodeClone( xNode );
+
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimateColor( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_COLOR : AFTEREFFECT_NONE );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ }
+ else
+ {
+ bSkipChildren = true;
+ }
+ }
+ break;
+
+ case AnimationNodeType::ANIMATETRANSFORM :
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimateTransform( rStrm, xNode );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ }
+ break;
+
+ case AnimationNodeType::TRANSITIONFILTER :
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+ exportAnimEvent( rStrm, xNode );
+ exportAnimValue( rStrm, xNode, false );
+ exportTransitionFilter( rStrm, xNode );
+ }
+ break;
+
+ case AnimationNodeType::AUDIO : // #i58428#
+ {
+ exportAnimNode( rStrm, xNode, nFillDefault );
+ exportAnimPropertySet( rStrm, xNode );
+
+ Reference< XAudio > xAudio( xNode, UNO_QUERY );
+ if( xAudio.is() )
+ {
+ Any aAny( xAudio->getSource() );
+ OUString aURL;
+
+ if ( ( aAny >>= aURL) && !aURL.isEmpty() )
+ {
+ sal_Int32 nU1 = 2;
+ sal_Int32 nTrigger = 3;
+ sal_Int32 nU3 = nAudioGroup;
+ sal_Int32 nBegin = 0;
+ {
+ EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, 1 );
+ {
+ EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
+ rStrm.WriteInt32( nU1 ).WriteInt32( nTrigger ).WriteInt32( nU3 ).WriteInt32( nBegin );
+ }
+ }
+ nU1 = 1;
+ nTrigger = 0xb;
+ nU3 = 0;
+ {
+ EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, 2 );
+ {
+ EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
+ rStrm.WriteInt32( nU1 ).WriteInt32( nTrigger ).WriteInt32( nU3 ).WriteInt32( nBegin );
+ }
+ }
+ EscherExContainer aAnimateTargetElement( rStrm, DFF_msofbtAnimateTargetElement );
+ {
+ sal_uInt32 const nRefMode = 3;
+ sal_uInt32 const nRefType = 2;
+ sal_uInt32 nRefId = mrExSoundCollection.GetId( aURL );
+ sal_Int32 const begin = -1;
+ sal_Int32 const end = -1;
+
+ EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference );
+ rStrm.WriteUInt32( nRefMode ).WriteUInt32( nRefType ).WriteUInt32( nRefId ).WriteInt32( begin ).WriteInt32( end );
+ }
+ }
+ }
+ exportAnimValue( rStrm, xNode, false );
+ }
+ break;
+ }
+ if( !bSkipChildren )
+ {
+ // export after effect node if one exists for this node
+ Reference< XAnimationNode > xAfterEffectNode;
+ if( hasAfterEffectNode( xNode, xAfterEffectNode ) )
+ {
+ exportNode( rStrm, xAfterEffectNode, DFF_msofbtAnimSubGoup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
+ }
+
+ Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
+ if( xChildNode.is() )
+ {
+ if ( xChildNode->getType() == AnimationNodeType::AUDIO )
+ {
+ xAudioNode = xChildNode;
+ nAudioGroup = mnCurrentGroup;
+ }
+ else
+ exportNode( rStrm, xChildNode, DFF_msofbtAnimGroup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
+ }
+ }
+ }
+ }
+ }
+ }
+ if ( xAudioNode.is() )
+ exportNode( rStrm, xAudioNode, DFF_msofbtAnimGroup, 1, nGroupLevel, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
+
+ if( xNode->getType() == AnimationNodeType::ITERATE )
+ aTarget = Any();
+}
+
+Reference< XAnimationNode > AnimationExporter::createAfterEffectNodeClone( const Reference< XAnimationNode >& xNode )
+{
+ try
+ {
+ Reference< css::util::XCloneable > xClonable( xNode, UNO_QUERY_THROW );
+ Reference< XAnimationNode > xCloneNode( xClonable->createClone(), UNO_QUERY_THROW );
+
+ Any aEmpty;
+ xCloneNode->setBegin( aEmpty );
+
+ return xCloneNode;
+ }
+ catch( Exception& )
+ {
+ OSL_FAIL("(@CL)sd::ppt::AnimationExporter::createAfterEffectNodeClone(), could not create clone!" );
+ }
+ return xNode;
+}
+
+bool AnimationExporter::GetNodeType( const Reference< XAnimationNode >& xNode, sal_Int16& nType )
+{
+ // trying to get the nodetype
+ const Sequence< NamedValue > aUserData = xNode->getUserData();
+ for( const NamedValue& rProp : aUserData )
+ {
+ if ( rProp.Name == "node-type" )
+ {
+ if ( rProp.Value >>= nType )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void AnimationExporter::exportAnimNode( SvStream& rStrm, const Reference< XAnimationNode >& xNode,
+ const sal_Int16 nFillDefault )
+{
+ EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode );
+ AnimationNode aAnim;
+
+ // attribute Restart
+ switch( xNode->getRestart() )
+ {
+ default:
+ case AnimationRestart::DEFAULT : aAnim.mnRestart = 0; break;
+ case AnimationRestart::ALWAYS : aAnim.mnRestart = 1; break;
+ case AnimationRestart::WHEN_NOT_ACTIVE : aAnim.mnRestart = 2; break;
+ case AnimationRestart::NEVER : aAnim.mnRestart = 3; break;
+ }
+
+ switch( nFillDefault )
+ {
+ default:
+ case AnimationFill::DEFAULT : aAnim.mnFill = 0; break;
+ case AnimationFill::REMOVE : aAnim.mnFill = 1; break;
+ case AnimationFill::FREEZE :
+ case AnimationFill::HOLD : aAnim.mnFill = 3; break;
+ case AnimationFill::TRANSITION : aAnim.mnFill = 4; break;
+ }
+ // attribute Duration
+ double fDuration = 0.0;
+ css::animations::Timing eTiming;
+ if ( xNode->getDuration() >>= eTiming )
+ {
+ if ( eTiming == Timing_INDEFINITE )
+ aAnim.mnDuration = -1;
+ }
+ else if ( xNode->getDuration() >>= fDuration )
+ {
+ aAnim.mnDuration = static_cast<sal_Int32>( fDuration * 1000.0 );
+ }
+ else
+ aAnim.mnDuration = -1;
+
+ // NodeType, NodeGroup
+ aAnim.mnNodeType = 1;
+ aAnim.mnGroupType = mso_Anim_GroupType_SEQ;
+ switch( xNode->getType() )
+ {
+ case AnimationNodeType::PAR :
+ aAnim.mnGroupType = mso_Anim_GroupType_PAR;
+ [[fallthrough]];
+ case AnimationNodeType::SEQ :
+ {
+ sal_Int16 nType = 0;
+ if( GetNodeType( xNode, nType ) )
+ switch( nType )
+ {
+ case css::presentation::EffectNodeType::TIMING_ROOT : aAnim.mnNodeType = 0x12; break;
+ case css::presentation::EffectNodeType::MAIN_SEQUENCE : aAnim.mnNodeType = 0x18; break;
+ }
+ }
+ break;
+
+ case AnimationNodeType::ANIMATE :
+ case AnimationNodeType::SET :
+
+ case AnimationNodeType::CUSTOM :
+ case AnimationNodeType::ITERATE :
+ case AnimationNodeType::ANIMATEMOTION :
+ case AnimationNodeType::ANIMATECOLOR :
+ case AnimationNodeType::ANIMATETRANSFORM :
+ {
+ aAnim.mnGroupType = mso_Anim_GroupType_NODE;
+ aAnim.mnNodeType = mso_Anim_Behaviour_ANIMATION;
+ }
+ break;
+
+ case AnimationNodeType::AUDIO :
+ {
+ aAnim.mnGroupType = mso_Anim_GroupType_MEDIA;
+ aAnim.mnNodeType = mso_Anim_Behaviour_ANIMATION;
+ }
+ break;
+
+ case AnimationNodeType::TRANSITIONFILTER :
+ {
+ aAnim.mnGroupType = mso_Anim_GroupType_NODE;
+ aAnim.mnNodeType = mso_Anim_Behaviour_FILTER;
+ }
+ break;
+ }
+
+ WriteAnimationNode( rStrm, aAnim );
+}
+
+void AnimationExporter::GetUserData( const Sequence< NamedValue >& rUserData, const Any ** pAny, std::size_t nLen )
+{
+ // storing user data into pAny, to allow direct access later
+ memset( pAny, 0, nLen );
+ if ( !rUserData.hasElements() )
+ return;
+
+ for( const NamedValue& rProp : rUserData )
+ {
+ if ( rProp.Name == "node-type" )
+ {
+ pAny[ DFF_ANIM_NODE_TYPE ] = &(rProp.Value);
+ }
+ else if ( rProp.Name == "preset-class" )
+ {
+ pAny[ DFF_ANIM_PRESET_CLASS ] = &(rProp.Value);
+ }
+ else if ( rProp.Name == "preset-id" )
+ {
+ pAny[ DFF_ANIM_PRESET_ID ] = &(rProp.Value);
+ }
+ else if ( rProp.Name == "preset-sub-type" )
+ {
+ pAny[ DFF_ANIM_PRESET_SUB_TYPE ] = &(rProp.Value);
+ }
+ else if ( rProp.Name == "master-element" )
+ {
+ pAny[ DFF_ANIM_AFTEREFFECT ] = &(rProp.Value);
+ }
+ }
+}
+
+sal_uInt32 AnimationExporter::GetPresetID( const OUString& rPreset, sal_uInt32 nAPIPresetClass, bool& bPresetId )
+{
+ sal_uInt32 nPresetId = 0;
+ bPresetId = false;
+
+ if ( rPreset.match("ppt_", 0) )
+ {
+ sal_Int32 nLast = rPreset.lastIndexOf( '_' );
+ if ( ( nLast != -1 ) && ( ( nLast + 1 ) < rPreset.getLength() ) )
+ {
+ std::u16string_view aNumber( rPreset.subView( nLast + 1 ) );
+ nPresetId = o3tl::toUInt32(aNumber);
+ bPresetId = true;
+ }
+ }
+ else
+ {
+ const oox::ppt::preset_mapping* p = oox::ppt::preset_mapping::getList();
+ while( p->mpStrPresetId && ((p->mnPresetClass != static_cast<sal_Int32>(nAPIPresetClass)) || !rPreset.equalsAscii( p->mpStrPresetId )) )
+ p++;
+
+ if( p->mpStrPresetId )
+ {
+ nPresetId = p->mnPresetId;
+ bPresetId = true;
+ }
+ }
+
+ return nPresetId;
+}
+
+sal_Int16 AnimationExporter::exportAnimPropertySet( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
+{
+ sal_Int16 nNodeType = css::presentation::EffectNodeType::DEFAULT;
+
+ EscherExContainer aAnimPropertySet( rStrm, DFF_msofbtAnimPropertySet );
+
+ Reference< XAnimationNode > xMaster;
+
+ Any aMasterRel, aOverride, aRunTimeContext;
+
+ // storing user data into pAny, to allow direct access later
+ const Sequence< NamedValue > aUserData = xNode->getUserData();
+ const css::uno::Any* pAny[ DFF_ANIM_PROPERTY_ID_COUNT ];
+ GetUserData( aUserData, pAny, sizeof( pAny ) );
+
+ if( pAny[ DFF_ANIM_AFTEREFFECT ] )
+ ( *pAny[ DFF_ANIM_AFTEREFFECT ] ) >>= xMaster;
+
+ // calculate master-rel
+ if( xMaster.is() )
+ {
+ sal_Int32 nMasterRel = 2;
+ if( xNode.is() && xMaster.is() && (xNode->getParent() == xMaster->getParent() ) )
+ nMasterRel = 0;
+
+ aMasterRel <<= nMasterRel;
+
+ pAny[ DFF_ANIM_MASTERREL ] = &aMasterRel;
+
+ aOverride <<= sal_Int32(1);
+ pAny[ DFF_ANIM_OVERRIDE ] = &aOverride;
+
+ aRunTimeContext <<= sal_Int32(1);
+ pAny[ DFF_ANIM_RUNTIMECONTEXT ] = &aRunTimeContext;
+ }
+
+ // the order is important
+ if ( pAny[ DFF_ANIM_NODE_TYPE ] )
+ {
+ if ( *pAny[ DFF_ANIM_NODE_TYPE ] >>= nNodeType )
+ {
+ sal_uInt32 nPPTNodeType = DFF_ANIM_NODE_TYPE_ON_CLICK;
+ switch( nNodeType )
+ {
+ case css::presentation::EffectNodeType::ON_CLICK : nPPTNodeType = DFF_ANIM_NODE_TYPE_ON_CLICK; break;
+ case css::presentation::EffectNodeType::WITH_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_WITH_PREVIOUS; break;
+ case css::presentation::EffectNodeType::AFTER_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_AFTER_PREVIOUS; break;
+ case css::presentation::EffectNodeType::MAIN_SEQUENCE : nPPTNodeType = DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE; break;
+ case css::presentation::EffectNodeType::TIMING_ROOT : nPPTNodeType = DFF_ANIM_NODE_TYPE_TIMING_ROOT; break;
+ case css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE: nPPTNodeType = DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ; break;
+ }
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_NODE_TYPE, nPPTNodeType );
+ }
+ }
+ sal_uInt32 nPresetId = 0;
+ sal_uInt32 nPresetSubType = 0;
+ sal_uInt32 nAPIPresetClass = EffectPresetClass::CUSTOM;
+ sal_uInt32 nPresetClass = DFF_ANIM_PRESS_CLASS_USER_DEFINED;
+ bool bPresetClass, bPresetId, bPresetSubType;
+ bPresetId = bPresetClass = bPresetSubType = false;
+
+ if ( pAny[ DFF_ANIM_PRESET_CLASS ] )
+ {
+ if ( *pAny[ DFF_ANIM_PRESET_CLASS ] >>= nAPIPresetClass )
+ {
+ sal_uInt8 nPPTPresetClass;
+ switch( nAPIPresetClass )
+ {
+ case EffectPresetClass::ENTRANCE : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_ENTRANCE; break;
+ case EffectPresetClass::EXIT : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_EXIT; break;
+ case EffectPresetClass::EMPHASIS : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_EMPHASIS; break;
+ case EffectPresetClass::MOTIONPATH : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_MOTIONPATH; break;
+ case EffectPresetClass::OLEACTION : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_OLE_ACTION; break;
+ case EffectPresetClass::MEDIACALL : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_MEDIACALL; break;
+ default :
+ nPPTPresetClass = DFF_ANIM_PRESS_CLASS_USER_DEFINED;
+ }
+ nPresetClass = nPPTPresetClass;
+ bPresetClass = true;
+ }
+ }
+ if ( pAny[ DFF_ANIM_PRESET_ID ] )
+ {
+ OUString sPreset;
+ if ( *pAny[ DFF_ANIM_PRESET_ID ] >>= sPreset )
+ nPresetId = GetPresetID( sPreset, nAPIPresetClass, bPresetId );
+ }
+
+ if ( pAny[ DFF_ANIM_PRESET_SUB_TYPE ] )
+ {
+ OUString sPresetSubType;
+ if ( *pAny[ DFF_ANIM_PRESET_SUB_TYPE ] >>= sPresetSubType )
+ {
+ nPresetSubType = TranslatePresetSubType( nPresetClass, nPresetId, sPresetSubType );
+ bPresetSubType = true;
+ }
+ }
+ if ( bPresetId )
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_ID, nPresetId );
+ if ( bPresetSubType )
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_SUB_TYPE, nPresetSubType );
+ if ( bPresetClass )
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_CLASS, nPresetClass );
+
+ if ( pAny[ DFF_ANIM_ID ] )
+ {
+ // TODO DFF_ANIM_ID
+ }
+
+ if ( pAny[ DFF_ANIM_AFTEREFFECT ] )
+ {
+ bool bAfterEffect = false;
+ if ( *pAny[ DFF_ANIM_AFTEREFFECT ] >>= bAfterEffect )
+ exportAnimPropertyByte( rStrm, DFF_ANIM_AFTEREFFECT, int(bAfterEffect) );
+ }
+
+ if ( pAny[ DFF_ANIM_RUNTIMECONTEXT ] )
+ {
+ sal_Int32 nRunTimeContext = 0;
+ if ( *pAny[ DFF_ANIM_RUNTIMECONTEXT ] >>= nRunTimeContext )
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_RUNTIMECONTEXT, nRunTimeContext );
+ }
+ if ( pAny[ DFF_ANIM_PATH_EDIT_MODE ] )
+ {
+ // TODO DFF_ANIM_ID
+ }
+
+ if( !xMaster.is() )
+ {
+ Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
+ if( xColor.is() )
+ {
+
+ bool bDirection = !xColor->getDirection();
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_DIRECTION, bDirection ? 1 : 0 );
+ }
+ }
+
+ if ( pAny[ DFF_ANIM_OVERRIDE ] )
+ {
+ sal_Int32 nOverride = 0;
+ if ( *pAny[ DFF_ANIM_OVERRIDE ] >>= nOverride )
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_OVERRIDE, nOverride );
+ }
+
+ if ( pAny[ DFF_ANIM_MASTERREL ] )
+ {
+ sal_Int32 nMasterRel = 0;
+ if ( *pAny[ DFF_ANIM_MASTERREL ] >>= nMasterRel )
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_MASTERREL, nMasterRel );
+ }
+
+/* todo
+ Reference< XAudio > xAudio( xNode, UNO_QUERY );
+ if( xAudio.is() )
+ {
+ sal_Int16 nEndAfterSlide = 0;
+ nEndAfterSlide = xAudio->getEndAfterSlide();
+ exportAnimPropertyuInt32( rStrm, DFF_ANIM_ENDAFTERSLIDE, nEndAfterSlide, TRANSLATE_NONE );
+ }
+*/
+ Reference< XAnimate > xAnim( xNode, UNO_QUERY );
+ if( xAnim.is() )
+ {
+ // TODO: DFF_ANIM_TIMEFILTER
+ }
+ if ( pAny[ DFF_ANIM_EVENT_FILTER ] )
+ {
+ // TODO DFF_ANIM_EVENT_FILTER
+ }
+ if ( pAny[ DFF_ANIM_VOLUME ] )
+ {
+ // TODO DFF_ANIM_VOLUME
+ }
+ return nNodeType;
+}
+
+bool AnimationExporter::exportAnimProperty( SvStream& rStrm, const sal_uInt16 nPropertyId, const css::uno::Any& rAny, const TranslateMode eTranslateMode )
+{
+ bool bRet = false;
+ if ( rAny.hasValue() )
+ {
+ switch( rAny.getValueType().getTypeClass() )
+ {
+ case css::uno::TypeClass_UNSIGNED_SHORT :
+ case css::uno::TypeClass_SHORT :
+ case css::uno::TypeClass_UNSIGNED_LONG :
+ case css::uno::TypeClass_LONG :
+ {
+ sal_Int32 nVal = 0;
+ if ( rAny >>= nVal )
+ {
+ exportAnimPropertyuInt32( rStrm, nPropertyId, nVal );
+ bRet = true;
+ }
+ }
+ break;
+
+ case css::uno::TypeClass_DOUBLE :
+ {
+ double fVal = 0.0;
+ if ( rAny >>= fVal )
+ {
+ exportAnimPropertyFloat( rStrm, nPropertyId, fVal );
+ bRet = true;
+ }
+ }
+ break;
+ case css::uno::TypeClass_FLOAT :
+ {
+ float fVal = 0.0;
+ if ( rAny >>= fVal )
+ {
+ if ( eTranslateMode & TRANSLATE_NUMBER_TO_STRING )
+ {
+ OUString aNumber( OUString::number( fVal ) );
+ exportAnimPropertyString( rStrm, nPropertyId, aNumber, eTranslateMode );
+ }
+ else
+ {
+ exportAnimPropertyFloat( rStrm, nPropertyId, fVal );
+ bRet = true;
+ }
+ }
+ }
+ break;
+ case css::uno::TypeClass_STRING :
+ {
+ OUString aStr;
+ if ( rAny >>= aStr )
+ {
+ exportAnimPropertyString( rStrm, nPropertyId, aStr, eTranslateMode );
+ bRet = true;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return bRet;
+}
+void AnimationExporter::exportAnimPropertyString( SvStream& rStrm, const sal_uInt16 nPropertyId, const OUString& rVal, const TranslateMode eTranslateMode )
+{
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
+ rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_UNISTRING );
+ OUString aStr( rVal );
+ if ( eTranslateMode != TRANSLATE_NONE )
+ ImplTranslateAttribute( aStr, eTranslateMode );
+ writeZString( rStrm, aStr );
+}
+
+void AnimationExporter::exportAnimPropertyFloat( SvStream& rStrm, const sal_uInt16 nPropertyId, const double& rVal )
+{
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
+ float fFloat = static_cast<float>(rVal);
+ rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_FLOAT )
+ .WriteFloat( fFloat );
+}
+
+void AnimationExporter::exportAnimPropertyuInt32( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt32 nVal )
+{
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
+ rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_INT32 )
+ .WriteUInt32( nVal );
+}
+
+void AnimationExporter::exportAnimPropertyByte( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt8 nVal )
+{
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
+ rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_BYTE )
+ .WriteUChar( nVal );
+}
+
+void AnimationExporter::writeZString( SvStream& rStrm, const OUString& rVal )
+{
+ sal_Int32 i;
+ for ( i = 0; i < rVal.getLength(); i++ )
+ rStrm.WriteUInt16( rVal[ i ] );
+ rStrm.WriteUInt16( 0 );
+}
+
+void AnimationExporter::exportAnimAction( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
+{
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAction );
+
+ sal_Int32 const nConcurrent = 1;
+ sal_Int32 const nNextAction = 1;
+ sal_Int32 nEndSync = 0;
+ sal_Int32 const nU4 = 0;
+ sal_Int32 const nU5 = 3;
+
+ sal_Int16 nAnimationEndSync = 0;
+ if ( xNode->getEndSync() >>= nAnimationEndSync )
+ {
+ if ( nAnimationEndSync == AnimationEndSync::ALL )
+ nEndSync = 1;
+ }
+ rStrm.WriteInt32( nConcurrent )
+ .WriteInt32( nNextAction )
+ .WriteInt32( nEndSync )
+ .WriteInt32( nU4 )
+ .WriteInt32( nU5 );
+
+}
+
+// nFlags Bit 6 = fixInteractiveSequenceTiming (for child)
+// nFlags Bit 5 = fixInteractiveSequenceTiming (for root)
+// nFlags Bit 4 = first node of main sequence -> begin event next has to be replaced to indefinite
+void AnimationExporter::exportAnimEvent( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const sal_Int32 nFlags )
+{
+ sal_uInt16 i;
+ for ( i = 0; i < 4; i++ )
+ {
+ sal_Int32 nU1 = 0;
+ sal_Int32 nTrigger = 0;
+ sal_Int32 nU3 = 0;
+ sal_Int32 nBegin = 0;
+
+ bool bCreateEvent = false;
+ Any aSource;
+
+ switch( i )
+ {
+ case 0 :
+ case 1 :
+ {
+ Any aAny;
+ Event aEvent;
+ css::animations::Timing eTiming;
+ if ( i == 0 )
+ {
+ if ( nFlags & 0x20 )
+ {
+ // taking the first child
+ Reference< XEnumerationAccess > xEA( xNode, UNO_QUERY_THROW );
+ Reference< XEnumeration > xE( xEA->createEnumeration(), css::uno::UNO_SET_THROW );
+ if ( xE->hasMoreElements() )
+ {
+ Reference< XAnimationNode > xClickNode( xE->nextElement(), UNO_QUERY );
+ aAny = xClickNode->getBegin();
+ }
+ }
+ else if ( nFlags & 0x40 )
+ {
+ // begin has to be replaced with void, so don't do anything
+ }
+ else
+ {
+ aAny = xNode->getBegin();
+ if ( nFlags & 0x10 ) // replace ON_NEXT with INDEFINITE
+ {
+ if ( ( aAny >>= aEvent ) && ( aEvent.Trigger == EventTrigger::ON_NEXT ) )
+ {
+ eTiming = Timing_INDEFINITE;
+ aAny <<= eTiming;
+ }
+ }
+ }
+ }
+ else
+ aAny = xNode->getEnd();
+
+ double fTiming = 0.0;
+ if ( aAny >>= aEvent )
+ {
+ bCreateEvent = true;
+ switch( aEvent.Trigger )
+ {
+ case EventTrigger::NONE : nTrigger = 0; break;
+ case EventTrigger::ON_BEGIN : nTrigger = 1; break;
+ case EventTrigger::ON_END : nTrigger = 2; break;
+ case EventTrigger::BEGIN_EVENT : nTrigger = 3; break;
+ case EventTrigger::END_EVENT : nTrigger = 4; nU1 = 2; nU3 = mnCurrentGroup; break;
+ case EventTrigger::ON_CLICK : nTrigger = 5; break;
+ case EventTrigger::ON_DBL_CLICK : nTrigger = 6; break;
+ case EventTrigger::ON_MOUSE_ENTER : nTrigger = 7; break;
+ case EventTrigger::ON_MOUSE_LEAVE : nTrigger = 8; break;
+ case EventTrigger::ON_NEXT : nTrigger = 9; break;
+ case EventTrigger::ON_PREV : nTrigger = 10; break;
+ case EventTrigger::ON_STOP_AUDIO : nTrigger = 11; break;
+ }
+ if ( aEvent.Offset.hasValue() )
+ {
+ if ( aEvent.Offset >>= eTiming )
+ {
+ if ( eTiming == Timing_INDEFINITE )
+ nBegin = -1;
+ }
+ else if ( aEvent.Offset >>= fTiming )
+ nBegin = static_cast<sal_Int32>( fTiming * 1000.0 );
+ }
+ aSource = aEvent.Source;
+ }
+ else if ( aAny >>= eTiming )
+ {
+ bCreateEvent = true;
+ if ( eTiming == Timing_INDEFINITE )
+ nBegin = -1;
+ }
+ else if ( aAny >>= fTiming )
+ {
+ bCreateEvent = true;
+ nBegin = static_cast<sal_Int32>( fTiming * 1000.0 );
+ }
+ }
+ break;
+
+ case 2 :
+ {
+ if ( nFlags & ( 1 << i ) )
+ {
+ bCreateEvent = true;
+ nU1 = 1;
+ nTrigger = 9;
+ }
+ }
+ break;
+ case 3 :
+ {
+ if ( nFlags & ( 1 << i ) )
+ {
+ bCreateEvent = true;
+ nU1 = 1;
+ nTrigger = 10;
+ }
+ }
+ break;
+ }
+ if ( bCreateEvent )
+ {
+ EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, i + 1 );
+ {
+ EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
+ rStrm.WriteInt32( nU1 )
+ .WriteInt32( nTrigger )
+ .WriteInt32( nU3 )
+ .WriteInt32( nBegin );
+ }
+ exportAnimateTargetElement( rStrm, aSource, ( nFlags & ( 1 << i ) ) != 0 );
+ }
+ }
+}
+
+Any AnimationExporter::convertAnimateValue( const Any& rSourceValue, std::u16string_view rAttributeName )
+{
+ OUString aDest;
+ if ( rAttributeName == u"X"
+ || rAttributeName == u"Y"
+ || rAttributeName == u"Width"
+ || rAttributeName == u"Height"
+ )
+ {
+ OUString aStr;
+ if ( rSourceValue >>= aStr )
+ {
+ ImplTranslateAttribute( aStr, TRANSLATE_MEASURE );
+ aDest += aStr;
+ }
+ }
+ else if ( rAttributeName == u"Rotate" // "r" or "style.rotation" ?
+ || rAttributeName == u"Opacity"
+ || rAttributeName == u"CharHeight"
+ || rAttributeName == u"SkewX"
+ )
+ {
+ double fNumber = 0.0;
+ if ( rSourceValue >>= fNumber )
+ aDest += OUString::number( fNumber );
+ }
+ else if ( rAttributeName == u"Color"
+ || rAttributeName == u"FillColor" // "Fillcolor" or "FillColor" ?
+ || rAttributeName == u"LineColor"
+ || rAttributeName == u"CharColor"
+ )
+ {
+ sal_Int32 nColor = 0;
+ Sequence< double > aHSL( 3 );
+ OUString aP( "," );
+ if ( rSourceValue >>= aHSL )
+ {
+ aDest += "hsl("
+ + OUString::number( static_cast<sal_Int32>( aHSL[ 0 ] / ( 360.0 / 255 ) ) )
+ + aP
+ + OUString::number( static_cast<sal_Int32>( aHSL[ 1 ] * 255.0 ) )
+ + aP
+ + OUString::number( static_cast<sal_Int32>( aHSL[ 2 ] * 255.0 ) )
+ + ")";
+ }
+ else if ( rSourceValue >>= nColor )
+ {
+ aDest += "rgb("
+ + OUString::number( static_cast<sal_Int8>(nColor) )
+ + aP
+ + OUString::number( static_cast<sal_Int8>( nColor >> 8 ) )
+ + aP
+ + OUString::number( static_cast<sal_Int8>( nColor >> 16 ) )
+ + ")";
+ }
+ }
+ else if ( rAttributeName == u"FillStyle" )
+ {
+ css::drawing::FillStyle eFillStyle;
+ if ( rSourceValue >>= eFillStyle )
+ {
+ if ( eFillStyle == css::drawing::FillStyle_NONE )
+ aDest += "none"; // ?
+ else
+ aDest += "solid";
+ }
+ }
+ else if (rAttributeName == u"FillOn")
+ {
+ bool bFillOn;
+ if ( rSourceValue >>= bFillOn )
+ {
+ if ( bFillOn )
+ aDest += "true";
+ else
+ aDest += "false";
+ }
+ }
+ else if ( rAttributeName == u"LineStyle" )
+ {
+ css::drawing::LineStyle eLineStyle;
+ if ( rSourceValue >>= eLineStyle )
+ {
+ if ( eLineStyle == css::drawing::LineStyle_NONE )
+ aDest += "false";
+ else
+ aDest += "true";
+ }
+ }
+ else if ( rAttributeName == u"CharWeight" )
+ {
+ float fFontWeight = 0.0;
+ if ( rSourceValue >>= fFontWeight )
+ {
+ if ( fFontWeight == css::awt::FontWeight::BOLD )
+ aDest += "bold";
+ else
+ aDest += "normal";
+ }
+ }
+ else if ( rAttributeName == u"CharUnderline" )
+ {
+ sal_Int16 nFontUnderline = 0;
+ if ( rSourceValue >>= nFontUnderline )
+ {
+ if ( nFontUnderline == css::awt::FontUnderline::NONE )
+ aDest += "false";
+ else
+ aDest += "true";
+ }
+ }
+ else if ( rAttributeName == u"CharPosture" )
+ {
+ css::awt::FontSlant eFontSlant;
+ if ( rSourceValue >>= eFontSlant )
+ {
+ if ( eFontSlant == css::awt::FontSlant_ITALIC )
+ aDest += "italic";
+ else
+ aDest += "normal"; // ?
+ }
+ }
+ else if ( rAttributeName == u"Visibility" )
+ {
+ bool bVisible = true;
+ if ( rSourceValue >>= bVisible )
+ {
+ if ( bVisible )
+ aDest += "visible";
+ else
+ aDest += "hidden";
+ }
+ }
+ Any aRet;
+ if ( !aDest.isEmpty() )
+ aRet <<= aDest;
+ else
+ aRet = rSourceValue;
+ return aRet;
+}
+
+void AnimationExporter::exportAnimateSet( SvStream& rStrm, const Reference< XAnimationNode >& xNode, int nAfterEffectType )
+{
+ Reference< XAnimateSet > xSet( xNode, UNO_QUERY );
+ if( !xSet.is() )
+ return;
+
+ EscherExContainer aAnimateSet( rStrm, DFF_msofbtAnimateSet, 0 );
+ {
+ EscherExAtom aAnimateSetData( rStrm, DFF_msofbtAnimateSetData );
+ sal_uInt32 const nId1 = 1; // ??
+ sal_uInt32 const nId2 = 1; // ??
+ rStrm.WriteUInt32( nId1 ).WriteUInt32( nId2 );
+ }
+ Any aConvertedValue( convertAnimateValue( xSet->getTo(), xSet->getAttributeName() ) );
+ if ( aConvertedValue.hasValue() )
+ exportAnimProperty( rStrm, 1, aConvertedValue, TRANSLATE_NONE );
+ exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType );
+}
+
+sal_uInt32 AnimationExporter::GetValueTypeForAttributeName( const OUString& rAttributeName )
+{
+ sal_uInt32 nValueType = 0;
+
+ struct Entry
+ {
+ const char* pName;
+ sal_uInt8 nType;
+ };
+ static const Entry lcl_attributeMap[] =
+ {
+ { "charcolor", 2 },
+ { "charfontname", 0 },
+ { "charheight", 1 },
+ { "charposture", 0 },
+ // TODO(Q1): This should prolly be changed in PPT import
+ // { "charrotation", ATTRIBUTE_CHAR_ROTATION },
+ { "charrotation", 1 },
+ { "charunderline", 0 },
+ { "charweight", 0 },
+ { "color", 2 },
+ { "dimcolor", 2 },
+ { "fillcolor", 2 },
+ { "fillstyle", 0 },
+ { "height", 1 },
+ { "linecolor", 2 },
+ { "linestyle", 0 },
+ { "opacity", 0 },
+ { "rotate", 1 },
+ { "skewx", 1 },
+ { "skewy", 1 },
+ { "visibility", 1 },
+ { "width", 1 },
+ { "x", 1 },
+ { "y", 1 },
+ { nullptr, 0 }
+ };
+ const Entry* pPtr = &lcl_attributeMap[ 0 ];
+ while( pPtr->pName )
+ {
+ if ( rAttributeName.equalsIgnoreAsciiCaseAscii( pPtr->pName ) )
+ {
+ nValueType = pPtr->nType;
+ break;
+ }
+ pPtr++;
+ }
+ DBG_ASSERT( pPtr->pName, "GetValueTypeForAttributeName, unknown property value!" );
+ return nValueType;
+}
+
+void AnimationExporter::exportAnimate( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
+ if ( !xAnimate.is() )
+ return;
+
+ Any aBy ( xAnimate->getBy() );
+ Any aFrom( xAnimate->getFrom() );
+ Any aTo ( xAnimate->getTo() );
+
+ EscherExContainer aContainer( rStrm, DFF_msofbtAnimate, 0 );
+ {
+ EscherExAtom aAnimateData( rStrm, DFF_msofbtAnimateData );
+ sal_uInt32 nBits = 0x38;
+ sal_Int16 nTmp = xAnimate->getCalcMode();
+ sal_uInt32 nCalcMode = /* (nTmp == AnimationCalcMode::FORMULA) ? 2 : */ (nTmp == AnimationCalcMode::LINEAR) ? 1 : 0;
+ sal_uInt32 nValueType = GetValueTypeForAttributeName( xAnimate->getAttributeName() );
+
+ if ( aBy.hasValue() )
+ nBits |= 1;
+ if ( aFrom.hasValue() )
+ nBits |= 2;
+ if ( aTo.hasValue() )
+ nBits |= 4;
+
+ rStrm.WriteUInt32( nCalcMode )
+ .WriteUInt32( nBits )
+ .WriteUInt32( nValueType );
+ }
+ if ( aBy.hasValue() )
+ exportAnimProperty( rStrm, 1, aBy, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE );
+ if ( aFrom.hasValue() )
+ exportAnimProperty( rStrm, 2, aFrom, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE );
+ if ( aTo.hasValue() )
+ exportAnimProperty( rStrm, 3, aTo, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE );
+
+ exportAnimateKeyPoints( rStrm, xAnimate );
+ exportAnimateTarget( rStrm, xNode );
+}
+
+void AnimationExporter::exportAnimateTarget( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const sal_uInt32 nForceAttributeNames, int nAfterEffectType )
+{
+ EscherExContainer aAnimateTarget( rStrm, DFF_msofbtAnimateTarget, 0 );
+ Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
+ if ( !xAnimate.is() )
+ return;
+
+ {
+ EscherExAtom aAnimateTargetSettings( rStrm, DFF_msofbtAnimateTargetSettings, 0 );
+ // nBits %0001: additive, %0010: accumulate, %0100: attributeName, %1000: transformtype
+ // nAdditive 0 = base, 1 = sum, 2 = replace, 3 = multiply, 4 = none
+ // nAccumulate 0 = none, 1 = always
+ // nTransformType 0: "property" else "image"
+ sal_uInt32 nBits = 0;
+ sal_uInt32 nAdditive = 0;
+ sal_uInt32 nAccumulate = 0;
+ sal_uInt32 const nTransformType = 0;
+ if ( xAnimate.is() )
+ {
+ if ( !xAnimate->getAttributeName().isEmpty() )
+ nBits |= 4; // what is attributeName ?, maybe this is set if a DFF_msofbtAnimateAttributeNames is written
+ sal_Int16 nAdditiveMode = xAnimate->getAdditive();
+ if ( nAdditiveMode != AnimationAdditiveMode::BASE )
+ {
+ nBits |= 1;
+ switch( nAdditiveMode )
+ {
+ case AnimationAdditiveMode::SUM : nAdditive = 1; break;
+ case AnimationAdditiveMode::REPLACE : nAdditive = 2; break;
+ case AnimationAdditiveMode::MULTIPLY : nAdditive = 3; break;
+ case AnimationAdditiveMode::NONE : nAdditive = 4; break;
+ }
+ }
+ if ( xAnimate->getAccumulate() )
+ {
+ nBits |= 2;
+ nAccumulate = 1;
+ }
+ }
+ rStrm.WriteUInt32( nBits )
+ .WriteUInt32( nAdditive )
+ .WriteUInt32( nAccumulate )
+ .WriteUInt32( nTransformType );
+ }
+ if ( !xAnimate->getAttributeName().isEmpty() || nForceAttributeNames )
+ {
+ EscherExContainer aAnimateAttributeNames( rStrm, DFF_msofbtAnimateAttributeNames, 1 );
+ OUString aAttributeName( xAnimate->getAttributeName() );
+ if ( nForceAttributeNames )
+ {
+ if( nForceAttributeNames == 1 )
+ {
+ aAttributeName = "r";
+ }
+ }
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OUString aToken( aAttributeName.getToken( 0, ';', nIndex ) );
+ exportAnimPropertyString( rStrm, 0, aToken, TRANSLATE_ATTRIBUTE );
+ }
+ while ( nIndex >= 0 );
+ }
+
+ if( nAfterEffectType != AFTEREFFECT_NONE )
+ {
+ EscherExContainer aAnimPropertySet( rStrm, DFF_msofbtAnimPropertySet );
+ exportAnimPropertyuInt32( rStrm, 6, 1 );
+ if( nAfterEffectType == AFTEREFFECT_COLOR )
+ {
+ exportAnimPropertyuInt32( rStrm, 4, 0 );
+ exportAnimPropertyuInt32( rStrm, 5, 0 );
+ }
+ }
+ exportAnimateTargetElement( rStrm, aTarget.hasValue() ? aTarget : xAnimate->getTarget(), false );
+}
+
+Reference< XShape > AnimationExporter::getTargetElementShape( const Any& rAny, sal_Int32& rBegin, sal_Int32& rEnd, bool& rParagraphTarget )
+{
+ Reference< XShape > xShape;
+ rAny >>= xShape;
+
+ rParagraphTarget = false;
+
+ if( xShape.is() )
+ return xShape;
+
+ ParagraphTarget aParaTarget;
+ if( rAny >>= aParaTarget )
+ xShape = aParaTarget.Shape;
+ if ( !xShape.is() )
+ return xShape;
+
+ // now calculating the character range for the paragraph
+ sal_Int16 nParagraph = aParaTarget.Paragraph;
+ Reference< XSimpleText > xText( xShape, UNO_QUERY );
+ if ( !xText.is() )
+ return xShape;
+
+ rParagraphTarget = true;
+ Reference< XEnumerationAccess > xTextParagraphEnumerationAccess( xText, UNO_QUERY );
+ if ( !xTextParagraphEnumerationAccess.is() )
+ return xShape;
+
+ Reference< XEnumeration > xTextParagraphEnumeration( xTextParagraphEnumerationAccess->createEnumeration() );
+ if ( !xTextParagraphEnumeration.is() )
+ return xShape;
+
+ sal_Int16 nCurrentParagraph;
+ rBegin = rEnd = nCurrentParagraph = 0;
+ while ( xTextParagraphEnumeration->hasMoreElements() )
+ {
+ Reference< XTextRange > xTextRange( xTextParagraphEnumeration->nextElement(), UNO_QUERY );
+ if ( xTextRange.is() )
+ {
+ OUString aParaText( xTextRange->getString() );
+ sal_Int32 nLength = aParaText.getLength() + 1;
+ rEnd += nLength;
+ if ( nCurrentParagraph == nParagraph )
+ break;
+ nCurrentParagraph++;
+ rBegin += nLength;
+ }
+ }
+
+ return xShape;
+}
+
+void AnimationExporter::exportAnimateTargetElement( SvStream& rStrm, const Any& rAny, const bool bCreate2b01Atom )
+{
+ sal_uInt32 nRefMode = 0; // nRefMode == 2 -> Paragraph
+ sal_Int32 begin = -1;
+ sal_Int32 end = -1;
+ bool bParagraphTarget;
+
+ Reference< XShape > xShape = getTargetElementShape(rAny, begin, end, bParagraphTarget);
+
+ if( bParagraphTarget )
+ nRefMode = 2;
+
+ if ( !(xShape.is() || bCreate2b01Atom) )
+ return;
+
+ EscherExContainer aAnimateTargetElement( rStrm, DFF_msofbtAnimateTargetElement );
+ if ( xShape.is() )
+ {
+ EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference );
+
+ sal_uInt32 const nRefType = 1; // TODO: nRefType == 2 -> Sound;
+ sal_uInt32 nRefId = mrSolverContainer.GetShapeId( xShape );
+
+ rStrm.WriteUInt32( nRefMode )
+ .WriteUInt32( nRefType )
+ .WriteUInt32( nRefId )
+ .WriteInt32( begin )
+ .WriteInt32( end );
+ }
+ if ( bCreate2b01Atom )
+ {
+ EscherExAtom a2b01Atom( rStrm, 0x2b01 );
+ rStrm.WriteUInt32( 1 ); // ?
+ }
+}
+
+void AnimationExporter::exportAnimateKeyPoints( SvStream& rStrm, const Reference< XAnimate >& xAnimate )
+{
+ Sequence< double > aKeyTimes( xAnimate->getKeyTimes() );
+ Sequence< Any > aValues( xAnimate->getValues() );
+ OUString aFormula( xAnimate->getFormula() );
+ if ( !aKeyTimes.hasElements() )
+ return;
+
+ EscherExContainer aAnimKeyPoints( rStrm, DFF_msofbtAnimKeyPoints );
+ sal_Int32 i;
+ for ( i = 0; i < aKeyTimes.getLength(); i++ )
+ {
+ {
+ EscherExAtom aAnimKeyTime( rStrm, DFF_msofbtAnimKeyTime );
+ sal_Int32 nKeyTime = static_cast<sal_Int32>( aKeyTimes[ i ] * 1000.0 );
+ rStrm.WriteInt32( nKeyTime );
+ }
+ Any aAny[ 2 ];
+ if ( aValues[ i ].hasValue() )
+ {
+ ValuePair aPair;
+ if ( aValues[ i ] >>= aPair )
+ {
+ aAny[ 0 ] = convertAnimateValue( aPair.First, xAnimate->getAttributeName() );
+ aAny[ 1 ] = convertAnimateValue( aPair.Second, xAnimate->getAttributeName() );
+ }
+ else
+ {
+ aAny[ 0 ] = convertAnimateValue( aValues[ i ], xAnimate->getAttributeName() );
+ }
+ if ( !i && !aFormula.isEmpty() )
+ {
+ ImplTranslateAttribute( aFormula, TRANSLATE_MEASURE );
+ aAny[ 1 ] <<= aFormula;
+ }
+ exportAnimProperty( rStrm, 0, aAny[ 0 ], TRANSLATE_NONE );
+ exportAnimProperty( rStrm, 1, aAny[ 1 ], TRANSLATE_NONE );
+ }
+ }
+}
+
+void AnimationExporter::exportAnimValue( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const bool bExportAlways )
+{
+ Any aAny;
+ // repeat count (0)
+ double fRepeat = 0.0;
+ float fRepeatCount = 0.0;
+ css::animations::Timing eTiming;
+ aAny = xNode->getRepeatCount();
+ if ( aAny >>= eTiming )
+ {
+ if ( eTiming == Timing_INDEFINITE )
+ fRepeatCount = (float(3.40282346638528860e+38));
+ }
+ else if ( aAny >>= fRepeat )
+ fRepeatCount = static_cast<float>(fRepeat);
+ if ( fRepeatCount != 0.0 )
+ {
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
+ sal_uInt32 const nType = 0;
+ rStrm.WriteUInt32( nType )
+ .WriteFloat( fRepeatCount );
+ }
+ // accelerate (3)
+ float fAccelerate = static_cast<float>(xNode->getAcceleration());
+ if ( bExportAlways || ( fAccelerate != 0.0 ) )
+ {
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
+ sal_uInt32 const nType = 3;
+ rStrm.WriteUInt32( nType )
+ .WriteFloat( fAccelerate );
+ }
+
+ // decelerate (4)
+ float fDecelerate = static_cast<float>(xNode->getDecelerate());
+ if ( bExportAlways || ( fDecelerate != 0.0 ) )
+ {
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
+ sal_uInt32 const nType = 4;
+ rStrm.WriteUInt32( nType )
+ .WriteFloat( fDecelerate );
+ }
+
+ // autoreverse (5)
+ bool bAutoReverse = xNode->getAutoReverse();
+ if ( bExportAlways || bAutoReverse )
+ {
+ EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
+ sal_uInt32 const nType = 5;
+ sal_uInt32 nVal = bAutoReverse ? 1 : 0;
+ rStrm.WriteUInt32( nType )
+ .WriteUInt32( nVal );
+ }
+}
+
+void AnimationExporter::exportTransitionFilter( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XTransitionFilter > xFilter( xNode, UNO_QUERY );
+ if ( !xFilter.is() )
+ return;
+
+ EscherExContainer aAnimateFilter( rStrm, DFF_msofbtAnimateFilter );
+ {
+ EscherExAtom aAnimateFilterData( rStrm, DFF_msofbtAnimateFilterData );
+ sal_uInt32 const nBits = 3; // bit 0 -> use AnimAttributeValue
+ // bit 1 -> use nTransition
+
+ sal_uInt32 nTransition = xFilter->getMode() ? 0 : 1;
+ rStrm.WriteUInt32( nBits )
+ .WriteUInt32( nTransition );
+ }
+ const char* pFilter = FindTransitionName( xFilter->getTransition(), xFilter->getSubtype(), xFilter->getDirection() );
+ if ( pFilter )
+ {
+ const OUString aStr( OUString::createFromAscii( pFilter ) );
+ exportAnimPropertyString( rStrm, 1, aStr, TRANSLATE_NONE );
+ }
+ exportAnimateTarget( rStrm, xNode );
+}
+
+void AnimationExporter::exportAnimateMotion( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimateMotion > xMotion( xNode, UNO_QUERY );
+ if ( !xMotion.is() )
+ return;
+
+ EscherExContainer aAnimateMotion( rStrm, DFF_msofbtAnimateMotion );
+ {
+ { //SJ: Ignored from import filter
+ EscherExAtom aAnimateMotionData( rStrm, DFF_msofbtAnimateMotionData );
+ sal_uInt32 const nBits = 0x98;
+ sal_uInt32 const nOrigin = 0x2;
+ float const fByX = 100.0; // nBits&1
+ float const fByY = 100.0; // nBits&1
+ float const fFromX = 0.0; // nBits&2
+ float const fFromY = 0.0; // nBits&2
+ float const fToX = 100.0; // nBits&4
+ float const fToY = 100.0; // nBits&4
+ rStrm.WriteUInt32( nBits ).WriteFloat( fByX ).WriteFloat( fByY ).WriteFloat( fFromX ).WriteFloat( fFromY ).WriteFloat( fToX ).WriteFloat( fToY ).WriteUInt32( nOrigin );
+ }
+
+ OUString aStr;
+ if ( xMotion->getPath() >>= aStr )
+ {
+ if ( !aStr.isEmpty() )
+ exportAnimPropertyString( rStrm, 1, aStr, TRANSLATE_NONE );
+ }
+ exportAnimateTarget( rStrm, xNode );
+ }
+}
+
+void AnimationExporter::exportAnimateTransform( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimateTransform > xTransform( xNode, UNO_QUERY );
+ if ( !xTransform.is() )
+ return;
+
+ if ( xTransform->getTransformType() == AnimationTransformType::SCALE )
+ {
+ EscherExContainer aAnimateScale( rStrm, DFF_msofbtAnimateScale );
+ {
+ EscherExAtom aAnimateScaleData( rStrm, DFF_msofbtAnimateScaleData );
+ sal_uInt32 nBits = 0;
+ sal_uInt32 const nZoomContents = 1;
+ float fByX = 100.0;
+ float fByY = 100.0;
+ float fFromX = 0.0;
+ float fFromY = 0.0;
+ float fToX = 100.0;
+ float fToY = 100.0;
+
+ double fX = 0.0, fY = 0.0;
+ ValuePair aPair;
+ if ( xTransform->getBy() >>= aPair )
+ {
+ if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
+ {
+ nBits |= 1;
+ fByX = static_cast<float>( fX * 100 );
+ fByY = static_cast<float>( fY * 100 );
+ }
+ }
+ if ( xTransform->getFrom() >>= aPair )
+ {
+ if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
+ {
+ nBits |= 2;
+ fFromX = static_cast<float>( fX * 100 );
+ fFromY = static_cast<float>( fY * 100 );
+ }
+ }
+ if( xTransform->getTo() >>= aPair )
+ {
+ if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
+ {
+ nBits |= 4;
+ fToX = static_cast<float>( fX * 100 );
+ fToY = static_cast<float>( fY * 100 );
+ }
+ }
+
+ // TODO: ZoomContents:
+ //if( nBits & 8 )
+ //( fprintf( mpFile, " zoomContents=\"%s\"", nZoomContents ? "true" : "false" );
+
+ rStrm.WriteUInt32( nBits ).WriteFloat( fByX ).WriteFloat( fByY ).WriteFloat( fFromX ).WriteFloat( fFromY ).WriteFloat( fToX ).WriteFloat( fToY ).WriteUInt32( nZoomContents );
+ }
+ exportAnimateTarget( rStrm, xNode );
+ }
+ else if ( xTransform->getTransformType() == AnimationTransformType::ROTATE )
+ {
+ EscherExContainer aAnimateRotation( rStrm, DFF_msofbtAnimateRotation );
+ {
+ EscherExAtom aAnimateRotationData( rStrm, DFF_msofbtAnimateRotationData );
+ sal_uInt32 nBits = 0;
+ sal_uInt32 const nU1 = 0;
+ float fBy = 360.0;
+ float fFrom = 0.0;
+ float fTo = 360.0;
+
+ double fVal = 0.0;
+ if ( xTransform->getBy() >>= fVal )
+ {
+ nBits |= 1;
+ fBy = static_cast<float>(fVal);
+ }
+ if ( xTransform->getFrom() >>= fVal )
+ {
+ nBits |= 2;
+ fFrom = static_cast<float>(fVal);
+ }
+ if ( xTransform->getTo() >>= fVal )
+ {
+ nBits |= 4;
+ fTo = static_cast<float>(fVal);
+ }
+ rStrm.WriteUInt32( nBits ).WriteFloat( fBy ).WriteFloat( fFrom ).WriteFloat( fTo ).WriteUInt32( nU1 );
+ }
+ exportAnimateTarget( rStrm, xNode, 1 );
+ }
+}
+
+bool AnimationExporter::getColorAny( const Any& rAny, const sal_Int16 nColorSpace, sal_Int32& rMode, sal_Int32& rA, sal_Int32& rB, sal_Int32& rC )
+{
+ bool bIsColor = true;
+
+ rMode = 0;
+ if ( nColorSpace == AnimationColorSpace::HSL )
+ rMode = 1;
+
+ sal_Int32 nColor = 0;
+ Sequence< double > aHSL( 3 );
+ if ( rAny >>= nColor ) // RGB color
+ {
+ rA = static_cast<sal_uInt8>( nColor >> 16 );
+ rB = static_cast<sal_uInt8>( nColor >> 8 );
+ rC = static_cast<sal_uInt8>(nColor);
+ }
+ else if ( rAny >>= aHSL ) // HSL
+ {
+ rA = static_cast<sal_Int32>( aHSL[ 0 ] * 255.0 / 360.0 );
+ rB = static_cast<sal_Int32>( aHSL[ 1 ] * 255.0 );
+ rC = static_cast<sal_Int32>( aHSL[ 2 ] * 255.0 );
+ }
+ else
+ bIsColor = false;
+ return bIsColor;
+}
+
+void AnimationExporter::exportAnimateColor( SvStream& rStrm, const Reference< XAnimationNode >& xNode, int nAfterEffectType )
+{
+ Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
+ if ( !xColor.is() )
+ return;
+
+ EscherExContainer aAnimateColor( rStrm, DFF_msofbtAnimateColor );
+ {
+ EscherExAtom aAnimateColorData( rStrm, DFF_msofbtAnimateColorData );
+ sal_uInt32 nBits = 8;
+
+ sal_Int32 nByMode, nByA, nByB, nByC;
+ nByMode = nByA = nByB = nByC = 0;
+
+ sal_Int32 nFromMode, nFromA, nFromB, nFromC;
+ nFromMode = nFromA = nFromB = nFromC = 0;
+
+ sal_Int32 nToMode, nToA, nToB, nToC;
+ nToMode = nToA = nToB = nToC = 0;
+
+ sal_Int16 nColorSpace = xColor->getColorInterpolation();
+
+ Any aAny( xColor->getBy() );
+ if ( aAny.hasValue() )
+ {
+ if ( getColorAny( aAny, nColorSpace, nByMode, nByA, nByB, nByC ) )
+ nBits |= 0x11;
+ }
+ aAny = xColor->getFrom();
+ if ( aAny.hasValue() )
+ {
+ if ( getColorAny( aAny, nColorSpace, nFromMode, nFromA, nFromB, nFromC ) )
+ nBits |= 0x12;
+ }
+ aAny = xColor->getTo();
+ if ( aAny.hasValue() )
+ {
+ if ( getColorAny( aAny, nColorSpace, nToMode, nToA, nToB, nToC ) )
+ nBits |= 0x14;
+ }
+ rStrm .WriteUInt32( nBits )
+ .WriteInt32( nByMode ).WriteInt32( nByA ).WriteInt32( nByB ).WriteInt32( nByC )
+ .WriteInt32( nFromMode ).WriteInt32( nFromA ).WriteInt32( nFromB ).WriteInt32( nFromC )
+ .WriteInt32( nToMode ).WriteInt32( nToA ).WriteInt32( nToB ).WriteInt32( nToC );
+ }
+ exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType );
+}
+
+void AnimationExporter::exportIterate( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XIterateContainer > xIterate( xNode, UNO_QUERY );
+ if ( !xIterate.is() )
+ return;
+
+ EscherExAtom aAnimIteration( rStrm, DFF_msofbtAnimIteration );
+
+ float fInterval = 10.0;
+ sal_Int32 nTextUnitEffect = 0;
+ sal_Int32 const nU1 = 1;
+ sal_Int32 const nU2 = 1;
+ sal_Int32 const nU3 = 0xe;
+
+ sal_Int16 nIterateType = xIterate->getIterateType();
+ switch( nIterateType )
+ {
+ case TextAnimationType::BY_WORD : nTextUnitEffect = 1; break;
+ case TextAnimationType::BY_LETTER : nTextUnitEffect = 2; break;
+ }
+
+ fInterval = static_cast<float>(xIterate->getIterateInterval());
+
+ // convert interval from absolute to percentage
+ double fDuration = 0.0;
+
+ Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimate > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
+ if( xChildNode.is() )
+ {
+ double fChildBegin = 0.0;
+ double fChildDuration = 0.0;
+ xChildNode->getBegin() >>= fChildBegin;
+ xChildNode->getDuration() >>= fChildDuration;
+
+ fChildDuration += fChildBegin;
+ if( fChildDuration > fDuration )
+ fDuration = fChildDuration;
+ }
+ }
+ }
+ }
+
+ if( fDuration )
+ fInterval = static_cast<float>(100.0 * fInterval / fDuration);
+
+ rStrm.WriteFloat( fInterval ).WriteInt32( nTextUnitEffect ).WriteInt32( nU1 ).WriteInt32( nU2 ).WriteInt32( nU3 );
+ aTarget = xIterate->getTarget();
+}
+
+} // namespace ppt;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptexanimations.hxx b/sd/source/filter/eppt/pptexanimations.hxx
new file mode 100644
index 000000000..daa54d85b
--- /dev/null
+++ b/sd/source/filter/eppt/pptexanimations.hxx
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#ifdef DBG_ANIM_LOG
+#include <stdio.h>
+#endif
+
+#include <rtl/ustring.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.h>
+
+#include <memory>
+#include <vector>
+
+namespace com::sun::star::animations { class XAnimate; }
+namespace com::sun::star::animations { class XAnimationNode; }
+namespace com::sun::star::beans { struct NamedValue; }
+namespace com::sun::star::drawing { class XDrawPage; }
+namespace com::sun::star::drawing { class XShape; }
+namespace ppt { class ExSoundCollection; }
+
+class SvStream;
+class EscherSolverContainer;
+
+namespace ppt
+{
+
+ struct AfterEffectNode
+ {
+ css::uno::Reference< css::animations::XAnimationNode > mxNode;
+ css::uno::Reference< css::animations::XAnimationNode > mxMaster;
+
+ AfterEffectNode( const css::uno::Reference< css::animations::XAnimationNode >& xNode,
+ const css::uno::Reference< css::animations::XAnimationNode >& xMaster )
+ : mxNode( xNode ), mxMaster( xMaster ) {}
+ };
+
+ typedef std::shared_ptr< AfterEffectNode > AfterEffectNodePtr;
+
+typedef sal_uInt32 TranslateMode;
+#define TRANSLATE_NONE 0
+#define TRANSLATE_VALUE 1
+#define TRANSLATE_ATTRIBUTE 2
+#define TRANSLATE_MEASURE 4
+#define TRANSLATE_NUMBER_TO_STRING 8
+
+const int AFTEREFFECT_NONE = 0;
+const int AFTEREFFECT_COLOR = 1;
+const int AFTEREFFECT_SET = 2;
+
+class AnimationExporter
+{
+ css::uno::Any aTarget;
+ const EscherSolverContainer& mrSolverContainer;
+ ppt::ExSoundCollection& mrExSoundCollection;
+ std::vector< AfterEffectNodePtr > maAfterEffectNodes;
+ sal_Int32 mnCurrentGroup;
+
+ static void writeZString( SvStream& rStrm, const OUString& rVal );
+ static bool getColorAny( const css::uno::Any& rAny, const sal_Int16 nColorSpace, sal_Int32& rMode, sal_Int32& rA, sal_Int32& rB, sal_Int32& rC );
+ static bool exportAnimProperty( SvStream& rStrm, const sal_uInt16 nPropertyId, const css::uno::Any& rAny, const TranslateMode eTranslateMode );
+ static void exportAnimPropertyString( SvStream& rStrm, const sal_uInt16 nPropertyId, const OUString& rVal, const TranslateMode eTranslateMode );
+ static void exportAnimPropertyFloat( SvStream& rStrm, const sal_uInt16 nPropertyId, const double& rVal );
+ static void exportAnimPropertyuInt32( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt32 nVal );
+ static void exportAnimPropertyByte( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt8 nVal );
+
+ /** if available exportAnimPropertySet
+ @return the css::presentation::EffectNodeType*/
+ static sal_Int16 exportAnimPropertySet( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ static void exportAnimNode( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode,
+ const sal_Int16 nFillDefault );
+ void exportAnimate( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void exportAnimateTarget( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode, const sal_uInt32 nForceAttributeName = 0, int nAfterEffectType = AFTEREFFECT_NONE );
+ void exportAnimateSet( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode, int nAfterEffectType );
+ static void exportAnimAction( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void exportAnimEvent( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode, const sal_Int32 nFlags = 0 );
+ void exportNode( SvStream& rStrm, css::uno::Reference< css::animations::XAnimationNode > const & xNode,
+ const sal_uInt16 nContainerRecType, const sal_uInt16 nInstance, const sal_Int32 nGroupLevel, const bool bTakeBackInteractiveSequenceTiming,
+ const sal_Int16 nFillDefault );
+ void exportAnimateTargetElement( SvStream& rStrm, const css::uno::Any& rAny, const bool bCreate2b01Atom );
+ static void exportAnimateKeyPoints( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimate >& xAnimate );
+ static void exportAnimValue( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode, const bool bExportAlways );
+ void exportTransitionFilter( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void exportAnimateMotion( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void exportAnimateTransform( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+ void exportAnimateColor( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode, int nAfterEffectType );
+ void exportIterate( SvStream& rStrm, const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+
+ void processAfterEffectNodes( const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+
+ bool isAfterEffectNode( const css::uno::Reference< css::animations::XAnimationNode >& xNode ) const;
+ bool hasAfterEffectNode( const css::uno::Reference< css::animations::XAnimationNode >& xNode, css::uno::Reference< css::animations::XAnimationNode >& xAfterEffectNode ) const;
+ bool isEmptyNode( const css::uno::Reference< css::animations::XAnimationNode >& xNode ) const;
+
+ static css::uno::Reference< css::animations::XAnimationNode > createAfterEffectNodeClone( const css::uno::Reference< css::animations::XAnimationNode >& xNode );
+
+public:
+ AnimationExporter( const EscherSolverContainer& rSolverContainer, ppt::ExSoundCollection& rExSoundCollection );
+
+ void doexport( const css::uno::Reference< css::drawing::XDrawPage >& xPage, SvStream& rStrm );
+
+ // helper methods also used in ooxml export
+ static css::uno::Any convertAnimateValue( const css::uno::Any& rSource, std::u16string_view rAttributeName );
+ static bool GetNodeType( const css::uno::Reference< css::animations::XAnimationNode >& xNode, sal_Int16& nType );
+ static sal_Int16 GetFillMode( const css::uno::Reference< css::animations::XAnimationNode >& xNode, const sal_Int16 nFillDefault );
+ static void GetUserData( const css::uno::Sequence< css::beans::NamedValue >& rUserData, const css::uno::Any ** pAny, std::size_t nLen );
+ static sal_uInt32 TranslatePresetSubType( const sal_uInt32 nPresetClass, const sal_uInt32 nPresetId, std::u16string_view rPresetSubType );
+ static sal_uInt32 GetPresetID( const OUString& rPreset, sal_uInt32 nAPIPresetClass, bool& bPresetId );
+ static sal_uInt32 GetValueTypeForAttributeName( const OUString& rAttributeName );
+
+ static const char* FindTransitionName( const sal_Int16 nType, const sal_Int16 nSubType, const bool bDirection );
+ static css::uno::Reference< css::drawing::XShape > getTargetElementShape( const css::uno::Any& rAny, sal_Int32& rBegin, sal_Int32& rEnd, bool& rParagraphTarget );
+};
+} // namespace ppt
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptexsoundcollection.cxx b/sd/source/filter/eppt/pptexsoundcollection.cxx
new file mode 100644
index 000000000..c4770e644
--- /dev/null
+++ b/sd/source/filter/eppt/pptexsoundcollection.cxx
@@ -0,0 +1,213 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include "pptexsoundcollection.hxx"
+#include "epptdef.hxx"
+#include <tools/stream.hxx>
+#include <tools/urlobj.hxx>
+#include <ucbhelper/content.hxx>
+#include <comphelper/processfactory.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+
+namespace ppt
+{
+
+ExSoundEntry::ExSoundEntry(const OUString& rString)
+ : nFileSize(0)
+ , aSoundURL(rString)
+{
+ try
+ {
+ ::ucbhelper::Content aCnt( aSoundURL,
+ css::uno::Reference< css::ucb::XCommandEnvironment >(),
+ comphelper::getProcessComponentContext() );
+ sal_Int64 nVal = 0;
+ aCnt.getPropertyValue("Size") >>= nVal;
+ nFileSize = static_cast<sal_uInt32>(nVal);
+ }
+ catch( css::uno::Exception& )
+ {
+
+ }
+};
+
+OUString ExSoundEntry::ImplGetName() const
+{
+ INetURLObject aTmp( aSoundURL );
+ return aTmp.GetLastName();
+}
+
+OUString ExSoundEntry::ImplGetExtension() const
+{
+ INetURLObject aTmp( aSoundURL );
+ OUString aExtension(aTmp.GetFileExtension());
+ if ( !aExtension.isEmpty() )
+ {
+ aExtension = "." + aExtension;
+ }
+ return aExtension;
+}
+
+bool ExSoundEntry::IsSameURL(std::u16string_view rURL) const
+{
+ return ( rURL == aSoundURL );
+}
+
+sal_uInt32 ExSoundEntry::GetSize( sal_uInt32 nId ) const
+{
+ OUString aName( ImplGetName() );
+ OUString aExtension( ImplGetExtension() );
+
+ sal_uInt32 nSize = 8; // SoundContainer Header
+ if ( !aName.isEmpty() ) // String Atom ( instance 0 - name of sound )
+ nSize += aName.getLength() * 2 + 8;
+ if ( !aExtension.isEmpty() ) // String Atom ( instance 1 - extension of sound )
+ nSize += aExtension.getLength() * 2 + 8;
+
+ OUString aId( OUString::number(nId) ); // String Atom ( instance 2 - reference id )
+ nSize += 2 * aId.getLength() + 8;
+
+ nSize += nFileSize + 8; // SoundData Atom
+
+ return nSize;
+}
+
+void ExSoundEntry::Write( SvStream& rSt, sal_uInt32 nId ) const
+{
+ try
+ {
+ ::ucbhelper::Content aLoadContentIfExists( aSoundURL,
+ css::uno::Reference< css::ucb::XCommandEnvironment >(),
+ comphelper::getProcessComponentContext() );
+
+ // create SoundContainer
+ rSt.WriteUInt32( ( EPP_Sound << 16 ) | 0xf ).WriteUInt32( GetSize( nId ) - 8 );
+
+ OUString aSoundName( ImplGetName() );
+ sal_Int32 i, nSoundNameLen = aSoundName.getLength();
+ if ( nSoundNameLen )
+ {
+ // name of sound ( instance 0 )
+ rSt.WriteUInt32( EPP_CString << 16 ).WriteUInt32( nSoundNameLen * 2 );
+ for ( i = 0; i < nSoundNameLen; ++i )
+ rSt.WriteUInt16( aSoundName[i] );
+ }
+ OUString aExtension( ImplGetExtension() );
+ sal_Int32 nExtensionLen = aExtension.getLength();
+ if ( nExtensionLen )
+ {
+ // extension of sound ( instance 1 )
+ rSt.WriteUInt32( ( EPP_CString << 16 ) | 16 ).WriteUInt32( nExtensionLen * 2 );
+ for ( i = 0; i < nExtensionLen; ++i )
+ rSt.WriteUInt16( aExtension[i] );
+ }
+ // id of sound ( instance 2 )
+ OUString aId( OUString::number(nId ) );
+ sal_Int32 nIdLen = aId.getLength();
+ rSt.WriteUInt32( ( EPP_CString << 16 ) | 32 ).WriteUInt32( nIdLen * 2 );
+ for ( i = 0; i < nIdLen; ++i )
+ rSt.WriteUInt16( aId[i] );
+
+ rSt.WriteUInt32( EPP_SoundData << 16 ).WriteUInt32( nFileSize );
+ sal_uInt32 nBytesLeft = nFileSize;
+ std::unique_ptr<SvStream> pSourceFile = ::utl::UcbStreamHelper::CreateStream( aSoundURL, StreamMode::READ );
+ if ( pSourceFile )
+ {
+ std::unique_ptr<sal_uInt8[]> pBuf( new sal_uInt8[ 0x10000 ] ); // 64 kB Buffer
+ while ( nBytesLeft )
+ {
+ sal_uInt32 nToDo = std::min<sal_uInt32>( nBytesLeft, 0x10000 );
+ pSourceFile->ReadBytes(pBuf.get(), nToDo);
+ rSt.WriteBytes(pBuf.get(), nToDo);
+ nBytesLeft -= nToDo;
+ }
+ }
+ }
+ catch( css::uno::Exception& )
+ {
+
+ }
+}
+
+sal_uInt32 ExSoundCollection::GetId(const OUString& rString)
+{
+ sal_uInt32 nSoundId = 0;
+ if (!rString.isEmpty())
+ {
+ const sal_uInt32 nSoundCount = maEntries.size();
+
+ auto iter = std::find_if(maEntries.begin(), maEntries.end(),
+ [&rString](const ExSoundEntry& rEntry) { return rEntry.IsSameURL(rString); });
+ nSoundId = static_cast<sal_uInt32>(std::distance(maEntries.begin(), iter));
+
+ if ( nSoundId++ == nSoundCount )
+ {
+ ExSoundEntry aEntry( rString );
+ if ( aEntry.GetFileSize() )
+ maEntries.push_back(aEntry);
+ else
+ {
+ nSoundId = 0; // only insert sounds that are accessible
+ }
+ }
+ }
+ return nSoundId;
+}
+
+sal_uInt32 ExSoundCollection::GetSize() const
+{
+ sal_uInt32 nSize = 0;
+ if (!maEntries.empty())
+ {
+ nSize += 8 + 12; // size of SoundCollectionContainerHeader + SoundCollAtom
+ sal_uInt32 i = 1;
+ for ( const auto& rEntry : maEntries )
+ {
+ nSize += rEntry.GetSize(i);
+ ++i;
+ }
+ }
+ return nSize;
+}
+
+void ExSoundCollection::Write( SvStream& rSt ) const
+{
+ if (maEntries.empty())
+ return;
+
+ sal_uInt32 i = 1;
+ sal_uInt32 nSoundCount = maEntries.size();
+
+ // create SoundCollection Container
+ rSt.WriteUInt16( 0xf ).WriteUInt16( EPP_SoundCollection ).WriteUInt32( GetSize() - 8 );
+
+ // create SoundCollAtom ( reference to the next free SoundId );
+ rSt.WriteUInt32( EPP_SoundCollAtom << 16 ).WriteUInt32( 4 ).WriteUInt32( nSoundCount );
+
+ for ( const auto& rEntry : maEntries )
+ {
+ rEntry.Write(rSt,i);
+ ++i;
+ }
+}
+
+} // namespace ppt;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptexsoundcollection.hxx b/sd/source/filter/eppt/pptexsoundcollection.hxx
new file mode 100644
index 000000000..d81bb8118
--- /dev/null
+++ b/sd/source/filter/eppt/pptexsoundcollection.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vector>
+
+#ifdef DBG_ANIM_LOG
+#include <stdio.h>
+#endif
+#include <rtl/ustring.hxx>
+
+class SvStream;
+
+namespace ppt
+{
+
+class ExSoundEntry
+{
+ sal_uInt32 nFileSize;
+ OUString aSoundURL;
+
+ OUString ImplGetName() const;
+ OUString ImplGetExtension() const;
+
+ public:
+
+ bool IsSameURL(std::u16string_view rURL) const;
+ sal_uInt32 GetFileSize( ) const { return nFileSize; };
+
+ ExSoundEntry(const OUString& rSoundURL);
+
+ /// @return size of a complete SoundContainer.
+ sal_uInt32 GetSize( sal_uInt32 nId ) const;
+ void Write( SvStream& rSt, sal_uInt32 nId ) const;
+};
+
+class ExSoundCollection
+{
+ public:
+
+ sal_uInt32 GetId(const OUString&);
+
+ /// @return size of a complete SoundCollectionContainer.
+ sal_uInt32 GetSize() const;
+ void Write( SvStream& rSt ) const;
+
+private:
+
+ std::vector<ExSoundEntry> maEntries;
+};
+
+} // namespace ppt
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptx-animations.cxx b/sd/source/filter/eppt/pptx-animations.cxx
new file mode 100644
index 000000000..1c901573c
--- /dev/null
+++ b/sd/source/filter/eppt/pptx-animations.cxx
@@ -0,0 +1,1539 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <o3tl/any.hxx>
+#include <oox/token/tokens.hxx>
+#include "epptooxml.hxx"
+#include <sax/fshelper.hxx>
+#include <sal/log.hxx>
+#include <rtl/math.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+
+#include <com/sun/star/animations/AnimationAdditiveMode.hpp>
+#include <com/sun/star/animations/AnimationCalcMode.hpp>
+#include <com/sun/star/animations/AnimationFill.hpp>
+#include <com/sun/star/animations/AnimationNodeType.hpp>
+#include <com/sun/star/animations/AnimationRestart.hpp>
+#include <com/sun/star/animations/AnimationTransformType.hpp>
+#include <com/sun/star/animations/AnimationValueType.hpp>
+#include <com/sun/star/animations/AnimationColorSpace.hpp>
+#include <com/sun/star/animations/Event.hpp>
+#include <com/sun/star/animations/EventTrigger.hpp>
+#include <com/sun/star/animations/Timing.hpp>
+#include <com/sun/star/animations/ValuePair.hpp>
+#include <com/sun/star/animations/XAnimateMotion.hpp>
+#include <com/sun/star/animations/XAnimateTransform.hpp>
+#include <com/sun/star/animations/XAnimationNode.hpp>
+#include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
+#include <com/sun/star/animations/XAnimateColor.hpp>
+#include <com/sun/star/animations/XCommand.hpp>
+#include <com/sun/star/animations/XAudio.hpp>
+#include <com/sun/star/animations/XTransitionFilter.hpp>
+#include <com/sun/star/animations/XIterateContainer.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/presentation/EffectCommands.hpp>
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/presentation/EffectPresetClass.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/presentation/TextAnimationType.hpp>
+#include <com/sun/star/text/XSimpleText.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <oox/export/utils.hxx>
+#include <oox/ppt/pptfilterhelpers.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+
+#include "pptexanimations.hxx"
+#include "pptx-animations.hxx"
+#include "../ppt/pptanimations.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::presentation;
+using namespace ::com::sun::star::uno;
+using namespace ::ppt;
+using namespace oox::drawingml;
+using namespace oox::core;
+using namespace oox;
+
+using ::com::sun::star::beans::NamedValue;
+using ::com::sun::star::drawing::XDrawPage;
+using ::com::sun::star::drawing::XShape;
+using ::com::sun::star::text::XSimpleText;
+using ::sax_fastparser::FSHelperPtr;
+
+namespace
+{
+void WriteAnimationProperty(const FSHelperPtr& pFS, const Any& rAny, sal_Int32 nToken = 0)
+{
+ if (!rAny.hasValue())
+ return;
+
+ ValuePair aPair;
+
+ if (rAny >>= aPair)
+ {
+ double x, y;
+ if ((aPair.First >>= x) && (aPair.Second >>= y))
+ {
+ if (nToken == XML_by)
+ {
+ // MS needs ending values but we have offset values.
+ x += 1.0;
+ y += 1.0;
+ }
+ pFS->singleElementNS(XML_p, nToken, XML_x, OString::number(x * 100000), XML_y,
+ OString::number(y * 100000));
+ }
+ return;
+ }
+
+ sal_Int32 nRgb = {}; // spurious -Werror=maybe-uninitialized
+ double fDouble = {}; // spurious -Werror=maybe-uninitialized
+
+ TypeClass aClass = rAny.getValueType().getTypeClass();
+ bool bWriteToken
+ = nToken
+ && (aClass == TypeClass_LONG || aClass == TypeClass_DOUBLE || aClass == TypeClass_STRING);
+
+ if (bWriteToken)
+ pFS->startElementNS(XML_p, nToken);
+
+ switch (rAny.getValueType().getTypeClass())
+ {
+ case TypeClass_LONG:
+ if (!(rAny >>= nRgb))
+ {
+ assert(false);
+ }
+ pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(nRgb));
+ break;
+ case TypeClass_DOUBLE:
+ if (!(rAny >>= fDouble))
+ {
+ assert(false);
+ }
+ pFS->singleElementNS(XML_p, XML_fltVal, XML_val, OString::number(fDouble));
+ break;
+ case TypeClass_STRING:
+ pFS->singleElementNS(XML_p, XML_strVal, XML_val, *o3tl::doAccess<OUString>(rAny));
+ break;
+ default:
+ break;
+ }
+
+ if (bWriteToken)
+ pFS->endElementNS(XML_p, nToken);
+}
+
+void WriteAnimateColorColor(const FSHelperPtr& pFS, const Any& rAny, sal_Int32 nToken)
+{
+ if (!rAny.hasValue())
+ return;
+
+ sal_Int32 nColor = 0;
+ if (rAny >>= nColor)
+ {
+ pFS->startElementNS(XML_p, nToken);
+
+ if (nToken == XML_by)
+ {
+ // CT_TLByRgbColorTransform
+ SAL_WARN("sd.eppt", "Export p:rgb in p:by of animClr isn't implemented yet.");
+ }
+ else
+ {
+ // CT_Color
+ pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(nColor));
+ }
+
+ pFS->endElementNS(XML_p, nToken);
+ }
+
+ Sequence<double> aHSL(3);
+ if (!(rAny >>= aHSL))
+ return;
+
+ pFS->startElementNS(XML_p, nToken);
+
+ if (nToken == XML_by)
+ {
+ // CT_TLByHslColorTransform
+ pFS->singleElementNS(XML_p, XML_hsl, XML_h, OString::number(aHSL[0] * 60000), // ST_Angel
+ XML_s, OString::number(aHSL[1] * 100000), XML_l,
+ OString::number(aHSL[2] * 100000));
+ }
+ else
+ {
+ // CT_Color
+ SAL_WARN("sd.eppt", "Export p:hsl in p:from or p:to of animClr isn't implemented yet.");
+ }
+
+ pFS->endElementNS(XML_p, nToken);
+}
+
+void WriteAnimateTo(const FSHelperPtr& pFS, const Any& rValue, const OUString& rAttributeName)
+{
+ if (!rValue.hasValue())
+ return;
+
+ SAL_INFO("sd.eppt", "to attribute name: " << rAttributeName.toUtf8());
+
+ WriteAnimationProperty(pFS, AnimationExporter::convertAnimateValue(rValue, rAttributeName),
+ XML_to);
+}
+
+void WriteAnimateValues(const FSHelperPtr& pFS, const Reference<XAnimate>& rXAnimate)
+{
+ const Sequence<double> aKeyTimes = rXAnimate->getKeyTimes();
+ if (!aKeyTimes.hasElements())
+ return;
+ const Sequence<Any> aValues = rXAnimate->getValues();
+ const OUString& sFormula = rXAnimate->getFormula();
+ const OUString& rAttributeName = rXAnimate->getAttributeName();
+
+ SAL_INFO("sd.eppt", "animate values, formula: " << sFormula.toUtf8());
+
+ assert(aValues.getLength() == aKeyTimes.getLength());
+
+ pFS->startElementNS(XML_p, XML_tavLst);
+
+ for (int i = 0; i < aKeyTimes.getLength(); i++)
+ {
+ SAL_INFO("sd.eppt", "animate value " << i << ": " << aKeyTimes[i]);
+ if (aValues[i].hasValue())
+ {
+ pFS->startElementNS(XML_p, XML_tav, XML_fmla,
+ sax_fastparser::UseIf(sFormula, !sFormula.isEmpty()), XML_tm,
+ OString::number(static_cast<sal_Int32>(aKeyTimes[i] * 100000.0)));
+ pFS->startElementNS(XML_p, XML_val);
+ ValuePair aPair;
+ if (aValues[i] >>= aPair)
+ {
+ WriteAnimationProperty(
+ pFS, AnimationExporter::convertAnimateValue(aPair.First, rAttributeName));
+ WriteAnimationProperty(
+ pFS, AnimationExporter::convertAnimateValue(aPair.Second, rAttributeName));
+ }
+ else
+ WriteAnimationProperty(
+ pFS, AnimationExporter::convertAnimateValue(aValues[i], rAttributeName));
+
+ pFS->endElementNS(XML_p, XML_val);
+ pFS->endElementNS(XML_p, XML_tav);
+ }
+ }
+
+ pFS->endElementNS(XML_p, XML_tavLst);
+}
+
+// Write condition list ( either prevCondlst or nextCondlst ) of Seq.
+void WriteAnimationCondListForSeq(const FSHelperPtr& pFS, sal_Int32 nToken)
+{
+ const char* pEvent = (nToken == XML_prevCondLst) ? "onPrev" : "onNext";
+
+ pFS->startElementNS(XML_p, nToken);
+ pFS->startElementNS(XML_p, XML_cond, XML_evt, pEvent);
+ pFS->startElementNS(XML_p, XML_tgtEl);
+ pFS->singleElementNS(XML_p, XML_sldTgt);
+ pFS->endElementNS(XML_p, XML_tgtEl);
+ pFS->endElementNS(XML_p, XML_cond);
+ pFS->endElementNS(XML_p, nToken);
+}
+
+const char* convertEventTrigger(sal_Int16 nTrigger)
+{
+ const char* pEvent = nullptr;
+ switch (nTrigger)
+ {
+ case EventTrigger::ON_NEXT:
+ pEvent = "onNext";
+ break;
+ case EventTrigger::ON_PREV:
+ pEvent = "onPrev";
+ break;
+ case EventTrigger::BEGIN_EVENT:
+ pEvent = "begin";
+ break;
+ case EventTrigger::END_EVENT:
+ pEvent = "end";
+ break;
+ case EventTrigger::ON_BEGIN:
+ pEvent = "onBegin";
+ break;
+ case EventTrigger::ON_END:
+ pEvent = "onEnd";
+ break;
+ case EventTrigger::ON_CLICK:
+ pEvent = "onClick";
+ break;
+ case EventTrigger::ON_DBL_CLICK:
+ pEvent = "onDblClick";
+ break;
+ case EventTrigger::ON_STOP_AUDIO:
+ pEvent = "onStopAudio";
+ break;
+ case EventTrigger::ON_MOUSE_ENTER:
+ pEvent = "onMouseOver"; // not exact?
+ break;
+ case EventTrigger::ON_MOUSE_LEAVE:
+ pEvent = "onMouseOut";
+ break;
+ }
+ return pEvent;
+}
+
+void WriteAnimationAttributeName(const FSHelperPtr& pFS, const OUString& rAttributeName)
+{
+ if (rAttributeName.isEmpty())
+ return;
+
+ pFS->startElementNS(XML_p, XML_attrNameLst);
+
+ SAL_INFO("sd.eppt", "write attribute name: " << rAttributeName.toUtf8());
+
+ if (rAttributeName == "X;Y")
+ {
+ pFS->startElementNS(XML_p, XML_attrName);
+ pFS->writeEscaped("ppt_x");
+ pFS->endElementNS(XML_p, XML_attrName);
+
+ pFS->startElementNS(XML_p, XML_attrName);
+ pFS->writeEscaped("ppt_y");
+ pFS->endElementNS(XML_p, XML_attrName);
+ }
+ else
+ {
+ const oox::ppt::ImplAttributeNameConversion* attrConv
+ = oox::ppt::getAttributeConversionList();
+ const char* pAttribute = nullptr;
+
+ while (attrConv->mpAPIName != nullptr)
+ {
+ if (rAttributeName.equalsAscii(attrConv->mpAPIName))
+ {
+ pAttribute = attrConv->mpMSName;
+ break;
+ }
+ attrConv++;
+ }
+
+ if (pAttribute)
+ {
+ pFS->startElementNS(XML_p, XML_attrName);
+ pFS->writeEscaped(pAttribute);
+ pFS->endElementNS(XML_p, XML_attrName);
+ }
+ else
+ {
+ SAL_WARN("sd.eppt", "unhandled animation attribute name: " << rAttributeName);
+ }
+ }
+
+ pFS->endElementNS(XML_p, XML_attrNameLst);
+}
+
+bool isValidTarget(const Any& rTarget)
+{
+ Reference<XShape> xShape;
+
+ if ((rTarget >>= xShape) && xShape.is())
+ return true;
+
+ ParagraphTarget aParagraphTarget;
+
+ return (rTarget >>= aParagraphTarget) && aParagraphTarget.Shape.is();
+}
+
+/// extract ooxml node type from a XAnimationNode.
+sal_Int32 extractNodeType(const Reference<XAnimationNode>& rXNode)
+{
+ sal_Int16 nType = rXNode->getType();
+ sal_Int32 xmlNodeType = -1;
+ switch (nType)
+ {
+ case AnimationNodeType::ITERATE:
+ case AnimationNodeType::PAR:
+ xmlNodeType = XML_par;
+ break;
+ case AnimationNodeType::SEQ:
+ xmlNodeType = XML_seq;
+ break;
+ case AnimationNodeType::ANIMATE:
+ xmlNodeType = XML_anim;
+ break;
+ case AnimationNodeType::ANIMATEMOTION:
+ xmlNodeType = XML_animMotion;
+ break;
+ case AnimationNodeType::ANIMATETRANSFORM:
+ {
+ Reference<XAnimateTransform> xTransform(rXNode, UNO_QUERY);
+ if (xTransform.is())
+ {
+ if (xTransform->getTransformType() == AnimationTransformType::SCALE)
+ xmlNodeType = XML_animScale;
+ else if (xTransform->getTransformType() == AnimationTransformType::ROTATE)
+ xmlNodeType = XML_animRot;
+ }
+ break;
+ }
+ case AnimationNodeType::ANIMATECOLOR:
+ xmlNodeType = XML_animClr;
+ break;
+ case AnimationNodeType::SET:
+ xmlNodeType = XML_set;
+ break;
+ case AnimationNodeType::TRANSITIONFILTER:
+ xmlNodeType = XML_animEffect;
+ break;
+ case AnimationNodeType::COMMAND:
+ xmlNodeType = XML_cmd;
+ break;
+ case AnimationNodeType::AUDIO:
+ xmlNodeType = XML_audio;
+ break;
+ default:
+ SAL_WARN("sd.eppt", "unhandled animation node: " << nType);
+ break;
+ }
+ return xmlNodeType;
+}
+
+/// Convert AnimationRestart to ST_TLTimeNodeRestartType value.
+const char* convertAnimationRestart(sal_Int16 nRestart)
+{
+ const char* pRestart = nullptr;
+ switch (nRestart)
+ {
+ case AnimationRestart::ALWAYS:
+ pRestart = "always";
+ break;
+ case AnimationRestart::WHEN_NOT_ACTIVE:
+ pRestart = "whenNotActive";
+ break;
+ case AnimationRestart::NEVER:
+ pRestart = "never";
+ break;
+ }
+ return pRestart;
+}
+
+/// Convert EffectNodeType to ST_TLTimeNodeType
+const char* convertEffectNodeType(sal_Int16 nType)
+{
+ const char* pNodeType = nullptr;
+ switch (nType)
+ {
+ case EffectNodeType::TIMING_ROOT:
+ pNodeType = "tmRoot";
+ break;
+ case EffectNodeType::MAIN_SEQUENCE:
+ pNodeType = "mainSeq";
+ break;
+ case EffectNodeType::ON_CLICK:
+ pNodeType = "clickEffect";
+ break;
+ case EffectNodeType::AFTER_PREVIOUS:
+ pNodeType = "afterEffect";
+ break;
+ case EffectNodeType::WITH_PREVIOUS:
+ pNodeType = "withEffect";
+ break;
+ case EffectNodeType::INTERACTIVE_SEQUENCE:
+ pNodeType = "interactiveSeq";
+ break;
+ }
+ return pNodeType;
+}
+
+/// Convert EffectPresetClass to ST_TLTimeNodePresetClassType
+const char* convertEffectPresetClass(sal_Int16 nPresetClass)
+{
+ const char* pPresetClass = nullptr;
+ switch (nPresetClass)
+ {
+ case EffectPresetClass::ENTRANCE:
+ pPresetClass = "entr";
+ break;
+ case EffectPresetClass::EXIT:
+ pPresetClass = "exit";
+ break;
+ case EffectPresetClass::EMPHASIS:
+ pPresetClass = "emph";
+ break;
+ case EffectPresetClass::MOTIONPATH:
+ pPresetClass = "path";
+ break;
+ case EffectPresetClass::OLEACTION:
+ pPresetClass = "verb"; // ?
+ break;
+ case EffectPresetClass::MEDIACALL:
+ pPresetClass = "mediacall";
+ break;
+ }
+ return pPresetClass;
+}
+
+/// convert AnimationFill to ST_TLTimeNodeFillType.
+const char* convertAnimationFill(sal_Int16 nFill)
+{
+ const char* pFill = nullptr;
+ switch (nFill)
+ {
+ case AnimationFill::FREEZE:
+ pFill = "hold";
+ break;
+ case AnimationFill::HOLD:
+ pFill = "hold";
+ break;
+ case AnimationFill::REMOVE:
+ pFill = "remove";
+ break;
+ case AnimationFill::TRANSITION:
+ pFill = "transition";
+ break;
+ }
+ return pFill;
+}
+
+/// Convert TextAnimationType to ST_IterateType.
+const char* convertTextAnimationType(sal_Int16 nType)
+{
+ const char* sType = nullptr;
+ switch (nType)
+ {
+ case TextAnimationType::BY_PARAGRAPH:
+ sType = "el";
+ break;
+ case TextAnimationType::BY_LETTER:
+ sType = "lt";
+ break;
+ case TextAnimationType::BY_WORD:
+ default:
+ sType = "wd";
+ break;
+ }
+ return sType;
+}
+
+class NodeContext;
+
+typedef std::unique_ptr<NodeContext> NodeContextPtr;
+
+class NodeContext
+{
+ const Reference<XAnimationNode> mxNode;
+ const bool mbMainSeqChild;
+
+ std::vector<NodeContextPtr> maChildNodes;
+ // if the node has valid target or contains at least one valid target.
+ bool mbValid;
+
+ // Attributes initialized from mxNode->getUserData().
+ sal_Int16 mnEffectNodeType;
+ sal_Int16 mnEffectPresetClass;
+ OUString msEffectPresetId;
+ OUString msEffectPresetSubType;
+
+ /// constructor helper for initializing user data.
+ void initUserData();
+
+ /// constructor helper to initialize maChildNodes.
+ /// return true if at least one childnode is valid.
+ bool initChildNodes();
+
+ /// constructor helper to initialize mbValid
+ void initValid(bool bHasValidChild, bool bIsIterateChild);
+
+public:
+ NodeContext(const Reference<XAnimationNode>& xNode, bool bMainSeqChild, bool bIsIterateChild);
+ const Reference<XAnimationNode>& getNode() const { return mxNode; }
+ bool isMainSeqChild() const { return mbMainSeqChild; }
+ sal_Int16 getEffectNodeType() const { return mnEffectNodeType; }
+ sal_Int16 getEffectPresetClass() const { return mnEffectPresetClass; }
+ const OUString& getEffectPresetId() const { return msEffectPresetId; }
+ const OUString& getEffectPresetSubType() const { return msEffectPresetSubType; }
+ bool isValid() const { return mbValid; }
+ const std::vector<NodeContextPtr>& getChildNodes() const { return maChildNodes; };
+ Any getCondition(bool bBegin) const;
+};
+
+struct Cond
+{
+ OString msDelay;
+ const char* mpEvent;
+ Reference<XShape> mxShape;
+ Reference<XAnimationNode> mxNode;
+
+ Cond(const Any& rAny, bool bIsMainSeqChild);
+
+ bool isValid() const { return msDelay.getLength() || mpEvent; }
+ const char* getDelay() const { return msDelay.getLength() ? msDelay.getStr() : nullptr; }
+};
+
+Cond::Cond(const Any& rAny, bool bIsMainSeqChild)
+ : mpEvent(nullptr)
+{
+ bool bHasFDelay = false;
+ double fDelay = 0;
+ Timing eTiming;
+ Event aEvent;
+
+ if (rAny >>= eTiming)
+ {
+ if (eTiming == Timing_INDEFINITE)
+ msDelay = "indefinite";
+ }
+ else if (rAny >>= aEvent)
+ {
+ if (aEvent.Trigger == EventTrigger::ON_NEXT && bIsMainSeqChild)
+ msDelay = "indefinite";
+ else
+ {
+ mpEvent = convertEventTrigger(aEvent.Trigger);
+ if (!(aEvent.Source >>= mxShape))
+ aEvent.Source >>= mxNode;
+
+ if (aEvent.Offset >>= fDelay)
+ bHasFDelay = true;
+ }
+ }
+ else if (rAny >>= fDelay)
+ bHasFDelay = true;
+
+ if (bHasFDelay)
+ {
+ sal_Int32 nDelay = static_cast<sal_uInt32>(fDelay * 1000.0);
+ msDelay = OString::number(nDelay);
+ }
+}
+
+class PPTXAnimationExport
+{
+ void WriteAnimationNode(const NodeContextPtr& pContext);
+ void WriteAnimationNodeAnimate(sal_Int32 nXmlNodeType);
+ void WriteAnimationNodeAnimateInside(bool bSimple, bool bWriteTo = true);
+ void WriteAnimationNodeSeq();
+ void WriteAnimationNodeEffect();
+ void WriteAnimationNodeCommand();
+ void WriteAnimationNodeAudio();
+ void WriteAnimationNodeCommonPropsStart();
+ void WriteAnimationTarget(const Any& rTarget);
+ void WriteAnimationCondList(const Any& rAny, sal_Int32 nToken);
+ void WriteAnimationCond(const Cond& rCond);
+ bool isMainSeqChild() const;
+ const Reference<XAnimationNode>& getCurrentNode() const;
+
+ PowerPointExport& mrPowerPointExport;
+ const FSHelperPtr& mpFS;
+ const NodeContext* mpContext;
+
+ std::map<Reference<XAnimationNode>, sal_Int32> maAnimationNodeIdMap;
+ sal_Int32 GetNextAnimationNodeId(const Reference<XAnimationNode>& rNode);
+ sal_Int32 GetAnimationNodeId(const Reference<XAnimationNode>& rNode);
+
+public:
+ PPTXAnimationExport(PowerPointExport& rExport, const FSHelperPtr& pFS);
+ void WriteAnimations(const Reference<XDrawPage>& rXDrawPage);
+};
+
+/// Returns if rURL has an extension which is an audio format.
+bool IsAudioURL(const OUString& rURL)
+{
+ return rURL.endsWithIgnoreAsciiCase(".wav") || rURL.endsWithIgnoreAsciiCase(".m4a");
+}
+
+/// Returns if rURL has an extension which is a video format.
+bool IsVideoURL(const OUString& rURL) { return rURL.endsWithIgnoreAsciiCase(".mp4"); }
+}
+
+namespace oox::core
+{
+void WriteAnimations(const FSHelperPtr& pFS, const Reference<XDrawPage>& rXDrawPage,
+ PowerPointExport& rExport)
+{
+ PPTXAnimationExport aAnimationExport(rExport, pFS);
+ aAnimationExport.WriteAnimations(rXDrawPage);
+}
+}
+
+PPTXAnimationExport::PPTXAnimationExport(PowerPointExport& rExport, const FSHelperPtr& pFS)
+ : mrPowerPointExport(rExport)
+ , mpFS(pFS)
+ , mpContext(nullptr)
+{
+}
+
+bool PPTXAnimationExport::isMainSeqChild() const
+{
+ assert(mpContext);
+ return mpContext->isMainSeqChild();
+}
+
+const Reference<XAnimationNode>& PPTXAnimationExport::getCurrentNode() const
+{
+ assert(mpContext);
+ return mpContext->getNode();
+}
+
+void PPTXAnimationExport::WriteAnimationTarget(const Any& rTarget)
+{
+ sal_Int32 nParagraph = -1;
+ bool bParagraphTarget = false;
+
+ Reference<XShape> rXShape;
+ rTarget >>= rXShape;
+
+ if (!rXShape.is())
+ {
+ ParagraphTarget aParagraphTarget;
+ if (rTarget >>= aParagraphTarget)
+ rXShape = aParagraphTarget.Shape;
+ if (rXShape.is())
+ {
+ nParagraph = static_cast<sal_Int32>(aParagraphTarget.Paragraph);
+ Reference<XSimpleText> xText(rXShape, UNO_QUERY);
+ if (xText.is())
+ {
+ bParagraphTarget = true;
+ }
+ }
+ }
+
+ if (!rXShape.is())
+ return;
+
+ sal_Int32 nShapeID = mrPowerPointExport.GetShapeID(rXShape);
+
+ mpFS->startElementNS(XML_p, XML_tgtEl);
+ mpFS->startElementNS(XML_p, XML_spTgt, XML_spid, OString::number(nShapeID));
+ if (bParagraphTarget)
+ {
+ mpFS->startElementNS(XML_p, XML_txEl);
+ mpFS->singleElementNS(XML_p, XML_pRg, XML_st, OString::number(nParagraph), XML_end,
+ OString::number(nParagraph));
+ mpFS->endElementNS(XML_p, XML_txEl);
+ }
+ mpFS->endElementNS(XML_p, XML_spTgt);
+ mpFS->endElementNS(XML_p, XML_tgtEl);
+}
+
+void PPTXAnimationExport::WriteAnimationCondList(const Any& rAny, sal_Int32 nToken)
+{
+ if (!rAny.hasValue())
+ return;
+
+ std::vector<Cond> aList;
+
+ bool bIsMainSeqChild = isMainSeqChild();
+
+ Sequence<Any> aCondSeq;
+ if (rAny >>= aCondSeq)
+ {
+ for (const auto& rCond : std::as_const(aCondSeq))
+ {
+ Cond aCond(rCond, bIsMainSeqChild);
+ if (aCond.isValid())
+ aList.push_back(aCond);
+ }
+ }
+ else
+ {
+ Cond aCond(rAny, bIsMainSeqChild);
+ if (aCond.isValid())
+ aList.push_back(aCond);
+ }
+
+ if (aList.size() > 0)
+ {
+ mpFS->startElementNS(XML_p, nToken);
+
+ for (const Cond& rCond : aList)
+ WriteAnimationCond(rCond);
+
+ mpFS->endElementNS(XML_p, nToken);
+ }
+}
+
+void PPTXAnimationExport::WriteAnimationCond(const Cond& rCond)
+{
+ if (rCond.mpEvent)
+ {
+ sal_Int32 nId = -1;
+ if (rCond.mxShape.is())
+ {
+ mpFS->startElementNS(XML_p, XML_cond, XML_delay, rCond.getDelay(), XML_evt,
+ rCond.mpEvent);
+ WriteAnimationTarget(Any(rCond.mxShape));
+ mpFS->endElementNS(XML_p, XML_cond);
+ }
+ else if (rCond.mxNode.is() && (nId = GetAnimationNodeId(rCond.mxNode)) != -1)
+ {
+ mpFS->startElementNS(XML_p, XML_cond, XML_delay, rCond.getDelay(), XML_evt,
+ rCond.mpEvent);
+ mpFS->singleElementNS(XML_p, XML_tn, XML_val, OString::number(nId));
+ mpFS->endElementNS(XML_p, XML_cond);
+ }
+ else
+ {
+ mpFS->singleElementNS(XML_p, XML_cond, XML_delay, rCond.getDelay(), XML_evt,
+ rCond.mpEvent);
+ }
+ }
+ else
+ mpFS->singleElementNS(XML_p, XML_cond, XML_delay, rCond.getDelay());
+}
+
+void PPTXAnimationExport::WriteAnimationNodeAnimate(sal_Int32 nXmlNodeType)
+{
+ const Reference<XAnimationNode>& rXNode = getCurrentNode();
+ Reference<XAnimate> rXAnimate(rXNode, UNO_QUERY);
+ if (!rXAnimate.is())
+ return;
+
+ const char* pCalcMode = nullptr;
+ const char* pValueType = nullptr;
+ bool bSimple = (nXmlNodeType != XML_anim);
+ bool bTo = true;
+
+ if (!bSimple)
+ {
+ switch (rXAnimate->getCalcMode())
+ {
+ case AnimationCalcMode::DISCRETE:
+ pCalcMode = "discrete";
+ break;
+ case AnimationCalcMode::LINEAR:
+ pCalcMode = "lin";
+ break;
+ }
+
+ switch (AnimationExporter::GetValueTypeForAttributeName(rXAnimate->getAttributeName()))
+ {
+ case AnimationValueType::STRING:
+ pValueType = "str";
+ break;
+ case AnimationValueType::NUMBER:
+ pValueType = "num";
+ break;
+ case AnimationValueType::COLOR:
+ pValueType = "clr";
+ break;
+ }
+ }
+
+ if (nXmlNodeType == XML_animMotion)
+ {
+ OUString aPath;
+ Reference<XAnimateMotion> xMotion(rXNode, UNO_QUERY);
+ if (xMotion.is())
+ {
+ xMotion->getPath() >>= aPath;
+ ::basegfx::B2DPolyPolygon aPolyPoly;
+ if (::basegfx::utils::importFromSvgD(aPolyPoly, aPath, true, nullptr))
+ aPath = ::basegfx::utils::exportToSvgD(aPolyPoly, false, false, true, true);
+ }
+
+ mpFS->startElementNS(XML_p, nXmlNodeType, XML_origin, "layout", XML_path, aPath);
+ }
+ else if (nXmlNodeType == XML_animRot)
+ {
+ // when const char* is nullptr, the attribute is completely omitted in the output
+ const char* pBy = nullptr;
+ const char* pFrom = nullptr;
+ const char* pTo = nullptr;
+ OString aBy, aFrom, aTo;
+
+ Reference<XAnimateTransform> xTransform(rXNode, UNO_QUERY);
+ if (xTransform.is())
+ {
+ double value;
+ if (xTransform->getBy() >>= value)
+ {
+ aBy = OString::number(static_cast<int>(value * PER_DEGREE));
+ pBy = aBy.getStr();
+ }
+
+ if (xTransform->getFrom() >>= value)
+ {
+ aFrom = OString::number(static_cast<int>(value * PER_DEGREE));
+ pFrom = aFrom.getStr();
+ }
+
+ if (xTransform->getTo() >>= value)
+ {
+ aTo = OString::number(static_cast<int>(value * PER_DEGREE));
+ pTo = aTo.getStr();
+ }
+ }
+
+ mpFS->startElementNS(XML_p, nXmlNodeType, XML_by, pBy, XML_from, pFrom, XML_to, pTo);
+ }
+ else if (nXmlNodeType == XML_animClr)
+ {
+ Reference<XAnimateColor> xColor(rXNode, UNO_QUERY);
+ const char* pColorSpace = "rgb";
+ const char* pDirection = nullptr;
+ if (xColor.is() && xColor->getColorInterpolation() == AnimationColorSpace::HSL)
+ {
+ // Note: from, to, by can still be specified in any supported format.
+ pColorSpace = "hsl";
+ pDirection = xColor->getDirection() ? "cw" : "ccw";
+ }
+ mpFS->startElementNS(XML_p, nXmlNodeType, XML_clrSpc, pColorSpace, XML_dir, pDirection,
+ XML_calcmode, pCalcMode, XML_valueType, pValueType);
+ }
+ else
+ {
+ OUString sFrom, sTo, sBy;
+ if (rXAnimate.is() && nXmlNodeType == XML_anim)
+ {
+ OUString sAttributeName = rXAnimate->getAttributeName();
+ Any aFrom
+ = AnimationExporter::convertAnimateValue(rXAnimate->getFrom(), sAttributeName);
+ aFrom >>= sFrom;
+ Any aTo = AnimationExporter::convertAnimateValue(rXAnimate->getTo(), sAttributeName);
+ aTo >>= sTo;
+ Any aBy = AnimationExporter::convertAnimateValue(rXAnimate->getBy(), sAttributeName);
+ aBy >>= sBy;
+ }
+
+ mpFS->startElementNS(XML_p, nXmlNodeType, XML_calcmode, pCalcMode, XML_valueType,
+ pValueType, XML_from, sax_fastparser::UseIf(sFrom, !sFrom.isEmpty()),
+ XML_to, sax_fastparser::UseIf(sTo, !sTo.isEmpty()), XML_by,
+ sax_fastparser::UseIf(sBy, !sBy.isEmpty()));
+ bTo = sTo.isEmpty() && sFrom.isEmpty() && sBy.isEmpty();
+ }
+
+ WriteAnimationNodeAnimateInside(bSimple, bTo);
+ mpFS->endElementNS(XML_p, nXmlNodeType);
+}
+
+void PPTXAnimationExport::WriteAnimationNodeAnimateInside(bool bSimple, bool bWriteTo)
+{
+ const Reference<XAnimationNode>& rXNode = getCurrentNode();
+ Reference<XAnimate> rXAnimate(rXNode, UNO_QUERY);
+ if (!rXAnimate.is())
+ return;
+
+ const char* pAdditive = nullptr;
+
+ if (!bSimple)
+ {
+ switch (rXAnimate->getAdditive())
+ {
+ case AnimationAdditiveMode::BASE:
+ pAdditive = "base";
+ break;
+ case AnimationAdditiveMode::SUM:
+ pAdditive = "sum";
+ break;
+ case AnimationAdditiveMode::REPLACE:
+ pAdditive = "repl";
+ break;
+ case AnimationAdditiveMode::MULTIPLY:
+ pAdditive = "mult";
+ break;
+ case AnimationAdditiveMode::NONE:
+ pAdditive = "none";
+ break;
+ }
+ }
+
+ mpFS->startElementNS(XML_p, XML_cBhvr, XML_additive, pAdditive);
+ WriteAnimationNodeCommonPropsStart();
+
+ Reference<XIterateContainer> xIterate(rXNode->getParent(), UNO_QUERY);
+ WriteAnimationTarget(xIterate.is() ? xIterate->getTarget() : rXAnimate->getTarget());
+
+ Reference<XAnimateTransform> xTransform(rXNode, UNO_QUERY);
+
+ // The attribute name of AnimateTransform is "Transform", we have to fix it.
+ OUString sNewAttr;
+ if (xTransform.is() && xTransform->getTransformType() == AnimationTransformType::ROTATE)
+ sNewAttr = "Rotate";
+
+ WriteAnimationAttributeName(mpFS, xTransform.is() ? sNewAttr : rXAnimate->getAttributeName());
+
+ mpFS->endElementNS(XML_p, XML_cBhvr);
+ WriteAnimateValues(mpFS, rXAnimate);
+
+ Reference<XAnimateColor> xColor(rXNode, UNO_QUERY);
+
+ if (xColor.is())
+ {
+ WriteAnimateColorColor(mpFS, xColor->getBy(), XML_by);
+ WriteAnimateColorColor(mpFS, xColor->getFrom(), XML_from);
+ WriteAnimateColorColor(mpFS, xColor->getTo(), XML_to);
+ }
+ else if (xTransform.is() && xTransform->getTransformType() == AnimationTransformType::SCALE)
+ {
+ WriteAnimationProperty(mpFS, rXAnimate->getBy(), XML_by);
+ WriteAnimationProperty(mpFS, rXAnimate->getFrom(), XML_from);
+ WriteAnimationProperty(mpFS, rXAnimate->getTo(), XML_to);
+ }
+ else if (bWriteTo)
+ WriteAnimateTo(mpFS, rXAnimate->getTo(), rXAnimate->getAttributeName());
+}
+
+void PPTXAnimationExport::WriteAnimationNodeCommonPropsStart()
+{
+ const Reference<XAnimationNode>& rXNode = getCurrentNode();
+ std::optional<OString> sDuration;
+ std::optional<OString> sRepeatCount;
+ const char* pRestart = nullptr;
+ const char* pNodeType = nullptr;
+ const char* pPresetClass = nullptr;
+ const char* pFill = nullptr;
+ double fDuration = 0;
+ double fRepeatCount = 0;
+ Any aAny;
+ assert(mpContext);
+
+ aAny = rXNode->getDuration();
+ if (aAny.hasValue())
+ {
+ Timing eTiming;
+
+ if (aAny >>= eTiming)
+ {
+ if (eTiming == Timing_INDEFINITE)
+ sDuration = "indefinite";
+ }
+ else
+ aAny >>= fDuration;
+ }
+
+ pRestart = convertAnimationRestart(rXNode->getRestart());
+
+ sal_Int16 nType = mpContext->getEffectNodeType();
+ if (nType != -1)
+ {
+ pNodeType = convertEffectNodeType(nType);
+ if (nType == EffectNodeType::TIMING_ROOT)
+ {
+ if (!sDuration)
+ sDuration = "indefinite";
+ if (!pRestart)
+ pRestart = "never";
+ }
+ else if (nType == EffectNodeType::MAIN_SEQUENCE)
+ {
+ sDuration = "indefinite";
+ }
+ }
+
+ if (fDuration != 0)
+ sDuration = OString::number(static_cast<sal_Int32>(fDuration * 1000.0));
+
+ sal_uInt32 nPresetClass = mpContext->getEffectPresetClass();
+ if (nPresetClass != DFF_ANIM_PRESS_CLASS_USER_DEFINED)
+ pPresetClass = convertEffectPresetClass(nPresetClass);
+
+ sal_uInt32 nPresetId = 0;
+ bool bPresetId = false;
+ const OUString& rPresetId = mpContext->getEffectPresetId();
+ if (rPresetId.getLength() > 0)
+ {
+ nPresetId = AnimationExporter::GetPresetID(rPresetId, nPresetClass, bPresetId);
+ bPresetId = true;
+ }
+
+ sal_uInt32 nPresetSubType = 0;
+ bool bPresetSubType = false;
+ const OUString& sPresetSubType = mpContext->getEffectPresetSubType();
+ if (sPresetSubType.getLength() > 0)
+ {
+ nPresetSubType
+ = AnimationExporter::TranslatePresetSubType(nPresetClass, nPresetId, sPresetSubType);
+ bPresetSubType = true;
+ }
+
+ if (nType != EffectNodeType::TIMING_ROOT && nType != EffectNodeType::MAIN_SEQUENCE)
+ {
+ // it doesn't seem to work right on root and mainseq nodes
+ sal_Int16 nFill = AnimationExporter::GetFillMode(rXNode, AnimationFill::AUTO);
+ pFill = convertAnimationFill(nFill);
+ }
+
+ bool bAutoReverse = rXNode->getAutoReverse();
+
+ aAny = rXNode->getRepeatCount();
+ if (aAny.hasValue())
+ {
+ Timing eTiming;
+
+ if (aAny >>= eTiming)
+ {
+ if (eTiming == Timing_INDEFINITE)
+ sRepeatCount = "indefinite";
+ }
+ else
+ aAny >>= fRepeatCount;
+ }
+
+ if (fRepeatCount != 0)
+ sRepeatCount = OString::number(static_cast<sal_Int32>(fRepeatCount * 1000.0));
+
+ mpFS->startElementNS(
+ XML_p, XML_cTn, XML_id, OString::number(GetNextAnimationNodeId(rXNode)), XML_dur, sDuration,
+ XML_autoRev, sax_fastparser::UseIf("1", bAutoReverse), XML_restart, pRestart, XML_nodeType,
+ pNodeType, XML_fill, pFill, XML_presetClass, pPresetClass, XML_presetID,
+ sax_fastparser::UseIf(OString::number(nPresetId), bPresetId), XML_presetSubtype,
+ sax_fastparser::UseIf(OString::number(nPresetSubType), bPresetSubType), XML_repeatCount,
+ sRepeatCount);
+
+ WriteAnimationCondList(mpContext->getCondition(true), XML_stCondLst);
+ WriteAnimationCondList(mpContext->getCondition(false), XML_endCondLst);
+
+ if (rXNode->getType() == AnimationNodeType::ITERATE)
+ {
+ Reference<XIterateContainer> xIterate(rXNode, UNO_QUERY);
+ if (xIterate.is())
+ {
+ const char* sType = convertTextAnimationType(xIterate->getIterateType());
+
+ mpFS->startElementNS(XML_p, XML_iterate, XML_type, sType);
+ mpFS->singleElementNS(XML_p, XML_tmAbs, XML_val,
+ OString::number(xIterate->getIterateInterval() * 1000));
+ mpFS->endElementNS(XML_p, XML_iterate);
+ }
+ }
+
+ const std::vector<NodeContextPtr>& aChildNodes = mpContext->getChildNodes();
+ if (!aChildNodes.empty())
+ {
+ mpFS->startElementNS(XML_p, XML_childTnLst);
+ for (const NodeContextPtr& pChildContext : aChildNodes)
+ {
+ if (pChildContext->isValid())
+ WriteAnimationNode(pChildContext);
+ }
+ mpFS->endElementNS(XML_p, XML_childTnLst);
+ }
+ mpFS->endElementNS(XML_p, XML_cTn);
+}
+
+void PPTXAnimationExport::WriteAnimationNodeSeq()
+{
+ SAL_INFO("sd.eppt", "write animation node SEQ");
+
+ mpFS->startElementNS(XML_p, XML_seq);
+
+ WriteAnimationNodeCommonPropsStart();
+
+ WriteAnimationCondListForSeq(mpFS, XML_prevCondLst);
+ WriteAnimationCondListForSeq(mpFS, XML_nextCondLst);
+
+ mpFS->endElementNS(XML_p, XML_seq);
+}
+
+void PPTXAnimationExport::WriteAnimationNodeEffect()
+{
+ SAL_INFO("sd.eppt", "write animation node FILTER");
+ Reference<XTransitionFilter> xFilter(getCurrentNode(), UNO_QUERY);
+ if (xFilter.is())
+ {
+ const char* pFilter = ::ppt::AnimationExporter::FindTransitionName(
+ xFilter->getTransition(), xFilter->getSubtype(), xFilter->getDirection());
+ const char* pMode = xFilter->getMode() ? "in" : "out";
+ mpFS->startElementNS(XML_p, XML_animEffect, XML_filter, pFilter, XML_transition, pMode);
+
+ WriteAnimationNodeAnimateInside(false);
+
+ mpFS->endElementNS(XML_p, XML_animEffect);
+ }
+}
+
+void PPTXAnimationExport::WriteAnimationNodeCommand()
+{
+ SAL_INFO("sd.eppt", "write animation node COMMAND");
+ Reference<XCommand> xCommand(getCurrentNode(), UNO_QUERY);
+ if (!xCommand.is())
+ return;
+
+ const char* pType = "call";
+ OString aCommand;
+ switch (xCommand->getCommand())
+ {
+ case EffectCommands::VERB:
+ pType = "verb";
+ aCommand = "1"; /* FIXME hardcoded viewing */
+ break;
+ case EffectCommands::PLAY:
+ {
+ aCommand = "play";
+ uno::Sequence<beans::NamedValue> aParamSeq;
+ xCommand->getParameter() >>= aParamSeq;
+ comphelper::SequenceAsHashMap aMap(aParamSeq);
+ auto it = aMap.find("MediaTime");
+ if (it != aMap.end())
+ {
+ double fMediaTime = 0;
+ it->second >>= fMediaTime;
+ // PowerPoint represents 0 as 0.0, so just use a single decimal.
+ OString aMediaTime
+ = rtl::math::doubleToString(fMediaTime, rtl_math_StringFormat_F, 1, '.');
+ aCommand += "From(" + aMediaTime + ")";
+ }
+ break;
+ }
+ case EffectCommands::TOGGLEPAUSE:
+ aCommand = "togglePause";
+ break;
+ case EffectCommands::STOP:
+ aCommand = "stop";
+ break;
+ default:
+ SAL_WARN("sd.eppt", "unknown command: " << xCommand->getCommand());
+ break;
+ }
+
+ mpFS->startElementNS(XML_p, XML_cmd, XML_type, pType, XML_cmd, aCommand.getStr());
+
+ WriteAnimationNodeAnimateInside(false);
+ mpFS->startElementNS(XML_p, XML_cBhvr);
+ WriteAnimationNodeCommonPropsStart();
+ WriteAnimationTarget(xCommand->getTarget());
+ mpFS->endElementNS(XML_p, XML_cBhvr);
+
+ mpFS->endElementNS(XML_p, XML_cmd);
+}
+
+void PPTXAnimationExport::WriteAnimationNodeAudio()
+{
+ SAL_INFO("sd.eppt", "write animation node audio");
+ Reference<XAudio> xAudio(getCurrentNode(), UNO_QUERY);
+
+ OUString sUrl;
+ uno::Reference<drawing::XShape> xShape;
+ OUString sRelId;
+ OUString sName;
+
+ if (!xAudio.is())
+ {
+ return;
+ }
+
+ bool bValid = false;
+ if ((xAudio->getSource() >>= sUrl) && !sUrl.isEmpty() && IsAudioURL(sUrl))
+ {
+ bValid = true;
+ }
+
+ bool bVideo = false;
+ if (!bValid)
+ {
+ if (xAudio->getSource() >>= xShape)
+ {
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ bool bHasMediaURL = xShapeProps->getPropertySetInfo()->hasPropertyByName("MediaURL");
+ if (bHasMediaURL && (xShapeProps->getPropertyValue("MediaURL") >>= sUrl))
+ {
+ bVideo = IsVideoURL(sUrl);
+ bValid = IsAudioURL(sUrl) || bVideo;
+ }
+ }
+ }
+
+ if (!bValid)
+ return;
+
+ if (!xShape.is())
+ {
+ mrPowerPointExport.embedEffectAudio(mpFS, sUrl, sRelId, sName);
+ }
+
+ if (bVideo)
+ {
+ mpFS->startElementNS(XML_p, XML_video);
+ mpFS->startElementNS(XML_p, XML_cMediaNode);
+ }
+ else
+ {
+ bool bNarration = xAudio->getNarration();
+ mpFS->startElementNS(XML_p, XML_audio, XML_isNarration, bNarration ? "1" : "0");
+ bool bHideDuringShow = xAudio->getHideDuringShow();
+ mpFS->startElementNS(XML_p, XML_cMediaNode, XML_showWhenStopped,
+ bHideDuringShow ? "0" : "1");
+ }
+
+ animations::Timing eTiming{};
+ bool bLooping
+ = (xAudio->getRepeatCount() >>= eTiming) && eTiming == animations::Timing_INDEFINITE;
+ if (bVideo && bLooping)
+ {
+ mpFS->startElementNS(XML_p, XML_cTn, XML_repeatCount, "indefinite");
+ }
+ else
+ {
+ mpFS->startElementNS(XML_p, XML_cTn);
+ }
+ WriteAnimationCondList(mpContext->getCondition(true), XML_stCondLst);
+ WriteAnimationCondList(mpContext->getCondition(false), XML_endCondLst);
+ mpFS->endElementNS(XML_p, XML_cTn);
+
+ mpFS->startElementNS(XML_p, XML_tgtEl);
+ if (xShape.is())
+ {
+ sal_Int32 nShapeID = mrPowerPointExport.GetShapeID(xShape);
+ mpFS->singleElementNS(XML_p, XML_spTgt, XML_spid, OString::number(nShapeID));
+ }
+ else
+ {
+ mpFS->singleElementNS(XML_p, XML_sndTgt, FSNS(XML_r, XML_embed),
+ sax_fastparser::UseIf(sRelId, !sRelId.isEmpty()), XML_name,
+ sax_fastparser::UseIf(sName, !sUrl.isEmpty()));
+ }
+ mpFS->endElementNS(XML_p, XML_tgtEl);
+
+ mpFS->endElementNS(XML_p, XML_cMediaNode);
+ if (bVideo)
+ {
+ mpFS->endElementNS(XML_p, XML_video);
+ }
+ else
+ {
+ mpFS->endElementNS(XML_p, XML_audio);
+ }
+}
+
+void PPTXAnimationExport::WriteAnimationNode(const NodeContextPtr& pContext)
+{
+ const NodeContext* pSavedContext = mpContext;
+ mpContext = pContext.get();
+
+ const Reference<XAnimationNode>& rXNode = getCurrentNode();
+
+ SAL_INFO("sd.eppt", "export node type: " << rXNode->getType());
+ sal_Int32 xmlNodeType = extractNodeType(rXNode);
+
+ switch (xmlNodeType)
+ {
+ case XML_par:
+ mpFS->startElementNS(XML_p, xmlNodeType);
+ WriteAnimationNodeCommonPropsStart();
+ mpFS->endElementNS(XML_p, xmlNodeType);
+ break;
+ case XML_seq:
+ WriteAnimationNodeSeq();
+ break;
+ case XML_animScale:
+ case XML_animRot:
+ case XML_anim:
+ case XML_animMotion:
+ case XML_animClr:
+ case XML_set:
+ WriteAnimationNodeAnimate(xmlNodeType);
+ break;
+ case XML_animEffect:
+ WriteAnimationNodeEffect();
+ break;
+ case XML_cmd:
+ WriteAnimationNodeCommand();
+ break;
+ case XML_audio:
+ WriteAnimationNodeAudio();
+ break;
+ default:
+ SAL_WARN("sd.eppt", "export ooxml node type: " << xmlNodeType);
+ break;
+ }
+
+ mpContext = pSavedContext;
+}
+
+void PPTXAnimationExport::WriteAnimations(const Reference<XDrawPage>& rXDrawPage)
+{
+ Reference<XAnimationNodeSupplier> xNodeSupplier(rXDrawPage, UNO_QUERY);
+ if (!xNodeSupplier.is())
+ return;
+
+ const Reference<XAnimationNode> xNode(xNodeSupplier->getAnimationNode());
+ if (!xNode.is())
+ return;
+
+ Reference<XEnumerationAccess> xEnumerationAccess(xNode, UNO_QUERY);
+ if (!xEnumerationAccess.is())
+ return;
+
+ Reference<XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();
+ if (!(xEnumeration.is() && xEnumeration->hasMoreElements()))
+ return;
+
+ auto pNodeContext = std::make_unique<NodeContext>(xNode, false, false);
+ if (pNodeContext->isValid())
+ {
+ mpFS->startElementNS(XML_p, XML_timing);
+ mpFS->startElementNS(XML_p, XML_tnLst);
+
+ WriteAnimationNode(pNodeContext);
+
+ mpFS->endElementNS(XML_p, XML_tnLst);
+ mpFS->endElementNS(XML_p, XML_timing);
+ }
+}
+
+sal_Int32 PPTXAnimationExport::GetNextAnimationNodeId(const Reference<XAnimationNode>& xNode)
+{
+ sal_Int32 nId = mrPowerPointExport.GetNextAnimationNodeID();
+ maAnimationNodeIdMap[xNode] = nId;
+ return nId;
+}
+
+sal_Int32 PPTXAnimationExport::GetAnimationNodeId(const Reference<XAnimationNode>& xNode)
+{
+ sal_Int32 nId = -1;
+ const auto& aIter = maAnimationNodeIdMap.find(xNode);
+ if (aIter != maAnimationNodeIdMap.end())
+ {
+ nId = aIter->second;
+ }
+ return nId;
+}
+
+NodeContext::NodeContext(const Reference<XAnimationNode>& xNode, bool bMainSeqChild,
+ bool bIsIterateChild)
+ : mxNode(xNode)
+ , mbMainSeqChild(bMainSeqChild)
+ , mbValid(true)
+ , mnEffectNodeType(-1)
+ , mnEffectPresetClass(DFF_ANIM_PRESS_CLASS_USER_DEFINED)
+{
+ assert(xNode.is());
+
+ initUserData();
+
+ initValid(initChildNodes(), bIsIterateChild);
+}
+
+void NodeContext::initUserData()
+{
+ assert(mxNode.is());
+
+ Sequence<NamedValue> aUserData = mxNode->getUserData();
+ const Any* aIndexedData[DFF_ANIM_PROPERTY_ID_COUNT];
+ AnimationExporter::GetUserData(aUserData, aIndexedData, sizeof(aIndexedData));
+
+ const Any* pAny = aIndexedData[DFF_ANIM_NODE_TYPE];
+ if (pAny)
+ *pAny >>= mnEffectNodeType;
+
+ pAny = aIndexedData[DFF_ANIM_PRESET_CLASS];
+ if (pAny)
+ *pAny >>= mnEffectPresetClass;
+
+ pAny = aIndexedData[DFF_ANIM_PRESET_ID];
+ if (pAny)
+ *pAny >>= msEffectPresetId;
+
+ pAny = aIndexedData[DFF_ANIM_PRESET_SUB_TYPE];
+ if (pAny)
+ *pAny >>= msEffectPresetSubType;
+}
+
+void NodeContext::initValid(bool bHasValidChild, bool bIsIterateChild)
+{
+ sal_Int16 nType = mxNode->getType();
+
+ if (nType == AnimationNodeType::ITERATE)
+ {
+ Reference<XIterateContainer> xIterate(mxNode, UNO_QUERY);
+ mbValid = xIterate.is() && (bIsIterateChild || isValidTarget(xIterate->getTarget()))
+ && !maChildNodes.empty();
+ }
+ else if (nType == AnimationNodeType::COMMAND)
+ {
+ Reference<XCommand> xCommand(mxNode, UNO_QUERY);
+ mbValid = xCommand.is() && (bIsIterateChild || isValidTarget(xCommand->getTarget()));
+ }
+ else if (nType == AnimationNodeType::PAR || nType == AnimationNodeType::SEQ)
+ {
+ mbValid = bHasValidChild;
+ }
+ else if (nType == AnimationNodeType::AUDIO)
+ {
+ Reference<XAudio> xAudio(mxNode, UNO_QUERY);
+ OUString sURL;
+ uno::Reference<drawing::XShape> xShape;
+ mbValid = false;
+ if (xAudio.is())
+ {
+ if (xAudio->getSource() >>= sURL)
+ {
+ mbValid = IsAudioURL(sURL);
+ }
+ else if (xAudio->getSource() >>= xShape)
+ {
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ bool bHasMediaURL
+ = xShapeProps->getPropertySetInfo()->hasPropertyByName("MediaURL");
+ if (bHasMediaURL && (xShapeProps->getPropertyValue("MediaURL") >>= sURL))
+ {
+ mbValid = IsAudioURL(sURL) || IsVideoURL(sURL);
+ }
+ }
+ }
+ }
+ else
+ {
+ Reference<XAnimate> xAnimate(mxNode, UNO_QUERY);
+ mbValid = xAnimate.is() && (bIsIterateChild || isValidTarget(xAnimate->getTarget()));
+ }
+}
+
+bool NodeContext::initChildNodes()
+{
+ bool bValid = false;
+ Reference<XEnumerationAccess> xEnumerationAccess(mxNode, UNO_QUERY);
+ if (xEnumerationAccess.is())
+ {
+ Reference<XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();
+ bool bIsMainSeq = mnEffectNodeType == EffectNodeType::MAIN_SEQUENCE;
+ bool bIsIterateChild = mxNode->getType() == AnimationNodeType::ITERATE;
+ if (xEnumeration.is())
+ {
+ while (xEnumeration->hasMoreElements())
+ {
+ Reference<XAnimationNode> xChildNode(xEnumeration->nextElement(), UNO_QUERY);
+ if (xChildNode.is())
+ {
+ auto pChildContext
+ = std::make_unique<NodeContext>(xChildNode, bIsMainSeq, bIsIterateChild);
+ if (pChildContext->isValid())
+ bValid = true;
+ maChildNodes.push_back(std::move(pChildContext));
+ }
+ }
+ }
+ }
+ return bValid;
+}
+
+Any NodeContext::getCondition(bool bBegin) const
+{
+ const bool bParent
+ = (mnEffectNodeType != EffectNodeType::INTERACTIVE_SEQUENCE || maChildNodes.empty());
+ const Reference<XAnimationNode>& rNode = bParent ? mxNode : maChildNodes[0]->getNode();
+
+ return bBegin ? rNode->getBegin() : rNode->getEnd();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptx-animations.hxx b/sd/source/filter/eppt/pptx-animations.hxx
new file mode 100644
index 000000000..24654abb8
--- /dev/null
+++ b/sd/source/filter/eppt/pptx-animations.hxx
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <sax/fshelper.hxx>
+
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+
+#include "epptooxml.hxx"
+
+namespace oox::core
+{
+void WriteAnimations(const ::sax_fastparser::FSHelperPtr& pFS,
+ const css::uno::Reference<css::drawing::XDrawPage>& rXDrawPage,
+ PowerPointExport& rExport);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptx-epptbase.cxx b/sd/source/filter/eppt/pptx-epptbase.cxx
new file mode 100644
index 000000000..690738996
--- /dev/null
+++ b/sd/source/filter/eppt/pptx-epptbase.cxx
@@ -0,0 +1,1000 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "epptbase.hxx"
+#include "epptdef.hxx"
+#include "../ppt/pptanimations.hxx"
+
+#include <o3tl/any.hxx>
+#include <vcl/outdev.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/strbuf.hxx>
+#include <sal/log.hxx>
+#include <tools/UnitConversion.hxx>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XMasterPageTarget.hpp>
+#include <com/sun/star/drawing/XMasterPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPages.hpp>
+#include <com/sun/star/animations/TransitionType.hpp>
+#include <com/sun/star/animations/TransitionSubType.hpp>
+#include <com/sun/star/awt/FontFamily.hpp>
+#include <com/sun/star/awt/FontPitch.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/presentation/XPresentationPage.hpp>
+#include <com/sun/star/text/XSimpleText.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+
+
+using namespace com::sun::star;
+
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::awt::FontFamily;
+using namespace ::com::sun::star::awt::FontPitch;
+using namespace ::com::sun::star::presentation;
+
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::container::XNamed;
+using ::com::sun::star::drawing::XMasterPageTarget;
+using ::com::sun::star::drawing::XDrawPage;
+using ::com::sun::star::frame::XModel;
+using ::com::sun::star::style::XStyleFamiliesSupplier;
+using ::com::sun::star::style::XStyle;
+using ::com::sun::star::task::XStatusIndicator;
+using ::com::sun::star::text::XSimpleText;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+
+PHLayout const pPHLayout[] =
+{
+ { EppLayout::TITLESLIDE, { 0x0d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x0d, 0x10, true, true, false },
+ { EppLayout::TITLEANDBODYSLIDE, { 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TITLEANDBODYSLIDE, { 0x0d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x14, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x0d, 0x0e, true, true, true },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x0e, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x14, 0x0d, 0x0e, true, true, false },
+ { EppLayout::BLANKSLIDE, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x0d, 0x0e, false, false, false },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x0e, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x16, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x14, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x14, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TITLEANDBODYSLIDE, { 0x0d, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x15, 0x0d, 0x0e, true, false, false },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x16, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x16, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x0e, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TITLEANDBODYSLIDE, { 0x0d, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, false, false },
+ { EppLayout::RIGHTCOLUMN2ROWS, { 0x0d, 0x0e, 0x13, 0x13, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x13, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TWOROWSANDTITLE, { 0x0d, 0x13, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, true, false },
+ { EppLayout::LEFTCOLUMN2ROWS, { 0x0d, 0x13, 0x13, 0x0e, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TOPROW2COLUMN, { 0x0d, 0x13, 0x13, 0x0e, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, true, false },
+ { EppLayout::TWOROWSANDTITLE, { 0x0d, 0x0e, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, true, false },
+ { EppLayout::FOUROBJECTS, { 0x0d, 0x13, 0x13, 0x13, 0x13, 0x00, 0x00, 0x00 }, 0x13, 0x0d, 0x0e, true, false, false },
+ { EppLayout::ONLYTITLE, { 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x0d, 0x0e, true, false, false },
+ { EppLayout::BLANKSLIDE, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x0d, 0x0e, false, false, false },
+ { EppLayout::TITLERIGHT2BODIESLEFT, { 0x11, 0x12, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x14, 0x11, 0x12, true, true, false },
+ { EppLayout::TITLERIGHTBODYLEFT, { 0x11, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x11, 0x12, true, true, false },
+ { EppLayout::TITLEANDBODYSLIDE, { 0x0d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x00, 0x0d, 0x12, true, true, false },
+ { EppLayout::TWOCOLUMNSANDTITLE, { 0x0d, 0x16, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0x16, 0x0d, 0x12, true, true, false }
+};
+
+PPTWriterBase::PPTWriterBase()
+ : mbStatusIndicator(false)
+ , mbPresObj(false)
+ , mbEmptyPresObj(false)
+ , mbIsBackgroundDark(false)
+ , mnAngle(0)
+ , mnPages(0)
+ , mnMasterPages(0)
+ , maFraction(1, 576)
+ , maMapModeSrc(MapUnit::Map100thMM)
+ , maMapModeDest(MapUnit::MapInch, Point(), maFraction, maFraction)
+ , meLatestPageType(NORMAL)
+ , mpStyleSheet(nullptr)
+{
+ SAL_INFO("sd.eppt", "PPTWriterBase::PPTWriterBase()");
+}
+
+PPTWriterBase::PPTWriterBase( const Reference< XModel > & rXModel,
+ const Reference< XStatusIndicator > & rXStatInd )
+ : mXModel(rXModel)
+ , mXStatusIndicator(rXStatInd)
+ , mbStatusIndicator(false)
+ , mbPresObj(false)
+ , mbEmptyPresObj(false)
+ , mbIsBackgroundDark(false)
+ , mnAngle(0)
+ , mnPages(0)
+ , mnMasterPages(0)
+ , maFraction(1, 576)
+ , maMapModeSrc(MapUnit::Map100thMM)
+ , maMapModeDest(MapUnit::MapInch, Point(), maFraction, maFraction)
+ , meLatestPageType (NORMAL)
+ , mpStyleSheet(nullptr)
+{
+}
+
+PPTWriterBase::~PPTWriterBase()
+{
+ // Possibly unnecessary sanity check for mXStatusIndicator.is().
+ // In 3.3 we had a bug report of a crash where it was null,
+ // https://bugzilla.novell.com/show_bug.cgi?id=694119 (non-public,
+ // bug report, sorry).
+ if ( mbStatusIndicator && mXStatusIndicator.is() )
+ mXStatusIndicator->end();
+}
+
+void PPTWriterBase::exportPPT( const std::vector< css::beans::PropertyValue >& rMediaData )
+{
+ if ( !InitSOIface() )
+ return;
+
+ FontCollectionEntry aDefaultFontDesc( "Times New Roman",
+ ROMAN,
+ awt::FontPitch::VARIABLE,
+ RTL_TEXTENCODING_MS_1252 );
+ maFontCollection.GetId( aDefaultFontDesc ); // default is always times new roman
+
+ if ( !GetPageByIndex( 0, NOTICE ) )
+ return;
+
+ sal_Int32 nWidth = 21000;
+ if ( ImplGetPropertyValue( mXPagePropSet, "Width" ) )
+ mAny >>= nWidth;
+ sal_Int32 nHeight = 29700;
+ if ( ImplGetPropertyValue( mXPagePropSet, "Height" ) )
+ mAny >>= nHeight;
+
+ maNotesPageSize = MapSize( awt::Size( nWidth, nHeight ) );
+
+ if ( !GetPageByIndex( 0, MASTER ) )
+ return;
+
+ nWidth = 28000;
+ if ( ImplGetPropertyValue( mXPagePropSet, "Width" ) )
+ mAny >>= nWidth;
+ nHeight = 21000;
+ if ( ImplGetPropertyValue( mXPagePropSet, "Height" ) )
+ mAny >>= nHeight;
+ maDestPageSize = MapSize( awt::Size( nWidth, nHeight ) );
+ maPageSize = awt::Size(nWidth, nHeight);
+
+ SAL_INFO("sd.eppt", "call exportDocumentPre()");
+ exportPPTPre(rMediaData);
+
+ if ( !GetStyleSheets() )
+ return;
+
+ if ( !ImplCreateDocument() )
+ return;
+
+ sal_uInt32 i;
+
+ for ( i = 0; i < mnMasterPages; i++ )
+ {
+ if ( !CreateSlideMaster( i ) )
+ return;
+ }
+ if ( !CreateMainNotes() )
+ return;
+
+ for ( i = 0; i < mnPages; i++ )
+ {
+ SAL_INFO("sd.eppt", "call ImplCreateSlide( " << i << " )");
+ if ( !CreateSlide( i ) )
+ return;
+ }
+
+ for ( i = 0; i < mnPages; i++ )
+ {
+ if ( !CreateNotes( i ) )
+ return;
+ }
+
+ SAL_INFO("sd.eppt", "call exportDocumentPost()");
+ exportPPTPost();
+}
+
+bool PPTWriterBase::InitSOIface()
+{
+ while( true )
+ {
+ mXDrawPagesSupplier.set( mXModel, UNO_QUERY );
+ if ( !mXDrawPagesSupplier.is() )
+ break;
+
+ mXMasterPagesSupplier.set( mXModel, UNO_QUERY );
+ if ( !mXMasterPagesSupplier.is() )
+ break;
+ mXDrawPages = mXMasterPagesSupplier->getMasterPages();
+ if ( !mXDrawPages.is() )
+ break;
+ mnMasterPages = mXDrawPages->getCount();
+ mXDrawPages = mXDrawPagesSupplier->getDrawPages();
+ if( !mXDrawPages.is() )
+ break;
+ mnPages = mXDrawPages->getCount();
+ if ( !GetPageByIndex( 0, NORMAL ) )
+ break;
+
+ return true;
+ }
+ return false;
+}
+
+bool PPTWriterBase::GetPageByIndex( sal_uInt32 nIndex, PageType ePageType )
+{
+ while( true )
+ {
+ if ( ePageType != meLatestPageType )
+ {
+ switch( ePageType )
+ {
+ case NORMAL :
+ case NOTICE :
+ {
+ mXDrawPages = mXDrawPagesSupplier->getDrawPages();
+ if( !mXDrawPages.is() )
+ return false;
+ }
+ break;
+
+ case MASTER :
+ {
+ mXDrawPages = mXMasterPagesSupplier->getMasterPages();
+ if( !mXDrawPages.is() )
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+ meLatestPageType = ePageType;
+ }
+ Any aAny( mXDrawPages->getByIndex( nIndex ) );
+ aAny >>= mXDrawPage;
+ if ( !mXDrawPage.is() )
+ break;
+ if ( ePageType == NOTICE )
+ {
+ Reference< XPresentationPage > aXPresentationPage( mXDrawPage, UNO_QUERY );
+ if ( !aXPresentationPage.is() )
+ break;
+ mXDrawPage = aXPresentationPage->getNotesPage();
+ if ( !mXDrawPage.is() )
+ break;
+ }
+ mXPagePropSet.set( mXDrawPage, UNO_QUERY );
+ if ( !mXPagePropSet.is() )
+ break;
+
+ if (GetPropertyValue( aAny, mXPagePropSet, "IsBackgroundDark" ) )
+ aAny >>= mbIsBackgroundDark;
+
+ mXShapes = mXDrawPage;
+ if ( !mXShapes.is() )
+ break;
+
+ /* try to get the "real" background PropertySet. If the normal page is not supporting this property, it is
+ taken the property from the master */
+ bool bHasBackground = GetPropertyValue( aAny, mXPagePropSet, "Background", true );
+ if ( bHasBackground )
+ bHasBackground = ( aAny >>= mXBackgroundPropSet );
+ if ( !bHasBackground )
+ {
+ Reference< XMasterPageTarget > aXMasterPageTarget( mXDrawPage, UNO_QUERY );
+ if ( aXMasterPageTarget.is() )
+ {
+ Reference< XDrawPage > aXMasterDrawPage = aXMasterPageTarget->getMasterPage();
+ if ( aXMasterDrawPage.is() )
+ {
+ Reference< XPropertySet > aXMasterPagePropSet;
+ aXMasterPagePropSet.set( aXMasterDrawPage, UNO_QUERY );
+ if ( aXMasterPagePropSet.is() )
+ {
+ bool bBackground = GetPropertyValue( aAny, aXMasterPagePropSet, "Background" );
+ if ( bBackground )
+ {
+ aAny >>= mXBackgroundPropSet;
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool PPTWriterBase::CreateSlide( sal_uInt32 nPageNum )
+{
+ Any aAny;
+
+ if ( !GetPageByIndex( nPageNum, NORMAL ) )
+ return false;
+
+ sal_uInt32 nMasterNum = GetMasterIndex( NORMAL );
+ SetCurrentStyleSheet( nMasterNum );
+
+ Reference< XPropertySet > aXBackgroundPropSet;
+ bool bHasBackground = GetPropertyValue( aAny, mXPagePropSet, "Background" );
+ if ( bHasBackground )
+ bHasBackground = ( aAny >>= aXBackgroundPropSet );
+
+ sal_uInt16 nMode = 7; // Bit 1: Follow master objects, Bit 2: Follow master scheme, Bit 3: Follow master background
+ if ( bHasBackground )
+ nMode &=~4;
+
+/* sj: Don't know what's IsBackgroundVisible for, have to ask cl
+ if ( GetPropertyValue( aAny, mXPagePropSet, OUString( "IsBackgroundVisible" ) ) )
+ {
+ bool bBackgroundVisible;
+ if ( aAny >>= bBackgroundVisible )
+ {
+ if ( bBackgroundVisible )
+ nMode &= ~4;
+ }
+ }
+*/
+ if ( GetPropertyValue( aAny, mXPagePropSet, "IsBackgroundObjectsVisible" ) )
+ {
+ bool bBackgroundObjectsVisible = false;
+ if ( aAny >>= bBackgroundObjectsVisible )
+ {
+ if ( !bBackgroundObjectsVisible )
+ nMode &= ~1;
+ }
+ }
+
+ ImplWriteSlide( nPageNum, nMasterNum, nMode, bHasBackground, aXBackgroundPropSet );
+
+ return true;
+};
+
+bool PPTWriterBase::CreateNotes( sal_uInt32 nPageNum )
+{
+ if ( !GetPageByIndex( nPageNum, NOTICE ) )
+ return false;
+ SetCurrentStyleSheet( GetMasterIndex( NORMAL ) );
+
+ ImplWriteNotes( nPageNum );
+
+ return true;
+};
+
+bool PPTWriterBase::CreateSlideMaster( sal_uInt32 nPageNum )
+{
+ if ( !GetPageByIndex( nPageNum, MASTER ) )
+ return false;
+ SetCurrentStyleSheet( nPageNum );
+
+ css::uno::Reference< css::beans::XPropertySet > aXBackgroundPropSet;
+ if (ImplGetPropertyValue(mXPagePropSet, "Background")) // load background shape
+ mAny >>= aXBackgroundPropSet;
+
+ ImplWriteSlideMaster( nPageNum, aXBackgroundPropSet );
+
+ return true;
+};
+
+sal_Int32 PPTWriterBase::GetLayoutOffset( const css::uno::Reference< css::beans::XPropertySet >& rXPropSet )
+{
+ css::uno::Any aAny;
+ sal_Int32 nLayout = 20;
+ if ( GetPropertyValue( aAny, rXPropSet, "Layout", true ) )
+ aAny >>= nLayout;
+
+ SAL_INFO("sd.eppt", "GetLayoutOffset " << nLayout);
+
+ return nLayout;
+}
+
+sal_Int32 PPTWriterBase::GetLayoutOffsetFixed( const css::uno::Reference< css::beans::XPropertySet >& rXPropSet )
+{
+ sal_Int32 nLayout = GetLayoutOffset( rXPropSet );
+
+ if ( ( nLayout >= 21 ) && ( nLayout <= 26 ) ) // NOTES _> HANDOUT6
+ nLayout = 20;
+ if ( ( nLayout >= 27 ) && ( nLayout <= 30 ) ) // VERTICAL LAYOUT
+ nLayout -= 6;
+ else if ( nLayout > 30 )
+ nLayout = 20;
+
+ return nLayout;
+}
+
+PHLayout const & PPTWriterBase::GetLayout( const css::uno::Reference< css::beans::XPropertySet >& rXPropSet )
+{
+ return pPHLayout[ GetLayoutOffsetFixed( rXPropSet ) ];
+}
+
+PHLayout const & PPTWriterBase::GetLayout( sal_Int32 nOffset )
+{
+ if( nOffset >= 0 && nOffset < EPP_LAYOUT_SIZE )
+ return pPHLayout[ nOffset ];
+
+ SAL_INFO("sd.eppt", "asked " << nOffset << " for layout outside of 0, " << EPP_LAYOUT_SIZE << " array scope");
+
+ return pPHLayout[ 0 ];
+}
+
+sal_uInt32 PPTWriterBase::GetMasterIndex( PageType ePageType )
+{
+ sal_uInt32 nRetValue = 0;
+ css::uno::Reference< css::drawing::XMasterPageTarget >aXMasterPageTarget( mXDrawPage, css::uno::UNO_QUERY );
+
+ if ( aXMasterPageTarget.is() )
+ {
+ css::uno::Reference< css::drawing::XDrawPage >aXDrawPage = aXMasterPageTarget->getMasterPage();
+ if ( aXDrawPage.is() )
+ {
+ css::uno::Reference< css::beans::XPropertySet > aXPropertySet( aXDrawPage, css::uno::UNO_QUERY );
+ if ( aXPropertySet.is() )
+ {
+ if ( ImplGetPropertyValue( aXPropertySet, "Number" ) )
+ nRetValue |= *o3tl::doAccess<sal_Int16>(mAny);
+ if ( nRetValue & 0xffff ) // avoid overflow
+ nRetValue--;
+ }
+ }
+ }
+ if ( ePageType == NOTICE )
+ nRetValue += mnMasterPages;
+ return nRetValue;
+}
+
+void PPTWriterBase::SetCurrentStyleSheet( sal_uInt32 nPageNum )
+{
+ if ( nPageNum >= maStyleSheetList.size() )
+ nPageNum = 0;
+ mpStyleSheet = maStyleSheetList[ nPageNum ].get();
+}
+
+bool PPTWriterBase::GetStyleSheets()
+{
+ int nInstance, nLevel;
+ bool bRetValue = false;
+ sal_uInt32 nPageNum;
+
+ for ( nPageNum = 0; nPageNum < mnMasterPages; nPageNum++ )
+ {
+ Reference< XNamed >
+ aXNamed;
+
+ Reference< XNameAccess >
+ aXNameAccess;
+
+ Reference< XStyleFamiliesSupplier >
+ aXStyleFamiliesSupplier( mXModel, UNO_QUERY );
+
+ Reference< XPropertySet >
+ aXPropSet( mXModel, UNO_QUERY );
+
+ sal_uInt16 nDefaultTab = ( aXPropSet.is() && ImplGetPropertyValue( aXPropSet, "TabStop" ) )
+ ? static_cast<sal_uInt16>( convertMm100ToMasterUnit(*o3tl::doAccess<sal_Int32>(mAny)) )
+ : 1250;
+
+ maStyleSheetList.emplace_back( new PPTExStyleSheet( nDefaultTab, dynamic_cast<PPTExBulletProvider*>(this) ) );
+ SetCurrentStyleSheet( nPageNum );
+ if ( GetPageByIndex( nPageNum, MASTER ) )
+ aXNamed.set( mXDrawPage, UNO_QUERY );
+
+ if ( aXStyleFamiliesSupplier.is() )
+ aXNameAccess = aXStyleFamiliesSupplier->getStyleFamilies();
+
+ bRetValue = aXNamed.is() && aXNameAccess.is() && aXStyleFamiliesSupplier.is();
+ if ( bRetValue )
+ {
+ for ( nInstance = EPP_TEXTTYPE_Title; nInstance <= EPP_TEXTTYPE_CenterTitle; nInstance++ )
+ {
+ OUString aStyle;
+ OUString aFamily;
+ switch ( nInstance )
+ {
+ case EPP_TEXTTYPE_CenterTitle :
+ case EPP_TEXTTYPE_Title :
+ {
+ aStyle = "title";
+ aFamily = aXNamed->getName();
+ }
+ break;
+ case EPP_TEXTTYPE_Body :
+ {
+ aStyle = "outline1"; // SD_LT_SEPARATOR
+ aFamily = aXNamed->getName();
+ }
+ break;
+ case EPP_TEXTTYPE_Other :
+ {
+ aStyle = "standard";
+ aFamily = "graphics";
+ }
+ break;
+ case EPP_TEXTTYPE_CenterBody :
+ {
+ aStyle = "subtitle";
+ aFamily = aXNamed->getName();
+ }
+ break;
+ }
+ if ( !aStyle.isEmpty() && !aFamily.isEmpty() )
+ {
+ try
+ {
+ Reference< XNameAccess >xNameAccess;
+ if ( aXNameAccess->hasByName( aFamily ) )
+ {
+ Any aAny( aXNameAccess->getByName( aFamily ) );
+ xNameAccess.set(aAny, css::uno::UNO_QUERY);
+ if( xNameAccess.is() )
+ {
+ Reference< XNameAccess > aXFamily;
+ if ( aAny >>= aXFamily )
+ {
+ if ( aXFamily->hasByName( aStyle ) )
+ {
+ aAny = aXFamily->getByName( aStyle );
+ Reference< XStyle > xStyle(
+ aAny, css::uno::UNO_QUERY);
+ if( xStyle.is() )
+ {
+ Reference< XStyle > aXStyle;
+ aAny >>= aXStyle;
+ Reference< XPropertySet >
+ xPropSet( aXStyle, UNO_QUERY );
+ if( xPropSet.is() )
+ mpStyleSheet->SetStyleSheet( xPropSet, maFontCollection, nInstance, 0 );
+ for ( nLevel = 1; nLevel < 5; nLevel++ )
+ {
+ if ( nInstance == EPP_TEXTTYPE_Body )
+ {
+ sal_Unicode cTemp = aStyle[aStyle.getLength() - 1];
+ aStyle = aStyle.subView(0, aStyle.getLength() - 1) + OUStringChar(++cTemp);
+ if ( aXFamily->hasByName( aStyle ) )
+ {
+ aXFamily->getByName( aStyle ) >>= xStyle;
+ if( xStyle.is() )
+ {
+ Reference< XPropertySet >
+ xPropertySet( xStyle, UNO_QUERY );
+ if ( xPropertySet.is() )
+ mpStyleSheet->SetStyleSheet( xPropertySet, maFontCollection, nInstance, nLevel );
+ }
+ }
+ }
+ else
+ mpStyleSheet->SetStyleSheet( xPropSet, maFontCollection, nInstance, nLevel );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ catch( Exception& )
+ {
+
+ }
+ }
+ }
+ for ( ; nInstance <= EPP_TEXTTYPE_QuarterBody; nInstance++ )
+ {
+
+ }
+ }
+ }
+ return bRetValue;
+}
+
+bool PPTWriterBase::CreateMainNotes()
+{
+ if ( !GetPageByIndex( 0, NOTICE ) )
+ return false;
+ SetCurrentStyleSheet( 0 );
+
+ css::uno::Reference< css::drawing::XMasterPageTarget > aXMasterPageTarget( mXDrawPage, css::uno::UNO_QUERY );
+
+ if ( !aXMasterPageTarget.is() )
+ return false;
+
+ mXDrawPage = aXMasterPageTarget->getMasterPage();
+ if ( !mXDrawPage.is() )
+ return false;
+
+ mXPropSet.set( mXDrawPage, css::uno::UNO_QUERY );
+ if ( !mXPropSet.is() )
+ return false;
+
+ mXShapes = mXDrawPage;
+ if ( !mXShapes.is() )
+ return false;
+
+ return ImplCreateMainNotes();
+}
+
+awt::Size PPTWriterBase::MapSize( const awt::Size& rSize )
+{
+ Size aRetSize( OutputDevice::LogicToLogic( Size( rSize.Width, rSize.Height ), maMapModeSrc, maMapModeDest ) );
+
+ if ( !aRetSize.Width() )
+ aRetSize.AdjustWidth( 1 );
+ if ( !aRetSize.Height() )
+ aRetSize.AdjustHeight( 1 );
+ return awt::Size( aRetSize.Width(), aRetSize.Height() );
+}
+
+awt::Point PPTWriterBase::MapPoint( const awt::Point& rPoint )
+{
+ Point aRet( OutputDevice::LogicToLogic( Point( rPoint.X, rPoint.Y ), maMapModeSrc, maMapModeDest ) );
+ return awt::Point( aRet.X(), aRet.Y() );
+}
+
+::tools::Rectangle PPTWriterBase::MapRectangle( const awt::Rectangle& rRect )
+{
+ css::awt::Point aPoint( rRect.X, rRect.Y );
+ css::awt::Size aSize( rRect.Width, rRect.Height );
+ css::awt::Point aP( MapPoint( aPoint ) );
+ css::awt::Size aS( MapSize( aSize ) );
+ return ::tools::Rectangle( Point( aP.X, aP.Y ), Size( aS.Width, aS.Height ) );
+}
+
+bool PPTWriterBase::GetShapeByIndex( sal_uInt32 nIndex, bool bGroup )
+{
+ while(true)
+ {
+ if ( !bGroup || ( GetCurrentGroupLevel() == 0 ) )
+ {
+ Any aAny( mXShapes->getByIndex( nIndex ) );
+ aAny >>= mXShape;
+ }
+ else
+ {
+ Any aAny( GetCurrentGroupAccess()->getByIndex( GetCurrentGroupIndex() ) );
+ aAny >>= mXShape;
+ }
+ if ( !mXShape.is() )
+ break;
+
+ Any aAny( mXShape->queryInterface( cppu::UnoType<XPropertySet>::get()));
+ aAny >>= mXPropSet;
+
+ if ( !mXPropSet.is() )
+ break;
+ maPosition = MapPoint( mXShape->getPosition() );
+ maSize = MapSize( mXShape->getSize() );
+ maRect = ::tools::Rectangle( Point( maPosition.X, maPosition.Y ), Size( maSize.Width, maSize.Height ) );
+
+ OStringBuffer aTypeBuffer(OUStringToOString(
+ mXShape->getShapeType(), RTL_TEXTENCODING_UTF8));
+ // remove "com.sun.star."
+ aTypeBuffer.remove(0, RTL_CONSTASCII_LENGTH("com.sun.star."));
+
+ sal_Int32 nPos = aTypeBuffer.toString().indexOf("Shape");
+ aTypeBuffer.remove(nPos, RTL_CONSTASCII_LENGTH("Shape"));
+ mType = aTypeBuffer.makeStringAndClear();
+
+ mbPresObj = mbEmptyPresObj = false;
+ if ( ImplGetPropertyValue( "IsPresentationObject" ) )
+ mAny >>= mbPresObj;
+
+ if ( mbPresObj && ImplGetPropertyValue( "IsEmptyPresentationObject" ) )
+ mAny >>= mbEmptyPresObj;
+
+ mnAngle = ( PropValue::GetPropertyValue( aAny,
+ mXPropSet, "RotateAngle", true ) )
+ ? *o3tl::doAccess<sal_Int32>(aAny)
+ : 0;
+
+ return true;
+ }
+ return false;
+}
+
+sal_Int8 PPTWriterBase::GetTransition( sal_Int16 nTransitionType, sal_Int16 nTransitionSubtype, FadeEffect eEffect,
+ sal_Int32 nTransitionFadeColor, sal_uInt8& nDirection )
+{
+ sal_Int8 nPPTTransitionType = 0;
+ nDirection = 0;
+
+ switch( nTransitionType )
+ {
+ case TransitionType::FADE :
+ {
+ if ( nTransitionSubtype == TransitionSubType::CROSSFADE )
+ nPPTTransitionType = PPT_TRANSITION_TYPE_SMOOTHFADE;
+ else if ( nTransitionSubtype == TransitionSubType::FADEOVERCOLOR )
+ {
+ if( nTransitionFadeColor == static_cast<sal_Int32>(COL_WHITE) )
+ nPPTTransitionType = PPT_TRANSITION_TYPE_FLASH;
+ else
+ nPPTTransitionType = PPT_TRANSITION_TYPE_FADE;
+ }
+ }
+ break;
+ case TransitionType::PUSHWIPE :
+ {
+ if (nTransitionSubtype == TransitionSubType::COMBVERTICAL ||
+ nTransitionSubtype == TransitionSubType::COMBHORIZONTAL)
+ {
+ nPPTTransitionType = PPT_TRANSITION_TYPE_COMB;
+ }
+ else
+ {
+ nPPTTransitionType = PPT_TRANSITION_TYPE_PUSH;
+ }
+ switch (nTransitionSubtype)
+ {
+ case TransitionSubType::FROMRIGHT: nDirection = 0; break;
+ case TransitionSubType::FROMBOTTOM: nDirection = 1; break;
+ case TransitionSubType::FROMLEFT: nDirection = 2; break;
+ case TransitionSubType::FROMTOP: nDirection = 3; break;
+ case TransitionSubType::COMBHORIZONTAL: nDirection = 0; break;
+ case TransitionSubType::COMBVERTICAL: nDirection = 1; break;
+ }
+ }
+ break;
+ case TransitionType::PINWHEELWIPE :
+ {
+ nPPTTransitionType = PPT_TRANSITION_TYPE_WHEEL;
+ switch( nTransitionSubtype )
+ {
+ case TransitionSubType::ONEBLADE: nDirection = 1; break;
+ case TransitionSubType::TWOBLADEVERTICAL : nDirection = 2; break;
+ case TransitionSubType::THREEBLADE : nDirection = 3; break;
+ case TransitionSubType::FOURBLADE: nDirection = 4; break;
+ case TransitionSubType::EIGHTBLADE: nDirection = 8; break;
+ }
+ }
+ break;
+ case TransitionType::FANWIPE :
+ {
+ nPPTTransitionType = PPT_TRANSITION_TYPE_WEDGE;
+ }
+ break;
+ case TransitionType::ELLIPSEWIPE :
+ {
+ switch( nTransitionSubtype ) {
+ case TransitionSubType::VERTICAL:
+ case TransitionSubType::HORIZONTAL:
+ // no ellipse or oval in PPT or OOXML, fallback to circle
+ default:
+ nPPTTransitionType = PPT_TRANSITION_TYPE_CIRCLE;
+ }
+ }
+ break;
+ case TransitionType::FOURBOXWIPE :
+ {
+ nPPTTransitionType = PPT_TRANSITION_TYPE_PLUS;
+ }
+ break;
+ case TransitionType::IRISWIPE :
+ {
+ switch( nTransitionSubtype ) {
+ case TransitionSubType::RECTANGLE:
+ nPPTTransitionType = PPT_TRANSITION_TYPE_ZOOM;
+ nDirection = (eEffect == FadeEffect_FADE_FROM_CENTER) ? 0 : 1;
+ break;
+ default:
+ nPPTTransitionType = PPT_TRANSITION_TYPE_DIAMOND;
+ break;
+ }
+ }
+ break;
+ case TransitionType::ZOOM:
+ {
+ switch(nTransitionSubtype)
+ {
+ case TransitionSubType::ROTATEIN:
+ nPPTTransitionType = PPT_TRANSITION_TYPE_NEWSFLASH;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+
+ return nPPTTransitionType;
+}
+
+sal_Int8 PPTWriterBase::GetTransition( FadeEffect eEffect, sal_uInt8& nDirection )
+{
+ sal_Int8 nPPTTransitionType = 0;
+
+ switch ( eEffect )
+ {
+ default :
+ case FadeEffect_RANDOM :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_RANDOM;
+ break;
+
+ case FadeEffect_HORIZONTAL_STRIPES :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_VERTICAL_STRIPES :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_BLINDS;
+ break;
+
+ case FadeEffect_VERTICAL_CHECKERBOARD :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_HORIZONTAL_CHECKERBOARD :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_CHECKER;
+ break;
+
+ case FadeEffect_MOVE_FROM_UPPERLEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_MOVE_FROM_UPPERRIGHT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_MOVE_FROM_LOWERLEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_MOVE_FROM_LOWERRIGHT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_MOVE_FROM_TOP :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_MOVE_FROM_LEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_MOVE_FROM_BOTTOM :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_MOVE_FROM_RIGHT :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_COVER;
+ break;
+
+ case FadeEffect_DISSOLVE :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_DISSOLVE;
+ break;
+
+ case FadeEffect_VERTICAL_LINES :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_HORIZONTAL_LINES :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_RANDOM_BARS;
+ break;
+
+ case FadeEffect_CLOSE_HORIZONTAL :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_OPEN_HORIZONTAL :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_CLOSE_VERTICAL :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_OPEN_VERTICAL :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_SPLIT;
+ break;
+
+ case FadeEffect_FADE_FROM_UPPERLEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_FADE_FROM_UPPERRIGHT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_FADE_FROM_LOWERLEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_FADE_FROM_LOWERRIGHT :
+ nDirection += 4;
+ nPPTTransitionType = PPT_TRANSITION_TYPE_STRIPS;
+ break;
+
+ case FadeEffect_UNCOVER_TO_LOWERRIGHT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_UNCOVER_TO_LOWERLEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_UNCOVER_TO_UPPERRIGHT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_UNCOVER_TO_UPPERLEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_UNCOVER_TO_BOTTOM :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_UNCOVER_TO_RIGHT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_UNCOVER_TO_TOP :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_UNCOVER_TO_LEFT :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_PULL;
+ break;
+
+ case FadeEffect_FADE_FROM_TOP :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_FADE_FROM_LEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_FADE_FROM_BOTTOM :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_FADE_FROM_RIGHT :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_WIPE;
+ break;
+
+ case FadeEffect_ROLL_FROM_TOP :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_ROLL_FROM_LEFT :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_ROLL_FROM_BOTTOM :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_ROLL_FROM_RIGHT :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_WIPE;
+ break;
+
+ case FadeEffect_FADE_TO_CENTER :
+ nDirection++;
+ [[fallthrough]];
+ case FadeEffect_FADE_FROM_CENTER :
+ nPPTTransitionType = PPT_TRANSITION_TYPE_ZOOM;
+ break;
+
+ case FadeEffect_NONE :
+ nDirection = 2;
+ break;
+ }
+
+ return nPPTTransitionType;
+}
+
+bool PPTWriterBase::ContainsOtherShapeThanPlaceholders()
+{
+ sal_uInt32 nShapes = mXShapes->getCount();
+ bool bOtherThanPlaceHolders = false;
+
+ if ( nShapes )
+ for ( sal_uInt32 nIndex = 0; ( nIndex < nShapes ) && !bOtherThanPlaceHolders; nIndex++ )
+ {
+ if ( GetShapeByIndex( nIndex, false ) && mType != "drawing.Page" )
+ {
+ if( mType == "presentation.Page" || mType == "presentation.Notes" )
+ {
+ Reference< XSimpleText > rXText( mXShape, UNO_QUERY );
+
+ if( rXText.is() && !rXText->getString().isEmpty() )
+ bOtherThanPlaceHolders = true;
+ }
+ else
+ bOtherThanPlaceHolders = true;
+ }
+ SAL_INFO("sd.eppt", "mType == " << mType);
+ }
+
+ return bOtherThanPlaceHolders;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptx-epptooxml.cxx b/sd/source/filter/eppt/pptx-epptooxml.cxx
new file mode 100644
index 000000000..6a338a6a6
--- /dev/null
+++ b/sd/source/filter/eppt/pptx-epptooxml.cxx
@@ -0,0 +1,2594 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <stdio.h>
+#include <oox/drawingml/clrscheme.hxx>
+#include <oox/token/namespaces.hxx>
+#include <oox/token/tokens.hxx>
+#include <oox/token/relationship.hxx>
+#include <oox/ole/vbaproject.hxx>
+#include "epptooxml.hxx"
+#include <oox/export/shapes.hxx>
+
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/xmltools.hxx>
+#include <sax/fshelper.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <tools/UnitConversion.hxx>
+#include <tools/datetime.hxx>
+#include <com/sun/star/animations/TransitionType.hpp>
+#include <com/sun/star/animations/TransitionSubType.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/XDrawPages.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/geometry/RealPoint2D.hpp>
+#include <com/sun/star/office/XAnnotationEnumeration.hpp>
+#include <com/sun/star/office/XAnnotationAccess.hpp>
+#include <com/sun/star/presentation/AnimationSpeed.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/presentation/XCustomPresentationSupplier.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/presentation/XPresentationSupplier.hpp>
+#include <tools/diagnose_ex.h>
+
+#include <oox/export/utils.hxx>
+
+#include "pptx-animations.hxx"
+#include "../ppt/pptanimations.hxx"
+
+#include <i18nlangtag/languagetag.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/svdogrp.hxx>
+#include <sdmod.hxx>
+#include <sdpage.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/document/XStorageBasedDocument.hpp>
+#include <utility>
+#if OSL_DEBUG_LEVEL > 1
+#include <com/sun/star/drawing/RectanglePoint.hpp>
+#endif
+
+// presentation namespaces
+#define PNMSS FSNS(XML_xmlns, XML_a), OUStringToOString(this->getNamespaceURL(OOX_NS(dml)), RTL_TEXTENCODING_UTF8).getStr(), \
+ FSNS(XML_xmlns, XML_p), OUStringToOString(this->getNamespaceURL(OOX_NS(ppt)), RTL_TEXTENCODING_UTF8).getStr(), \
+ FSNS(XML_xmlns, XML_r), OUStringToOString(this->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr(), \
+ FSNS(XML_xmlns, XML_p14), OUStringToOString(this->getNamespaceURL(OOX_NS(p14)), RTL_TEXTENCODING_UTF8).getStr(), \
+ FSNS(XML_xmlns, XML_p15), OUStringToOString(this->getNamespaceURL(OOX_NS(p15)), RTL_TEXTENCODING_UTF8).getStr(), \
+ FSNS(XML_xmlns, XML_mc), OUStringToOString(this->getNamespaceURL(OOX_NS(mce)), RTL_TEXTENCODING_UTF8).getStr()
+
+// presentationPr namespace
+#define PPRNMSS FSNS(XML_xmlns, XML_a), OUStringToOString(this->getNamespaceURL(OOX_NS(dml)), RTL_TEXTENCODING_UTF8).getStr(), \
+ FSNS(XML_xmlns, XML_r), OUStringToOString(this->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr(), \
+ FSNS(XML_xmlns, XML_p), OUStringToOString(this->getNamespaceURL(OOX_NS(ppt)), RTL_TEXTENCODING_UTF8).getStr()
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::geometry;
+using namespace ::com::sun::star::presentation;
+using namespace ::com::sun::star::office;
+using namespace ::com::sun::star::text;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::ppt;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::beans::XPropertySetInfo;
+using ::sax_fastparser::FSHelperPtr;
+using namespace oox::drawingml;
+using namespace oox::core;
+
+#if OSL_DEBUG_LEVEL > 1
+void dump_pset(Reference< XPropertySet > const& rXPropSet);
+#endif
+
+namespace oox::core
+{
+
+class PowerPointShapeExport : public ShapeExport
+{
+ PowerPointExport& mrExport;
+ PageType mePageType;
+ bool mbMaster;
+public:
+ PowerPointShapeExport(FSHelperPtr pFS, ShapeHashMap* pShapeMap, PowerPointExport* pFB);
+ void SetMaster(bool bMaster);
+ void SetPageType(PageType ePageType);
+ ShapeExport& WriteNonVisualProperties(const Reference< XShape >& xShape) override;
+ ShapeExport& WriteTextShape(const Reference< XShape >& xShape) override;
+ ShapeExport& WriteUnknownShape(const Reference< XShape >& xShape) override;
+ ShapeExport& WritePlaceholderShape(const Reference< XShape >& xShape, PlaceholderType ePlaceholder);
+ /** Writes a placeholder shape that references the placeholder on the master slide */
+ ShapeExport& WritePlaceholderReferenceShape(PlaceholderType ePlaceholder, sal_Int32 nReferencedPlaceholderIdx, PageType ePageType, const Reference<XPropertySet>& rXPagePropSet);
+ ShapeExport& WritePageShape(const Reference< XShape >& xShape, PageType ePageType, bool bPresObj);
+ /** Writes textbody of a placeholder that references the placeholder on the master slide */
+ ShapeExport& WritePlaceholderReferenceTextBody(PlaceholderType ePlaceholder, PageType ePageType, const Reference<XPropertySet> xPagePropSet);
+
+ // helper parts
+ bool WritePlaceholder(const Reference< XShape >& xShape, PlaceholderType ePlaceholder, bool bMaster);
+};
+
+
+namespace
+{
+void WriteSndAc(const FSHelperPtr& pFS, const OUString& sSoundRelId, const OUString& sSoundName)
+{
+ pFS->startElementNS(XML_p, XML_sndAc);
+ pFS->startElementNS(XML_p, XML_stSnd);
+ pFS->singleElementNS(XML_p, XML_snd, FSNS(XML_r, XML_embed),
+ sax_fastparser::UseIf(sSoundRelId, !sSoundRelId.isEmpty()), XML_name,
+ sax_fastparser::UseIf(sSoundName, !sSoundName.isEmpty()));
+ pFS->endElement(FSNS(XML_p, XML_stSnd));
+ pFS->endElement(FSNS(XML_p, XML_sndAc));
+}
+
+const char* getPlaceholderTypeName(PlaceholderType ePlaceholder)
+{
+ switch (ePlaceholder)
+ {
+ case SlideImage:
+ return "sldImg";
+ case Notes:
+ return "body";
+ case Header:
+ return "hdr";
+ case Footer:
+ return "ftr";
+ case SlideNumber:
+ return "sldNum";
+ case DateAndTime:
+ return "dt";
+ case Outliner:
+ return "body";
+ case Title:
+ return "title";
+ case Subtitle:
+ return "subTitle";
+ default:
+ SAL_INFO("sd.eppt", "warning: unhandled placeholder type: " << ePlaceholder);
+ return "";
+ }
+}
+}
+}
+
+namespace {
+
+enum PPTXLayout
+{
+ LAYOUT_BLANK,
+ LAYOUT_TITLE_SLIDE,
+ LAYOUT_TITLE_CONTENT,
+ LAYOUT_TITLE_2CONTENT,
+ LAYOUT_TITLE,
+ LAYOUT_CENTERED_TEXT,
+ LAYOUT_TITLE_2CONTENT_CONTENT,
+ LAYOUT_TITLE_CONTENT_2CONTENT,
+ LAYOUT_TITLE_2CONTENT_OVER_CONTENT,
+ LAYOUT_TITLE_CONTENT_OVER_CONTENT,
+ LAYOUT_TITLE_4CONTENT,
+ LAYOUT_TITLE_6CONTENT,
+ LAYOUT_SIZE
+};
+
+struct PPTXLayoutInfo
+{
+ int nType;
+ const char* sName;
+ const char* sType;
+};
+
+}
+
+const PPTXLayoutInfo aLayoutInfo[LAYOUT_SIZE] =
+{
+ { 20, "Blank Slide", "blank" },
+ { 0, "Title Slide", "tx" },
+ { 1, "Title, Content", "obj" },
+ { 3, "Title, 2 Content", "twoObj" },
+ { 19, "Title Only", "titleOnly" },
+ { 32, "Centered Text", "objOnly" }, // not exactly, but close
+ { 15, "Title, 2 Content and Content", "twoObjAndObj" },
+ { 12, "Title Content and 2 Content", "objAndTwoObj" },
+ { 16, "Title, 2 Content over Content", "twoObjOverTx" }, // not exactly, but close
+ { 14, "Title, Content over Content", "objOverTx" }, // not exactly, but close
+ { 18, "Title, 4 Content", "fourObj" },
+ { 34, "Title, 6 Content", "blank" } // not defined => blank
+};
+
+int PowerPointExport::GetPPTXLayoutId(int nOffset)
+{
+ int nId = LAYOUT_BLANK;
+
+ SAL_INFO("sd.eppt", "GetPPTXLayoutId " << nOffset);
+
+ switch (nOffset)
+ {
+ case 0:
+ nId = LAYOUT_TITLE_SLIDE;
+ break;
+ case 1:
+ nId = LAYOUT_TITLE_CONTENT;
+ break;
+ case 3:
+ nId = LAYOUT_TITLE_2CONTENT;
+ break;
+ case 19:
+ nId = LAYOUT_TITLE;
+ break;
+ case 15:
+ nId = LAYOUT_TITLE_2CONTENT_CONTENT;
+ break;
+ case 12:
+ nId = LAYOUT_TITLE_CONTENT_2CONTENT;
+ break;
+ case 16:
+ nId = LAYOUT_TITLE_2CONTENT_OVER_CONTENT;
+ break;
+ case 14:
+ nId = LAYOUT_TITLE_CONTENT_OVER_CONTENT;
+ break;
+ case 18:
+ nId = LAYOUT_TITLE_4CONTENT;
+ break;
+ case 32:
+ nId = LAYOUT_CENTERED_TEXT;
+ break;
+ case 34:
+ nId = LAYOUT_TITLE_6CONTENT;
+ break;
+ case 20:
+ default:
+ nId = LAYOUT_BLANK;
+ break;
+ }
+
+ return nId;
+}
+
+PowerPointShapeExport::PowerPointShapeExport(FSHelperPtr pFS, ShapeHashMap* pShapeMap,
+ PowerPointExport* pFB)
+ : ShapeExport(XML_p, std::move(pFS), pShapeMap, pFB)
+ , mrExport(*pFB)
+ , mePageType(UNDEFINED)
+ , mbMaster(false)
+{
+}
+
+void PowerPointShapeExport::SetMaster(bool bMaster)
+{
+ mbMaster = bMaster;
+}
+
+void PowerPointShapeExport::SetPageType(PageType ePageType)
+{
+ mePageType = ePageType;
+}
+
+ShapeExport& PowerPointShapeExport::WriteNonVisualProperties(const Reference< XShape >&)
+{
+ GetFS()->singleElementNS(XML_p, XML_nvPr);
+
+ return *this;
+}
+
+ShapeExport& PowerPointShapeExport::WriteTextShape(const Reference< XShape >& xShape)
+{
+ OUString sShapeType = xShape->getShapeType();
+
+ SAL_INFO("sd.eppt", "shape(text) : " << sShapeType.toUtf8());
+
+ if (sShapeType == "com.sun.star.drawing.TextShape" || sShapeType == "com.sun.star.drawing.GraphicObjectShape")
+ {
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else if (sShapeType == "com.sun.star.presentation.DateTimeShape")
+ {
+ if (!WritePlaceholder(xShape, DateAndTime, mbMaster))
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else if (sShapeType == "com.sun.star.presentation.FooterShape")
+ {
+ if (!WritePlaceholder(xShape, Footer, mbMaster))
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else if (sShapeType == "com.sun.star.presentation.HeaderShape")
+ {
+ if (!WritePlaceholder(xShape, Header, mbMaster))
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else if (sShapeType == "com.sun.star.presentation.NotesShape")
+ {
+ if (mePageType == NOTICE && mrExport.GetPresObj())
+ WritePlaceholderShape(xShape, Notes);
+ else
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else if (sShapeType == "com.sun.star.presentation.OutlinerShape")
+ {
+ if (!WritePlaceholder(xShape, Outliner, mbMaster))
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else if (sShapeType == "com.sun.star.presentation.SlideNumberShape")
+ {
+ if (!WritePlaceholder(xShape, SlideNumber, mbMaster))
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else if (sShapeType == "com.sun.star.presentation.TitleTextShape")
+ {
+ if (!WritePlaceholder(xShape, Title, mbMaster))
+ ShapeExport::WriteTextShape(xShape);
+ }
+ else
+ SAL_WARN("sd.eppt", "PowerPointShapeExport::WriteTextShape: shape of type '" << sShapeType << "' is ignored");
+
+ return *this;
+}
+
+ShapeExport& PowerPointShapeExport::WriteUnknownShape(const Reference< XShape >& xShape)
+{
+ OUString sShapeType = xShape->getShapeType();
+
+ SAL_INFO("sd.eppt", "shape(unknown): " << sShapeType.toUtf8());
+
+ if (sShapeType == "com.sun.star.presentation.PageShape")
+ {
+ WritePageShape(xShape, mePageType, mrExport.GetPresObj());
+ }
+ else if (sShapeType == "com.sun.star.presentation.SubtitleShape")
+ {
+ if(mePageType != MASTER)
+ {
+ if (!WritePlaceholder(xShape, Subtitle, mbMaster))
+ ShapeExport::WriteTextShape(xShape);
+ }
+ }
+ else
+ SAL_WARN("sd.eppt", "unknown shape not handled: " << sShapeType.toUtf8());
+
+ return *this;
+}
+
+PowerPointExport::PowerPointExport(const Reference< XComponentContext >& rContext, const uno::Sequence<uno::Any>& rArguments)
+ : XmlFilterBase(rContext)
+ , mnLayoutFileIdMax(1)
+ , mnSlideIdMax(1 << 8)
+ , mnSlideMasterIdMax(1U << 31)
+ , mnAnimationNodeIdMax(1)
+ , mnDiagramId(1)
+ , mbCreateNotes(false)
+ , mnPlaceholderIndexMax(1)
+{
+ comphelper::SequenceAsHashMap aArgumentsMap(rArguments);
+ mbPptm = aArgumentsMap.getUnpackedValueOrDefault("IsPPTM", false);
+ mbExportTemplate = aArgumentsMap.getUnpackedValueOrDefault("IsTemplate", false);
+}
+
+PowerPointExport::~PowerPointExport()
+{
+}
+
+void PowerPointExport::writeDocumentProperties()
+{
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(mXModel, uno::UNO_QUERY);
+ uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties();
+
+ if (xDocProps.is())
+ {
+ bool bSecurityOptOpenReadOnly = false;
+ uno::Reference< lang::XMultiServiceFactory > xFactory(mXModel, uno::UNO_QUERY);
+ uno::Reference< beans::XPropertySet > xSettings(xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
+ try
+ {
+ xSettings->getPropertyValue("LoadReadonly") >>= bSecurityOptOpenReadOnly;
+ }
+ catch( Exception& )
+ {
+ }
+ exportDocumentProperties(xDocProps, bSecurityOptOpenReadOnly);
+ }
+
+ exportCustomFragments();
+}
+
+bool PowerPointExport::importDocument() noexcept
+{
+ return false;
+}
+
+bool PowerPointExport::exportDocument()
+{
+ DrawingML::PushExportGraphics();
+ maShapeMap.clear();
+
+ mXModel = getModel();
+
+ //write document properties
+ writeDocumentProperties();
+
+ addRelation(oox::getRelationship(Relationship::OFFICEDOCUMENT), u"ppt/presentation.xml");
+
+ OUString aMediaType;
+ if (mbPptm)
+ {
+ if (mbExportTemplate)
+ {
+ aMediaType = "application/vnd.ms-powerpoint.template.macroEnabled.main+xml";
+ }
+ else
+ {
+ aMediaType = "application/vnd.ms-powerpoint.presentation.macroEnabled.main+xml";
+ }
+ }
+ else
+ {
+ if (mbExportTemplate)
+ {
+ aMediaType = "application/vnd.openxmlformats-officedocument.presentationml.template.main+xml";
+ }
+ else
+ {
+ aMediaType = "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml";
+ }
+ }
+
+ mPresentationFS = openFragmentStreamWithSerializer("ppt/presentation.xml", aMediaType);
+
+ addRelation(mPresentationFS->getOutputStream(),
+ oox::getRelationship(Relationship::THEME),
+ u"theme/theme1.xml");
+
+ mPresentationFS->startElementNS(XML_p, XML_presentation, PNMSS);
+
+ mXStatusIndicator = getStatusIndicator();
+
+ std::vector< PropertyValue > aProperties;
+ PropertyValue aProperty;
+ aProperty.Name = "BaseURI";
+ aProperty.Value <<= getFileUrl();
+ aProperties.push_back(aProperty);
+
+ exportPPT(aProperties);
+
+ mPresentationFS->singleElementNS(XML_p, XML_sldSz,
+ XML_cx, OString::number(PPTtoEMU(maDestPageSize.Width)),
+ XML_cy, OString::number(PPTtoEMU(maDestPageSize.Height)));
+ // for some reason if added before slides list it will not load the slides (alas with error reports) in mso
+ mPresentationFS->singleElementNS(XML_p, XML_notesSz,
+ XML_cx, OString::number(PPTtoEMU(maNotesPageSize.Width)),
+ XML_cy, OString::number(PPTtoEMU(maNotesPageSize.Height)));
+
+ WriteCustomSlideShow();
+
+ WritePresentationProps();
+
+ WriteAuthors();
+
+ WriteVBA();
+
+ WriteModifyVerifier();
+
+ mPresentationFS->endElementNS(XML_p, XML_presentation);
+ mPresentationFS.reset();
+ // Free all FSHelperPtr, to flush data before committing storage
+ mpSlidesFSArray.clear();
+
+ commitStorage();
+
+ DrawingML::PopExportGraphics();
+ maShapeMap.clear();
+ maAuthors.clear();
+ maRelId.clear();
+
+ return true;
+}
+
+::oox::ole::VbaProject* PowerPointExport::implCreateVbaProject() const
+{
+ return new ::oox::ole::VbaProject(getComponentContext(), getModel(), u"Impress");
+}
+
+void PowerPointExport::WriteCustomSlideShow()
+{
+ Reference<XCustomPresentationSupplier> aXCPSup(mXModel, css::uno::UNO_QUERY);
+ if (!aXCPSup.is() || !aXCPSup->getCustomPresentations()->hasElements())
+ return;
+
+ mPresentationFS->startElementNS(XML_p, XML_custShowLst);
+
+ Reference<XDrawPagesSupplier> xDPS(getModel(), uno::UNO_QUERY_THROW);
+ Reference<XDrawPages> xDrawPages(xDPS->getDrawPages(), uno::UNO_SET_THROW);
+ Reference<XNameContainer> aXNameCont(aXCPSup->getCustomPresentations());
+ const Sequence<OUString> aNameSeq(aXNameCont->getElementNames());
+
+ OUString sRelId;
+ sal_uInt32 nCustomShowIndex = 0;
+ sal_Int32 nSlideCount = xDrawPages->getCount();
+
+ for (OUString const& customShowName : aNameSeq)
+ {
+ mPresentationFS->startElementNS(XML_p, XML_custShow, XML_name, customShowName, XML_id,
+ OUString::number(nCustomShowIndex++));
+
+ mAny = aXNameCont->getByName(customShowName);
+ Reference<XIndexContainer> aXIContainer;
+ if (mAny >>= aXIContainer)
+ {
+ mPresentationFS->startElementNS(XML_p, XML_sldLst);
+
+ sal_Int32 nCustomShowSlideCount = aXIContainer->getCount();
+ for (sal_Int32 i = 0; i < nCustomShowSlideCount; ++i)
+ {
+ Reference<XDrawPage> aXCustomShowDrawPage;
+ aXIContainer->getByIndex(i) >>= aXCustomShowDrawPage;
+ Reference<XNamed> aXName(aXCustomShowDrawPage, UNO_QUERY_THROW);
+ OUString sCustomShowSlideName = aXName->getName();
+
+ for (sal_Int32 j = 0; j < nSlideCount; ++j)
+ {
+ Reference<XDrawPage> xDrawPage;
+ xDrawPages->getByIndex(j) >>= xDrawPage;
+ Reference<XNamed> xNamed(xDrawPage, UNO_QUERY_THROW);
+ OUString sSlideName = xNamed->getName();
+
+ if (sCustomShowSlideName == sSlideName)
+ {
+ sRelId = maRelId[j];
+ break;
+ }
+ }
+ mPresentationFS->singleElementNS(XML_p, XML_sld, FSNS(XML_r, XML_id), sRelId);
+ }
+ mPresentationFS->endElementNS(XML_p, XML_sldLst);
+ }
+ mPresentationFS->endElementNS(XML_p, XML_custShow);
+ }
+ mPresentationFS->endElementNS(XML_p, XML_custShowLst);
+}
+
+void PowerPointExport::ImplWriteBackground(const FSHelperPtr& pFS, const Reference< XPropertySet >& rXPropSet)
+{
+ FillStyle aFillStyle(FillStyle_NONE);
+ if (ImplGetPropertyValue(rXPropSet, "FillStyle"))
+ mAny >>= aFillStyle;
+
+ if (aFillStyle == FillStyle_NONE ||
+ aFillStyle == FillStyle_HATCH)
+ return;
+
+ pFS->startElementNS(XML_p, XML_bg);
+ pFS->startElementNS(XML_p, XML_bgPr);
+
+ PowerPointShapeExport aDML(pFS, &maShapeMap, this);
+ aDML.SetBackgroundDark(mbIsBackgroundDark);
+ aDML.WriteFill(rXPropSet);
+
+ pFS->endElementNS(XML_p, XML_bgPr);
+ pFS->endElementNS(XML_p, XML_bg);
+}
+
+#define MAIN_GROUP \
+ "<p:nvGrpSpPr>\
+ <p:cNvPr id=\"1\" name=\"\"/>\
+ <p:cNvGrpSpPr/>\
+ <p:nvPr/>\
+ </p:nvGrpSpPr>\
+ <p:grpSpPr>\
+ <a:xfrm>\
+ <a:off x=\"0\" y=\"0\"/>\
+ <a:ext cx=\"0\" cy=\"0\"/>\
+ <a:chOff x=\"0\" y=\"0\"/>\
+ <a:chExt cx=\"0\" cy=\"0\"/>\
+ </a:xfrm>\
+ </p:grpSpPr>"
+
+const char* PowerPointExport::GetSideDirection(sal_uInt8 nDirection)
+{
+ const char* pDirection = nullptr;
+
+ switch (nDirection)
+ {
+ case 0:
+ pDirection = "l";
+ break;
+ case 1:
+ pDirection = "u";
+ break;
+ case 2:
+ pDirection = "r";
+ break;
+ case 3:
+ pDirection = "d";
+ break;
+ }
+
+ return pDirection;
+}
+
+const char* PowerPointExport::GetCornerDirection(sal_uInt8 nDirection)
+{
+ const char* pDirection = nullptr;
+
+ switch (nDirection)
+ {
+ case 4:
+ pDirection = "lu";
+ break;
+ case 5:
+ pDirection = "ru";
+ break;
+ case 6:
+ pDirection = "ld";
+ break;
+ case 7:
+ pDirection = "rd";
+ break;
+ }
+
+ return pDirection;
+}
+
+const char* PowerPointExport::Get8Direction(sal_uInt8 nDirection)
+{
+ const char* pDirection = GetSideDirection(nDirection);
+
+ if (!pDirection)
+ pDirection = GetCornerDirection(nDirection);
+
+ return pDirection;
+}
+
+void PowerPointExport::WriteTransition(const FSHelperPtr& pFS)
+{
+ FadeEffect eFadeEffect = FadeEffect_NONE;
+ if (ImplGetPropertyValue(mXPagePropSet, "Effect"))
+ mAny >>= eFadeEffect;
+
+ sal_Int16 nTransitionType = 0, nTransitionSubtype = 0;
+ sal_Int8 nPPTTransitionType = 0;
+ sal_uInt8 nDirection = 0;
+
+ OUString sSoundUrl;
+ OUString sSoundRelId;
+ OUString sSoundName;
+
+ if (ImplGetPropertyValue(mXPagePropSet, "TransitionType") && (mAny >>= nTransitionType) &&
+ ImplGetPropertyValue(mXPagePropSet, "TransitionSubtype") && (mAny >>= nTransitionSubtype))
+ {
+ // FADEOVERCOLOR with black -> fade, with white -> flash
+ sal_Int32 nTransitionFadeColor = 0;
+ if( ImplGetPropertyValue(mXPagePropSet, "TransitionFadeColor"))
+ mAny >>= nTransitionFadeColor;
+ nPPTTransitionType = GetTransition(nTransitionType, nTransitionSubtype, eFadeEffect, nTransitionFadeColor, nDirection);
+ }
+
+ if (!nPPTTransitionType && eFadeEffect != FadeEffect_NONE)
+ nPPTTransitionType = GetTransition(eFadeEffect, nDirection);
+
+ if (ImplGetPropertyValue(mXPagePropSet, "Sound") && (mAny >>= sSoundUrl))
+ embedEffectAudio(pFS, sSoundUrl, sSoundRelId, sSoundName);
+
+ bool bOOXmlSpecificTransition = false;
+
+ sal_Int32 nTransition = 0;
+ const char* pDirection = nullptr;
+ const char* pOrientation = nullptr;
+ const char* pThruBlk = nullptr;
+ const char* pSpokes = nullptr;
+
+ char pSpokesTmp[2] = "0";
+
+ // p14
+ sal_Int32 nTransition14 = 0;
+ const char* pDirection14 = nullptr;
+ const char* pInverted = nullptr;
+ const char* pPattern = nullptr; // diamond or hexagon
+
+ //p15
+ const char* pPresetTransition = nullptr;
+
+ if (!nPPTTransitionType)
+ {
+ switch (nTransitionType)
+ {
+ case animations::TransitionType::BARWIPE:
+ {
+ if (nTransitionSubtype == animations::TransitionSubType::FADEOVERCOLOR)
+ {
+ nTransition = XML_cut;
+ pThruBlk = "true";
+ bOOXmlSpecificTransition = true;
+ }
+ break;
+ }
+ case animations::TransitionType::MISCSHAPEWIPE:
+ {
+ switch (nTransitionSubtype)
+ {
+ case animations::TransitionSubType::TOPTOBOTTOM: // Turn around
+ nTransition = XML_fade;
+ nTransition14 = XML_flip;
+ pDirection14 = "l";
+ bOOXmlSpecificTransition = true;
+ break;
+ case animations::TransitionSubType::BOTTOMRIGHT: // Rochade
+ nTransition = XML_fade;
+ nTransition14 = XML_switch;
+ pDirection14 = "r";
+ bOOXmlSpecificTransition = true;
+ break;
+ case animations::TransitionSubType::VERTICAL: // Vortex
+ nTransition = XML_fade;
+ nTransition14 = XML_vortex;
+ bOOXmlSpecificTransition = true;
+ break;
+ case animations::TransitionSubType::HORIZONTAL: // Ripple
+ nTransition = XML_fade;
+ nTransition14 = XML_ripple;
+ bOOXmlSpecificTransition = true;
+ break;
+ case animations::TransitionSubType::LEFTTORIGHT: // Fall
+ nTransition = XML_fade;
+ pPresetTransition = "fallOver";
+ bOOXmlSpecificTransition = true;
+ break;
+ case animations::TransitionSubType::CORNERSIN: // Inside turning cube
+ pInverted = "true";
+ [[fallthrough]];
+ case animations::TransitionSubType::CORNERSOUT: // Outside turning cube
+ nTransition = XML_fade;
+ nTransition14 = XML_prism;
+ bOOXmlSpecificTransition = true;
+ break;
+ case animations::TransitionSubType::DIAMOND: // Glitter
+ nTransition = XML_fade;
+ nTransition14 = XML_glitter;
+ pDirection14 = "l";
+ pPattern = "hexagon";
+ bOOXmlSpecificTransition = true;
+ break;
+ case animations::TransitionSubType::HEART: // Honeycomb
+ nTransition = XML_fade;
+ nTransition14 = XML_honeycomb;
+ bOOXmlSpecificTransition = true;
+ break;
+ }
+ break;
+ }
+ }
+ }
+
+ AnimationSpeed animationSpeed = AnimationSpeed_MEDIUM;
+ const char* speed = nullptr;
+ sal_Int32 advanceTiming = -1;
+ sal_Int32 changeType = 0;
+
+ sal_Int32 nTransitionDuration = -1;
+ bool isTransitionDurationSet = false;
+
+ // try to use TransitionDuration instead of old Speed property
+ if (ImplGetPropertyValue(mXPagePropSet, "TransitionDuration"))
+ {
+ double fTransitionDuration = -1.0;
+ mAny >>= fTransitionDuration;
+ if (fTransitionDuration >= 0)
+ {
+ nTransitionDuration = fTransitionDuration * 1000.0;
+
+ // override values because in MS formats meaning of fast/medium/slow is different
+ if (nTransitionDuration <= 500)
+ {
+ // fast is default
+ speed = nullptr;
+ }
+ else if (nTransitionDuration >= 1000)
+ {
+ speed = "slow";
+ }
+ else
+ {
+ speed = "med";
+ }
+
+ bool isStandardValue = nTransitionDuration == 500
+ || nTransitionDuration == 750
+ || nTransitionDuration == 1000;
+
+ if(!isStandardValue)
+ isTransitionDurationSet = true;
+ }
+ }
+ else if (ImplGetPropertyValue(mXPagePropSet, "Speed"))
+ {
+ mAny >>= animationSpeed;
+
+ switch (animationSpeed)
+ {
+ default:
+ case AnimationSpeed_MEDIUM:
+ speed = "med";
+ break;
+ case AnimationSpeed_SLOW:
+ speed = "slow";
+ break;
+ case AnimationSpeed_FAST:
+ break;
+ }
+ }
+
+ // check if we resolved what transition to export or time is set
+ if (!nPPTTransitionType && !bOOXmlSpecificTransition && !isTransitionDurationSet)
+ return;
+
+ if (ImplGetPropertyValue(mXPagePropSet, "Change"))
+ mAny >>= changeType;
+
+ // 1 means automatic, 2 half automatic - not sure what it means - at least I don't see it in UI
+ if (changeType == 1 && ImplGetPropertyValue(mXPagePropSet, "Duration"))
+ mAny >>= advanceTiming;
+
+ if (!bOOXmlSpecificTransition)
+ {
+ switch (nPPTTransitionType)
+ {
+ case PPT_TRANSITION_TYPE_BLINDS:
+ nTransition = XML_blinds;
+ pDirection = (nDirection == 0) ? "vert" : "horz";
+ break;
+ case PPT_TRANSITION_TYPE_CHECKER:
+ nTransition = XML_checker;
+ pDirection = (nDirection == 1) ? "vert" : "horz";
+ break;
+ case PPT_TRANSITION_TYPE_CIRCLE:
+ nTransition = XML_circle;
+ break;
+ case PPT_TRANSITION_TYPE_COMB:
+ nTransition = XML_comb;
+ pDirection = (nDirection == 1) ? "vert" : "horz";
+ break;
+ case PPT_TRANSITION_TYPE_COVER:
+ nTransition = XML_cover;
+ pDirection = Get8Direction(nDirection);
+ break;
+ case PPT_TRANSITION_TYPE_DIAMOND:
+ nTransition = XML_diamond;
+ break;
+ case PPT_TRANSITION_TYPE_DISSOLVE:
+ nTransition = XML_dissolve;
+ break;
+ case PPT_TRANSITION_TYPE_FADE:
+ nTransition = XML_fade;
+ pThruBlk = "true";
+ break;
+ case PPT_TRANSITION_TYPE_SMOOTHFADE:
+ nTransition = XML_fade;
+ break;
+ case PPT_TRANSITION_TYPE_NEWSFLASH:
+ nTransition = XML_newsflash;
+ break;
+ case PPT_TRANSITION_TYPE_PLUS:
+ nTransition = XML_plus;
+ break;
+ case PPT_TRANSITION_TYPE_PULL:
+ nTransition = XML_pull;
+ pDirection = Get8Direction(nDirection);
+ break;
+ case PPT_TRANSITION_TYPE_PUSH:
+ nTransition = XML_push;
+ pDirection = GetSideDirection(nDirection);
+ break;
+ case PPT_TRANSITION_TYPE_RANDOM:
+ nTransition = XML_random;
+ break;
+ case PPT_TRANSITION_TYPE_RANDOM_BARS:
+ nTransition = XML_randomBar;
+ pDirection = (nDirection == 1) ? "vert" : "horz";
+ break;
+ case PPT_TRANSITION_TYPE_SPLIT:
+ nTransition = XML_split;
+ pDirection = (nDirection & 1) ? "in" : "out";
+ pOrientation = (nDirection < 2) ? "horz" : "vert";
+ break;
+ case PPT_TRANSITION_TYPE_STRIPS:
+ nTransition = XML_strips;
+ pDirection = GetCornerDirection(nDirection);
+ break;
+ case PPT_TRANSITION_TYPE_WEDGE:
+ nTransition = XML_wedge;
+ break;
+ case PPT_TRANSITION_TYPE_WHEEL:
+ nTransition = XML_wheel;
+ if (nDirection != 4 && nDirection <= 9)
+ {
+ pSpokesTmp[0] = '0' + nDirection;
+ pSpokes = pSpokesTmp;
+ }
+ break;
+ case PPT_TRANSITION_TYPE_WIPE:
+ nTransition = XML_wipe;
+ pDirection = GetSideDirection(nDirection);
+ break;
+ case PPT_TRANSITION_TYPE_ZOOM:
+ nTransition = XML_zoom;
+ pDirection = (nDirection == 1) ? "in" : "out";
+ break;
+ case PPT_TRANSITION_TYPE_FLASH:
+ nTransition14 = XML_flash;
+ nTransition = XML_fade;
+ bOOXmlSpecificTransition = true;
+ break;
+ // coverity[dead_error_line] - following conditions exist to avoid compiler warning
+ case PPT_TRANSITION_TYPE_NONE:
+ default:
+ nTransition = 0;
+ break;
+ }
+ }
+
+ bool isAdvanceTimingSet = advanceTiming != -1;
+ if (nTransition14 || pPresetTransition || isTransitionDurationSet)
+ {
+ const char* pRequiresNS = (nTransition14 || isTransitionDurationSet) ? "p14" : "p15";
+
+ pFS->startElement(FSNS(XML_mc, XML_AlternateContent));
+ pFS->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, pRequiresNS);
+
+ if(isTransitionDurationSet && isAdvanceTimingSet)
+ {
+ pFS->startElementNS(XML_p, XML_transition,
+ XML_spd, speed,
+ XML_advTm, OString::number(advanceTiming * 1000),
+ FSNS(XML_p14, XML_dur), OString::number(nTransitionDuration));
+ }
+ else if(isTransitionDurationSet)
+ {
+ pFS->startElementNS(XML_p, XML_transition,
+ XML_spd, speed,
+ FSNS(XML_p14, XML_dur), OString::number(nTransitionDuration));
+ }
+ else if(isAdvanceTimingSet)
+ {
+ pFS->startElementNS(XML_p, XML_transition,
+ XML_spd, speed,
+ XML_advTm, OString::number(advanceTiming * 1000));
+ }
+ else
+ {
+ pFS->startElementNS(XML_p, XML_transition, XML_spd, speed);
+ }
+
+ if (nTransition14)
+ {
+ pFS->singleElementNS(XML_p14, nTransition14,
+ XML_isInverted, pInverted,
+ XML_dir, pDirection14,
+ XML_pattern, pPattern);
+ }
+ else if (pPresetTransition)
+ {
+ pFS->singleElementNS(XML_p15, XML_prstTrans,
+ XML_prst, pPresetTransition);
+ }
+ else if (isTransitionDurationSet && nTransition)
+ {
+ pFS->singleElementNS(XML_p, nTransition,
+ XML_dir, pDirection,
+ XML_orient, pOrientation,
+ XML_spokes, pSpokes,
+ XML_thruBlk, pThruBlk);
+ }
+
+ if (!sSoundRelId.isEmpty())
+ WriteSndAc(pFS, sSoundRelId, sSoundName);
+
+ pFS->endElement(FSNS(XML_p, XML_transition));
+
+ pFS->endElement(FSNS(XML_mc, XML_Choice));
+ pFS->startElement(FSNS(XML_mc, XML_Fallback));
+ }
+
+ pFS->startElementNS(XML_p, XML_transition,
+ XML_spd, speed,
+ XML_advTm, sax_fastparser::UseIf(OString::number(advanceTiming * 1000), isAdvanceTimingSet));
+
+ if (nTransition)
+ {
+ pFS->singleElementNS(XML_p, nTransition,
+ XML_dir, pDirection,
+ XML_orient, pOrientation,
+ XML_spokes, pSpokes,
+ XML_thruBlk, pThruBlk);
+ }
+
+ if (!sSoundRelId.isEmpty())
+ WriteSndAc(pFS, sSoundRelId, sSoundName);
+
+ pFS->endElementNS(XML_p, XML_transition);
+
+ if (nTransition14 || pPresetTransition || isTransitionDurationSet)
+ {
+ pFS->endElement(FSNS(XML_mc, XML_Fallback));
+ pFS->endElement(FSNS(XML_mc, XML_AlternateContent));
+ }
+}
+
+static OUString lcl_GetInitials(const OUString& sName)
+{
+ OUStringBuffer sRet;
+
+ if (!sName.isEmpty())
+ {
+ sRet.append(sName[0]);
+ sal_Int32 nStart = 0, nOffset;
+
+ while ((nOffset = sName.indexOf(' ', nStart)) != -1)
+ {
+ if (nOffset + 1 < sName.getLength())
+ sRet.append(sName[ nOffset + 1 ]);
+ nStart = nOffset + 1;
+ }
+ }
+
+ return sRet.makeStringAndClear();
+}
+
+void PowerPointExport::WriteAuthors()
+{
+ if (maAuthors.empty())
+ return;
+
+ FSHelperPtr pFS = openFragmentStreamWithSerializer("ppt/commentAuthors.xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.commentAuthors+xml");
+ addRelation(mPresentationFS->getOutputStream(),
+ oox::getRelationship(Relationship::COMMENTAUTHORS),
+ u"commentAuthors.xml");
+
+ pFS->startElementNS(XML_p, XML_cmAuthorLst,
+ FSNS(XML_xmlns, XML_p), getNamespaceURL(OOX_NS(ppt)));
+
+ for (const AuthorsMap::value_type& i : maAuthors)
+ {
+ pFS->singleElementNS(XML_p, XML_cmAuthor,
+ XML_id, OString::number(i.second.nId),
+ XML_name, i.first,
+ XML_initials, lcl_GetInitials(i.first),
+ XML_lastIdx, OString::number(i.second.nLastIndex),
+ XML_clrIdx, OString::number(i.second.nId));
+ }
+
+ pFS->endElementNS(XML_p, XML_cmAuthorLst);
+}
+
+sal_Int32 PowerPointExport::GetAuthorIdAndLastIndex(const OUString& sAuthor, sal_Int32& nLastIndex)
+{
+ if (maAuthors.count(sAuthor) <= 0)
+ {
+ struct AuthorComments aAuthorComments;
+
+ aAuthorComments.nId = maAuthors.size();
+ aAuthorComments.nLastIndex = 0;
+
+ maAuthors[ sAuthor ] = aAuthorComments;
+ }
+
+ nLastIndex = ++maAuthors[ sAuthor ].nLastIndex;
+
+ return maAuthors[ sAuthor ].nId;
+}
+
+void PowerPointExport::WritePresentationProps()
+{
+ Reference<XPresentationSupplier> xPresentationSupplier(mXModel, uno::UNO_QUERY);
+ if (!xPresentationSupplier.is())
+ return;
+
+ Reference<beans::XPropertySet> xPresentationProps(xPresentationSupplier->getPresentation(),
+ uno::UNO_QUERY);
+ bool bEndlessVal = xPresentationProps->getPropertyValue("IsEndless").get<bool>();
+ bool bChangeManually = xPresentationProps->getPropertyValue("IsAutomatic").get<bool>();
+ OUString sFirstPage = xPresentationProps->getPropertyValue("FirstPage").get<OUString>();
+ OUString sCustomShow = xPresentationProps->getPropertyValue("CustomShow").get<OUString>();
+
+ FSHelperPtr pFS = openFragmentStreamWithSerializer(
+ "ppt/presProps.xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.presProps+xml");
+
+ addRelation(mPresentationFS->getOutputStream(),
+ oox::getRelationship(Relationship::PRESPROPS), u"presProps.xml");
+
+ pFS->startElementNS(XML_p, XML_presentationPr, PPRNMSS);
+
+ pFS->startElementNS(XML_p, XML_showPr, XML_loop, sax_fastparser::UseIf("1", bEndlessVal),
+ XML_useTimings, sax_fastparser::UseIf("0", bChangeManually),
+ XML_showNarration, "1");
+
+ Reference<drawing::XDrawPagesSupplier> xDPS(mXModel, uno::UNO_QUERY_THROW);
+ Reference<drawing::XDrawPages> xDrawPages(xDPS->getDrawPages(), uno::UNO_SET_THROW);
+ if (!sFirstPage.isEmpty())
+ {
+ sal_Int32 nStartSlide = 1;
+ sal_Int32 nEndSlide = xDrawPages->getCount();
+ for (sal_Int32 i = 0; i < nEndSlide; i++)
+ {
+ Reference<drawing::XDrawPage> xDrawPage;
+ xDrawPages->getByIndex(i) >>= xDrawPage;
+ Reference<container::XNamed> xNamed(xDrawPage, uno::UNO_QUERY_THROW);
+ if (xNamed->getName() == sFirstPage)
+ {
+ nStartSlide = i + 1;
+ break;
+ }
+ }
+
+ pFS->singleElementNS(XML_p, XML_sldRg, XML_st, OUString::number(nStartSlide), XML_end,
+ OUString::number(nEndSlide));
+ }
+
+ if (!sCustomShow.isEmpty())
+ {
+ css::uno::Reference<css::presentation::XCustomPresentationSupplier>
+ XCustPresentationSupplier(mXModel, css::uno::UNO_QUERY_THROW);
+ css::uno::Reference<css::container::XNameContainer> mxCustShows;
+ mxCustShows = XCustPresentationSupplier->getCustomPresentations();
+ const css::uno::Sequence<OUString> aNameSeq(mxCustShows->getElementNames());
+
+ sal_Int32 nCustShowIndex = 0;
+ for (sal_Int32 i = 0; i < aNameSeq.getLength(); i++)
+ {
+ if (aNameSeq[i] == sCustomShow)
+ {
+ nCustShowIndex = i;
+ break;
+ }
+ }
+
+ pFS->singleElementNS(XML_p, XML_custShow, XML_id, OUString::number(nCustShowIndex));
+ }
+
+ pFS->endElementNS(XML_p, XML_showPr);
+
+ pFS->endElementNS(XML_p, XML_presentationPr);
+}
+
+bool PowerPointExport::WriteComments(sal_uInt32 nPageNum)
+{
+ Reference< XAnnotationAccess > xAnnotationAccess(mXDrawPage, uno::UNO_QUERY);
+ if (xAnnotationAccess.is())
+ {
+ Reference< XAnnotationEnumeration > xAnnotationEnumeration(xAnnotationAccess->createAnnotationEnumeration());
+
+ if (xAnnotationEnumeration->hasMoreElements())
+ {
+ FSHelperPtr pFS = openFragmentStreamWithSerializer(
+ "ppt/comments/comment" + OUString::number(nPageNum + 1) + ".xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.comments+xml");
+
+ pFS->startElementNS(XML_p, XML_cmLst,
+ FSNS(XML_xmlns, XML_p), this->getNamespaceURL(OOX_NS(ppt)));
+
+ do
+ {
+ Reference< XAnnotation > xAnnotation(xAnnotationEnumeration->nextElement());
+ util::DateTime aDateTime(xAnnotation->getDateTime());
+ RealPoint2D aRealPoint2D(xAnnotation->getPosition());
+ Reference< XText > xText(xAnnotation->getTextRange());
+ sal_Int32 nLastIndex;
+ sal_Int32 nId = GetAuthorIdAndLastIndex(xAnnotation->getAuthor(), nLastIndex);
+ char cDateTime[sizeof("-32768-65535-65535T65535:65535:65535.4294967295")];
+ // reserve enough space for hypothetical max length
+
+ snprintf(cDateTime, sizeof cDateTime, "%02" SAL_PRIdINT32 "-%02" SAL_PRIuUINT32 "-%02" SAL_PRIuUINT32 "T%02" SAL_PRIuUINT32 ":%02" SAL_PRIuUINT32 ":%02" SAL_PRIuUINT32 ".%09" SAL_PRIuUINT32, sal_Int32(aDateTime.Year), sal_uInt32(aDateTime.Month), sal_uInt32(aDateTime.Day), sal_uInt32(aDateTime.Hours), sal_uInt32(aDateTime.Minutes), sal_uInt32(aDateTime.Seconds), aDateTime.NanoSeconds);
+
+ pFS->startElementNS(XML_p, XML_cm,
+ XML_authorId, OString::number(nId),
+ XML_dt, cDateTime,
+ XML_idx, OString::number(nLastIndex));
+
+ pFS->singleElementNS(XML_p, XML_pos,
+ XML_x, OString::number(std::round(convertMm100ToMasterUnit(aRealPoint2D.X * 100))),
+ XML_y, OString::number(std::round(convertMm100ToMasterUnit(aRealPoint2D.Y * 100))));
+
+ pFS->startElementNS(XML_p, XML_text);
+ pFS->write(xText->getString());
+ pFS->endElementNS(XML_p, XML_text);
+
+ pFS->endElementNS(XML_p, XML_cm);
+
+ }
+ while (xAnnotationEnumeration->hasMoreElements());
+
+ pFS->endElementNS(XML_p, XML_cmLst);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void PowerPointExport::WriteVBA()
+{
+ if (!mbPptm)
+ return;
+
+ uno::Reference<document::XStorageBasedDocument> xStorageBasedDocument(getModel(), uno::UNO_QUERY);
+ if (!xStorageBasedDocument.is())
+ return;
+
+ uno::Reference<embed::XStorage> xDocumentStorage = xStorageBasedDocument->getDocumentStorage();
+ OUString aMacrosName("_MS_VBA_Macros");
+ if (!xDocumentStorage.is() || !xDocumentStorage->hasByName(aMacrosName))
+ return;
+
+ const sal_Int32 nOpenMode = embed::ElementModes::READ;
+ uno::Reference<io::XInputStream> xMacrosStream(xDocumentStorage->openStreamElement(aMacrosName, nOpenMode), uno::UNO_QUERY);
+ if (!xMacrosStream.is())
+ return;
+
+ uno::Reference<io::XOutputStream> xOutputStream = openFragmentStream("ppt/vbaProject.bin", "application/vnd.ms-office.vbaProject");
+ comphelper::OStorageHelper::CopyInputToOutput(xMacrosStream, xOutputStream);
+
+ // Write the relationship.
+ addRelation(mPresentationFS->getOutputStream(), oox::getRelationship(Relationship::VBAPROJECT), u"vbaProject.bin");
+}
+
+void PowerPointExport::WriteModifyVerifier()
+{
+ Sequence<PropertyValue> aInfo;
+
+ try
+ {
+ Reference<lang::XMultiServiceFactory> xFactory(mXModel, UNO_QUERY);
+ Reference<XPropertySet> xDocSettings(
+ xFactory->createInstance("com.sun.star.document.Settings"), UNO_QUERY);
+ xDocSettings->getPropertyValue("ModifyPasswordInfo") >>= aInfo;
+ }
+ catch (const Exception&)
+ {
+ }
+
+ if (aInfo.hasElements())
+ {
+ OUString sAlgorithm, sSalt, sHash;
+ sal_Int32 nCount = 0;
+ for (auto& prop : aInfo)
+ {
+ if (prop.Name == "algorithm-name")
+ prop.Value >>= sAlgorithm;
+ else if (prop.Name == "salt")
+ prop.Value >>= sSalt;
+ else if (prop.Name == "iteration-count")
+ prop.Value >>= nCount;
+ else if (prop.Name == "hash")
+ prop.Value >>= sHash;
+ }
+ if (!sAlgorithm.isEmpty() && !sSalt.isEmpty() && !sHash.isEmpty())
+ {
+ sal_Int32 nAlgorithmSid = 0;
+ if (sAlgorithm == "MD2")
+ nAlgorithmSid = 1;
+ else if (sAlgorithm == "MD4")
+ nAlgorithmSid = 2;
+ else if (sAlgorithm == "MD5")
+ nAlgorithmSid = 3;
+ else if (sAlgorithm == "SHA-1")
+ nAlgorithmSid = 4;
+ else if (sAlgorithm == "MAC")
+ nAlgorithmSid = 5;
+ else if (sAlgorithm == "RIPEMD")
+ nAlgorithmSid = 6;
+ else if (sAlgorithm == "RIPEMD-160")
+ nAlgorithmSid = 7;
+ else if (sAlgorithm == "HMAC")
+ nAlgorithmSid = 9;
+ else if (sAlgorithm == "SHA-256")
+ nAlgorithmSid = 12;
+ else if (sAlgorithm == "SHA-384")
+ nAlgorithmSid = 13;
+ else if (sAlgorithm == "SHA-512")
+ nAlgorithmSid = 14;
+
+ if (nAlgorithmSid != 0)
+ mPresentationFS->singleElementNS(XML_p, XML_modifyVerifier,
+ XML_cryptProviderType, "rsaAES",
+ XML_cryptAlgorithmClass, "hash",
+ XML_cryptAlgorithmType, "typeAny",
+ XML_cryptAlgorithmSid, OString::number(nAlgorithmSid).getStr(),
+ XML_spinCount, OString::number(nCount).getStr(),
+ XML_saltData, sSalt.toUtf8().getStr(),
+ XML_hashData, sHash.toUtf8().getStr());
+ }
+ }
+}
+
+void PowerPointExport::ImplWriteSlide(sal_uInt32 nPageNum, sal_uInt32 nMasterNum, sal_uInt16 /* nMode */,
+ bool bHasBackground, Reference< XPropertySet > const& aXBackgroundPropSet)
+{
+ SAL_INFO("sd.eppt", "write slide: " << nPageNum << "\n----------------");
+
+ // slides list
+ if (nPageNum == 0)
+ mPresentationFS->startElementNS(XML_p, XML_sldIdLst);
+
+ // add explicit relation of presentation to this slide
+ OUString sRelId = addRelation(mPresentationFS->getOutputStream(),
+ oox::getRelationship(Relationship::SLIDE),
+ OUStringConcatenation("slides/slide" + OUString::number(nPageNum + 1) +".xml"));
+
+ mPresentationFS->singleElementNS(XML_p, XML_sldId,
+ XML_id, OString::number(GetNewSlideId()),
+ FSNS(XML_r, XML_id), sRelId);
+
+ maRelId.push_back(sRelId);
+
+ if (nPageNum == mnPages - 1)
+ mPresentationFS->endElementNS(XML_p, XML_sldIdLst);
+
+ FSHelperPtr pFS = openFragmentStreamWithSerializer(
+ "ppt/slides/slide" + OUString::number(nPageNum + 1) + ".xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.slide+xml");
+
+ if (mpSlidesFSArray.size() < mnPages)
+ mpSlidesFSArray.resize(mnPages);
+ mpSlidesFSArray[ nPageNum ] = pFS;
+
+ const char* pShow = nullptr;
+ const char* pShowMasterShape = nullptr;
+
+ if (ImplGetPropertyValue(mXPagePropSet, "Visible"))
+ {
+ bool bShow(false);
+ if ((mAny >>= bShow) && !bShow)
+ pShow = "0";
+ }
+
+ if (ImplGetPropertyValue(mXPagePropSet, "IsBackgroundObjectsVisible"))
+ {
+ bool bShowMasterShape(false);
+ if ((mAny >>= bShowMasterShape) && !bShowMasterShape)
+ pShowMasterShape = "0";
+ }
+
+ pFS->startElementNS(XML_p, XML_sld, PNMSS, XML_show, pShow, XML_showMasterSp, pShowMasterShape);
+
+ pFS->startElementNS(XML_p, XML_cSld);
+
+ // background
+ if (bHasBackground)
+ {
+ ImplWriteBackground(pFS, aXBackgroundPropSet);
+ }
+
+ WriteShapeTree(pFS, NORMAL, false);
+
+ pFS->endElementNS(XML_p, XML_cSld);
+
+ WriteTransition(pFS);
+ WriteAnimations(pFS, mXDrawPage, *this);
+
+ pFS->endElementNS(XML_p, XML_sld);
+
+ // add implicit relation to slide layout
+ addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::SLIDELAYOUT),
+ OUStringConcatenation("../slideLayouts/slideLayout" +
+ OUString::number(GetLayoutFileId(GetPPTXLayoutId(GetLayoutOffset(mXPagePropSet)), nMasterNum)) +
+ ".xml"));
+
+ if (WriteComments(nPageNum))
+ // add implicit relation to slide comments
+ addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::COMMENTS),
+ OUStringConcatenation("../comments/comment" + OUString::number(nPageNum + 1) + ".xml"));
+
+ SAL_INFO("sd.eppt", "----------------");
+}
+
+void PowerPointExport::ImplWriteNotes(sal_uInt32 nPageNum)
+{
+ if (!mbCreateNotes || !ContainsOtherShapeThanPlaceholders())
+ return;
+
+ SAL_INFO("sd.eppt", "write Notes " << nPageNum << "\n----------------");
+
+ FSHelperPtr pFS = openFragmentStreamWithSerializer(
+ "ppt/notesSlides/notesSlide" +
+ OUString::number(nPageNum + 1) +
+ ".xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml");
+
+ pFS->startElementNS(XML_p, XML_notes, PNMSS);
+
+ pFS->startElementNS(XML_p, XML_cSld);
+
+ WriteShapeTree(pFS, NOTICE, false);
+
+ pFS->endElementNS(XML_p, XML_cSld);
+
+ pFS->endElementNS(XML_p, XML_notes);
+
+ // add implicit relation to slide
+ addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::SLIDE),
+ OUStringConcatenation("../slides/slide" + OUString::number(nPageNum + 1) + ".xml"));
+
+ // add slide implicit relation to notes
+ if (nPageNum < mpSlidesFSArray.size())
+ addRelation(mpSlidesFSArray[ nPageNum ]->getOutputStream(),
+ oox::getRelationship(Relationship::NOTESSLIDE),
+ OUStringConcatenation("../notesSlides/notesSlide" + OUString::number(nPageNum + 1) + ".xml"));
+
+ // add implicit relation to notes master
+ addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::NOTESMASTER),
+ u"../notesMasters/notesMaster1.xml");
+
+ SAL_INFO("sd.eppt", "-----------------");
+}
+
+void PowerPointExport::AddLayoutIdAndRelation(const FSHelperPtr& pFS, sal_Int32 nLayoutFileId)
+{
+ // add implicit relation of slide master to slide layout
+ OUString sRelId = addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::SLIDELAYOUT),
+ OUStringConcatenation("../slideLayouts/slideLayout" + OUString::number(nLayoutFileId) + ".xml"));
+
+ pFS->singleElementNS(XML_p, XML_sldLayoutId,
+ XML_id, OString::number(GetNewSlideMasterId()),
+ FSNS(XML_r, XML_id), sRelId);
+}
+
+void PowerPointExport::ImplWriteSlideMaster(sal_uInt32 nPageNum, Reference< XPropertySet > const& aXBackgroundPropSet)
+{
+ SAL_INFO("sd.eppt", "write master slide: " << nPageNum << "\n--------------");
+
+ // slides list
+ if (nPageNum == 0)
+ mPresentationFS->startElementNS(XML_p, XML_sldMasterIdLst);
+
+ OUString sRelId = addRelation(mPresentationFS->getOutputStream(),
+ oox::getRelationship(Relationship::SLIDEMASTER),
+ OUStringConcatenation("slideMasters/slideMaster" + OUString::number(nPageNum + 1) + ".xml"));
+
+ mPresentationFS->singleElementNS(XML_p, XML_sldMasterId,
+ XML_id, OString::number(GetNewSlideMasterId()),
+ FSNS(XML_r, XML_id), sRelId);
+
+ if (nPageNum == mnMasterPages - 1)
+ mPresentationFS->endElementNS(XML_p, XML_sldMasterIdLst);
+
+ FSHelperPtr pFS =
+ openFragmentStreamWithSerializer("ppt/slideMasters/slideMaster" +
+ OUString::number(nPageNum + 1) + ".xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml");
+
+ SdrPage* pMasterPage = SdPage::getImplementation(mXDrawPage);
+ svx::Theme* pTheme = nullptr;
+ if (pMasterPage)
+ {
+ pTheme = pMasterPage->getSdrPageProperties().GetTheme();
+ }
+
+ // write theme per master
+ WriteTheme(nPageNum, pTheme);
+
+ // add implicit relation to the presentation theme
+ addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::THEME),
+ OUStringConcatenation("../theme/theme" + OUString::number(nPageNum + 1) + ".xml"));
+
+ pFS->startElementNS(XML_p, XML_sldMaster, PNMSS);
+
+ pFS->startElementNS(XML_p, XML_cSld);
+
+ if (aXBackgroundPropSet)
+ ImplWriteBackground(pFS, aXBackgroundPropSet);
+ WriteShapeTree(pFS, MASTER, true);
+
+ pFS->endElementNS(XML_p, XML_cSld);
+
+ // color map - now it uses colors from hardcoded theme, once we eventually generate theme, this might need update
+ pFS->singleElementNS(XML_p, XML_clrMap,
+ XML_bg1, "lt1",
+ XML_bg2, "lt2",
+ XML_tx1, "dk1",
+ XML_tx2, "dk2",
+ XML_accent1, "accent1",
+ XML_accent2, "accent2",
+ XML_accent3, "accent3",
+ XML_accent4, "accent4",
+ XML_accent5, "accent5",
+ XML_accent6, "accent6",
+ XML_hlink, "hlink",
+ XML_folHlink, "folHlink");
+
+ // use master's id type as they have same range, mso does that as well
+ pFS->startElementNS(XML_p, XML_sldLayoutIdLst);
+
+ for (int i = 0; i < LAYOUT_SIZE; i++)
+ {
+ sal_Int32 nLayoutFileId = GetLayoutFileId(i, nPageNum);
+ if (nLayoutFileId > 0)
+ {
+ AddLayoutIdAndRelation(pFS, nLayoutFileId);
+ }
+ else
+ {
+ ImplWritePPTXLayout(i, nPageNum);
+ AddLayoutIdAndRelation(pFS, GetLayoutFileId(i, nPageNum));
+ }
+ }
+
+ pFS->endElementNS(XML_p, XML_sldLayoutIdLst);
+
+ pFS->endElementNS(XML_p, XML_sldMaster);
+
+ SAL_INFO("sd.eppt", "----------------");
+}
+
+sal_Int32 PowerPointExport::GetLayoutFileId(sal_Int32 nOffset, sal_uInt32 nMasterNum)
+{
+ SAL_INFO("sd.eppt", "GetLayoutFileId offset: " << nOffset << " master: " << nMasterNum);
+ if (mLayoutInfo[ nOffset ].mnFileIdArray.size() <= nMasterNum)
+ return 0;
+
+ return mLayoutInfo[ nOffset ].mnFileIdArray[ nMasterNum ];
+}
+
+void PowerPointExport::ImplWritePPTXLayout(sal_Int32 nOffset, sal_uInt32 nMasterNum)
+{
+ SAL_INFO("sd.eppt", "write layout: " << nOffset);
+
+ Reference< drawing::XDrawPagesSupplier > xDPS(getModel(), uno::UNO_QUERY);
+ Reference< drawing::XDrawPages > xDrawPages = xDPS->getDrawPages();
+ Reference< drawing::XDrawPage > xSlide = xDrawPages->insertNewByIndex(xDrawPages->getCount());
+
+#ifdef DEBUG
+ if (xSlide.is())
+ printf("new page created\n");
+#endif
+
+ Reference< beans::XPropertySet > xPropSet(xSlide, uno::UNO_QUERY);
+ xPropSet->setPropertyValue("Layout", Any(short(aLayoutInfo[ nOffset ].nType)));
+#if OSL_DEBUG_LEVEL > 1
+ dump_pset(xPropSet);
+#endif
+ mXPagePropSet.set(xSlide, UNO_QUERY);
+ mXShapes = xSlide;
+
+ if (mLayoutInfo[ nOffset ].mnFileIdArray.size() < mnMasterPages)
+ {
+ mLayoutInfo[ nOffset ].mnFileIdArray.resize(mnMasterPages);
+ }
+
+ if (mLayoutInfo[ nOffset ].mnFileIdArray[ nMasterNum ] != 0)
+ return;
+
+ FSHelperPtr pFS
+ = openFragmentStreamWithSerializer("ppt/slideLayouts/slideLayout" +
+ OUString::number(mnLayoutFileIdMax) + ".xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml");
+
+ // add implicit relation of slide layout to slide master
+ addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::SLIDEMASTER),
+ OUStringConcatenation("../slideMasters/slideMaster" + OUString::number(nMasterNum + 1) + ".xml"));
+
+ pFS->startElementNS(XML_p, XML_sldLayout,
+ PNMSS,
+ XML_type, aLayoutInfo[ nOffset ].sType,
+ XML_preserve, "1");
+
+ pFS->startElementNS(XML_p, XML_cSld,
+ XML_name, aLayoutInfo[ nOffset ].sName);
+ //pFS->write( MINIMAL_SPTREE ); // TODO: write actual shape tree
+ WriteShapeTree(pFS, LAYOUT, true);
+
+ pFS->endElementNS(XML_p, XML_cSld);
+
+ pFS->endElementNS(XML_p, XML_sldLayout);
+
+ mLayoutInfo[ nOffset ].mnFileIdArray[ nMasterNum ] = mnLayoutFileIdMax;
+
+ mnLayoutFileIdMax ++;
+
+ xDrawPages->remove(xSlide);
+}
+
+void PowerPointExport::WriteShapeTree(const FSHelperPtr& pFS, PageType ePageType, bool bMaster)
+{
+ PowerPointShapeExport aDML(pFS, &maShapeMap, this);
+ aDML.SetMaster(bMaster);
+ aDML.SetPageType(ePageType);
+ aDML.SetBackgroundDark(mbIsBackgroundDark);
+
+ pFS->startElementNS(XML_p, XML_spTree);
+ pFS->write(MAIN_GROUP);
+
+ ResetGroupTable(mXShapes->getCount());
+
+ while (GetNextGroupEntry())
+ {
+
+ sal_uInt32 nGroups = GetGroupsClosed();
+ for (sal_uInt32 i = 0; i < nGroups; i++)
+ {
+ SAL_INFO("sd.eppt", "leave group");
+ }
+
+ if (GetShapeByIndex(GetCurrentGroupIndex(), true))
+ {
+ SAL_INFO("sd.eppt", "mType: " << mType);
+ const SdrObjGroup* pDiagramCandidate(dynamic_cast<const SdrObjGroup*>(SdrObject::getSdrObjectFromXShape(mXShape)));
+ const bool bIsDiagram(nullptr != pDiagramCandidate && pDiagramCandidate->isDiagram());
+
+ if (bIsDiagram)
+ WriteDiagram(pFS, aDML, mXShape, mnDiagramId++);
+ else
+ aDML.WriteShape(mXShape);
+ }
+ }
+
+ if ( ePageType == NORMAL || ePageType == LAYOUT )
+ WritePlaceholderReferenceShapes(aDML, ePageType);
+ pFS->endElementNS(XML_p, XML_spTree);
+}
+
+ShapeExport& PowerPointShapeExport::WritePageShape(const Reference< XShape >& xShape, PageType ePageType, bool bPresObj)
+{
+ if ((ePageType == NOTICE && bPresObj) || ePageType == LAYOUT || ePageType == MASTER)
+ return WritePlaceholderShape(xShape, SlideImage);
+
+ return WriteTextShape(xShape);
+}
+
+bool PowerPointShapeExport::WritePlaceholder(const Reference< XShape >& xShape, PlaceholderType ePlaceholder, bool bMaster)
+{
+ SAL_INFO("sd.eppt", "WritePlaceholder " << bMaster << " " << ShapeExport::NonEmptyText(xShape));
+ if (!xShape)
+ return false;
+ try
+ {
+ Reference<XPropertySet> xShapeProps(xShape, UNO_QUERY);
+ if (xShapeProps->getPropertyValue("IsPresentationObject").get<bool>())
+ {
+ WritePlaceholderShape(xShape, ePlaceholder);
+
+ return true;
+ }
+ }
+ catch (Exception&)
+ {
+ return false;
+ }
+ return false;
+}
+
+ShapeExport& PowerPointShapeExport::WritePlaceholderShape(const Reference< XShape >& xShape, PlaceholderType ePlaceholder)
+{
+ Reference<XPropertySet> xProps(xShape, UNO_QUERY);
+ bool bUseBackground(false);
+ if (xProps.is() && xProps->getPropertySetInfo()->hasPropertyByName("FillUseSlideBackground"))
+ xProps->getPropertyValue("FillUseSlideBackground") >>= bUseBackground;
+
+ if (bUseBackground)
+ mpFS->startElementNS(XML_p, XML_sp, XML_useBgFill, "1");
+ else
+ mpFS->startElementNS(XML_p, XML_sp);
+
+ // non visual shape properties
+ mpFS->startElementNS(XML_p, XML_nvSpPr);
+ const OString aPlaceholderID("PlaceHolder " + OString::number(mnShapeIdMax++));
+ WriteNonVisualDrawingProperties(xShape, aPlaceholderID.getStr());
+ mpFS->startElementNS(XML_p, XML_cNvSpPr);
+ mpFS->singleElementNS(XML_a, XML_spLocks, XML_noGrp, "1");
+ mpFS->endElementNS(XML_p, XML_cNvSpPr);
+ mpFS->startElementNS(XML_p, XML_nvPr);
+
+ bool bUsePlaceholderIndex
+ = ePlaceholder == Footer || ePlaceholder == DateAndTime || ePlaceholder == SlideNumber;
+ const char* pType = getPlaceholderTypeName(ePlaceholder);
+
+ SAL_INFO("sd.eppt", "write placeholder " << pType);
+ if (bUsePlaceholderIndex)
+ {
+ mpFS->singleElementNS(
+ XML_p, XML_ph, XML_type, pType, XML_idx,
+ OString::number(
+ static_cast<PowerPointExport*>(GetFB())->CreateNewPlaceholderIndex(xShape)));
+ }
+ else
+ {
+ if ((mePageType == PageType::LAYOUT || mePageType == PageType::NORMAL)
+ && ePlaceholder == Outliner)
+ mpFS->singleElementNS(XML_p, XML_ph);
+ else
+ mpFS->singleElementNS(XML_p, XML_ph, XML_type, pType);
+ }
+ mpFS->endElementNS(XML_p, XML_nvPr);
+ mpFS->endElementNS(XML_p, XML_nvSpPr);
+
+ // visual shape properties
+ mpFS->startElementNS(XML_p, XML_spPr);
+ WriteShapeTransformation(xShape, XML_a);
+ WritePresetShape("rect");
+ if (xProps.is())
+ {
+ WriteBlipFill(xProps, "Graphic");
+ // Do not forget to export the visible properties.
+ WriteFill( xProps );
+ WriteOutline( xProps );
+ WriteShapeEffects( xProps );
+
+ bool bHas3DEffectinShape = false;
+ uno::Sequence<beans::PropertyValue> grabBag;
+ if (xProps->getPropertySetInfo()->hasPropertyByName("InteropGrabBag"))
+ xProps->getPropertyValue("InteropGrabBag") >>= grabBag;
+
+ for (auto const& it : std::as_const(grabBag))
+ if (it.Name == "3DEffectProperties")
+ bHas3DEffectinShape = true;
+
+ if( bHas3DEffectinShape)
+ Write3DEffects( xProps, /*bIsText=*/false );
+ }
+ mpFS->endElementNS(XML_p, XML_spPr);
+
+ WriteTextBox(xShape, XML_p, /*bWritePropertiesAsLstStyles=*/bUsePlaceholderIndex);
+
+ mpFS->endElementNS(XML_p, XML_sp);
+
+ return *this;
+}
+
+ShapeExport& PowerPointShapeExport::WritePlaceholderReferenceShape(
+ PlaceholderType ePlaceholder, sal_Int32 nReferencedPlaceholderIdx, PageType ePageType,
+ const Reference<XPropertySet>& rXPagePropSet)
+{
+ mpFS->startElementNS(XML_p, XML_sp);
+
+ // non visual shape properties
+ mpFS->startElementNS(XML_p, XML_nvSpPr);
+ const OString aPlaceholderID("PlaceHolder " + OString::number(mnShapeIdMax++));
+ GetFS()->singleElementNS(XML_p, XML_cNvPr, XML_id, OString::number(mnShapeIdMax), XML_name,
+ aPlaceholderID.getStr());
+
+ mpFS->startElementNS(XML_p, XML_cNvSpPr);
+ mpFS->singleElementNS(XML_a, XML_spLocks, XML_noGrp, "1");
+ mpFS->endElementNS(XML_p, XML_cNvSpPr);
+ mpFS->startElementNS(XML_p, XML_nvPr);
+
+ const char* pType = getPlaceholderTypeName(ePlaceholder);
+ mpFS->singleElementNS(XML_p, XML_ph, XML_type, pType, XML_idx,
+ OString::number(nReferencedPlaceholderIdx));
+ mpFS->endElementNS(XML_p, XML_nvPr);
+ mpFS->endElementNS(XML_p, XML_nvSpPr);
+
+ // visual shape properties
+ mpFS->startElementNS(XML_p, XML_spPr);
+ mpFS->endElementNS(XML_p, XML_spPr);
+
+ WritePlaceholderReferenceTextBody(ePlaceholder, ePageType, rXPagePropSet);
+
+ mpFS->endElementNS(XML_p, XML_sp);
+
+ return *this;
+}
+
+ShapeExport& PowerPointShapeExport::WritePlaceholderReferenceTextBody(
+ PlaceholderType ePlaceholder, PageType ePageType, const Reference<XPropertySet> xPagePropSet)
+{
+ mpFS->startElementNS(XML_p, XML_txBody);
+ mpFS->singleElementNS(XML_a, XML_bodyPr);
+ mpFS->startElementNS(XML_a, XML_p);
+
+ switch (ePlaceholder)
+ {
+ case Header:
+ break;
+ case Footer:
+ {
+ OUString aFooterText;
+ if (ePageType == LAYOUT)
+ {
+ aFooterText = "Footer";
+ }
+ else
+ {
+ xPagePropSet->getPropertyValue("FooterText") >>= aFooterText;
+ }
+ mpFS->startElementNS(XML_a, XML_r);
+ mpFS->startElementNS(XML_a, XML_t);
+ mpFS->writeEscaped(aFooterText);
+ mpFS->endElementNS(XML_a, XML_t);
+ mpFS->endElementNS(XML_a, XML_r);
+ break;
+ }
+ case SlideNumber:
+ {
+ OUString aSlideNum;
+ sal_Int32 nSlideNum = 0;
+ if (ePageType == LAYOUT)
+ {
+ aSlideNum = "<#>";
+ }
+ else
+ {
+ xPagePropSet->getPropertyValue("Number") >>= nSlideNum;
+ aSlideNum = OUString::number(nSlideNum);
+ }
+ OString aUUID(comphelper::xml::generateGUIDString());
+ mpFS->startElementNS(XML_a, XML_fld, XML_id, aUUID.getStr(), XML_type, "slidenum");
+ mpFS->startElementNS(XML_a, XML_t);
+ mpFS->writeEscaped(aSlideNum);
+ mpFS->endElementNS(XML_a, XML_t);
+ mpFS->endElementNS(XML_a, XML_fld);
+ break;
+ }
+ case DateAndTime:
+ {
+ OUString aDateTimeType = "datetime1";
+ bool bIsDateTimeFixed = false;
+ xPagePropSet->getPropertyValue("IsDateTimeFixed") >>= bIsDateTimeFixed;
+
+ OUString aDateTimeText = "Date";
+ const LanguageTag& rLanguageTag = Application::GetSettings().GetLanguageTag();
+
+ if(ePageType != LAYOUT && !bIsDateTimeFixed)
+ {
+ sal_Int32 nDateTimeFormat = 0;
+ xPagePropSet->getPropertyValue("DateTimeFormat") >>= nDateTimeFormat;
+
+ // 4 LSBs represent the date
+ SvxDateFormat eDate = static_cast<SvxDateFormat>(nDateTimeFormat & 0x0f);
+ // the 4 bits after the date bits represent the time
+ SvxTimeFormat eTime = static_cast<SvxTimeFormat>(nDateTimeFormat >> 4);
+ aDateTimeType = GetDatetimeTypeFromDateTime(eDate, eTime);
+
+ if (aDateTimeType == "datetime")
+ aDateTimeType = "datetime1";
+
+ ::DateTime aDateTime( ::DateTime::SYSTEM );
+
+ aDateTimeText = SvxDateTimeField::GetFormatted(
+ aDateTime, aDateTime, eDate,
+ eTime, *(SD_MOD()->GetNumberFormatter()),
+ rLanguageTag.getLanguageType());
+ }
+
+ if(!bIsDateTimeFixed)
+ {
+ OString aUUID(comphelper::xml::generateGUIDString());
+ mpFS->startElementNS(XML_a, XML_fld, XML_id, aUUID.getStr(), XML_type, aDateTimeType);
+ }
+ else
+ {
+ xPagePropSet->getPropertyValue("DateTimeText") >>= aDateTimeText;
+ mpFS->startElementNS(XML_a, XML_r);
+ }
+
+ mpFS->startElementNS(XML_a, XML_rPr, XML_lang, rLanguageTag.getBcp47MS());
+ mpFS->endElementNS(XML_a, XML_rPr);
+
+ mpFS->startElementNS(XML_a, XML_t);
+ mpFS->writeEscaped(aDateTimeText);
+ mpFS->endElementNS(XML_a, XML_t);
+
+ mpFS->endElementNS(XML_a, bIsDateTimeFixed ? XML_r : XML_fld);
+ break;
+ }
+ default:
+ SAL_INFO("sd.eppt", "warning: no defined textbody for referenced placeholder type: "
+ << ePlaceholder);
+ }
+ mpFS->endElementNS(XML_a, XML_p);
+ mpFS->endElementNS(XML_p, XML_txBody);
+
+ return *this;
+}
+
+#define SYS_COLOR_SCHEMES " <a:dk1>\
+ <a:sysClr val=\"windowText\" lastClr=\"000000\"/>\
+ </a:dk1>\
+ <a:lt1>\
+ <a:sysClr val=\"window\" lastClr=\"FFFFFF\"/>\
+ </a:lt1>"
+
+#define MINIMAL_THEME " <a:fontScheme name=\"Office\">\
+ <a:majorFont>\
+ <a:latin typeface=\"Arial\"/>\
+ <a:ea typeface=\"DejaVu Sans\"/>\
+ <a:cs typeface=\"DejaVu Sans\"/>\
+ </a:majorFont>\
+ <a:minorFont>\
+ <a:latin typeface=\"Arial\"/>\
+ <a:ea typeface=\"DejaVu Sans\"/>\
+ <a:cs typeface=\"DejaVu Sans\"/>\
+ </a:minorFont>\
+ </a:fontScheme>\
+ <a:fmtScheme name=\"Office\">\
+ <a:fillStyleLst>\
+ <a:solidFill>\
+ <a:schemeClr val=\"phClr\"/>\
+ </a:solidFill>\
+ <a:gradFill rotWithShape=\"1\">\
+ <a:gsLst>\
+ <a:gs pos=\"0\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:tint val=\"50000\"/>\
+ <a:satMod val=\"300000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ <a:gs pos=\"35000\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:tint val=\"37000\"/>\
+ <a:satMod val=\"300000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ <a:gs pos=\"100000\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:tint val=\"15000\"/>\
+ <a:satMod val=\"350000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ </a:gsLst>\
+ <a:lin ang=\"16200000\" scaled=\"1\"/>\
+ </a:gradFill>\
+ <a:gradFill rotWithShape=\"1\">\
+ <a:gsLst>\
+ <a:gs pos=\"0\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:shade val=\"51000\"/>\
+ <a:satMod val=\"130000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ <a:gs pos=\"80000\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:shade val=\"93000\"/>\
+ <a:satMod val=\"130000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ <a:gs pos=\"100000\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:shade val=\"94000\"/>\
+ <a:satMod val=\"135000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ </a:gsLst>\
+ <a:lin ang=\"16200000\" scaled=\"0\"/>\
+ </a:gradFill>\
+ </a:fillStyleLst>\
+ <a:lnStyleLst>\
+ <a:ln w=\"6350\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\
+ <a:solidFill>\
+ <a:schemeClr val=\"phClr\">\
+ <a:shade val=\"95000\"/>\
+ <a:satMod val=\"105000\"/>\
+ </a:schemeClr>\
+ </a:solidFill>\
+ <a:prstDash val=\"solid\"/>\
+ <a:miter/>\
+ </a:ln>\
+ <a:ln w=\"12700\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\
+ <a:solidFill>\
+ <a:schemeClr val=\"phClr\"/>\
+ </a:solidFill>\
+ <a:prstDash val=\"solid\"/>\
+ <a:miter/>\
+ </a:ln>\
+ <a:ln w=\"19050\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">\
+ <a:solidFill>\
+ <a:schemeClr val=\"phClr\"/>\
+ </a:solidFill>\
+ <a:prstDash val=\"solid\"/>\
+ <a:miter/>\
+ </a:ln>\
+ </a:lnStyleLst>\
+ <a:effectStyleLst>\
+ <a:effectStyle>\
+ <a:effectLst/>\
+ </a:effectStyle>\
+ <a:effectStyle>\
+ <a:effectLst/>\
+ </a:effectStyle>\
+ <a:effectStyle>\
+ <a:effectLst>\
+ <a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\">\
+ <a:srgbClr val=\"000000\">\
+ <a:alpha val=\"35000\"/>\
+ </a:srgbClr>\
+ </a:outerShdw>\
+ </a:effectLst>\
+ <a:scene3d>\
+ <a:camera prst=\"orthographicFront\">\
+ <a:rot lat=\"0\" lon=\"0\" rev=\"0\"/>\
+ </a:camera>\
+ <a:lightRig rig=\"threePt\" dir=\"t\">\
+ <a:rot lat=\"0\" lon=\"0\" rev=\"1200000\"/>\
+ </a:lightRig>\
+ </a:scene3d>\
+ <a:sp3d>\
+ <a:bevelT w=\"63500\" h=\"25400\"/>\
+ </a:sp3d>\
+ </a:effectStyle>\
+ </a:effectStyleLst>\
+ <a:bgFillStyleLst>\
+ <a:solidFill>\
+ <a:schemeClr val=\"phClr\"/>\
+ </a:solidFill>\
+ <a:gradFill rotWithShape=\"1\">\
+ <a:gsLst>\
+ <a:gs pos=\"0\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:tint val=\"40000\"/>\
+ <a:satMod val=\"350000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ <a:gs pos=\"40000\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:tint val=\"45000\"/>\
+ <a:shade val=\"99000\"/>\
+ <a:satMod val=\"350000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ <a:gs pos=\"100000\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:shade val=\"20000\"/>\
+ <a:satMod val=\"255000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ </a:gsLst>\
+ <a:path path=\"circle\">\
+ <a:fillToRect l=\"50000\" t=\"-80000\" r=\"50000\" b=\"180000\"/>\
+ </a:path>\
+ </a:gradFill>\
+ <a:gradFill rotWithShape=\"1\">\
+ <a:gsLst>\
+ <a:gs pos=\"0\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:tint val=\"80000\"/>\
+ <a:satMod val=\"300000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ <a:gs pos=\"100000\">\
+ <a:schemeClr val=\"phClr\">\
+ <a:shade val=\"30000\"/>\
+ <a:satMod val=\"200000\"/>\
+ </a:schemeClr>\
+ </a:gs>\
+ </a:gsLst>\
+ <a:path path=\"circle\">\
+ <a:fillToRect l=\"50000\" t=\"50000\" r=\"50000\" b=\"50000\"/>\
+ </a:path>\
+ </a:gradFill>\
+ </a:bgFillStyleLst>\
+ </a:fmtScheme>"
+
+void PowerPointExport::WriteDefaultColorSchemes(const FSHelperPtr& pFS)
+{
+ for (int nId = PredefinedClrSchemeId::dk2; nId != PredefinedClrSchemeId::Count; nId++)
+ {
+ OUString sName = PredefinedClrNames[static_cast<PredefinedClrSchemeId>(nId)];
+ sal_Int32 nColor = 0;
+
+ switch (nId)
+ {
+ case PredefinedClrSchemeId::dk2:
+ nColor = 0x1F497D;
+ break;
+ case PredefinedClrSchemeId::lt2:
+ nColor = 0xEEECE1;
+ break;
+ case PredefinedClrSchemeId::accent1:
+ nColor = 0x4F81BD;
+ break;
+ case PredefinedClrSchemeId::accent2:
+ nColor = 0xC0504D;
+ break;
+ case PredefinedClrSchemeId::accent3:
+ nColor = 0x9BBB59;
+ break;
+ case PredefinedClrSchemeId::accent4:
+ nColor = 0x8064A2;
+ break;
+ case PredefinedClrSchemeId::accent5:
+ nColor = 0x4BACC6;
+ break;
+ case PredefinedClrSchemeId::accent6:
+ nColor = 0xF79646;
+ break;
+ case PredefinedClrSchemeId::hlink:
+ nColor = 0x0000FF;
+ break;
+ case PredefinedClrSchemeId::folHlink:
+ nColor = 0x800080;
+ break;
+ }
+
+ OUString sOpenColorScheme = "<a:" + sName + ">";
+ pFS->write(sOpenColorScheme);
+
+ pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(nColor));
+
+ OUString sCloseColorScheme = "</a:" + sName + ">";
+ pFS->write(sCloseColorScheme);
+ }
+}
+
+bool PowerPointExport::WriteColorSets(const FSHelperPtr& pFS, svx::Theme* pTheme)
+{
+ static std::map<PredefinedClrSchemeId, sal_Int32> aPredefinedClrTokens =
+ {
+ { dk1, XML_dk1 },
+ { lt1, XML_lt1 },
+ { dk2, XML_dk2 },
+ { lt2, XML_lt2 },
+ { accent1, XML_accent1 },
+ { accent2, XML_accent2 },
+ { accent3, XML_accent3 },
+ { accent4, XML_accent4 },
+ { accent5, XML_accent5 },
+ { accent6, XML_accent6 },
+ { hlink, XML_hlink },
+ { folHlink, XML_folHlink }
+ };
+
+ if (!pTheme)
+ {
+ return false;
+ }
+
+ svx::ColorSet* pColorSet = pTheme->GetColorSet();
+ if (!pColorSet)
+ {
+ return false;
+ }
+
+ for (int nId = PredefinedClrSchemeId::dk1; nId < PredefinedClrSchemeId::Count; nId++)
+ {
+ sal_Int32 nToken = aPredefinedClrTokens[static_cast<PredefinedClrSchemeId>(nId)];
+ pFS->startElementNS(XML_a, nToken);
+ pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(static_cast<sal_Int32>(pColorSet->getColor(nId))));
+ pFS->endElementNS(XML_a, nToken);
+ }
+
+ return true;
+}
+
+bool PowerPointExport::WriteColorSchemes(const FSHelperPtr& pFS, const OUString& rThemePath)
+{
+ try
+ {
+ uno::Reference<beans::XPropertySet> xDocProps(getModel(), uno::UNO_QUERY);
+ if (xDocProps.is())
+ {
+ uno::Reference<beans::XPropertySetInfo> xPropsInfo = xDocProps->getPropertySetInfo();
+
+ static const OUStringLiteral aGrabBagPropName = u"InteropGrabBag";
+ if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(aGrabBagPropName))
+ {
+ comphelper::SequenceAsHashMap aGrabBag(xDocProps->getPropertyValue(aGrabBagPropName));
+ uno::Sequence<beans::PropertyValue> aCurrentTheme;
+
+ aGrabBag.getValue(rThemePath) >>= aCurrentTheme;
+
+ if (!aCurrentTheme.hasElements())
+ return false;
+
+ // Order is important
+ for (int nId = PredefinedClrSchemeId::dk2; nId != PredefinedClrSchemeId::Count; nId++)
+ {
+ OUString sName = PredefinedClrNames[static_cast<PredefinedClrSchemeId>(nId)];
+ sal_Int32 nColor = 0;
+
+ for (auto aIt = std::cbegin(aCurrentTheme); aIt != std::cend(aCurrentTheme); aIt++)
+ {
+ if (aIt->Name == sName)
+ {
+ aIt->Value >>= nColor;
+ break;
+ }
+ }
+
+ OUString sOpenColorScheme ="<a:" + sName + ">";
+ pFS->write(sOpenColorScheme);
+
+ pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(nColor));
+
+ OUString sCloseColorScheme = "</a:" + sName + ">";
+ pFS->write(sCloseColorScheme);
+ }
+
+ // TODO: write complete color schemes & only if successful, protection against partial export
+ return true;
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ SAL_WARN("writerfilter", "Failed to save documents grab bag");
+ }
+
+ return false;
+}
+
+void PowerPointExport::WriteTheme(sal_Int32 nThemeNum, svx::Theme* pTheme)
+{
+ OUString sThemePath = "ppt/theme/theme" + OUString::number(nThemeNum + 1) + ".xml";
+
+ FSHelperPtr pFS = openFragmentStreamWithSerializer(sThemePath,
+ "application/vnd.openxmlformats-officedocument.theme+xml");
+
+ OUString aThemeName("Office Theme");
+ if (pTheme)
+ {
+ aThemeName = pTheme->GetName();
+ }
+ pFS->startElementNS(XML_a, XML_theme,
+ FSNS(XML_xmlns, XML_a), this->getNamespaceURL(OOX_NS(dml)),
+ XML_name, aThemeName);
+
+ pFS->startElementNS(XML_a, XML_themeElements);
+ OUString aColorSchemeName("Office");
+ if (pTheme)
+ {
+ svx::ColorSet* pColorSet = pTheme->GetColorSet();
+ if (pColorSet)
+ {
+ aColorSchemeName = pColorSet->getName();
+ }
+ }
+ pFS->startElementNS(XML_a, XML_clrScheme, XML_name, aColorSchemeName);
+
+ if (!WriteColorSets(pFS, pTheme))
+ {
+ pFS->write(SYS_COLOR_SCHEMES);
+ if (!WriteColorSchemes(pFS, sThemePath))
+ {
+ // if style is not defined, try to use first one
+ if (!WriteColorSchemes(pFS, "ppt/theme/theme1.xml"))
+ {
+ // color schemes are required - use default values
+ WriteDefaultColorSchemes(pFS);
+ }
+ }
+ }
+
+ pFS->endElementNS(XML_a, XML_clrScheme);
+
+ // export remaining part
+ pFS->write(MINIMAL_THEME);
+
+ pFS->endElementNS(XML_a, XML_themeElements);
+ pFS->endElementNS(XML_a, XML_theme);
+}
+
+bool PowerPointExport::ImplCreateDocument()
+{
+ mbCreateNotes = false;
+
+ for (sal_uInt32 i = 0; i < mnPages; i++)
+ {
+ if (!GetPageByIndex(i, NOTICE))
+ return false;
+
+ if (ContainsOtherShapeThanPlaceholders())
+ {
+ mbCreateNotes = true;
+ break;
+ }
+ }
+
+ return true;
+}
+
+void PowerPointExport::WriteNotesMaster()
+{
+ SAL_INFO("sd.eppt", "write Notes master\n---------------");
+
+ mPresentationFS->startElementNS(XML_p, XML_notesMasterIdLst);
+
+ OUString sRelId = addRelation(mPresentationFS->getOutputStream(),
+ oox::getRelationship(Relationship::NOTESMASTER),
+ u"notesMasters/notesMaster1.xml");
+
+ mPresentationFS->singleElementNS(XML_p, XML_notesMasterId,
+ FSNS(XML_r, XML_id), sRelId);
+
+ mPresentationFS->endElementNS(XML_p, XML_notesMasterIdLst);
+
+ FSHelperPtr pFS =
+ openFragmentStreamWithSerializer("ppt/notesMasters/notesMaster1.xml",
+ "application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml");
+ // write theme per master
+ WriteTheme(mnMasterPages, nullptr);
+
+ // add implicit relation to the presentation theme
+ addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::THEME),
+ OUStringConcatenation("../theme/theme" + OUString::number(mnMasterPages + 1) + ".xml"));
+
+ pFS->startElementNS(XML_p, XML_notesMaster, PNMSS);
+
+ pFS->startElementNS(XML_p, XML_cSld);
+
+ Reference< XPropertySet > aXBackgroundPropSet;
+ if (ImplGetPropertyValue(mXPagePropSet, "Background") &&
+ (mAny >>= aXBackgroundPropSet))
+ ImplWriteBackground(pFS, aXBackgroundPropSet);
+
+ WriteShapeTree(pFS, NOTICE, true);
+
+ pFS->endElementNS(XML_p, XML_cSld);
+
+ // color map - now it uses colors from hardcoded theme, once we eventually generate theme, this might need update
+ pFS->singleElementNS(XML_p, XML_clrMap,
+ XML_bg1, "lt1",
+ XML_bg2, "lt2",
+ XML_tx1, "dk1",
+ XML_tx2, "dk2",
+ XML_accent1, "accent1",
+ XML_accent2, "accent2",
+ XML_accent3, "accent3",
+ XML_accent4, "accent4",
+ XML_accent5, "accent5",
+ XML_accent6, "accent6",
+ XML_hlink, "hlink",
+ XML_folHlink, "folHlink");
+
+ pFS->endElementNS(XML_p, XML_notesMaster);
+
+ SAL_INFO("sd.eppt", "----------------");
+}
+
+void PowerPointExport::embedEffectAudio(const FSHelperPtr& pFS, const OUString& sUrl, OUString& sRelId, OUString& sName)
+{
+ comphelper::LifecycleProxy aProxy;
+
+ if (!sUrl.endsWithIgnoreAsciiCase(".wav"))
+ return;
+
+ uno::Reference<io::XInputStream> xAudioStream;
+ try
+ {
+ if (sUrl.startsWith("vnd.sun.star.Package:"))
+ {
+ uno::Reference<document::XStorageBasedDocument> xStorageBasedDocument(getModel(), uno::UNO_QUERY);
+ if (!xStorageBasedDocument.is())
+ return;
+
+ uno::Reference<embed::XStorage> xDocumentStorage = xStorageBasedDocument->getDocumentStorage();
+ if (!xDocumentStorage.is())
+ return;
+
+ uno::Reference<io::XStream> xStream = comphelper::OStorageHelper::GetStreamAtPackageURL(xDocumentStorage, sUrl,
+ css::embed::ElementModes::READ, aProxy);
+
+ if (xStream.is())
+ xAudioStream = xStream->getInputStream();
+ }
+ else
+ xAudioStream = comphelper::OStorageHelper::GetInputStreamFromURL(sUrl, getComponentContext());
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("sd", "PowerPointExport::embedEffectAudio");
+ }
+
+ if (!xAudioStream.is())
+ return;
+
+ int nLastSlash = sUrl.lastIndexOf('/');
+ sName = sUrl.copy(nLastSlash >= 0 ? nLastSlash + 1 : 0);
+
+ OUString sPath = "../media/" + sName;
+ sRelId = addRelation(pFS->getOutputStream(),
+ oox::getRelationship(Relationship::AUDIO), sPath);
+
+ uno::Reference<io::XOutputStream> xOutputStream = openFragmentStream(sPath.replaceAt(0, 2, u"/ppt"),
+ "audio/x-wav");
+
+ comphelper::OStorageHelper::CopyInputToOutput(xAudioStream, xOutputStream);
+}
+
+sal_Int32 PowerPointExport::GetShapeID(const Reference<XShape>& rXShape)
+{
+ return ShapeExport::GetShapeID(rXShape, &maShapeMap);
+}
+
+sal_Int32 PowerPointExport::GetNextAnimationNodeID()
+{
+ return mnAnimationNodeIdMax++;
+}
+
+bool PowerPointExport::ImplCreateMainNotes()
+{
+ if (mbCreateNotes)
+ WriteNotesMaster();
+
+ return true;
+}
+
+OUString PowerPointExport::getImplementationName()
+{
+ return "com.sun.star.comp.Impress.oox.PowerPointExport";
+}
+
+void PowerPointExport::WriteDiagram(const FSHelperPtr& pFS, PowerPointShapeExport& rDML, const css::uno::Reference<css::drawing::XShape>& rXShape, int nDiagramId)
+{
+ SAL_INFO("sd.eppt", "writing Diagram " + OUString::number(nDiagramId));
+ pFS->startElementNS(XML_p, XML_graphicFrame);
+ rDML.WriteDiagram(rXShape, nDiagramId);
+ pFS->endElementNS(XML_p, XML_graphicFrame);
+}
+
+void PowerPointExport::WritePlaceholderReferenceShapes(PowerPointShapeExport& rDML, PageType ePageType)
+{
+ bool bCheckProps = ePageType == NORMAL;
+ Reference<XShape> xShape;
+ Any aAny;
+ OUString aText;
+ if (ePageType == LAYOUT
+ || (bCheckProps && PropValue::GetPropertyValue(aAny, mXPagePropSet, "IsFooterVisible", true)
+ && aAny == true && GetPropertyValue(aAny, mXPagePropSet, "FooterText", true)
+ && (aAny >>= aText) && !aText.isEmpty()))
+ {
+ if ((xShape = GetReferencedPlaceholderXShape(Footer, ePageType)))
+ rDML.WritePlaceholderReferenceShape(Footer,
+ maPlaceholderShapeToIndexMap.find(xShape)->second,
+ ePageType, mXPagePropSet);
+ }
+
+ if (ePageType == LAYOUT
+ || (bCheckProps
+ && PropValue::GetPropertyValue(aAny, mXPagePropSet, "IsPageNumberVisible", true)
+ && aAny == true))
+ {
+ if ((xShape = GetReferencedPlaceholderXShape(SlideNumber, ePageType)))
+ rDML.WritePlaceholderReferenceShape(SlideNumber,
+ maPlaceholderShapeToIndexMap.find(xShape)->second,
+ ePageType, mXPagePropSet);
+ }
+
+ if (ePageType == LAYOUT
+ || (bCheckProps
+ && PropValue::GetPropertyValue(aAny, mXPagePropSet, "IsDateTimeVisible", true)
+ && aAny == true
+ && ((GetPropertyValue(aAny, mXPagePropSet, "DateTimeText", true) && (aAny >>= aText)
+ && !aText.isEmpty())
+ || mXPagePropSet->getPropertyValue("IsDateTimeFixed") == false)))
+ {
+ if ((xShape = GetReferencedPlaceholderXShape(DateAndTime, ePageType)))
+ rDML.WritePlaceholderReferenceShape(DateAndTime,
+ maPlaceholderShapeToIndexMap.find(xShape)->second,
+ ePageType, mXPagePropSet);
+ }
+}
+
+sal_Int32 PowerPointExport::CreateNewPlaceholderIndex(const css::uno::Reference<XShape> &rXShape)
+{
+ maPlaceholderShapeToIndexMap.insert({rXShape, mnPlaceholderIndexMax});
+ return mnPlaceholderIndexMax++;
+}
+
+Reference<XShape> PowerPointExport::GetReferencedPlaceholderXShape(const PlaceholderType eType,
+ PageType ePageType) const
+{
+ PresObjKind ePresObjKind = PresObjKind::NONE;
+ switch (eType)
+ {
+ case oox::core::None:
+ break;
+ case oox::core::SlideImage:
+ break;
+ case oox::core::Notes:
+ break;
+ case oox::core::Header:
+ ePresObjKind = PresObjKind::Header;
+ break;
+ case oox::core::Footer:
+ ePresObjKind = PresObjKind::Footer;
+ break;
+ case oox::core::SlideNumber:
+ ePresObjKind = PresObjKind::SlideNumber;
+ break;
+ case oox::core::DateAndTime:
+ ePresObjKind = PresObjKind::DateTime;
+ break;
+ case oox::core::Outliner:
+ break;
+ case oox::core::Title:
+ ePresObjKind = PresObjKind::Title;
+ break;
+ case oox::core::Subtitle:
+ break;
+ }
+ if (ePresObjKind != PresObjKind::NONE)
+ {
+ SdPage* pMasterPage;
+ if (ePageType == LAYOUT)
+ {
+ // since Layout pages do not have drawpages themselves - mXDrawPage is still the master they reference to..
+ pMasterPage = SdPage::getImplementation(mXDrawPage);
+ }
+ else
+ {
+ pMasterPage
+ = &static_cast<SdPage&>(SdPage::getImplementation(mXDrawPage)->TRG_GetMasterPage());
+ }
+ if (SdrObject* pMasterFooter = pMasterPage->GetPresObj(ePresObjKind))
+ return GetXShapeForSdrObject(pMasterFooter);
+ }
+ return nullptr;
+}
+
+// UNO component
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+css_comp_Impress_oox_PowerPointExport(uno::XComponentContext* rxCtxt,
+ uno::Sequence<css::uno::Any> const& rArguments)
+{
+ return cppu::acquire(new PowerPointExport(rxCtxt, rArguments));
+}
+
+#if OSL_DEBUG_LEVEL > 1
+void dump_pset(Reference< XPropertySet > const& rXPropSet)
+{
+ Reference< XPropertySetInfo > info = rXPropSet->getPropertySetInfo();
+ Sequence< beans::Property > props = info->getProperties();
+
+ for (int i=0; i < props.getLength(); i++)
+ {
+ OString name = OUStringToOString(props [i].Name, RTL_TEXTENCODING_UTF8);
+
+ Any value = rXPropSet->getPropertyValue(props [i].Name);
+
+ OUString strValue;
+ sal_Int32 intValue;
+ bool boolValue;
+ RectanglePoint pointValue;
+
+ if (value >>= strValue)
+ SAL_INFO("sd.eppt", name << " = \"" << strValue << "\"");
+ else if (value >>= intValue)
+ SAL_INFO("sd.eppt", name << " = " << intValue << "(hex : " << std::hex << intValue << ")");
+ else if (value >>= boolValue)
+ SAL_INFO("sd.eppt", name << " = " << boolValue << " (bool)");
+ else if (value >>= pointValue)
+ SAL_INFO("sd.eppt", name << " = " << static_cast<int>(pointValue) << " (RectanglePoint)");
+ else
+ SAL_INFO("sd.eppt", "??? <unhandled type>");
+ }
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptx-grouptable.cxx b/sd/source/filter/eppt/pptx-grouptable.cxx
new file mode 100644
index 000000000..bf91f2fb6
--- /dev/null
+++ b/sd/source/filter/eppt/pptx-grouptable.cxx
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "grouptable.hxx"
+
+using ::com::sun::star::container::XIndexAccess;
+
+GroupTable::GroupTable()
+ : mnIndex(0)
+ , mnGroupsClosed(0)
+{
+ mvGroupEntry.reserve(32);
+}
+
+GroupTable::~GroupTable()
+{
+}
+
+bool GroupTable::EnterGroup( css::uno::Reference< css::container::XIndexAccess > const & rXIndexAccessRef )
+{
+ bool bRet = false;
+ if ( rXIndexAccessRef.is() )
+ {
+ GroupEntry aNewGroup( rXIndexAccessRef );
+ if ( aNewGroup.mnCount )
+ {
+ mvGroupEntry.push_back( std::move(aNewGroup) );
+ bRet = true;
+ }
+ }
+ return bRet;
+}
+
+sal_uInt32 GroupTable::GetGroupsClosed()
+{
+ sal_uInt32 nRet = mnGroupsClosed;
+ mnGroupsClosed = 0;
+ return nRet;
+}
+
+void GroupTable::ClearGroupTable()
+{
+ mvGroupEntry.clear();
+}
+
+void GroupTable::ResetGroupTable( sal_uInt32 nCount )
+{
+ ClearGroupTable();
+ mvGroupEntry.push_back( GroupEntry( nCount ) );
+}
+
+bool GroupTable::GetNextGroupEntry()
+{
+ while ( !mvGroupEntry.empty() )
+ {
+ mnIndex = mvGroupEntry.back().mnCurrentPos++;
+
+ if ( mvGroupEntry.back().mnCount > mnIndex )
+ return true;
+
+ mvGroupEntry.pop_back();
+
+ if ( !mvGroupEntry.empty() )
+ mnGroupsClosed++;
+ }
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptx-stylesheet.cxx b/sd/source/filter/eppt/pptx-stylesheet.cxx
new file mode 100644
index 000000000..459020278
--- /dev/null
+++ b/sd/source/filter/eppt/pptx-stylesheet.cxx
@@ -0,0 +1,489 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "epptbase.hxx"
+#include "epptdef.hxx"
+#include "text.hxx"
+#include <tools/color.hxx>
+#include <tools/UnitConversion.hxx>
+#include <editeng/svxenum.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+using namespace ::com::sun::star;
+
+PPTExCharSheet::PPTExCharSheet( int nInstance )
+{
+ sal_uInt16 nFontHeight = 24;
+
+ for ( int nDepth = 0; nDepth < 5; nDepth++ )
+ {
+ PPTExCharLevel& rLev = maCharLevel[ nDepth ];
+ switch ( nInstance )
+ {
+ case EPP_TEXTTYPE_Title :
+ case EPP_TEXTTYPE_CenterTitle :
+ nFontHeight = 44;
+ break;
+ case EPP_TEXTTYPE_Body :
+ case EPP_TEXTTYPE_CenterBody :
+ case EPP_TEXTTYPE_HalfBody :
+ case EPP_TEXTTYPE_QuarterBody :
+ {
+ switch ( nDepth )
+ {
+ case 0 : nFontHeight = 32; break;
+ case 1 : nFontHeight = 28; break;
+ case 2 : nFontHeight = 24; break;
+ default :nFontHeight = 20; break;
+ }
+ }
+ break;
+ case EPP_TEXTTYPE_Notes :
+ nFontHeight = 12;
+ break;
+ case EPP_TEXTTYPE_notUsed :
+ case EPP_TEXTTYPE_Other :
+ nFontHeight = 24;
+ break;
+ }
+ rLev.mnFlags = 0;
+ rLev.mnFont = 0;
+ rLev.mnAsianOrComplexFont = 0xffff;
+ rLev.mnFontHeight = nFontHeight;
+ rLev.mnFontColor = 0;
+ rLev.mnEscapement = 0;
+ }
+}
+
+void PPTExCharSheet::SetStyleSheet( const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
+ FontCollection& rFontCollection, int nLevel )
+{
+ PortionObj aPortionObj( rXPropSet, rFontCollection );
+
+ PPTExCharLevel& rLev = maCharLevel[ nLevel ];
+
+ if ( aPortionObj.meCharColor == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnFontColor = Color(ColorTransparency, aPortionObj.mnCharColor);
+ if ( aPortionObj.meCharEscapement == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnEscapement = aPortionObj.mnCharEscapement;
+ if ( aPortionObj.meCharHeight == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnFontHeight = aPortionObj.mnCharHeight;
+ if ( aPortionObj.meFontName == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnFont = aPortionObj.mnFont;
+ if ( aPortionObj.meAsianOrComplexFont == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnAsianOrComplexFont = aPortionObj.mnAsianOrComplexFont;
+ rLev.mnFlags = aPortionObj.mnCharAttr;
+}
+
+void PPTExCharSheet::Write( SvStream& rSt, sal_uInt16 nLev, bool bSimpleText,
+ const css::uno::Reference< css::beans::XPropertySet > & rPagePropSet )
+{
+ const PPTExCharLevel& rLev = maCharLevel[ nLev ];
+
+ sal_uInt32 nCharFlags = 0xefffff;
+ if ( bSimpleText )
+ nCharFlags = 0x7ffff;
+
+ rSt.WriteUInt32( nCharFlags )
+ .WriteUInt16( rLev.mnFlags )
+ .WriteUInt16( rLev.mnFont );
+
+ Color nFontColor = rLev.mnFontColor;
+ if ( nFontColor == COL_AUTO )
+ {
+ bool bIsDark = false;
+ css::uno::Any aAny;
+ if ( PropValue::GetPropertyValue( aAny, rPagePropSet, "IsBackgroundDark", true ) )
+ aAny >>= bIsDark;
+ nFontColor = Color(ColorTransparency, bIsDark ? 0xffffff : 0x000000);
+ }
+ nFontColor.SetAlpha(1);
+ if ( bSimpleText )
+ {
+ rSt.WriteUInt16( rLev.mnFontHeight )
+ .WriteUInt32( sal_uInt32(nFontColor) );
+ }
+ else
+ {
+ rSt.WriteUInt16( rLev.mnAsianOrComplexFont )
+ .WriteUInt16( 0xffff ) // unknown
+ .WriteUInt16( 0xffff ) // unknown
+ .WriteUInt16( rLev.mnFontHeight )
+ .WriteUInt32( sal_uInt32(nFontColor) )
+ .WriteUInt16( rLev.mnEscapement );
+ }
+}
+
+PPTExParaSheet::PPTExParaSheet( int nInstance, sal_uInt16 nDefaultTab, PPTExBulletProvider* pProv ) :
+ pBuProv ( pProv ),
+ mnInstance ( nInstance )
+{
+ bool bHasBullet = false;
+
+ sal_uInt16 nUpperDist = 0;
+ sal_uInt16 nBulletChar = 0x2022;
+ sal_uInt16 nBulletOfs = 0;
+ sal_uInt16 nTextOfs = 0;
+
+ for ( int nDepth = 0; nDepth < 5; nDepth++ )
+ {
+ PPTExParaLevel& rLev = maParaLevel[ nDepth ];
+ switch ( nInstance )
+ {
+ case EPP_TEXTTYPE_Title :
+ case EPP_TEXTTYPE_CenterTitle :
+ break;
+ case EPP_TEXTTYPE_Body :
+ case EPP_TEXTTYPE_CenterBody :
+ case EPP_TEXTTYPE_HalfBody :
+ case EPP_TEXTTYPE_QuarterBody :
+ {
+ bHasBullet = true;
+ nUpperDist = 0x14;
+ }
+ break;
+ case EPP_TEXTTYPE_Notes :
+ nUpperDist = 0x1e;
+ break;
+
+ }
+ switch ( nDepth )
+ {
+ case 0 :
+ {
+ nBulletChar = 0x2022;
+ nBulletOfs = 0;
+ nTextOfs = bHasBullet ? 0xd8 : 0;
+ }
+ break;
+ case 1 :
+ {
+ nBulletChar = 0x2013;
+ nBulletOfs = 0x120;
+ nTextOfs = 0x1d4;
+ }
+ break;
+ case 2 :
+ {
+ nBulletChar = 0x2022;
+ nBulletOfs = 0x240;
+ nTextOfs = 0x2d0;
+ }
+ break;
+ case 3 :
+ {
+ nBulletChar = 0x2013;
+ nBulletOfs = 0x360;
+ nTextOfs = 0x3f0;
+ }
+ break;
+ case 4 :
+ {
+ nBulletChar = 0xbb;
+ nBulletOfs = 0x480;
+ nTextOfs = 0x510;
+ }
+ break;
+ }
+ rLev.mbIsBullet = bHasBullet;
+ rLev.mnBulletChar = nBulletChar;
+ rLev.mnBulletFont = 0;
+ rLev.mnBulletHeight = 100;
+ rLev.mnBulletColor = 0;
+ rLev.mnAdjust = 0;
+ rLev.mnLineFeed = 100;
+ rLev.mnLowerDist = 0;
+ rLev.mnUpperDist = nUpperDist;
+ rLev.mnTextOfs = nTextOfs;
+ rLev.mnBulletOfs = nBulletOfs;
+ rLev.mnDefaultTab = nDefaultTab;
+ rLev.mnAsianSettings = 2;
+ rLev.mnBiDi = 0;
+
+ rLev.mbExtendedBulletsUsed = false;
+ rLev.mnBulletId = 0xffff;
+ rLev.mnBulletStart = 0;
+ rLev.mnMappedNumType = 0;
+ rLev.mnNumberingType = 0;
+ }
+}
+
+void PPTExParaSheet::SetStyleSheet( const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
+ FontCollection& rFontCollection, int nLevel, const PPTExCharLevel& rCharLevel )
+{
+ ParagraphObj aParagraphObj( rXPropSet, pBuProv );
+ aParagraphObj.CalculateGraphicBulletSize( rCharLevel.mnFontHeight );
+ PPTExParaLevel& rLev = maParaLevel[ nLevel ];
+
+ if ( aParagraphObj.meTextAdjust == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnAdjust = aParagraphObj.mnTextAdjust;
+ if ( aParagraphObj.meLineSpacing == css::beans::PropertyState_DIRECT_VALUE )
+ {
+ sal_Int16 nLineSpacing = aParagraphObj.mnLineSpacing;
+ if ( nLineSpacing > 0 ) // if nLinespacing is < 0 the linespacing is an absolute spacing
+ {
+ bool bFixedLineSpacing = false;
+ uno::Any aAny = rXPropSet->getPropertyValue("FontIndependentLineSpacing");
+ if( !(aAny >>= bFixedLineSpacing) || !bFixedLineSpacing )
+ {
+ const FontCollectionEntry* pDesc = rFontCollection.GetById( rCharLevel.mnFont );
+ if ( pDesc )
+ nLineSpacing = static_cast<sal_Int16>( static_cast<double>(nLineSpacing) * pDesc->Scaling + 0.5 );
+ }
+ }
+ else
+ {
+ if ( rCharLevel.mnFontHeight > static_cast<sal_uInt16>( static_cast<double>(-nLineSpacing) * 0.001 * 72.0 / 2.54 ) ) // 1/100mm to point
+ {
+ const FontCollectionEntry* pDesc = rFontCollection.GetById( rCharLevel.mnFont );
+ if ( pDesc )
+ nLineSpacing = static_cast<sal_Int16>( 100.0 * pDesc->Scaling + 0.5 );
+ else
+ nLineSpacing = 100;
+ }
+ else
+ nLineSpacing = static_cast<sal_Int16>(convertMm100ToMasterUnit(nLineSpacing));
+ }
+ rLev.mnLineFeed = nLineSpacing;
+ }
+ if ( aParagraphObj.meLineSpacingBottom == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnLowerDist = aParagraphObj.mnLineSpacingBottom;
+ if ( aParagraphObj.meLineSpacingTop == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnUpperDist = aParagraphObj.mnLineSpacingTop;
+ if ( aParagraphObj.meForbiddenRules == css::beans::PropertyState_DIRECT_VALUE )
+ {
+ rLev.mnAsianSettings &=~1;
+ if ( aParagraphObj.mbForbiddenRules )
+ rLev.mnAsianSettings |= 1;
+ }
+ if ( aParagraphObj.meParagraphPunctation == css::beans::PropertyState_DIRECT_VALUE )
+ {
+ rLev.mnAsianSettings &=~4;
+ if ( aParagraphObj.mbParagraphPunctation )
+ rLev.mnAsianSettings |= 4;
+ }
+
+ if ( aParagraphObj.meBiDi == css::beans::PropertyState_DIRECT_VALUE )
+ rLev.mnBiDi = aParagraphObj.mnBiDi;
+
+ rLev.mbIsBullet = aParagraphObj.mbIsBullet; //( ( aParagraphObj.nBulletFlags & 1 ) != 0 );
+
+ if ( nLevel )
+ return;
+
+ if (!(aParagraphObj.bExtendedParameters &&
+ aParagraphObj.meBullet == css::beans::PropertyState_DIRECT_VALUE))
+ return;
+
+ for ( sal_Int16 i = 0; i < 5; i++ )
+ {
+ PPTExParaLevel& rLevel = maParaLevel[ i ];
+ if ( i )
+ aParagraphObj.ImplGetNumberingLevel( pBuProv, i, false, false );
+ rLevel.mnTextOfs = aParagraphObj.nTextOfs;
+ rLevel.mnBulletOfs = static_cast<sal_uInt16>(aParagraphObj.nBulletOfs);
+ rLevel.mnBulletChar = aParagraphObj.cBulletId;
+ FontCollectionEntry aFontDescEntry( aParagraphObj.aFontDesc.Name, aParagraphObj.aFontDesc.Family,
+ aParagraphObj.aFontDesc.Pitch, aParagraphObj.aFontDesc.CharSet );
+ rLevel.mnBulletFont = static_cast<sal_uInt16>(rFontCollection.GetId( aFontDescEntry ));
+ rLevel.mnBulletHeight = aParagraphObj.nBulletRealSize;
+ rLevel.mnBulletColor = aParagraphObj.nBulletColor;
+
+ rLevel.mbExtendedBulletsUsed = aParagraphObj.bExtendedBulletsUsed;
+ rLevel.mnBulletId = aParagraphObj.nBulletId;
+ rLevel.mnNumberingType = aParagraphObj.nNumberingType;
+ rLevel.mnBulletStart = aParagraphObj.nStartWith;
+ rLevel.mnMappedNumType = aParagraphObj.nMappedNumType;
+ }
+}
+
+void PPTExParaSheet::Write( SvStream& rSt, sal_uInt16 nLev, bool bSimpleText,
+ const css::uno::Reference< css::beans::XPropertySet > & rPagePropSet )
+{
+ const PPTExParaLevel& rLev = maParaLevel[ nLev ];
+
+ if ( maParaLevel[ 0 ].mbExtendedBulletsUsed || maParaLevel[ 1 ].mbExtendedBulletsUsed ||
+ maParaLevel[ 2 ].mbExtendedBulletsUsed || maParaLevel[ 3 ].mbExtendedBulletsUsed ||
+ maParaLevel[ 4 ].mbExtendedBulletsUsed )
+ {
+ SvStream& rOut = pBuProv->aBuExMasterStream;
+ if ( !nLev )
+ {
+ rOut.WriteUInt32( ( EPP_PST_ExtendedParagraphMasterAtom << 16 ) | ( mnInstance << 4 ) )
+ .WriteUInt32( 5 * 16 + 2 )
+ .WriteUInt16( 5 ); // depth
+ }
+ sal_uInt16 nBulletId = rLev.mnBulletId;
+ if ( rLev.mnNumberingType != SVX_NUM_BITMAP )
+ nBulletId = 0xffff;
+ rOut.WriteUInt32( 0x03800000 )
+ .WriteUInt16( nBulletId )
+ .WriteUInt32( rLev.mnMappedNumType )
+ .WriteUInt16( rLev.mnBulletStart )
+ .WriteUInt32( 0 );
+ }
+
+ sal_uInt32 nParaFlags = 0x3ffdff;
+ sal_uInt16 nBulletFlags = ( rLev.mbIsBullet ) ? 0xf : 0xe;
+
+ if ( nLev )
+ nParaFlags &= 0x207fff;
+ if ( bSimpleText )
+ nParaFlags &= 0x7fff;
+ sal_uInt32 nBulletColor = rLev.mnBulletColor;
+ if ( nBulletColor == sal_uInt32(COL_AUTO) )
+ {
+ bool bIsDark = false;
+ css::uno::Any aAny;
+ if ( PropValue::GetPropertyValue( aAny, rPagePropSet, "IsBackgroundDark", true ) )
+ aAny >>= bIsDark;
+ nBulletColor = bIsDark ? 0xffffff : 0x000000;
+ }
+ nBulletColor &= 0xffffff;
+ nBulletColor |= 0xfe000000;
+ rSt.WriteUInt32( nParaFlags )
+ .WriteUInt16( nBulletFlags )
+ .WriteUInt16( rLev.mnBulletChar )
+ .WriteUInt16( rLev.mnBulletFont )
+ .WriteUInt16( rLev.mnBulletHeight )
+ .WriteUInt32( nBulletColor )
+ .WriteUInt16( rLev.mnAdjust )
+ .WriteUInt16( rLev.mnLineFeed )
+ .WriteUInt16( rLev.mnUpperDist )
+ .WriteUInt16( rLev.mnLowerDist )
+ .WriteUInt16( rLev.mnTextOfs )
+ .WriteUInt16( rLev.mnBulletOfs );
+
+ if ( bSimpleText || nLev )
+ {
+ if ( nParaFlags & 0x200000 )
+ rSt.WriteUInt16( rLev.mnBiDi );
+ }
+ else
+ {
+ rSt.WriteUInt16( rLev.mnDefaultTab )
+ .WriteUInt16( 0 )
+ .WriteUInt16( 0 )
+ .WriteUInt16( rLev.mnAsianSettings )
+ .WriteUInt16( rLev.mnBiDi );
+ }
+}
+
+PPTExStyleSheet::PPTExStyleSheet( sal_uInt16 nDefaultTab, PPTExBulletProvider* pBuProv )
+{
+ for ( int nInstance = EPP_TEXTTYPE_Title; nInstance <= EPP_TEXTTYPE_QuarterBody; nInstance++ )
+ {
+ if (nInstance != EPP_TEXTTYPE_notUsed)
+ {
+ mpParaSheet[ nInstance ].reset(new PPTExParaSheet( nInstance, nDefaultTab, pBuProv ));
+ mpCharSheet[ nInstance ].reset(new PPTExCharSheet( nInstance ));
+ }
+ }
+}
+
+PPTExStyleSheet::~PPTExStyleSheet()
+{
+}
+
+void PPTExStyleSheet::SetStyleSheet( const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
+ FontCollection& rFontCollection, int nInstance, int nLevel )
+{
+ if ( nInstance == EPP_TEXTTYPE_notUsed )
+ return;
+ mpCharSheet[ nInstance ]->SetStyleSheet( rXPropSet, rFontCollection, nLevel );
+ mpParaSheet[ nInstance ]->SetStyleSheet( rXPropSet, rFontCollection, nLevel, mpCharSheet[ nInstance ]->maCharLevel[ nLevel ] );
+}
+
+bool PPTExStyleSheet::IsHardAttribute( sal_uInt32 nInstance, sal_uInt32 nLevel, PPTExTextAttr eAttr, sal_uInt32 nValue )
+{
+ assert(nInstance < PPTEX_STYLESHEETENTRIES && nLevel < 5);
+
+ const PPTExParaLevel& rPara = mpParaSheet[ nInstance ]->maParaLevel[ nLevel ];
+ const PPTExCharLevel& rChar = mpCharSheet[ nInstance ]->maCharLevel[ nLevel ];
+
+ sal_uInt32 nFlag = 0;
+
+ switch ( eAttr )
+ {
+ case ParaAttr_BulletOn : return ( rPara.mbIsBullet ) ? nValue == 0 : nValue != 0;
+ case ParaAttr_BuHardFont :
+ case ParaAttr_BulletFont : return ( rPara.mnBulletFont != nValue );
+ case ParaAttr_BuHardColor :
+ case ParaAttr_BulletColor : return ( rPara.mnBulletColor != nValue );
+ case ParaAttr_BuHardHeight :
+ case ParaAttr_BulletHeight : return ( rPara.mnBulletHeight != nValue );
+ case ParaAttr_BulletChar : return ( rPara.mnBulletChar != nValue );
+ case ParaAttr_Adjust : return ( rPara.mnAdjust != nValue );
+ case ParaAttr_LineFeed : return ( rPara.mnLineFeed != nValue );
+ case ParaAttr_UpperDist : return ( rPara.mnUpperDist != nValue );
+ case ParaAttr_LowerDist : return ( rPara.mnLowerDist != nValue );
+ case ParaAttr_TextOfs : return ( rPara.mnTextOfs != nValue );
+ case ParaAttr_BulletOfs : return ( rPara.mnBulletOfs != nValue );
+ case ParaAttr_DefaultTab : return ( rPara.mnDefaultTab != nValue );
+ case ParaAttr_BiDi : return ( rPara.mnBiDi != nValue );
+ case CharAttr_Bold : nFlag = 1; break;
+ case CharAttr_Italic : nFlag = 2; break;
+ case CharAttr_Underline : nFlag = 4; break;
+ case CharAttr_Shadow : nFlag = 16; break;
+ case CharAttr_Strikeout : nFlag = 256; break;
+ case CharAttr_Embossed : nFlag = 512; break;
+ case CharAttr_Font : return ( rChar.mnFont != nValue );
+ case CharAttr_AsianOrComplexFont : return ( rChar.mnAsianOrComplexFont != nValue );
+ case CharAttr_Symbol : return true;
+ case CharAttr_FontHeight : return ( rChar.mnFontHeight != nValue );
+ case CharAttr_FontColor : return ( rChar.mnFontColor != Color(ColorTransparency, nValue) );
+ case CharAttr_Escapement : return ( rChar.mnEscapement != nValue );
+ default:
+ break;
+ }
+ if ( nFlag )
+ {
+ if ( rChar.mnFlags & nFlag )
+ return ( ( nValue & nFlag ) == 0 );
+ else
+ return ( ( nValue & nFlag ) != 0 );
+ }
+ return true;
+}
+
+// the TxCFStyleAtom stores the text properties that are used
+// when creating new objects in PowerPoint.
+
+void PPTExStyleSheet::WriteTxCFStyleAtom( SvStream& rSt )
+{
+ const PPTExCharLevel& rCharStyle = mpCharSheet[ EPP_TEXTTYPE_Other ]->maCharLevel[ 0 ];
+
+ sal_uInt16 const nFlags = 0x60 // ??
+ | 0x02 // fontsize;
+ | 0x04; // fontcolor
+
+ sal_uInt32 nCharFlags = rCharStyle.mnFlags;
+ nCharFlags &= CharAttr_Italic | CharAttr_Bold | CharAttr_Underline | CharAttr_Shadow;
+
+ rSt.WriteUInt32( EPP_TxCFStyleAtom << 16 ) // recordheader
+ .WriteUInt32( SizeOfTxCFStyleAtom() - 8 )
+ .WriteUInt16( 0x80 | nCharFlags )
+ .WriteUInt16( nFlags )
+ .WriteUInt16( nCharFlags )
+ .WriteInt32( -1 ) // ?
+ .WriteUInt16( rCharStyle.mnFontHeight )
+ .WriteUInt32( sal_uInt32(rCharStyle.mnFontColor) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/pptx-text.cxx b/sd/source/filter/eppt/pptx-text.cxx
new file mode 100644
index 000000000..85c37f77d
--- /dev/null
+++ b/sd/source/filter/eppt/pptx-text.cxx
@@ -0,0 +1,1400 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include "text.hxx"
+
+#include <com/sun/star/awt/CharSet.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XIndexReplace.hpp>
+#include <com/sun/star/i18n/BreakIterator.hpp>
+#include <com/sun/star/i18n/ScriptDirection.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <com/sun/star/text/FontRelief.hpp>
+#include <com/sun/star/text/XTextField.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/style/LineSpacing.hpp>
+#include <com/sun/star/style/LineSpacingMode.hpp>
+#include <com/sun/star/style/ParagraphAdjust.hpp>
+#include <com/sun/star/style/TabStop.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <editeng/svxenum.hxx>
+#include <editeng/frmdir.hxx>
+#include <filter/msfilter/util.hxx>
+#include <i18nutil/scripttypedetector.hxx>
+#include <o3tl/any.hxx>
+#include <svl/languageoptions.hxx>
+#include <osl/diagnose.h>
+#include <i18nlangtag/languagetag.hxx>
+#include <tools/UnitConversion.hxx>
+
+#include <vcl/settings.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace css;
+
+static css::uno::Reference< css::i18n::XBreakIterator > xPPTBreakIter;
+
+PortionObj::PortionObj(const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
+ FontCollection& rFontCollection)
+ : meCharColor(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meCharHeight(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meFontName(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meAsianOrComplexFont(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meCharEscapement(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , mnCharAttrHard(0)
+ , mnCharColor(0)
+ , mnCharAttr(0)
+ , mnFont(0)
+ , mnAsianOrComplexFont(0xffff)
+ , mnTextSize(0)
+ , mbLastPortion(true)
+{
+ mXPropSet = rXPropSet;
+
+ ImplGetPortionValues( rFontCollection, false );
+}
+
+PortionObj::PortionObj(css::uno::Reference< css::text::XTextRange > & rXTextRange,
+ bool bLast, FontCollection& rFontCollection)
+ : meCharColor(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meCharHeight(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meFontName(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meAsianOrComplexFont(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meCharEscapement(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , mnCharAttrHard(0)
+ , mnCharColor(0)
+ , mnCharAttr(0)
+ , mnCharHeight(0)
+ , mnFont(0)
+ , mnAsianOrComplexFont(0xffff)
+ , mnCharEscapement(0)
+ , mbLastPortion(bLast)
+{
+ OUString aString( rXTextRange->getString() );
+ OUString aURL;
+
+ mnTextSize = aString.getLength();
+ if ( bLast )
+ mnTextSize++;
+
+ if ( !mnTextSize )
+ return;
+
+ bool bRTL_endingParen = false;
+ mpFieldEntry = nullptr;
+ sal_uInt32 nFieldType = 0;
+
+ mXPropSet.set( rXTextRange, css::uno::UNO_QUERY );
+ mXPropState.set( rXTextRange, css::uno::UNO_QUERY );
+
+ bool bPropSetsValid = ( mXPropSet.is() && mXPropState.is() );
+ if ( bPropSetsValid )
+ nFieldType = ImplGetTextField( rXTextRange, mXPropSet, aURL );
+ if ( nFieldType )
+ {
+ mpFieldEntry.reset( new FieldEntry( nFieldType, 0, mnTextSize ) );
+ if ( nFieldType >> 28 == 4 )
+ {
+ mpFieldEntry->aRepresentation = aString;
+ mpFieldEntry->aFieldUrl = aURL;
+ }
+ }
+ bool bSymbol = false;
+
+ if ( bPropSetsValid && ImplGetPropertyValue( "CharFontCharSet", false ) )
+ {
+ sal_Int16 nCharset = 0;
+ mAny >>= nCharset;
+ if ( nCharset == css::awt::CharSet::SYMBOL )
+ bSymbol = true;
+ }
+ if ( mpFieldEntry && ( nFieldType & 0x800000 ) ) // placeholder ?
+ {
+ mnTextSize = 1;
+ if ( bLast )
+ mnTextSize++;
+ mpText.reset( new sal_uInt16[ mnTextSize ] );
+ mpText[ 0 ] = 0x2a;
+ }
+ else
+ {
+ // For i39516 - a closing parenthesis that ends an RTL string is displayed backwards by PPT
+ // Solution: add a Unicode Right-to-Left Mark, following the method described in i18024
+ if (bLast && !aString.isEmpty()
+ && aString[aString.getLength() - 1] == ')'
+ && FontCollection::GetScriptDirection(aString) == css::i18n::ScriptDirection::RIGHT_TO_LEFT)
+ {
+ mnTextSize++;
+ bRTL_endingParen = true;
+ }
+ mpText.reset( new sal_uInt16[ mnTextSize ] );
+ sal_uInt16 nChar;
+ for ( sal_Int32 i = 0; i < aString.getLength(); i++ )
+ {
+ nChar = static_cast<sal_uInt16>(aString[ i ]);
+ if ( nChar == 0xa )
+ nChar++;
+ else if ( !bSymbol )
+ {
+ switch ( nChar )
+ {
+ // Currency
+ case 128: nChar = 0x20AC; break;
+ // Punctuation and other
+ case 130: nChar = 0x201A; break;// SINGLE LOW-9 QUOTATION MARK
+ case 131: nChar = 0x0192; break;// LATIN SMALL LETTER F WITH HOOK
+ case 132: nChar = 0x201E; break;// DOUBLE LOW-9 QUOTATION MARK
+ // LOW DOUBLE PRIME QUOTATION MARK
+ case 133: nChar = 0x2026; break;// HORIZONTAL ELLIPSES
+ case 134: nChar = 0x2020; break;// DAGGER
+ case 135: nChar = 0x2021; break;// DOUBLE DAGGER
+ case 136: nChar = 0x02C6; break;// MODIFIER LETTER CIRCUMFLEX ACCENT
+ case 137: nChar = 0x2030; break;// PER MILLE SIGN
+ case 138: nChar = 0x0160; break;// LATIN CAPITAL LETTER S WITH CARON
+ case 139: nChar = 0x2039; break;// SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ case 140: nChar = 0x0152; break;// LATIN CAPITAL LIGATURE OE
+ case 142: nChar = 0x017D; break;// LATIN CAPITAL LETTER Z WITH CARON
+ case 145: nChar = 0x2018; break;// LEFT SINGLE QUOTATION MARK
+ // MODIFIER LETTER TURNED COMMA
+ case 146: nChar = 0x2019; break;// RIGHT SINGLE QUOTATION MARK
+ // MODIFIER LETTER APOSTROPHE
+ case 147: nChar = 0x201C; break;// LEFT DOUBLE QUOTATION MARK
+ // REVERSED DOUBLE PRIME QUOTATION MARK
+ case 148: nChar = 0x201D; break;// RIGHT DOUBLE QUOTATION MARK
+ // REVERSED DOUBLE PRIME QUOTATION MARK
+ case 149: nChar = 0x2022; break;// BULLET
+ case 150: nChar = 0x2013; break;// EN DASH
+ case 151: nChar = 0x2014; break;// EM DASH
+ case 152: nChar = 0x02DC; break;// SMALL TILDE
+ case 153: nChar = 0x2122; break;// TRADE MARK SIGN
+ case 154: nChar = 0x0161; break;// LATIN SMALL LETTER S WITH CARON
+ case 155: nChar = 0x203A; break;// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ case 156: nChar = 0x0153; break;// LATIN SMALL LIGATURE OE
+ case 158: nChar = 0x017E; break;// LATIN SMALL LETTER Z WITH CARON
+ case 159: nChar = 0x0178; break;// LATIN CAPITAL LETTER Y WITH DIAERESIS
+ }
+ }
+ mpText[ i ] = nChar;
+ }
+ }
+ if ( bRTL_endingParen )
+ mpText[ mnTextSize - 2 ] = 0x200F; // Unicode Right-to-Left mark
+
+ if ( bLast )
+ mpText[ mnTextSize - 1 ] = 0xd;
+
+ if ( bPropSetsValid )
+ ImplGetPortionValues( rFontCollection, true );
+}
+
+PortionObj::PortionObj( const PortionObj& rPortionObj )
+: PropStateValue( rPortionObj )
+{
+ ImplConstruct( rPortionObj );
+}
+
+PortionObj::~PortionObj()
+{
+ ImplClear();
+}
+
+void PortionObj::Write( SvStream* pStrm, bool bLast )
+{
+ sal_uInt32 nCount = mnTextSize;
+ if ( bLast && mbLastPortion )
+ nCount--;
+ for ( sal_uInt32 i = 0; i < nCount; i++ )
+ pStrm->WriteUInt16( mpText[ i ] );
+}
+
+void PortionObj::ImplGetPortionValues( FontCollection& rFontCollection, bool bGetPropStateValue )
+{
+
+ bool bOk = ImplGetPropertyValue( "CharFontName", bGetPropStateValue );
+ meFontName = ePropState;
+ if ( bOk )
+ {
+ FontCollectionEntry aFontDesc( *o3tl::doAccess<OUString>(mAny) );
+ sal_uInt32 nCount = rFontCollection.GetCount();
+ mnFont = static_cast<sal_uInt16>(rFontCollection.GetId( aFontDesc ));
+ if ( mnFont == nCount )
+ {
+ FontCollectionEntry& rFontDesc = rFontCollection.GetLast();
+ if ( ImplGetPropertyValue( "CharFontCharSet", false ) )
+ mAny >>= rFontDesc.CharSet;
+ if ( ImplGetPropertyValue( "CharFontFamily", false ) )
+ mAny >>= rFontDesc.Family;
+ if ( ImplGetPropertyValue( "CharFontPitch", false ) )
+ mAny >>= rFontDesc.Pitch;
+ }
+ }
+
+ sal_Int16 nScriptType = SvtLanguageOptions::FromSvtScriptTypeToI18N( SvtLanguageOptions::GetScriptTypeOfLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ) );
+ if ( mpText && mnTextSize && xPPTBreakIter.is() )
+ {
+ OUString sT( reinterpret_cast<sal_Unicode *>(mpText.get()), mnTextSize );
+ nScriptType = xPPTBreakIter->getScriptType( sT, 0 );
+ }
+ if ( nScriptType != css::i18n::ScriptType::COMPLEX )
+ {
+ bOk = ImplGetPropertyValue( "CharFontNameAsian", bGetPropStateValue );
+ meAsianOrComplexFont = ePropState;
+ if ( bOk )
+ {
+ FontCollectionEntry aFontDesc( *o3tl::doAccess<OUString>(mAny) );
+ sal_uInt32 nCount = rFontCollection.GetCount();
+ mnAsianOrComplexFont = static_cast<sal_uInt16>(rFontCollection.GetId( aFontDesc ));
+ if ( mnAsianOrComplexFont == nCount )
+ {
+ FontCollectionEntry& rFontDesc = rFontCollection.GetLast();
+ if ( ImplGetPropertyValue( "CharFontCharSetAsian", false ) )
+ mAny >>= rFontDesc.CharSet;
+ if ( ImplGetPropertyValue( "CharFontFamilyAsian", false ) )
+ mAny >>= rFontDesc.Family;
+ if ( ImplGetPropertyValue( "CharFontPitchAsian", false ) )
+ mAny >>= rFontDesc.Pitch;
+ }
+ }
+ }
+ else
+ {
+ bOk = ImplGetPropertyValue( "CharFontNameComplex", bGetPropStateValue );
+ meAsianOrComplexFont = ePropState;
+ if ( bOk )
+ {
+ FontCollectionEntry aFontDesc( *o3tl::doAccess<OUString>(mAny) );
+ sal_uInt32 nCount = rFontCollection.GetCount();
+ mnAsianOrComplexFont = static_cast<sal_uInt16>(rFontCollection.GetId( aFontDesc ));
+ if ( mnAsianOrComplexFont == nCount )
+ {
+ FontCollectionEntry& rFontDesc = rFontCollection.GetLast();
+ if ( ImplGetPropertyValue( "CharFontCharSetComplex", false ) )
+ mAny >>= rFontDesc.CharSet;
+ if ( ImplGetPropertyValue( "CharFontFamilyComplex", false ) )
+ mAny >>= rFontDesc.Family;
+ if ( ImplGetPropertyValue( "CharFontPitchComplex", false ) )
+ mAny >>= rFontDesc.Pitch;
+ }
+ }
+ }
+
+ OUString aCharHeightName, aCharWeightName, aCharLocaleName, aCharPostureName;
+ switch( nScriptType )
+ {
+ case css::i18n::ScriptType::ASIAN :
+ {
+ aCharHeightName = "CharHeightAsian";
+ aCharWeightName = "CharWeightAsian";
+ aCharLocaleName = "CharLocaleAsian";
+ aCharPostureName = "CharPostureAsian";
+ break;
+ }
+ case css::i18n::ScriptType::COMPLEX :
+ {
+ aCharHeightName = "CharHeightComplex";
+ aCharWeightName = "CharWeightComplex";
+ aCharLocaleName = "CharLocaleComplex";
+ aCharPostureName = "CharPostureComplex";
+ break;
+ }
+ default:
+ {
+ aCharHeightName = "CharHeight";
+ aCharWeightName = "CharWeight";
+ aCharLocaleName = "CharLocale";
+ aCharPostureName = "CharPosture";
+ break;
+ }
+ }
+
+ mnCharHeight = 24;
+ if ( GetPropertyValue( mAny, mXPropSet, aCharHeightName ) )
+ {
+ float fVal(0.0);
+ if ( mAny >>= fVal )
+ {
+ mnCharHeight = static_cast<sal_uInt16>( fVal + 0.5 );
+ meCharHeight = GetPropertyState( mXPropSet, aCharHeightName );
+ }
+ }
+ if ( GetPropertyValue( mAny, mXPropSet, aCharWeightName ) )
+ {
+ float fFloat(0.0);
+ if ( mAny >>= fFloat )
+ {
+ if ( fFloat >= css::awt::FontWeight::SEMIBOLD )
+ mnCharAttr |= 1;
+ if ( GetPropertyState( mXPropSet, aCharWeightName ) == css::beans::PropertyState_DIRECT_VALUE )
+ mnCharAttrHard |= 1;
+ }
+ }
+ if ( GetPropertyValue( mAny, mXPropSet, aCharLocaleName ) )
+ {
+ css::lang::Locale eLocale;
+ if ( mAny >>= eLocale )
+ meCharLocale = eLocale;
+ }
+ if ( GetPropertyValue( mAny, mXPropSet, aCharPostureName ) )
+ {
+ css::awt::FontSlant aFS;
+ if ( mAny >>= aFS )
+ {
+ switch( aFS )
+ {
+ case css::awt::FontSlant_OBLIQUE :
+ case css::awt::FontSlant_ITALIC :
+ mnCharAttr |= 2;
+ break;
+ default:
+ break;
+ }
+ if ( GetPropertyState( mXPropSet, aCharPostureName ) == css::beans::PropertyState_DIRECT_VALUE )
+ mnCharAttrHard |= 2;
+ }
+ }
+
+ if ( ImplGetPropertyValue( "CharUnderline", bGetPropStateValue ) )
+ {
+ sal_Int16 nVal(0);
+ mAny >>= nVal;
+ switch ( nVal )
+ {
+ case css::awt::FontUnderline::SINGLE :
+ case css::awt::FontUnderline::DOUBLE :
+ case css::awt::FontUnderline::DOTTED :
+ mnCharAttr |= 4;
+ }
+ }
+ if ( ePropState == css::beans::PropertyState_DIRECT_VALUE )
+ mnCharAttrHard |= 4;
+
+ if ( ImplGetPropertyValue( "CharShadowed", bGetPropStateValue ) )
+ {
+ bool bBool(false);
+ mAny >>= bBool;
+ if ( bBool )
+ mnCharAttr |= 0x10;
+ }
+ if ( ePropState == css::beans::PropertyState_DIRECT_VALUE )
+ mnCharAttrHard |= 16;
+
+ if ( ImplGetPropertyValue( "CharRelief", bGetPropStateValue ) )
+ {
+ sal_Int16 nVal(0);
+ mAny >>= nVal;
+ if ( nVal != css::text::FontRelief::NONE )
+ mnCharAttr |= 512;
+ }
+ if ( ePropState == css::beans::PropertyState_DIRECT_VALUE )
+ mnCharAttrHard |= 512;
+
+ if ( ImplGetPropertyValue( "CharColor", bGetPropStateValue ) )
+ {
+ sal_uInt32 nSOColor = *( o3tl::doAccess<sal_uInt32>(mAny) );
+ mnCharColor = nSOColor & 0xff00ff00; // green and hibyte
+ mnCharColor |= static_cast<sal_uInt8>(nSOColor) << 16; // red and blue is switched
+ mnCharColor |= static_cast<sal_uInt8>( nSOColor >> 16 );
+ }
+ meCharColor = ePropState;
+
+ mnCharEscapement = 0;
+ if ( ImplGetPropertyValue( "CharEscapement", bGetPropStateValue ) )
+ {
+ mAny >>= mnCharEscapement;
+ if ( mnCharEscapement > 100 )
+ mnCharEscapement = 33;
+ else if ( mnCharEscapement < -100 )
+ mnCharEscapement = -33;
+ }
+ meCharEscapement = ePropState;
+}
+
+void PortionObj::ImplClear()
+{
+ mpFieldEntry.reset();
+ mpText.reset();
+}
+
+void PortionObj::ImplConstruct( const PortionObj& rPortionObj )
+{
+ meCharColor = rPortionObj.meCharColor;
+ meCharHeight = rPortionObj.meCharHeight;
+ meFontName = rPortionObj.meFontName;
+ meAsianOrComplexFont = rPortionObj.meAsianOrComplexFont;
+ meCharEscapement = rPortionObj.meCharEscapement;
+ meCharLocale = rPortionObj.meCharLocale;
+ mnCharAttrHard = rPortionObj.mnCharAttrHard;
+
+ mbLastPortion = rPortionObj.mbLastPortion;
+ mnTextSize = rPortionObj.mnTextSize;
+ mnCharColor = rPortionObj.mnCharColor;
+ mnCharEscapement = rPortionObj.mnCharEscapement;
+ mnCharAttr = rPortionObj.mnCharAttr;
+ mnCharHeight = rPortionObj.mnCharHeight;
+ mnFont = rPortionObj.mnFont;
+ mnAsianOrComplexFont = rPortionObj.mnAsianOrComplexFont;
+
+ if ( rPortionObj.mpText )
+ {
+ mpText.reset( new sal_uInt16[ mnTextSize ] );
+ memcpy( mpText.get(), rPortionObj.mpText.get(), mnTextSize << 1 );
+ }
+
+ if ( rPortionObj.mpFieldEntry )
+ mpFieldEntry.reset( new FieldEntry( *( rPortionObj.mpFieldEntry ) ) );
+}
+
+sal_uInt32 PortionObj::ImplCalculateTextPositions( sal_uInt32 nCurrentTextPosition )
+{
+ if ( mpFieldEntry && ( !mpFieldEntry->nFieldStartPos ) )
+ {
+ mpFieldEntry->nFieldStartPos += nCurrentTextPosition;
+ mpFieldEntry->nFieldEndPos += nCurrentTextPosition;
+ }
+ return mnTextSize;
+}
+
+// Return: 0 = no TextField
+// bit28->31 text field type :
+// 1 = Date
+// 2 = Time
+// 3 = SlideNumber
+// 4 = Url
+// 5 = DateTime
+// 6 = header
+// 7 = footer
+// bit24->27 text field sub type (optional)
+// 23-> PPT Textfield needs a placeholder
+
+sal_uInt32 PortionObj::ImplGetTextField( css::uno::Reference< css::text::XTextRange > & ,
+ const css::uno::Reference< css::beans::XPropertySet > & rXPropSet, OUString& rURL )
+{
+ sal_uInt32 nRetValue = 0;
+ sal_Int32 nFormat;
+ css::uno::Any aAny;
+ if ( GetPropertyValue( aAny, rXPropSet, "TextPortionType", true ) )
+ {
+ auto aTextFieldType = o3tl::doAccess<OUString>(aAny);
+ if ( *aTextFieldType == "TextField" )
+ {
+ if ( GetPropertyValue( aAny, rXPropSet, *aTextFieldType, true ) )
+ {
+ css::uno::Reference< css::text::XTextField > aXTextField;
+ if ( aAny >>= aXTextField )
+ {
+ if ( aXTextField.is() )
+ {
+ css::uno::Reference< css::beans::XPropertySet > xFieldPropSet( aXTextField, css::uno::UNO_QUERY );
+ if ( xFieldPropSet.is() )
+ {
+ OUString aFieldKind( aXTextField->getPresentation( true ) );
+ if ( aFieldKind == "Date" )
+ {
+ if ( GetPropertyValue( aAny, xFieldPropSet, "IsFix", true ) )
+ {
+ bool bBool = false;
+ aAny >>= bBool;
+ if ( !bBool ) // Fixed DateFields does not exist in PPT
+ {
+ if ( GetPropertyValue( aAny, xFieldPropSet, "Format", true ) )
+ {
+ nFormat = *o3tl::doAccess<sal_Int32>(aAny);
+ switch ( nFormat )
+ {
+ default:
+ case 5 :
+ case 4 :
+ case 2 : nFormat = 0; break;
+ case 8 :
+ case 9 :
+ case 3 : nFormat = 1; break;
+ case 7 :
+ case 6 : nFormat = 2; break;
+ }
+ nRetValue |= ( ( ( 1 << 4 ) | nFormat ) << 24 ) | 0x800000;
+ }
+ }
+ }
+ }
+ else if ( aFieldKind == "URL" )
+ {
+ if ( GetPropertyValue( aAny, xFieldPropSet, "URL", true ) )
+ rURL = *o3tl::doAccess<OUString>(aAny);
+ nRetValue = 4 << 28;
+ }
+ else if ( aFieldKind == "Page" )
+ {
+ nRetValue = 3 << 28 | 0x800000;
+ }
+ else if ( aFieldKind == "Pages" )
+ {
+
+ }
+ else if ( aFieldKind == "Time" )
+ {
+ if ( GetPropertyValue( aAny, xFieldPropSet, "IsFix", true ) )
+ {
+ bool bBool = false;
+ aAny >>= bBool;
+ if ( !bBool )
+ {
+ if ( GetPropertyValue( aAny, xFieldPropSet, "IsFix", true ) )
+ {
+ nFormat = *o3tl::doAccess<sal_Int32>(aAny);
+ nRetValue |= ( ( ( 2 << 4 ) | nFormat ) << 24 ) | 0x800000;
+ }
+ }
+ }
+ }
+ else if ( aFieldKind == "File" )
+ {
+
+ }
+ else if ( aFieldKind == "Table" )
+ {
+
+ }
+ else if ( aFieldKind == "ExtTime" )
+ {
+ if ( GetPropertyValue( aAny, xFieldPropSet, "IsFix", true ) )
+ {
+ bool bBool = false;
+ aAny >>= bBool;
+ if ( !bBool )
+ {
+ if ( GetPropertyValue( aAny, xFieldPropSet, "Format", true ) )
+ {
+ nFormat = *o3tl::doAccess<sal_Int32>(aAny);
+ switch ( nFormat )
+ {
+ default:
+ case 6 :
+ case 7 :
+ case 8 :
+ case 2 : nFormat = 12; break;
+ case 3 : nFormat = 9; break;
+ case 5 :
+ case 4 : nFormat = 10; break;
+
+ }
+ nRetValue |= ( ( ( 2 << 4 ) | nFormat ) << 24 ) | 0x800000;
+ }
+ }
+ }
+ }
+ else if ( aFieldKind == "ExtFile" )
+ {
+
+ }
+ else if ( aFieldKind == "Author" )
+ {
+
+ }
+ else if ( aFieldKind == "DateTime" )
+ {
+ nRetValue = 5 << 28 | 0x800000;
+ }
+ else if ( aFieldKind == "Header" )
+ {
+ nRetValue = 6 << 28 | 0x800000;
+ }
+ else if ( aFieldKind == "Footer" )
+ {
+ nRetValue = 7 << 28 | 0x800000;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return nRetValue;
+}
+
+PortionObj& PortionObj::operator=( const PortionObj& rPortionObj )
+{
+ if ( this != &rPortionObj )
+ {
+ ImplClear();
+ ImplConstruct( rPortionObj );
+ }
+ return *this;
+}
+
+ParagraphObj::ParagraphObj(const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
+ PPTExBulletProvider* pProv)
+ : mnTextSize(0)
+ , mbFirstParagraph(false)
+ , mbLastParagraph(false)
+ , meBullet(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , mnTextAdjust(0)
+ , mnLineSpacing(0)
+ , mbFixedLineSpacing(false)
+ , mnLineSpacingTop(0)
+ , mnLineSpacingBottom(0)
+ , mbForbiddenRules(false)
+ , mbParagraphPunctation(false)
+ , mnBiDi(0)
+{
+ mXPropSet = rXPropSet;
+
+ bExtendedParameters = false;
+
+ nDepth = 0;
+ nBulletFlags = 0;
+ nParaFlags = 0;
+
+ ImplGetParagraphValues( pProv, false );
+}
+
+ParagraphObj::ParagraphObj(css::uno::Reference< css::text::XTextContent > const & rXTextContent,
+ ParaFlags aParaFlags, FontCollection& rFontCollection, PPTExBulletProvider& rProv )
+ : mnTextSize(0)
+ , mbIsBullet(false)
+ , mbFirstParagraph( aParaFlags.bFirstParagraph )
+ , mbLastParagraph( aParaFlags.bLastParagraph )
+ , meBullet(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meTextAdjust(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meLineSpacing(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meLineSpacingTop(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meLineSpacingBottom(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meForbiddenRules(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meParagraphPunctation(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , meBiDi(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ , mnTextAdjust(0)
+ , mnLineSpacing(0)
+ , mbFixedLineSpacing(false)
+ , mnLineSpacingTop(0)
+ , mnLineSpacingBottom(0)
+ , mbForbiddenRules(false)
+ , mbParagraphPunctation(false)
+ , mnBiDi(0)
+{
+ bExtendedParameters = false;
+
+ nDepth = 0;
+ nBulletFlags = 0;
+ nParaFlags = 0;
+
+ mXPropSet.set( rXTextContent, css::uno::UNO_QUERY );
+
+ mXPropState.set( rXTextContent, css::uno::UNO_QUERY );
+
+ if ( !(mXPropSet.is() && mXPropState.is()) )
+ return;
+
+ css::uno::Reference< css::container::XEnumerationAccess > aXTextPortionEA( rXTextContent, css::uno::UNO_QUERY );
+ if ( aXTextPortionEA.is() )
+ {
+ css::uno::Reference< css::container::XEnumeration > aXTextPortionE( aXTextPortionEA->createEnumeration() );
+ if ( aXTextPortionE.is() )
+ {
+ while ( aXTextPortionE->hasMoreElements() )
+ {
+ css::uno::Reference< css::text::XTextRange > aXCursorText;
+ css::uno::Any aAny( aXTextPortionE->nextElement() );
+ if ( aAny >>= aXCursorText )
+ {
+ std::unique_ptr<PortionObj> pPortionObj(new PortionObj( aXCursorText, !aXTextPortionE->hasMoreElements(), rFontCollection ));
+ if ( pPortionObj->Count() )
+ mvPortions.push_back( std::move(pPortionObj) );
+ }
+ }
+ }
+ }
+ ImplGetParagraphValues( &rProv, true );
+}
+
+ParagraphObj::~ParagraphObj()
+{
+ ImplClear();
+}
+
+void ParagraphObj::Write( SvStream* pStrm )
+{
+ for ( std::vector<std::unique_ptr<PortionObj> >::iterator it = mvPortions.begin(); it != mvPortions.end(); ++it )
+ (*it)->Write( pStrm, mbLastParagraph );
+}
+
+void ParagraphObj::ImplClear()
+{
+ mvPortions.clear();
+}
+
+void ParagraphObj::CalculateGraphicBulletSize( sal_uInt16 nFontHeight )
+{
+ if ( ( nNumberingType != SVX_NUM_BITMAP ) || ( nBulletId == 0xffff ) )
+ return;
+
+ // calculate the bullet real size for this graphic
+ if ( aBuGraSize.Width() && aBuGraSize.Height() )
+ {
+ double fCharHeight = nFontHeight;
+ double fLen = aBuGraSize.Height();
+ fCharHeight = fCharHeight * 0.2540;
+ double fQuo = fLen / fCharHeight;
+ nBulletRealSize = static_cast<sal_Int16>( fQuo + 0.5 );
+ if ( static_cast<sal_uInt16>(nBulletRealSize) > 400 )
+ nBulletRealSize = 400;
+ }
+}
+
+void ParagraphObj::ImplGetNumberingLevel( PPTExBulletProvider* pBuProv, sal_Int16 nNumberingDepth, bool bIsBullet, bool bGetPropStateValue )
+{
+ css::uno::Any aAny;
+ if ( GetPropertyValue( aAny, mXPropSet, "ParaLeftMargin" ) )
+ {
+ sal_Int32 nVal(0);
+ if ( aAny >>= nVal )
+ nTextOfs = convertMm100ToMasterUnit(nVal);
+ }
+ if ( GetPropertyValue( aAny, mXPropSet, "ParaFirstLineIndent" ) )
+ {
+ if ( aAny >>= nBulletOfs )
+ nBulletOfs = convertMm100ToMasterUnit(nBulletOfs);
+ }
+ if ( GetPropertyValue( aAny, mXPropSet, "NumberingIsNumber" ) )
+ aAny >>= bNumberingIsNumber;
+
+ css::uno::Reference< css::container::XIndexReplace > aXIndexReplace;
+
+ if ( bIsBullet && ImplGetPropertyValue( "NumberingRules", bGetPropStateValue ) )
+ {
+ if ( ( mAny >>= aXIndexReplace ) && nNumberingDepth < aXIndexReplace->getCount() )
+ {
+ mAny = aXIndexReplace->getByIndex( nNumberingDepth );
+ auto aPropertySequence = o3tl::doAccess<css::uno::Sequence<css::beans::PropertyValue>>(mAny);
+
+ if ( aPropertySequence->hasElements() )
+ {
+ bExtendedParameters = true;
+ nBulletRealSize = 100;
+ nMappedNumType = 0;
+
+ uno::Reference<graphic::XGraphic> xGraphic;
+ for ( const css::beans::PropertyValue& rPropValue : *aPropertySequence )
+ {
+ OUString aPropName( rPropValue.Name );
+ if ( aPropName == "NumberingType" )
+ nNumberingType = static_cast<SvxNumType>(*o3tl::doAccess<sal_Int16>(rPropValue.Value));
+ else if ( aPropName == "Adjust" )
+ nHorzAdjust = *o3tl::doAccess<sal_Int16>(rPropValue.Value);
+ else if ( aPropName == "BulletChar" )
+ {
+ OUString aString( *o3tl::doAccess<OUString>(rPropValue.Value) );
+ if ( !aString.isEmpty() )
+ cBulletId = aString[ 0 ];
+ }
+ else if ( aPropName == "BulletFont" )
+ {
+ aFontDesc = *o3tl::doAccess<css::awt::FontDescriptor>(rPropValue.Value);
+
+ // Our numbullet dialog has set the wrong textencoding for our "StarSymbol" font,
+ // instead of a Unicode encoding the encoding RTL_TEXTENCODING_SYMBOL was used.
+ // Because there might exist a lot of damaged documents I added this two lines
+ // which fixes the bullet problem for the export.
+ if ( aFontDesc.Name.equalsIgnoreAsciiCase("StarSymbol") )
+ aFontDesc.CharSet = RTL_TEXTENCODING_MS_1252;
+
+ }
+ else if ( aPropName == "GraphicBitmap" )
+ {
+ auto xBitmap = rPropValue.Value.get<uno::Reference<awt::XBitmap>>();
+ xGraphic.set(xBitmap, uno::UNO_QUERY);
+ }
+ else if ( aPropName == "GraphicSize" )
+ {
+ if (auto aSize = o3tl::tryAccess<css::awt::Size>(rPropValue.Value))
+ {
+ // don't cast awt::Size to Size as on 64-bits they are not the same.
+ aBuGraSize.setWidth( aSize->Width );
+ aBuGraSize.setHeight( aSize->Height );
+ }
+ }
+ else if ( aPropName == "StartWith" )
+ nStartWith = *o3tl::doAccess<sal_Int16>(rPropValue.Value);
+ else if ( aPropName == "LeftMargin" )
+ nTextOfs += convertMm100ToMasterUnit(*o3tl::doAccess<sal_Int32>(rPropValue.Value));
+ else if ( aPropName == "FirstLineOffset" )
+ nBulletOfs += convertMm100ToMasterUnit(*o3tl::doAccess<sal_Int32>(rPropValue.Value));
+ else if ( aPropName == "BulletColor" )
+ {
+ sal_uInt32 nSOColor = *o3tl::doAccess<sal_uInt32>(rPropValue.Value);
+ nBulletColor = nSOColor & 0xff00ff00; // green and hibyte
+ nBulletColor |= static_cast<sal_uInt8>(nSOColor) << 16; // red
+ nBulletColor |= static_cast<sal_uInt8>( nSOColor >> 16 ) | 0xfe000000; // blue
+ }
+ else if ( aPropName == "BulletRelSize" )
+ {
+ nBulletRealSize = *o3tl::doAccess<sal_Int16>(rPropValue.Value);
+ nParaFlags |= 0x40;
+ nBulletFlags |= 8;
+ }
+ else if ( aPropName == "Prefix" )
+ sPrefix = *o3tl::doAccess<OUString>(rPropValue.Value);
+ else if ( aPropName == "Suffix" )
+ sSuffix = *o3tl::doAccess<OUString>(rPropValue.Value);
+#ifdef DBG_UTIL
+ else if ( aPropName != "SymbolTextDistance" && aPropName != "GraphicBitmap" )
+ {
+ OSL_FAIL( "Unknown Property" );
+ }
+#endif
+ }
+
+ if (xGraphic.is())
+ {
+ if ( aBuGraSize.Width() && aBuGraSize.Height() )
+ {
+ nBulletId = pBuProv->GetId(xGraphic, aBuGraSize );
+ if ( nBulletId != 0xffff )
+ bExtendedBulletsUsed = true;
+ }
+ else
+ {
+ nNumberingType = SVX_NUM_NUMBER_NONE;
+ }
+ }
+
+ CalculateGraphicBulletSize( ( mvPortions.empty() ) ? 24 : mvPortions.front()->mnCharHeight );
+
+ switch( nNumberingType )
+ {
+ case SVX_NUM_NUMBER_NONE : nParaFlags |= 0xf; break;
+
+ case SVX_NUM_CHAR_SPECIAL : // Bullet
+ {
+ if ( IsStarSymbol(aFontDesc.Name) )
+ {
+ rtl_TextEncoding eChrSet = aFontDesc.CharSet;
+ cBulletId = msfilter::util::bestFitOpenSymbolToMSFont(cBulletId, eChrSet, aFontDesc.Name);
+ aFontDesc.CharSet = eChrSet;
+ }
+
+ if ( !aFontDesc.Name.isEmpty() )
+ {
+ nParaFlags |= 0x90; // we define the font and charset
+ }
+
+ [[fallthrough]];
+ }
+ case SVX_NUM_CHARS_UPPER_LETTER : // count from a-z, aa - az, ba - bz, ...
+ case SVX_NUM_CHARS_LOWER_LETTER :
+ case SVX_NUM_ROMAN_UPPER :
+ case SVX_NUM_ROMAN_LOWER :
+ case SVX_NUM_ARABIC :
+ case SVX_NUM_PAGEDESC : // numbering from the page template
+ case SVX_NUM_BITMAP :
+ case SVX_NUM_CHARS_UPPER_LETTER_N : // count from a-z, aa-zz, aaa-zzz
+ case SVX_NUM_CHARS_LOWER_LETTER_N :
+ case SVX_NUM_NUMBER_UPPER_ZH:
+ case SVX_NUM_CIRCLE_NUMBER:
+ case SVX_NUM_NUMBER_UPPER_ZH_TW:
+ case SVX_NUM_NUMBER_LOWER_ZH:
+ case SVX_NUM_FULL_WIDTH_ARABIC:
+ {
+ if ( nNumberingType != SVX_NUM_CHAR_SPECIAL )
+ {
+ bExtendedBulletsUsed = true;
+ if ( nNumberingDepth & 1 )
+ cBulletId = 0x2013; // defaulting bullet characters for ppt97
+ else if ( nNumberingDepth == 4 )
+ cBulletId = 0xbb;
+ else
+ cBulletId = 0x2022;
+
+ switch( nNumberingType )
+ {
+ case SVX_NUM_CHARS_UPPER_LETTER :
+ case SVX_NUM_CHARS_UPPER_LETTER_N :
+ {
+ if ( sSuffix == ")" )
+ {
+ if ( sPrefix == "(" )
+ nMappedNumType = 0xa0001; // (A)
+ else
+ nMappedNumType = 0xb0001; // A)
+ }
+ else
+ nMappedNumType = 0x10001; // A.
+ }
+ break;
+ case SVX_NUM_CHARS_LOWER_LETTER :
+ case SVX_NUM_CHARS_LOWER_LETTER_N :
+ {
+ if ( sSuffix == ")" )
+ {
+ if ( sPrefix == "(" )
+ nMappedNumType = 0x80001; // (a)
+ else
+ nMappedNumType = 0x90001; // a)
+ }
+ else
+ nMappedNumType = 0x00001; // a.
+ }
+ break;
+ case SVX_NUM_ROMAN_UPPER :
+ {
+ if ( sSuffix == ")" )
+ {
+ if ( sPrefix == "(" )
+ nMappedNumType = 0xe0001; // (I)
+ else
+ nMappedNumType = 0xf0001; // I)
+ }
+ else
+ nMappedNumType = 0x70001; // I.
+ }
+ break;
+ case SVX_NUM_ROMAN_LOWER :
+ {
+ if ( sSuffix == ")" )
+ {
+ if ( sPrefix == "(" )
+ nMappedNumType = 0x40001; // (i)
+ else
+ nMappedNumType = 0x50001; // i)
+ }
+ else
+ nMappedNumType = 0x60001; // i.
+ }
+ break;
+ case SVX_NUM_ARABIC :
+ {
+ if ( sSuffix == ")" )
+ {
+ if ( sPrefix == "(" )
+ nMappedNumType = 0xc0001; // (1)
+ else
+ nMappedNumType = 0x20001; // 1)
+ }
+ else
+ {
+ if ( sSuffix.isEmpty() && sPrefix.isEmpty() )
+ nMappedNumType = 0xd0001; // 1
+ else
+ nMappedNumType = 0x30001; // 1.
+ }
+ }
+ break;
+ case SVX_NUM_NUMBER_UPPER_ZH :
+ {
+ if ( !sSuffix.isEmpty() )
+ nMappedNumType = 0x110001; // Simplified Chinese with single-byte period.
+ else
+ nMappedNumType = 0x100001; // Simplified Chinese.
+ }
+ break;
+ case SVX_NUM_CIRCLE_NUMBER :
+ {
+ nMappedNumType = 0x120001; // Double byte circle numbers.
+ }
+ break;
+ case SVX_NUM_NUMBER_UPPER_ZH_TW :
+ {
+ if ( !sSuffix.isEmpty() )
+ nMappedNumType = 0x160001; // Traditional Chinese with single-byte period.
+ else
+ nMappedNumType = 0x150001; // Traditional Chinese.
+ }
+ break;
+ case SVX_NUM_NUMBER_LOWER_ZH :
+ {
+ if ( sSuffix == u"\uff0e" )
+ nMappedNumType = 0x260001; // Japanese with double-byte period.
+ else if ( !sSuffix.isEmpty() )
+ nMappedNumType = 0x1B0001; // Japanese/Korean with single-byte period.
+ else
+ nMappedNumType = 0x1A0001; // Japanese/Korean.
+ }
+ break;
+ case SVX_NUM_FULL_WIDTH_ARABIC :
+ {
+ if ( !sSuffix.isEmpty() )
+ nMappedNumType = 0x1D0001; // Double-byte Arabic numbers with double-byte period.
+ else
+ nMappedNumType = 0x1C0001; // Double-byte Arabic numbers.
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ nParaFlags |= 0x2f;
+ nBulletFlags |= 6;
+ if ( mbIsBullet && bNumberingIsNumber )
+ nBulletFlags |= 1;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+ nBulletOfs = nTextOfs + nBulletOfs;
+ if ( nBulletOfs < 0 )
+ nBulletOfs = 0;
+}
+
+void ParagraphObj::ImplGetParagraphValues( PPTExBulletProvider* pBuProv, bool bGetPropStateValue )
+{
+ css::uno::Any aAny;
+ if ( GetPropertyValue( aAny, mXPropSet, "NumberingLevel", true ) )
+ {
+ if ( bGetPropStateValue )
+ meBullet = GetPropertyState( mXPropSet, "NumberingLevel" );
+ nDepth = *o3tl::doAccess<sal_Int16>(aAny);
+
+ if ( nDepth < 0 )
+ {
+ mbIsBullet = false;
+ nDepth = 0;
+ }
+ else
+ {
+ if ( nDepth > 4 )
+ nDepth = 4;
+ mbIsBullet = true;
+ }
+ }
+ else
+ {
+ nDepth = 0;
+ mbIsBullet = false;
+ }
+ ImplGetNumberingLevel( pBuProv, nDepth, mbIsBullet, bGetPropStateValue );
+
+ if ( ImplGetPropertyValue( "ParaTabStops", bGetPropStateValue ) )
+ maTabStop = *o3tl::doAccess<css::uno::Sequence<css::style::TabStop>>(mAny);
+ sal_Int16 eTextAdjust = sal_Int16(css::style::ParagraphAdjust_LEFT);
+ if ( GetPropertyValue( aAny, mXPropSet, "ParaAdjust", bGetPropStateValue ) )
+ aAny >>= eTextAdjust;
+ switch ( static_cast<css::style::ParagraphAdjust>(eTextAdjust) )
+ {
+ case css::style::ParagraphAdjust_CENTER :
+ mnTextAdjust = 1;
+ break;
+ case css::style::ParagraphAdjust_RIGHT :
+ mnTextAdjust = 2;
+ break;
+ case css::style::ParagraphAdjust_BLOCK :
+ mnTextAdjust = 3;
+ break;
+ default :
+ case css::style::ParagraphAdjust_LEFT :
+ mnTextAdjust = 0;
+ break;
+ }
+ meTextAdjust = ePropState;
+
+ if ( ImplGetPropertyValue( "ParaLineSpacing", bGetPropStateValue ) )
+ {
+ css::style::LineSpacing aLineSpacing
+ = *o3tl::doAccess<css::style::LineSpacing>(mAny);
+ switch ( aLineSpacing.Mode )
+ {
+ case css::style::LineSpacingMode::FIX :
+ mnLineSpacing = static_cast<sal_Int16>(-( aLineSpacing.Height ) );
+ mbFixedLineSpacing = true;
+ break;
+ case css::style::LineSpacingMode::MINIMUM :
+ case css::style::LineSpacingMode::LEADING :
+ mnLineSpacing = static_cast<sal_Int16>(-( aLineSpacing.Height ) );
+ mbFixedLineSpacing = false;
+ break;
+
+ case css::style::LineSpacingMode::PROP :
+ default:
+ mnLineSpacing = aLineSpacing.Height;
+ break;
+ }
+ }
+ meLineSpacing = ePropState;
+
+ if ( ImplGetPropertyValue( "ParaBottomMargin", bGetPropStateValue ) )
+ {
+ double fSpacing = *o3tl::doAccess<sal_uInt32>(mAny) + convertMasterUnitToMm100(1.0) - 1;
+ mnLineSpacingBottom = std::round(-convertMm100ToMasterUnit(fSpacing));
+ }
+ meLineSpacingBottom = ePropState;
+
+ if ( ImplGetPropertyValue( "ParaTopMargin", bGetPropStateValue ) )
+ {
+ double fSpacing = *o3tl::doAccess<sal_uInt32>(mAny) + convertMasterUnitToMm100(1.0) - 1;
+ mnLineSpacingTop = std::round(-convertMm100ToMasterUnit(fSpacing));
+ }
+ meLineSpacingTop = ePropState;
+
+ if ( ImplGetPropertyValue( "ParaIsForbiddenRules", bGetPropStateValue ) )
+ mAny >>= mbForbiddenRules;
+ meForbiddenRules = ePropState;
+
+ if ( ImplGetPropertyValue( "ParaIsHangingPunctuation", bGetPropStateValue ) )
+ mAny >>= mbParagraphPunctation;
+ meParagraphPunctation = ePropState;
+
+ mnBiDi = 0;
+ if ( ImplGetPropertyValue( "WritingMode", bGetPropStateValue ) )
+ {
+ sal_Int16 nWritingMode = 0;
+ mAny >>= nWritingMode;
+
+ SvxFrameDirection eWritingMode = static_cast<SvxFrameDirection>(nWritingMode);
+ if ( ( eWritingMode == SvxFrameDirection::Horizontal_RL_TB )
+ || ( eWritingMode == SvxFrameDirection::Vertical_RL_TB ) )
+ {
+ mnBiDi = 1;
+ }
+ }
+ meBiDi = ePropState;
+}
+
+void ParagraphObj::ImplConstruct( const ParagraphObj& rParagraphObj )
+{
+ mbIsBullet = rParagraphObj.mbIsBullet;
+ meBullet = rParagraphObj.meBullet;
+ meTextAdjust = rParagraphObj.meTextAdjust;
+ meLineSpacing = rParagraphObj.meLineSpacing;
+ meLineSpacingTop = rParagraphObj.meLineSpacingTop;
+ meLineSpacingBottom = rParagraphObj.meLineSpacingBottom;
+ meForbiddenRules = rParagraphObj.meForbiddenRules;
+ meParagraphPunctation = rParagraphObj.meParagraphPunctation;
+ meBiDi =rParagraphObj.meBiDi;
+ mbFixedLineSpacing = rParagraphObj.mbFixedLineSpacing;
+ mnTextSize = rParagraphObj.mnTextSize;
+ mnTextAdjust = rParagraphObj.mnTextAdjust;
+ mnLineSpacing = rParagraphObj.mnLineSpacing;
+ mnLineSpacingTop = rParagraphObj.mnLineSpacingTop;
+ mnLineSpacingBottom = rParagraphObj.mnLineSpacingBottom;
+ mbFirstParagraph = rParagraphObj.mbFirstParagraph;
+ mbLastParagraph = rParagraphObj.mbLastParagraph;
+ mbParagraphPunctation = rParagraphObj.mbParagraphPunctation;
+ mbForbiddenRules = rParagraphObj.mbForbiddenRules;
+ mnBiDi = rParagraphObj.mnBiDi;
+
+ for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = rParagraphObj.begin(); it != rParagraphObj.end(); ++it )
+ mvPortions.push_back( std::make_unique<PortionObj>( **it ) );
+
+ maTabStop = rParagraphObj.maTabStop;
+ bExtendedParameters = rParagraphObj.bExtendedParameters;
+ nParaFlags = rParagraphObj.nParaFlags;
+ nBulletFlags = rParagraphObj.nBulletFlags;
+ sPrefix = rParagraphObj.sPrefix;
+ sSuffix = rParagraphObj.sSuffix;
+ sGraphicUrl = rParagraphObj.sGraphicUrl; // String to a graphic
+ aBuGraSize = rParagraphObj.aBuGraSize;
+ nNumberingType = rParagraphObj.nNumberingType; // this is actually a SvxEnum
+ nHorzAdjust = rParagraphObj.nHorzAdjust;
+ nBulletColor = rParagraphObj.nBulletColor;
+ nBulletOfs = rParagraphObj.nBulletOfs;
+ nStartWith = rParagraphObj.nStartWith; // start of numbering
+ nTextOfs = rParagraphObj.nTextOfs;
+ nBulletRealSize = rParagraphObj.nBulletRealSize; // scale in percent
+ nDepth = rParagraphObj.nDepth; // actual depth
+ cBulletId = rParagraphObj.cBulletId; // if Numbering Type == CharSpecial
+ aFontDesc = rParagraphObj.aFontDesc;
+
+ bExtendedBulletsUsed = rParagraphObj.bExtendedBulletsUsed;
+ nBulletId = rParagraphObj.nBulletId;
+}
+
+sal_uInt32 ParagraphObj::ImplCalculateTextPositions( sal_uInt32 nCurrentTextPosition )
+{
+ mnTextSize = 0;
+ for ( std::vector<std::unique_ptr<PortionObj> >::iterator it = mvPortions.begin(); it != mvPortions.end(); ++it )
+ mnTextSize += (*it)->ImplCalculateTextPositions( nCurrentTextPosition + mnTextSize );
+ return mnTextSize;
+}
+
+ParagraphObj& ParagraphObj::operator=( const ParagraphObj& rParagraphObj )
+{
+ if ( this != &rParagraphObj )
+ {
+ ImplClear();
+ ImplConstruct( rParagraphObj );
+ }
+ return *this;
+}
+
+struct ImplTextObj
+{
+ sal_uInt32 mnTextSize;
+ int mnInstance;
+ std::vector<std::unique_ptr<ParagraphObj>> maList;
+ bool mbHasExtendedBullets;
+
+ explicit ImplTextObj( int nInstance );
+};
+
+ImplTextObj::ImplTextObj( int nInstance )
+ : mnTextSize(0),
+ mnInstance(nInstance),
+ mbHasExtendedBullets(false)
+{
+}
+
+TextObj::TextObj( css::uno::Reference< css::text::XSimpleText > const & rXTextRef,
+ int nInstance, FontCollection& rFontCollection, PPTExBulletProvider& rProv ):
+ mpImplTextObj(std::make_shared<ImplTextObj>(nInstance))
+{
+ css::uno::Reference< css::container::XEnumerationAccess > aXTextParagraphEA( rXTextRef, css::uno::UNO_QUERY );
+
+ if ( aXTextParagraphEA.is() )
+ {
+ css::uno::Reference< css::container::XEnumeration > aXTextParagraphE( aXTextParagraphEA->createEnumeration() );
+ if ( aXTextParagraphE.is() )
+ {
+ ParaFlags aParaFlags;
+ while ( aXTextParagraphE->hasMoreElements() )
+ {
+ css::uno::Reference< css::text::XTextContent > aXParagraph;
+ css::uno::Any aAny( aXTextParagraphE->nextElement() );
+ if ( aAny >>= aXParagraph )
+ {
+ if ( !aXTextParagraphE->hasMoreElements() )
+ aParaFlags.bLastParagraph = true;
+ std::unique_ptr<ParagraphObj> pPara(new ParagraphObj( aXParagraph, aParaFlags, rFontCollection, rProv ));
+ mpImplTextObj->mbHasExtendedBullets |= pPara->bExtendedBulletsUsed;
+ mpImplTextObj->maList.push_back( std::move(pPara) );
+ aParaFlags.bFirstParagraph = false;
+ }
+ }
+ }
+ }
+ ImplCalculateTextPositions();
+}
+
+void TextObj::ImplCalculateTextPositions()
+{
+ mpImplTextObj->mnTextSize = 0;
+ for ( sal_uInt32 i = 0; i < ParagraphCount(); ++i )
+ mpImplTextObj->mnTextSize += GetParagraph(i)->ImplCalculateTextPositions( mpImplTextObj->mnTextSize );
+}
+
+ParagraphObj* TextObj::GetParagraph(int idx)
+{
+ return mpImplTextObj->maList[idx].get();
+}
+
+sal_uInt32 TextObj::ParagraphCount() const
+{
+ return mpImplTextObj->maList.size();
+}
+
+sal_uInt32 TextObj::Count() const
+{
+ return mpImplTextObj->mnTextSize;
+}
+
+int TextObj::GetInstance() const
+{
+ return mpImplTextObj->mnInstance;
+}
+
+bool TextObj::HasExtendedBullets() const
+{
+ return mpImplTextObj->mbHasExtendedBullets;
+}
+
+void FontCollectionEntry::ImplInit( const OUString& rName )
+{
+ OUString aSubstName( GetSubsFontName( rName, SubsFontFlags::ONLYONE | SubsFontFlags::MS ) );
+ if ( !aSubstName.isEmpty() )
+ {
+ Name = aSubstName;
+ }
+ else
+ {
+ Name = rName;
+ }
+}
+
+FontCollection::~FontCollection()
+{
+ pVDev.disposeAndClear();
+ xPPTBreakIter = nullptr;
+}
+
+FontCollection::FontCollection() :
+ pVDev ( nullptr )
+{
+ xPPTBreakIter = css::i18n::BreakIterator::create( ::comphelper::getProcessComponentContext() );
+}
+
+short FontCollection::GetScriptDirection( std::u16string_view rString )
+{
+ short nRet = ScriptTypeDetector::getScriptDirection( rString, 0, css::i18n::ScriptDirection::NEUTRAL );
+ return nRet;
+}
+
+sal_uInt32 FontCollection::GetId( FontCollectionEntry& rEntry )
+{
+ if( !rEntry.Name.isEmpty() )
+ {
+ const sal_uInt32 nFonts = maFonts.size();
+
+ for( sal_uInt32 i = 0; i < nFonts; i++ )
+ {
+ const FontCollectionEntry* pEntry = GetById( i );
+ if( pEntry->Name == rEntry.Name )
+ return i;
+ }
+ vcl::Font aFont;
+ aFont.SetCharSet( rEntry.CharSet );
+ aFont.SetFamilyName( rEntry.Original );
+ aFont.SetFontHeight( 100 );
+
+ if ( !pVDev )
+ pVDev = VclPtr<VirtualDevice>::Create();
+
+ pVDev->SetFont( aFont );
+ FontMetric aMetric( pVDev->GetFontMetric() );
+
+ sal_uInt16 nTxtHeight = static_cast<sal_uInt16>(aMetric.GetAscent()) + static_cast<sal_uInt16>(aMetric.GetDescent());
+
+ if ( nTxtHeight )
+ {
+ double fScaling = static_cast<double>(nTxtHeight) / 120.0;
+ if ( ( fScaling > 0.50 ) && ( fScaling < 1.5 ) )
+ rEntry.Scaling = fScaling;
+ }
+
+ maFonts.push_back(rEntry);
+ return nFonts;
+ }
+ return 0;
+}
+
+const FontCollectionEntry* FontCollection::GetById( sal_uInt32 nId )
+{
+ return nId < maFonts.size() ? &maFonts[nId] : nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/source/filter/eppt/text.hxx b/sd/source/filter/eppt/text.hxx
new file mode 100644
index 000000000..ee2fc537c
--- /dev/null
+++ b/sd/source/filter/eppt/text.hxx
@@ -0,0 +1,254 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "epptbase.hxx"
+
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <editeng/svxenum.hxx>
+#include <vector>
+#include <memory>
+
+namespace com::sun::star {
+ namespace awt { struct FontDescriptor; }
+ namespace beans { class XPropertyState; }
+ namespace text { class XTextRange; class XTextContent; class XSimpleText; }
+ namespace style { struct TabStop; }
+}
+
+struct SOParagraph
+{
+ bool bExtendedParameters;
+ sal_uInt32 nParaFlags;
+ sal_Int16 nBulletFlags;
+ OUString sPrefix;
+ OUString sSuffix;
+ OUString sGraphicUrl; // String to a graphic
+ Size aBuGraSize;
+ SvxNumType nNumberingType;
+ sal_uInt32 nHorzAdjust;
+ sal_uInt32 nBulletColor;
+ sal_Int32 nBulletOfs;
+ sal_Int16 nStartWith; // start of numbering
+ sal_Int16 nTextOfs;
+ sal_Int16 nBulletRealSize; // scale in percent
+ sal_Int16 nDepth; // actual depth
+ sal_Unicode cBulletId; // if Numbering Type == CharSpecial
+ css::awt::FontDescriptor aFontDesc;
+
+ bool bExtendedBulletsUsed;
+ sal_uInt16 nBulletId;
+ sal_uInt32 nMappedNumType;
+ bool bNumberingIsNumber;
+
+ SOParagraph()
+ : bExtendedParameters(false)
+ , nParaFlags(0)
+ , nBulletFlags(0)
+ , nNumberingType(SVX_NUM_NUMBER_NONE)
+ , nHorzAdjust(0)
+ , nBulletColor(0)
+ , nBulletOfs(0)
+ , nStartWith(0)
+ , nTextOfs(0)
+ , nBulletRealSize(0)
+ , nDepth(0)
+ , cBulletId(0)
+ , bExtendedBulletsUsed(false)
+ , nBulletId(0xffff)
+ , nMappedNumType(0)
+ , bNumberingIsNumber(true)
+ {
+ }
+};
+
+class PropStateValue : public PropValue
+{
+public:
+ PropStateValue()
+ : PropValue()
+ , ePropState(css::beans::PropertyState_AMBIGUOUS_VALUE)
+ {
+ }
+protected:
+ css::beans::PropertyState ePropState;
+ css::uno::Reference < css::beans::XPropertyState > mXPropState;
+
+ bool ImplGetPropertyValue( const OUString& rString, bool bGetPropertyState );
+};
+
+struct FieldEntry
+{
+ sal_uInt32 nFieldType;
+ sal_uInt32 nFieldStartPos;
+ sal_uInt32 nFieldEndPos;
+ OUString aRepresentation;
+ OUString aFieldUrl;
+
+ FieldEntry( sal_uInt32 nType, sal_uInt32 nStart, sal_uInt32 nEnd )
+ : nFieldType(nType),
+ nFieldStartPos(nStart),
+ nFieldEndPos(nEnd)
+ {
+ }
+};
+
+class PortionObj final : public PropStateValue
+{
+
+ friend class ParagraphObj;
+
+ void ImplClear();
+ void ImplConstruct( const PortionObj& rPortionObj );
+ static sal_uInt32 ImplGetTextField( css::uno::Reference< css::text::XTextRange > & rXTextRangeRef,
+ const css::uno::Reference< css::beans::XPropertySet > & rXPropSetRef, OUString& rURL );
+ sal_uInt32 ImplCalculateTextPositions( sal_uInt32 nCurrentTextPosition );
+ void ImplGetPortionValues( FontCollection& rFontCollection, bool bGetPropStateValue );
+
+ public:
+
+ css::beans::PropertyState meCharColor;
+ css::beans::PropertyState meCharHeight;
+ css::beans::PropertyState meFontName;
+ css::beans::PropertyState meAsianOrComplexFont;
+ css::beans::PropertyState meCharEscapement;
+ css::lang::Locale meCharLocale;
+ sal_uInt16 mnCharAttrHard;
+
+ sal_uInt32 mnCharColor;
+ sal_uInt16 mnCharAttr;
+ sal_uInt16 mnCharHeight;
+ sal_uInt16 mnFont;
+ sal_uInt16 mnAsianOrComplexFont;
+ sal_Int16 mnCharEscapement;
+
+ sal_uInt32 mnTextSize;
+ bool mbLastPortion;
+
+ std::unique_ptr<sal_uInt16[]> mpText;
+ std::unique_ptr<FieldEntry> mpFieldEntry;
+
+ PortionObj( css::uno::Reference< css::text::XTextRange > & rXTextRangeRef,
+ bool bLast, FontCollection& rFontCollection );
+ PortionObj( const css::uno::Reference< css::beans::XPropertySet > & rXPropSetRef,
+ FontCollection& rFontCollection );
+ PortionObj( const PortionObj& rPortionObj );
+ ~PortionObj();
+
+ void Write( SvStream* pStrm, bool bLast );
+ sal_uInt32 Count() const { return mnTextSize; };
+
+ PortionObj& operator=( const PortionObj& rPortionObj );
+};
+
+struct ParaFlags
+{
+ bool bFirstParagraph : 1;
+ bool bLastParagraph : 1;
+
+ ParaFlags() { bFirstParagraph = true; bLastParagraph = false; };
+};
+
+class ParagraphObj : public PropStateValue, public SOParagraph
+{
+ friend class TextObj;
+ friend struct PPTExParaSheet;
+
+ std::vector<std::unique_ptr<PortionObj> > mvPortions;
+
+ protected:
+
+ void ImplConstruct( const ParagraphObj& rParagraphObj );
+ void ImplClear();
+ sal_uInt32 ImplCalculateTextPositions( sal_uInt32 nCurrentTextPosition );
+ void ImplGetParagraphValues( PPTExBulletProvider* pBuProv, bool bGetPropStateValue );
+ void ImplGetNumberingLevel( PPTExBulletProvider* pBuProv, sal_Int16 nDepth, bool bIsBullet, bool bGetPropStateValue );
+
+ public:
+
+ css::uno::Sequence< css::style::TabStop > maTabStop;
+
+ sal_uInt32 mnTextSize;
+
+ bool mbIsBullet;
+ bool mbFirstParagraph;
+ bool mbLastParagraph;
+
+ css::beans::PropertyState meBullet;
+ css::beans::PropertyState meTextAdjust;
+ css::beans::PropertyState meLineSpacing;
+ css::beans::PropertyState meLineSpacingTop;
+ css::beans::PropertyState meLineSpacingBottom;
+ css::beans::PropertyState meForbiddenRules;
+ css::beans::PropertyState meParagraphPunctation;
+ css::beans::PropertyState meBiDi;
+
+ sal_uInt16 mnTextAdjust;
+ sal_Int16 mnLineSpacing;
+ bool mbFixedLineSpacing;
+ sal_Int16 mnLineSpacingTop;
+ sal_Int16 mnLineSpacingBottom;
+ bool mbForbiddenRules;
+ bool mbParagraphPunctation;
+ sal_uInt16 mnBiDi;
+
+ ParagraphObj( css::uno::Reference< css::text::XTextContent > const & rXTextContentRef,
+ ParaFlags, FontCollection& rFontCollection,
+ PPTExBulletProvider& rBuProv );
+ ParagraphObj( const ParagraphObj& rParargraphObj ) = delete;
+ ParagraphObj( const css::uno::Reference< css::beans::XPropertySet > & rXPropSetRef,
+ PPTExBulletProvider* pBuProv );
+
+ bool empty() const { return mvPortions.empty(); }
+
+ const PortionObj& front() const { return *mvPortions.front(); }
+
+ std::vector<std::unique_ptr<PortionObj> >::const_iterator begin() const { return mvPortions.begin(); }
+ std::vector<std::unique_ptr<PortionObj> >::const_iterator end() const { return mvPortions.end(); }
+
+ void CalculateGraphicBulletSize( sal_uInt16 nFontHeight );
+ ~ParagraphObj();
+
+ void Write( SvStream* pStrm );
+ sal_uInt32 CharacterCount() const { return mnTextSize; };
+
+ ParagraphObj& operator=( const ParagraphObj& rParagraphObj );
+};
+
+struct ImplTextObj;
+
+class TextObj
+{
+ std::shared_ptr<ImplTextObj> mpImplTextObj;
+ void ImplCalculateTextPositions();
+
+public:
+ TextObj( css::uno::Reference< css::text::XSimpleText > const &
+ rXText, int nInstance, FontCollection& rFontCollection, PPTExBulletProvider& rBuProv );
+
+ ParagraphObj* GetParagraph(int idx);
+ sal_uInt32 ParagraphCount() const;
+ sal_uInt32 Count() const;
+ int GetInstance() const;
+ bool HasExtendedBullets() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */