nss: upgrade to release 3.73
[LibreOffice.git] / sd / source / filter / eppt / epptso.cxx
blob0c5ab79f3c82e29ec89c3e1a6b5c51ebf0429e3f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include <sal/config.h>
23 #include <basegfx/numeric/ftools.hxx>
24 #include <o3tl/any.hxx>
25 #include "eppt.hxx"
26 #include "text.hxx"
27 #include "epptdef.hxx"
28 #include "escherex.hxx"
29 #include <tools/poly.hxx>
30 #include <tools/stream.hxx>
31 #include <tools/fontenum.hxx>
32 #include <tools/UnitConversion.hxx>
33 #include <sot/storage.hxx>
34 #include <vcl/graph.hxx>
35 #include <editeng/svxenum.hxx>
36 #include <svx/svdobj.hxx>
37 #include <svx/unoapi.hxx>
38 #include <com/sun/star/awt/FontFamily.hpp>
39 #include <com/sun/star/awt/FontPitch.hpp>
40 #include <com/sun/star/awt/Rectangle.hpp>
41 #include <com/sun/star/awt/FontDescriptor.hpp>
42 #include <com/sun/star/frame/XModel.hpp>
43 #include <com/sun/star/style/TabStop.hpp>
44 #include <com/sun/star/drawing/CircleKind.hpp>
45 #include <com/sun/star/drawing/FillStyle.hpp>
46 #include <com/sun/star/beans/XPropertyState.hpp>
47 #include <com/sun/star/drawing/XControlShape.hpp>
48 #include <com/sun/star/embed/Aspects.hpp>
49 #include <tools/urlobj.hxx>
50 #include <com/sun/star/text/XSimpleText.hpp>
51 #include <com/sun/star/task/XStatusIndicator.hpp>
52 #include <com/sun/star/table/XTable.hpp>
53 #include <com/sun/star/table/XMergeableCell.hpp>
54 #include <com/sun/star/table/BorderLine.hpp>
55 #include <com/sun/star/table/XColumnRowRange.hpp>
56 #include <com/sun/star/table/XCellRange.hpp>
57 #include <oox/ole/olehelper.hxx>
58 #include <i18nlangtag/languagetag.hxx>
60 using namespace ::com::sun::star;
62 #define ANSI_CHARSET 0
63 #define SYMBOL_CHARSET 2
65 /* Font Families */
66 #define FF_ROMAN 0x10
67 #define FF_SWISS 0x20
68 #define FF_MODERN 0x30
69 #define FF_SCRIPT 0x40
70 #define FF_DECORATIVE 0x50
72 #define DEFAULT_PITCH 0x00
73 #define FIXED_PITCH 0x01
75 PPTExBulletProvider::PPTExBulletProvider()
76 : pGraphicProv( new EscherGraphicProvider( EscherGraphicProviderFlags::UseInstances ) )
80 PPTExBulletProvider::~PPTExBulletProvider()
84 sal_uInt16 PPTExBulletProvider::GetId(Graphic const & rGraphic, Size& rGraphicSize )
86 sal_uInt16 nRetValue = 0xffff;
88 if (!rGraphic.IsNone())
90 Graphic aMappedGraphic, aGraphic(rGraphic);
91 std::unique_ptr<GraphicObject> xGraphicObject(new GraphicObject(aGraphic));
92 Size aPrefSize( aGraphic.GetPrefSize() );
93 BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
95 if ( rGraphicSize.Width() && rGraphicSize.Height() )
97 if (aPrefSize.IsEmpty())
99 aBmpEx.Scale(aPrefSize);
101 else
103 double fQ1 = static_cast<double>(aPrefSize.Width()) / static_cast<double>(aPrefSize.Height());
104 double fQ2 = static_cast<double>(rGraphicSize.Width()) / static_cast<double>(rGraphicSize.Height());
105 double fXScale = 1;
106 double fYScale = 1;
108 if ( fQ1 > fQ2 )
109 fYScale = fQ1 / fQ2;
110 else if ( fQ1 < fQ2 )
111 fXScale = fQ2 / fQ1;
113 if ( ( fXScale != 1.0 ) || ( fYScale != 1.0 ) )
115 aBmpEx.Scale( fXScale, fYScale );
116 rGraphicSize = Size( static_cast<sal_Int32>(static_cast<double>(rGraphicSize.Width()) / fXScale + 0.5 ),
117 static_cast<sal_Int32>(static_cast<double>(rGraphicSize.Height()) / fYScale + 0.5 ) );
119 aMappedGraphic = Graphic( aBmpEx );
120 xGraphicObject.reset(new GraphicObject(aMappedGraphic));
124 sal_uInt32 nId = pGraphicProv->GetBlibID(aBuExPictureStream, *xGraphicObject);
126 if ( nId && ( nId < 0x10000 ) )
127 nRetValue = static_cast<sal_uInt16>(nId) - 1;
129 return nRetValue;
132 sal_uInt32 PPTWriter::ImplVBAInfoContainer( SvStream* pStrm )
134 sal_uInt32 nSize = 28;
135 if ( pStrm )
137 pStrm->WriteUInt32( 0x1f | ( EPP_VBAInfo << 16 ) )
138 .WriteUInt32( nSize - 8 )
139 .WriteUInt32( 2 | ( EPP_VBAInfoAtom << 16 ) )
140 .WriteUInt32( 12 );
141 mpPptEscherEx->InsertPersistOffset( EPP_Persist_VBAInfoAtom, pStrm->Tell() );
142 pStrm->WriteUInt32( 0 )
143 .WriteUInt32( 0 )
144 .WriteUInt32( 1 );
146 return nSize;
149 sal_uInt32 PPTWriter::ImplSlideViewInfoContainer( sal_uInt32 nInstance, SvStream* pStrm )
151 sal_uInt32 nSize = 111;
152 if ( pStrm )
154 sal_uInt8 bShowGuides = 0;
155 sal_uInt8 const bSnapToGrid = 1;
156 sal_uInt8 const bSnapToShape = 0;
158 sal_Int32 nScaling = 85;
159 sal_Int32 nMasterCoordinate = 0xdda;
160 sal_Int32 nXOrigin = -780;
161 sal_Int32 nYOrigin = -84;
163 sal_Int32 nPosition1 = 0x870;
164 sal_Int32 nPosition2 = 0xb40;
166 if ( nInstance )
168 bShowGuides = 1;
169 nScaling = 0x3b;
170 nMasterCoordinate = 0xf0c;
171 nXOrigin = -1752;
172 nYOrigin = -72;
173 nPosition1 = 0xb40;
174 nPosition2 = 0x870;
176 pStrm->WriteUInt32( 0xf | ( EPP_SlideViewInfo << 16 ) | ( nInstance << 4 ) )
177 .WriteUInt32( nSize - 8 )
178 .WriteUInt32( EPP_SlideViewInfoAtom << 16 ).WriteUInt32( 3 )
179 .WriteUChar( bShowGuides ).WriteUChar( bSnapToGrid ).WriteUChar( bSnapToShape )
180 .WriteUInt32( EPP_ViewInfoAtom << 16 ).WriteUInt32( 52 )
181 .WriteInt32( nScaling ).WriteInt32( 100 ).WriteInt32( nScaling ).WriteInt32( 100 ) // scaling atom - Keeps the current scale
182 .WriteInt32( nScaling ).WriteInt32( 100 ).WriteInt32( nScaling ).WriteInt32( 100 ) // scaling atom - Keeps the previous scale
183 .WriteInt32( 0x17ac ).WriteInt32( nMasterCoordinate )// Origin - Keeps the origin in master coordinates
184 .WriteInt32( nXOrigin ).WriteInt32( nYOrigin ) // Origin
185 .WriteUChar( 1 ) // Bool1 varScale - Set if zoom to fit is set
186 .WriteUChar( 0 ) // bool1 draftMode - Not used
187 .WriteUInt16( 0 ) // padword
188 .WriteUInt32( ( 7 << 4 ) | ( EPP_GuideAtom << 16 ) ).WriteUInt32( 8 )
189 .WriteUInt32( 0 ) // Type of the guide. If the guide is horizontal this value is zero. If it's vertical, it's one.
190 .WriteInt32( nPosition1 ) // Position of the guide in master coordinates. X coordinate if it's vertical, and Y coordinate if it's horizontal.
191 .WriteUInt32( ( 7 << 4 ) | ( EPP_GuideAtom << 16 ) ).WriteUInt32( 8 )
192 .WriteInt32( 1 ) // Type of the guide. If the guide is horizontal this value is zero. If it's vertical, it's one.
193 .WriteInt32( nPosition2 ); // Position of the guide in master coordinates. X coordinate if it's vertical, and Y coordinate if it's horizontal.
195 return nSize;
198 sal_uInt32 PPTWriter::ImplOutlineViewInfoContainer( SvStream* pStrm )
200 sal_uInt32 nSize = 68;
201 if ( pStrm )
203 pStrm->WriteUInt32( 0xf | ( EPP_OutlineViewInfo << 16 ) ).WriteUInt32( nSize - 8 )
204 .WriteUInt32( EPP_ViewInfoAtom << 16 ).WriteUInt32( 52 )
205 .WriteInt32( 170 ).WriteInt32( 200 ).WriteInt32( 170 ).WriteInt32( 200 ) // scaling atom - Keeps the current scale
206 .WriteInt32( 170 ).WriteInt32( 200 ).WriteInt32( 170 ).WriteInt32( 200 ) // scaling atom - Keeps the previous scale
207 .WriteInt32( 0x17ac ).WriteInt32( 0xdda ) // Origin - Keeps the origin in master coordinates
208 .WriteInt32( -780 ).WriteInt32( -84 ) // Origin
209 .WriteUChar( 1 ) // bool1 varScale - Set if zoom to fit is set
210 .WriteUChar( 0 ) // bool1 draftMode - Not used
211 .WriteUInt16( 0 ); // padword
213 return nSize;
216 sal_uInt32 PPTWriter::ImplProgBinaryTag( SvStream* pStrm )
218 sal_uInt32 nPictureStreamSize, nOutlineStreamSize, nSize = 8;
220 nPictureStreamSize = aBuExPictureStream.Tell();
221 if ( nPictureStreamSize )
222 nSize += nPictureStreamSize + 8;
224 nOutlineStreamSize = aBuExOutlineStream.Tell();
225 if ( nOutlineStreamSize )
226 nSize += nOutlineStreamSize + 8;
228 if ( pStrm )
230 pStrm->WriteUInt32( EPP_BinaryTagData << 16 ).WriteUInt32( nSize - 8 );
231 if ( nPictureStreamSize )
233 pStrm->WriteUInt32( 0xf | ( EPP_PST_ExtendedBuGraContainer << 16 ) ).WriteUInt32( nPictureStreamSize );
234 pStrm->WriteBytes(aBuExPictureStream.GetData(), nPictureStreamSize);
236 if ( nOutlineStreamSize )
238 pStrm->WriteUInt32( 0xf | ( EPP_PST_ExtendedPresRuleContainer << 16 ) ).WriteUInt32( nOutlineStreamSize );
239 pStrm->WriteBytes(aBuExOutlineStream.GetData(), nOutlineStreamSize);
242 return nSize;
245 sal_uInt32 PPTWriter::ImplProgBinaryTagContainer( SvStream* pStrm, SvMemoryStream* pBinTagStrm )
247 sal_uInt32 nSize = 8 + 8 + 14;
248 if ( pStrm )
250 pStrm->WriteUInt32( 0xf | ( EPP_ProgBinaryTag << 16 ) ).WriteUInt32( 0 )
251 .WriteUInt32( EPP_CString << 16 ).WriteUInt32( 14 )
252 .WriteUInt32( 0x5f005f ).WriteUInt32( 0x50005f )
253 .WriteUInt32( 0x540050 ).WriteUInt16( 0x39 );
255 if ( pStrm && pBinTagStrm )
257 sal_uInt32 nLen = pBinTagStrm->Tell();
258 nSize += nLen + 8;
259 pStrm->WriteUInt32( EPP_BinaryTagData << 16 ).WriteUInt32( nLen );
260 pStrm->WriteBytes(pBinTagStrm->GetData(), nLen);
262 else
263 nSize += ImplProgBinaryTag( pStrm );
265 if ( pStrm )
267 pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
268 pStrm->WriteUInt32( nSize - 8 );
269 pStrm->SeekRel( nSize - 8 );
271 return nSize;
274 sal_uInt32 PPTWriter::ImplProgTagContainer( SvStream* pStrm, SvMemoryStream* pBinTagStrm )
276 sal_uInt32 nSize = 0;
277 if ( aBuExPictureStream.Tell() || aBuExOutlineStream.Tell() || pBinTagStrm )
279 nSize = 8;
280 if ( pStrm )
282 pStrm->WriteUInt32( 0xf | ( EPP_ProgTags << 16 ) ).WriteUInt32( 0 );
284 nSize += ImplProgBinaryTagContainer( pStrm, pBinTagStrm );
285 if ( pStrm )
287 pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
288 pStrm->WriteUInt32( nSize - 8 );
289 pStrm->SeekRel( nSize - 8 );
292 return nSize;
295 sal_uInt32 PPTWriter::ImplDocumentListContainer( SvStream* pStrm )
297 sal_uInt32 nSize = 8;
298 if ( pStrm )
300 pStrm->WriteUInt32( ( EPP_List << 16 ) | 0xf ).WriteUInt32( 0 );
303 nSize += ImplVBAInfoContainer( pStrm );
304 nSize += ImplSlideViewInfoContainer( 0, pStrm );
305 nSize += ImplOutlineViewInfoContainer( pStrm );
306 nSize += ImplSlideViewInfoContainer( 1, pStrm );
307 nSize += ImplProgTagContainer( pStrm );
309 if ( pStrm )
311 pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
312 pStrm->WriteUInt32( nSize - 8 );
313 pStrm->SeekRel( nSize - 8 );
315 return nSize;
318 sal_uInt32 PPTWriter::ImplMasterSlideListContainer( SvStream* pStrm )
320 sal_uInt32 i, nSize = 28 * mnMasterPages + 8;
321 if ( pStrm )
323 pStrm->WriteUInt32( 0x1f | ( EPP_SlideListWithText << 16 ) ).WriteUInt32( nSize - 8 );
325 for ( i = 0; i < mnMasterPages; i++ )
327 pStrm->WriteUInt32( EPP_SlidePersistAtom << 16 ).WriteUInt32( 20 );
328 mpPptEscherEx->InsertPersistOffset( EPP_MAINMASTER_PERSIST_KEY | i, pStrm->Tell() );
329 pStrm->WriteUInt32( 0 ) // psrReference - logical reference to the slide persist object ( EPP_MAINMASTER_PERSIST_KEY )
330 .WriteUInt32( 0 ) // flags - only bit 3 used, if set then slide contains shapes other than placeholders
331 .WriteInt32( 0 ) // numberTexts - number of placeholder texts stored with the persist object. Allows to display outline view without loading the slide persist objects
332 .WriteInt32( 0x80000000 | i ) // slideId - Unique slide identifier, used for OLE link monikers for example
333 .WriteUInt32( 0 ); // reserved, usually 0
336 return nSize;
339 sal_uInt32 PPTWriter::ImplInsertBookmarkURL( const OUString& rBookmarkURL, const sal_uInt32 nType,
340 const OUString& rStringVer0, const OUString& rStringVer1, const OUString& rStringVer2, const OUString& rStringVer3 )
342 sal_uInt32 nHyperId = ++mnExEmbed;
344 OUString sBookmarkURL( rBookmarkURL );
345 INetURLObject aBaseURI( maBaseURI );
346 INetURLObject aBookmarkURI( rBookmarkURL );
347 if( aBaseURI.GetProtocol() == aBookmarkURI.GetProtocol() )
349 OUString aRelUrl( INetURLObject::GetRelURL( maBaseURI, rBookmarkURL ) );
350 if ( !aRelUrl.isEmpty() )
351 sBookmarkURL = aRelUrl;
353 maHyperlink.emplace_back( sBookmarkURL, nType );
355 mpExEmbed->WriteUInt16( 0xf )
356 .WriteUInt16( EPP_ExHyperlink )
357 .WriteUInt32( 0 );
358 sal_uInt32 nHyperSize, nHyperStart = mpExEmbed->Tell();
359 mpExEmbed->WriteUInt16( 0 )
360 .WriteUInt16( EPP_ExHyperlinkAtom )
361 .WriteUInt32( 4 )
362 .WriteUInt32( nHyperId );
364 PPTWriter::WriteCString( *mpExEmbed, rStringVer0 );
365 PPTWriter::WriteCString( *mpExEmbed, rStringVer1, 1 );
366 PPTWriter::WriteCString( *mpExEmbed, rStringVer2, 2 );
367 PPTWriter::WriteCString( *mpExEmbed, rStringVer3, 3 );
369 nHyperSize = mpExEmbed->Tell() - nHyperStart;
370 mpExEmbed->SeekRel( - ( static_cast<sal_Int32>(nHyperSize) + 4 ) );
371 mpExEmbed->WriteUInt32( nHyperSize );
372 mpExEmbed->SeekRel( nHyperSize );
373 return nHyperId;
376 bool PPTWriter::ImplCloseDocument()
378 sal_uInt32 nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_Document );
379 if ( nOfs )
381 mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_CurrentPos, mpStrm->Tell() );
382 mpStrm->Seek( nOfs );
384 // creating the TxMasterStyleAtom
385 SvMemoryStream aTxMasterStyleAtomStrm( 0x200, 0x200 );
387 EscherExAtom aTxMasterStyleAtom( aTxMasterStyleAtomStrm, EPP_TxMasterStyleAtom, EPP_TEXTTYPE_Other );
388 aTxMasterStyleAtomStrm.WriteUInt16( 5 ); // paragraph count
389 sal_uInt16 nLev;
390 for ( nLev = 0; nLev < 5; nLev++ )
392 mpStyleSheet->mpParaSheet[ EPP_TEXTTYPE_Other ]->Write( aTxMasterStyleAtomStrm, nLev, false, mXPagePropSet );
393 mpStyleSheet->mpCharSheet[ EPP_TEXTTYPE_Other ]->Write( aTxMasterStyleAtomStrm, nLev, false, mXPagePropSet );
397 sal_uInt32 nExEmbedSize = mpExEmbed->TellEnd();
399 // nEnvironment : whole size of the environment container
400 sal_uInt32 nEnvironment = maFontCollection.GetCount() * 76 // 68 bytes per Fontenityatom and 8 Bytes per header
401 + 8 // 1 FontCollection container
402 + 20 // SrKinsoku container
403 + 18 // 1 TxSiStyleAtom
404 + aTxMasterStyleAtomStrm.Tell() // 1 TxMasterStyleAtom;
405 + PPTExStyleSheet::SizeOfTxCFStyleAtom();
407 sal_uInt32 nBytesToInsert = nEnvironment + 8;
409 if ( nExEmbedSize )
410 nBytesToInsert += nExEmbedSize + 8 + 12;
412 nBytesToInsert += maSoundCollection.GetSize();
413 nBytesToInsert += mpPptEscherEx->DrawingGroupContainerSize();
414 nBytesToInsert += ImplMasterSlideListContainer(nullptr);
415 nBytesToInsert += ImplDocumentListContainer(nullptr);
417 // insert nBytes into stream and adjust depending container
418 mpPptEscherEx->InsertAtCurrentPos( nBytesToInsert );
420 // CREATE HYPERLINK CONTAINER
421 if ( nExEmbedSize )
423 mpStrm->WriteUInt16( 0xf )
424 .WriteUInt16( EPP_ExObjList )
425 .WriteUInt32( nExEmbedSize + 12 )
426 .WriteUInt16( 0 )
427 .WriteUInt16( EPP_ExObjListAtom )
428 .WriteUInt32( 4 )
429 .WriteUInt32( mnExEmbed );
430 mpPptEscherEx->InsertPersistOffset( EPP_Persist_ExObj, mpStrm->Tell() );
431 mpStrm->WriteBytes(mpExEmbed->GetData(), nExEmbedSize);
434 // CREATE ENVIRONMENT
435 mpStrm->WriteUInt16( 0xf ).WriteUInt16( EPP_Environment ).WriteUInt32( nEnvironment );
437 // Open Container ( EPP_SrKinsoku )
438 mpStrm->WriteUInt16( 0x2f ).WriteUInt16( EPP_SrKinsoku ).WriteUInt32( 12 );
439 mpPptEscherEx->AddAtom( 4, EPP_SrKinsokuAtom, 0, 3 );
440 mpStrm->WriteInt32( 0 ); // SrKinsoku Level 0
442 // Open Container ( EPP_FontCollection )
443 mpStrm->WriteUInt16( 0xf ).WriteUInt16( EPP_FontCollection ).WriteUInt32( maFontCollection.GetCount() * 76 );
445 for ( sal_uInt32 i = 0; i < maFontCollection.GetCount(); i++ )
447 mpPptEscherEx->AddAtom( 68, EPP_FontEnityAtom, 0, i );
448 const FontCollectionEntry* pDesc = maFontCollection.GetById( i );
449 sal_Int32 nFontLen = pDesc->Name.getLength();
450 if ( nFontLen > 31 )
451 nFontLen = 31;
452 for ( sal_Int32 n = 0; n < 32; n++ )
454 sal_Unicode nUniCode = 0;
455 if ( n < nFontLen )
456 nUniCode = pDesc->Name[n];
457 mpStrm->WriteUInt16( nUniCode );
459 sal_uInt8 lfCharSet = ANSI_CHARSET;
460 sal_uInt8 const lfClipPrecision = 0;
461 sal_uInt8 const lfQuality = 6;
462 sal_uInt8 lfPitchAndFamily = 0;
464 if ( pDesc->CharSet == RTL_TEXTENCODING_SYMBOL )
465 lfCharSet = SYMBOL_CHARSET;
467 switch( pDesc->Family )
469 case css::awt::FontFamily::ROMAN :
470 lfPitchAndFamily |= FF_ROMAN;
471 break;
473 case css::awt::FontFamily::SWISS :
474 lfPitchAndFamily |= FF_SWISS;
475 break;
477 case css::awt::FontFamily::MODERN :
478 lfPitchAndFamily |= FF_MODERN;
479 break;
481 case css::awt::FontFamily::SCRIPT:
482 lfPitchAndFamily |= FF_SCRIPT;
483 break;
485 case css::awt::FontFamily::DECORATIVE:
486 lfPitchAndFamily |= FF_DECORATIVE;
487 break;
489 default:
490 lfPitchAndFamily |= FAMILY_DONTKNOW;
491 break;
493 switch( pDesc->Pitch )
495 case css::awt::FontPitch::FIXED:
496 lfPitchAndFamily |= FIXED_PITCH;
497 break;
499 default:
500 lfPitchAndFamily |= DEFAULT_PITCH;
501 break;
503 mpStrm->WriteUChar( lfCharSet )
504 .WriteUChar( lfClipPrecision )
505 .WriteUChar( lfQuality )
506 .WriteUChar( lfPitchAndFamily );
508 mpStyleSheet->WriteTxCFStyleAtom( *mpStrm ); // create style that is used for new standard objects
509 mpPptEscherEx->AddAtom( 10, EPP_TxSIStyleAtom );
510 mpStrm->WriteUInt32( 7 ) // ?
511 .WriteInt16( 2 ) // ?
512 .WriteUChar( 9 ) // ?
513 .WriteUChar( 8 ) // ?
514 .WriteInt16( 0 ); // ?
516 mpStrm->WriteBytes(aTxMasterStyleAtomStrm.GetData(), aTxMasterStyleAtomStrm.Tell());
517 maSoundCollection.Write( *mpStrm );
518 mpPptEscherEx->WriteDrawingGroupContainer( *mpStrm );
519 ImplMasterSlideListContainer( mpStrm.get() );
520 ImplDocumentListContainer( mpStrm.get() );
522 sal_uInt32 nOldPos = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_CurrentPos );
523 if ( nOldPos )
525 mpStrm->Seek( nOldPos );
526 return true;
529 return false;
532 bool PropValue::GetPropertyValue(
533 css::uno::Any& rAny,
534 const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
535 const OUString& rString,
536 bool bTestPropertyAvailability )
538 bool bRetValue = true;
539 if ( bTestPropertyAvailability )
541 bRetValue = false;
544 css::uno::Reference< css::beans::XPropertySetInfo > aXPropSetInfo( rXPropSet->getPropertySetInfo() );
545 if ( aXPropSetInfo.is() )
546 bRetValue = aXPropSetInfo->hasPropertyByName( rString );
548 catch( css::uno::Exception& )
550 bRetValue = false;
553 if ( bRetValue )
557 rAny = rXPropSet->getPropertyValue( rString );
558 if ( !rAny.hasValue() )
559 bRetValue = false;
561 catch( css::uno::Exception& )
563 bRetValue = false;
566 return bRetValue;
569 css::beans::PropertyState PropValue::GetPropertyState(
570 const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
571 const OUString& rPropertyName )
573 css::beans::PropertyState eRetValue = css::beans::PropertyState_AMBIGUOUS_VALUE;
576 css::uno::Reference< css::beans::XPropertyState > aXPropState( rXPropSet, css::uno::UNO_QUERY );
577 if ( aXPropState.is() )
578 eRetValue = aXPropState->getPropertyState( rPropertyName );
580 catch( css::uno::Exception& )
584 return eRetValue;
587 bool PropValue::ImplGetPropertyValue( const OUString& rString )
589 return GetPropertyValue( mAny, mXPropSet, rString );
592 bool PropValue::ImplGetPropertyValue( const css::uno::Reference< css::beans::XPropertySet > & aXPropSet, const OUString& rString )
594 return GetPropertyValue( mAny, aXPropSet, rString );
597 bool PropStateValue::ImplGetPropertyValue( const OUString& rString, bool bGetPropertyState )
599 ePropState = css::beans::PropertyState_AMBIGUOUS_VALUE;
600 bool bRetValue = true;
601 #ifdef UNX
602 css::uno::Reference< css::beans::XPropertySetInfo >
603 aXPropSetInfo( mXPropSet->getPropertySetInfo() );
604 if ( !aXPropSetInfo.is() )
605 return false;
606 #endif
609 mAny = mXPropSet->getPropertyValue( rString );
610 if ( !mAny.hasValue() )
611 bRetValue = false;
612 else if ( bGetPropertyState )
613 ePropState = mXPropState->getPropertyState( rString );
614 else
615 ePropState = css::beans::PropertyState_DIRECT_VALUE;
617 catch( css::uno::Exception& )
619 bRetValue = false;
621 return bRetValue;
624 void PPTWriter::ImplWriteParagraphs( SvStream& rOut, TextObj& rTextObj )
626 bool bFirstParagraph = true;
627 sal_uInt32 nCharCount;
628 sal_uInt32 nPropertyFlags = 0;
629 sal_Int16 nLineSpacing;
630 int nInstance = rTextObj.GetInstance();
632 for ( sal_uInt32 i = 0; i < rTextObj.ParagraphCount(); ++i, bFirstParagraph = false )
634 ParagraphObj* pPara = rTextObj.GetParagraph(i);
635 const PortionObj& rPortion = pPara->front();
636 nCharCount = pPara->CharacterCount();
638 if ( ( pPara->meTextAdjust == css::beans::PropertyState_DIRECT_VALUE ) ||
639 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_Adjust, pPara->mnTextAdjust ) ) )
640 nPropertyFlags |= 0x00000800;
641 nLineSpacing = pPara->mnLineSpacing;
643 const FontCollectionEntry* pDesc = maFontCollection.GetById( rPortion.mnFont );
644 sal_Int16 nNormalSpacing = 100;
645 if ( !mbFontIndependentLineSpacing && pDesc )
647 double fN = 100.0;
648 fN *= pDesc->Scaling;
649 nNormalSpacing = static_cast<sal_Int16>( fN + 0.5 );
651 if ( !mbFontIndependentLineSpacing && bFirstParagraph && ( nLineSpacing > nNormalSpacing ) ) // sj: i28747, no replacement for fixed linespacing
653 nLineSpacing = nNormalSpacing;
654 nPropertyFlags |= 0x00001000;
656 else
658 if ( nLineSpacing > 0 )
660 if ( !mbFontIndependentLineSpacing && pDesc )
661 nLineSpacing = static_cast<sal_Int16>( static_cast<double>(nLineSpacing) * pDesc->Scaling + 0.5 );
663 else
665 if ( !pPara->mbFixedLineSpacing && rPortion.mnCharHeight > static_cast<sal_uInt16>( static_cast<double>(-nLineSpacing) * 0.001 * 72.0 / 2.54 ) ) // 1/100mm to point
666 nLineSpacing = nNormalSpacing;
667 else
668 nLineSpacing = static_cast<sal_Int16>( convertMm100ToMasterUnit(nLineSpacing) );
670 if ( ( pPara->meLineSpacing == css::beans::PropertyState_DIRECT_VALUE ) ||
671 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_LineFeed, nLineSpacing ) ) )
672 nPropertyFlags |= 0x00001000;
674 if ( ( pPara->meLineSpacingTop == css::beans::PropertyState_DIRECT_VALUE ) ||
675 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_UpperDist, pPara->mnLineSpacingTop ) ) )
676 nPropertyFlags |= 0x00002000;
677 if ( ( pPara->meLineSpacingBottom == css::beans::PropertyState_DIRECT_VALUE ) ||
678 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_LowerDist, pPara->mnLineSpacingBottom ) ) )
679 nPropertyFlags |= 0x00004000;
680 if ( ( pPara->meForbiddenRules == css::beans::PropertyState_DIRECT_VALUE ) ||
681 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_UpperDist, pPara->mbForbiddenRules ? 1 : 0 ) ) )
682 nPropertyFlags |= 0x00020000;
683 if ( ( pPara->meParagraphPunctation == css::beans::PropertyState_DIRECT_VALUE ) ||
684 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_UpperDist, pPara->mbParagraphPunctation ? 1 : 0 ) ) )
685 nPropertyFlags |= 0x00080000;
686 if ( ( pPara->meBiDi == css::beans::PropertyState_DIRECT_VALUE ) ||
687 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_BiDi, pPara->mnBiDi ) ) )
688 nPropertyFlags |= 0x00200000;
690 sal_Int32 nBuRealSize = pPara->nBulletRealSize;
691 sal_Int16 nBulletFlags = pPara->nBulletFlags;
693 if ( pPara->bExtendedParameters )
694 nPropertyFlags |= pPara->nParaFlags;
695 else
697 nPropertyFlags |= 1; // turn off bullet explicit
698 nBulletFlags = 0;
701 // Write nTextOfs and nBullets
702 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_TextOfs, pPara->nTextOfs ) )
703 nPropertyFlags |= 0x100;
704 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_BulletOfs, pPara->nBulletOfs ))
705 nPropertyFlags |= 0x400;
707 FontCollectionEntry aFontDescEntry( pPara->aFontDesc.Name, pPara->aFontDesc.Family, pPara->aFontDesc.Pitch, pPara->aFontDesc.CharSet );
708 sal_uInt16 nFontId = static_cast<sal_uInt16>(maFontCollection.GetId( aFontDescEntry ));
710 rOut.WriteUInt32( nCharCount )
711 .WriteUInt16( pPara->nDepth ) // Level
712 .WriteUInt32( nPropertyFlags ); // Paragraph Attribut Set
714 if ( nPropertyFlags & 0xf )
715 rOut.WriteInt16( nBulletFlags );
716 if ( nPropertyFlags & 0x80 )
717 rOut.WriteUInt16( pPara->cBulletId );
718 if ( nPropertyFlags & 0x10 )
719 rOut.WriteUInt16( nFontId );
720 if ( nPropertyFlags & 0x40 )
721 rOut.WriteInt16( nBuRealSize );
722 if ( nPropertyFlags & 0x20 )
724 sal_uInt32 nBulletColor = pPara->nBulletColor;
725 if ( nBulletColor == sal_uInt32(COL_AUTO) )
727 bool bIsDark = false;
728 css::uno::Any aAny;
729 if ( PropValue::GetPropertyValue( aAny, mXPagePropSet, "IsBackgroundDark", true ) )
730 aAny >>= bIsDark;
731 nBulletColor = bIsDark ? 0xffffff : 0x000000;
733 nBulletColor &= 0xffffff;
734 nBulletColor |= 0xfe000000;
735 rOut.WriteUInt32( nBulletColor );
737 if ( nPropertyFlags & 0x00000800 )
738 rOut.WriteUInt16( pPara->mnTextAdjust );
739 if ( nPropertyFlags & 0x00001000 )
740 rOut.WriteUInt16( nLineSpacing );
741 if ( nPropertyFlags & 0x00002000 )
742 rOut.WriteUInt16( pPara->mnLineSpacingTop );
743 if ( nPropertyFlags & 0x00004000 )
744 rOut.WriteUInt16( pPara->mnLineSpacingBottom );
745 if ( nPropertyFlags & 0x100 )
746 rOut.WriteUInt16( pPara->nTextOfs );
747 if ( nPropertyFlags & 0x400 )
748 rOut.WriteUInt16( pPara->nBulletOfs );
749 if ( nPropertyFlags & 0x000e0000 )
751 sal_uInt16 nAsianSettings = 0;
752 if ( pPara->mbForbiddenRules )
753 nAsianSettings |= 1;
754 if ( pPara->mbParagraphPunctation )
755 nAsianSettings |= 4;
756 rOut.WriteUInt16( nAsianSettings );
758 if ( nPropertyFlags & 0x200000 )
759 rOut.WriteUInt16( pPara->mnBiDi );
763 void PPTWriter::ImplWritePortions( SvStream& rOut, TextObj& rTextObj )
765 sal_uInt32 nPropertyFlags;
766 int nInstance = rTextObj.GetInstance();
768 for ( sal_uInt32 i = 0; i < rTextObj.ParagraphCount(); ++i )
770 ParagraphObj* pPara = rTextObj.GetParagraph(i);
771 for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = pPara->begin(); it != pPara->end(); ++it )
773 const PortionObj& rPortion = **it;
774 nPropertyFlags = 0;
775 sal_uInt32 nCharAttr = rPortion.mnCharAttr;
776 sal_uInt32 nCharColor = rPortion.mnCharColor;
778 if ( nCharColor == sal_uInt32(COL_AUTO) ) // nCharColor depends to the background color
780 bool bIsDark = false;
781 css::uno::Any aAny;
782 if ( PropValue::GetPropertyValue( aAny, mXPagePropSet, "IsBackgroundDark", true ) )
783 aAny >>= bIsDark;
784 nCharColor = bIsDark ? 0xffffff : 0x000000;
787 nCharColor &= 0xffffff;
789 /* the portion is using the embossed or engraved attribute, which we want to map to the relief feature of PPT.
790 Because the relief feature of PPT is dependent to the background color, such a mapping can not always be used. */
791 if ( nCharAttr & 0x200 )
793 sal_uInt32 nBackgroundColor = 0xffffff;
795 if ( !nCharColor ) // special treatment for
796 nCharColor = 0xffffff; // black fontcolor
798 css::uno::Any aAny;
799 css::drawing::FillStyle aFS( css::drawing::FillStyle_NONE );
800 if ( PropValue::GetPropertyValue( aAny, mXPropSet, "FillStyle" ) )
801 aAny >>= aFS;
802 switch( aFS )
804 case css::drawing::FillStyle_GRADIENT :
806 ::tools::Rectangle aRect( Point(), Size( 28000, 21000 ) );
807 EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect );
808 aPropOpt.CreateGradientProperties( mXPropSet );
809 aPropOpt.GetOpt( ESCHER_Prop_fillColor, nBackgroundColor );
811 break;
812 case css::drawing::FillStyle_SOLID :
814 if ( PropValue::GetPropertyValue( aAny, mXPropSet, "FillColor" ) )
815 nBackgroundColor = EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(aAny) );
817 break;
818 case css::drawing::FillStyle_NONE :
820 css::uno::Any aBackAny;
821 css::drawing::FillStyle aBackFS( css::drawing::FillStyle_NONE );
822 if ( PropValue::GetPropertyValue( aBackAny, mXBackgroundPropSet, "FillStyle" ) )
823 aBackAny >>= aBackFS;
824 switch( aBackFS )
826 case css::drawing::FillStyle_GRADIENT :
828 ::tools::Rectangle aRect( Point(), Size( 28000, 21000 ) );
829 EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect );
830 aPropOpt.CreateGradientProperties( mXBackgroundPropSet );
831 aPropOpt.GetOpt( ESCHER_Prop_fillColor, nBackgroundColor );
833 break;
834 case css::drawing::FillStyle_SOLID :
836 if ( PropValue::GetPropertyValue( aAny, mXBackgroundPropSet, "FillColor" ) )
837 nBackgroundColor = EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(aAny) );
839 break;
840 default:
841 break;
844 break;
845 default:
846 break;
849 sal_Int32 nB = nBackgroundColor & 0xff;
850 nB += static_cast<sal_uInt8>( nBackgroundColor >> 8 );
851 nB += static_cast<sal_uInt8>( nBackgroundColor >> 16 );
852 // if the background color is nearly black, relief can't been used, because the text would not be visible
853 if ( nB < 0x60 || ( nBackgroundColor != nCharColor ) )
855 nCharAttr &=~ 0x200;
857 // now check if the text is part of a group, and if the previous object has the same color than the fontcolor
858 // ( and if fillcolor is not available the background color ), it is sometimes
859 // not possible to export the 'embossed' flag
860 if ( ( GetCurrentGroupLevel() > 0 ) && ( GetCurrentGroupIndex() >= 1 ) )
862 css::uno::Reference< css::drawing::XShape > aGroupedShape( GetCurrentGroupAccess()->getByIndex( GetCurrentGroupIndex() - 1 ), uno::UNO_QUERY );
863 if( aGroupedShape.is() )
865 css::uno::Reference< css::beans::XPropertySet > aPropSetOfNextShape
866 ( aGroupedShape, css::uno::UNO_QUERY );
867 if ( aPropSetOfNextShape.is() )
869 if ( PropValue::GetPropertyValue( aAny, aPropSetOfNextShape,
870 "FillColor", true ) )
872 if ( nCharColor == EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(aAny) ) )
874 nCharAttr |= 0x200;
882 nCharColor |= 0xfe000000;
883 if ( nInstance == 4 ) // special handling for normal textobjects:
884 nPropertyFlags |= nCharAttr & 0x217; // not all attributes are inherited
885 else
887 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Bold, nCharAttr ) )
888 nPropertyFlags |= 1;
889 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Italic, nCharAttr ) )
890 nPropertyFlags |= 2;
891 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Underline, nCharAttr ) )
892 nPropertyFlags |= 4;
893 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Shadow, nCharAttr ) )
894 nPropertyFlags |= 0x10;
895 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Embossed, nCharAttr ) )
896 nPropertyFlags |= 512;
898 if ( rTextObj.HasExtendedBullets() )
900 nPropertyFlags |= ( i & 0x3f ) << 10 ;
901 nCharAttr |= ( i & 0x3f ) << 10;
903 if ( ( rPortion.meFontName == css::beans::PropertyState_DIRECT_VALUE ) ||
904 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Font, rPortion.mnFont ) ) )
905 nPropertyFlags |= 0x00010000;
906 if ( ( rPortion.meAsianOrComplexFont == css::beans::PropertyState_DIRECT_VALUE ) ||
907 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_AsianOrComplexFont, rPortion.mnAsianOrComplexFont ) ) )
908 nPropertyFlags |= 0x00200000;
909 if ( ( rPortion.meCharHeight == css::beans::PropertyState_DIRECT_VALUE ) ||
910 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_FontHeight, rPortion.mnCharHeight ) ) )
911 nPropertyFlags |= 0x00020000;
912 if ( ( rPortion.meCharColor == css::beans::PropertyState_DIRECT_VALUE ) ||
913 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_FontColor, nCharColor & 0xffffff ) ) )
914 nPropertyFlags |= 0x00040000;
915 if ( ( rPortion.meCharEscapement == css::beans::PropertyState_DIRECT_VALUE ) ||
916 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Escapement, rPortion.mnCharEscapement ) ) )
917 nPropertyFlags |= 0x00080000;
919 sal_uInt32 nCharCount = rPortion.Count();
921 rOut.WriteUInt32( nCharCount )
922 .WriteUInt32( nPropertyFlags ); //PropertyFlags
924 if ( nPropertyFlags & 0xffff )
925 rOut.WriteUInt16( nCharAttr );
926 if ( nPropertyFlags & 0x00010000 )
927 rOut.WriteUInt16( rPortion.mnFont );
928 if ( nPropertyFlags & 0x00200000 )
929 rOut.WriteUInt16( rPortion.mnAsianOrComplexFont );
930 if ( nPropertyFlags & 0x00020000 )
931 rOut.WriteUInt16( rPortion.mnCharHeight );
932 if ( nPropertyFlags & 0x00040000 )
933 rOut.WriteUInt32( nCharColor );
934 if ( nPropertyFlags & 0x00080000 )
935 rOut.WriteInt16( rPortion.mnCharEscapement );
941 * Loads and converts text from shape, value is stored in mnTextSize.
943 bool PPTWriter::ImplGetText()
945 mnTextSize = 0;
946 mbFontIndependentLineSpacing = false;
947 mXText.set( mXShape, css::uno::UNO_QUERY );
949 if ( mXText.is() )
951 mnTextSize = mXText->getString().getLength();
952 css::uno::Any aAny;
953 if ( GetPropertyValue( aAny, mXPropSet, "FontIndependentLineSpacing", true ) )
954 aAny >>= mbFontIndependentLineSpacing;
956 return ( mnTextSize != 0 );
959 void PPTWriter::ImplFlipBoundingBox( EscherPropertyContainer& rPropOpt )
961 if ( mnAngle < 0 )
962 mnAngle = ( 36000 + mnAngle ) % 36000;
963 else
964 mnAngle = ( 36000 - ( mnAngle % 36000 ) );
966 double fCos = cos( static_cast<double>(mnAngle) * F_PI18000 );
967 double fSin = sin( static_cast<double>(mnAngle) * F_PI18000 );
969 double fWidthHalf = maRect.GetWidth() / 2.0;
970 double fHeightHalf = maRect.GetHeight() / 2.0;
972 double fXDiff = fCos * fWidthHalf + fSin * (-fHeightHalf);
973 double fYDiff = - ( fSin * fWidthHalf - fCos * ( -fHeightHalf ) );
975 maRect.Move( static_cast<sal_Int32>( -( fWidthHalf - fXDiff ) ), static_cast<sal_Int32>( - ( fHeightHalf + fYDiff ) ) );
976 mnAngle *= 655;
977 mnAngle += 0x8000;
978 mnAngle &=~0xffff; // round nAngle to full grads
979 rPropOpt.AddOpt( ESCHER_Prop_Rotation, mnAngle );
981 if ( ( mnAngle >= ( 45 << 16 ) && mnAngle < ( 135 << 16 ) ) ||
982 ( mnAngle >= ( 225 << 16 ) && mnAngle < ( 315 << 16 ) ) )
984 // Maddeningly, in those two areas of PPT is the BoundingBox already
985 // vertical. Therefore, we need to put down it BEFORE THE ROTATION.
986 css::awt::Point aTopLeft( static_cast<sal_Int32>( maRect.Left() + fWidthHalf - fHeightHalf ), static_cast<sal_Int32>( maRect.Top() + fHeightHalf - fWidthHalf ) );
987 const tools::Long nRotatedWidth(maRect.GetHeight());
988 const tools::Long nRotatedHeight(maRect.GetWidth());
989 const Size aNewSize(nRotatedWidth, nRotatedHeight);
990 maRect = ::tools::Rectangle( Point( aTopLeft.X, aTopLeft.Y ), aNewSize );
994 void PPTWriter::ImplAdjustFirstLineLineSpacing( TextObj& rTextObj, EscherPropertyContainer& rPropOpt )
996 if ( mbFontIndependentLineSpacing )
997 return;
999 if ( !rTextObj.ParagraphCount() )
1000 return;
1002 ParagraphObj* pPara = rTextObj.GetParagraph(0);
1003 if ( pPara->empty() )
1004 return;
1006 const PortionObj& rPortion = pPara->front();
1007 sal_Int16 nLineSpacing = pPara->mnLineSpacing;
1008 const FontCollectionEntry* pDesc = maFontCollection.GetById( rPortion.mnFont );
1009 if ( pDesc )
1010 nLineSpacing = static_cast<sal_Int16>( static_cast<double>(nLineSpacing) * pDesc->Scaling + 0.5 );
1012 if ( ( nLineSpacing > 0 ) && ( nLineSpacing < 100 ) )
1014 double fCharHeight = rPortion.mnCharHeight;
1015 fCharHeight *= 2540 / 72.0;
1016 fCharHeight *= 100 - nLineSpacing;
1017 fCharHeight /= 100;
1019 sal_uInt32 nUpperDistance = 0;
1020 rPropOpt.GetOpt( ESCHER_Prop_dyTextTop, nUpperDistance );
1021 nUpperDistance += static_cast< sal_uInt32 >( fCharHeight * 360.0 );
1022 rPropOpt.AddOpt( ESCHER_Prop_dyTextTop, nUpperDistance );
1026 void PPTWriter::ImplWriteTextStyleAtom( SvStream& rOut, int nTextInstance, sal_uInt32 nAtomInstance,
1027 TextRuleEntry* pTextRule, SvStream& rExtBuStr, EscherPropertyContainer* pPropOpt )
1029 PPTExParaSheet& rParaSheet = mpStyleSheet->GetParaSheet( nTextInstance );
1031 rOut.WriteUInt32( ( EPP_TextHeaderAtom << 16 ) | ( nAtomInstance << 4 ) ).WriteUInt32( 4 )
1032 .WriteInt32( nTextInstance );
1034 if ( mbEmptyPresObj )
1035 mnTextSize = 0;
1036 if ( mbEmptyPresObj )
1037 return;
1039 ParagraphObj* pPara;
1040 TextObjBinary aTextObj( mXText, nTextInstance, maFontCollection, static_cast<PPTExBulletProvider&>(*this) );
1042 // leaving out EPP_TextCharsAtom w/o text - still write out
1043 // attribute info though
1044 if ( mnTextSize )
1045 aTextObj.Write( &rOut );
1047 if ( pPropOpt && mType != "drawing.Table" )
1048 ImplAdjustFirstLineLineSpacing( aTextObj, *pPropOpt );
1050 sal_uInt32 nSize, nPos = rOut.Tell();
1052 rOut.WriteUInt32( EPP_StyleTextPropAtom << 16 ).WriteUInt32( 0 );
1053 ImplWriteParagraphs( rOut, aTextObj );
1054 ImplWritePortions( rOut, aTextObj );
1055 nSize = rOut.Tell() - nPos;
1056 rOut.SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
1057 rOut.WriteUInt32( nSize - 8 );
1058 rOut.SeekRel( nSize - 8 );
1060 for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount(); ++i )
1062 pPara = aTextObj.GetParagraph(i);
1063 for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = pPara->begin(); it != pPara->end(); ++it )
1065 const PortionObj& rPortion = **it;
1066 if ( rPortion.mpFieldEntry )
1068 const FieldEntry* pFieldEntry = rPortion.mpFieldEntry.get();
1070 switch ( pFieldEntry->nFieldType >> 28 )
1072 case 1 :
1073 case 2 :
1075 rOut.WriteUInt32( EPP_DateTimeMCAtom << 16 ).WriteUInt32( 8 )
1076 .WriteUInt32( pFieldEntry->nFieldStartPos ) // TxtOffset to TxtField;
1077 .WriteUChar( pFieldEntry->nFieldType & 0xff ) // Type
1078 .WriteUChar( 0 ).WriteUInt16( 0 ); // PadBytes
1080 break;
1081 case 3 :
1083 rOut.WriteUInt32( EPP_SlideNumberMCAtom << 16 ).WriteUInt32( 4 )
1084 .WriteUInt32( pFieldEntry->nFieldStartPos );
1086 break;
1087 case 4 :
1089 sal_uInt32 nPageIndex = 0;
1090 OUString aPageUrl;
1091 OUString aFile( pFieldEntry->aFieldUrl );
1092 OUString aTarget( pFieldEntry->aFieldUrl );
1093 INetURLObject aUrl( pFieldEntry->aFieldUrl );
1094 if ( INetProtocol::File == aUrl.GetProtocol() )
1095 aFile = aUrl.PathToFileName();
1096 else if ( INetProtocol::Smb == aUrl.GetProtocol() )
1098 // Convert smb notation to '\\' and skip the 'smb:' part
1099 aFile = aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE).copy(4);
1100 aFile = aFile.replaceAll( "/", "\\" );
1101 aTarget = aFile;
1103 else if ( pFieldEntry->aFieldUrl.startsWith("#") )
1105 OUString aPage( INetURLObject::decode( pFieldEntry->aFieldUrl, INetURLObject::DecodeMechanism::WithCharset ) );
1106 aPage = aPage.copy( 1 );
1108 std::vector<OUString>::const_iterator pIter = std::find(
1109 maSlideNameList.begin(),maSlideNameList.end(),aPage);
1111 if ( pIter != maSlideNameList.end() )
1113 nPageIndex = pIter - maSlideNameList.begin();
1114 aPageUrl = OUString::number(256 + nPageIndex) +
1115 "," +
1116 OUString::number(nPageIndex + 1) +
1117 ",Slide " +
1118 OUString::number(nPageIndex + 1);
1121 sal_uInt32 nHyperId(0);
1122 if ( !aPageUrl.isEmpty() )
1123 nHyperId = ImplInsertBookmarkURL( aPageUrl, 1 | ( nPageIndex << 8 ) | ( 1U << 31 ), pFieldEntry->aRepresentation, "", "", aPageUrl );
1124 else
1125 nHyperId = ImplInsertBookmarkURL( pFieldEntry->aFieldUrl, 2 | ( nHyperId << 8 ), aFile, aTarget, "", "" );
1127 rOut.WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0xf ).WriteUInt32( 24 )
1128 .WriteUInt32( EPP_InteractiveInfoAtom << 16 ).WriteUInt32( 16 )
1129 .WriteUInt32( 0 ) // soundref
1130 .WriteUInt32( nHyperId ) // hyperlink id
1131 .WriteUChar( 4 ) // hyperlink action
1132 .WriteUChar( 0 ) // ole verb
1133 .WriteUChar( 0 ) // jump
1134 .WriteUChar( 0 ) // flags
1135 .WriteUChar( 8 ) // hyperlink type ?
1136 .WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 )
1137 .WriteUInt32( EPP_TxInteractiveInfoAtom << 16 ).WriteUInt32( 8 )
1138 .WriteUInt32( pFieldEntry->nFieldStartPos )
1139 .WriteUInt32( pFieldEntry->nFieldEndPos );
1141 break;
1142 case 5 :
1144 rOut.WriteUInt32( EPP_GenericDateMCAtom << 16 ).WriteUInt32( 4 )
1145 .WriteUInt32( pFieldEntry->nFieldStartPos );
1147 break;
1148 case 6 :
1150 rOut.WriteUInt32( EPP_HeaderMCAtom << 16 ).WriteUInt32( 4 )
1151 .WriteUInt32( pFieldEntry->nFieldStartPos );
1153 break;
1154 case 7 :
1156 rOut.WriteUInt32( EPP_FooterMCAtom << 16 ).WriteUInt32( 4 )
1157 .WriteUInt32( pFieldEntry->nFieldStartPos );
1159 break;
1160 default:
1161 break;
1167 aTextObj.WriteTextSpecInfo( &rOut );
1169 // write Star Office Default TabSizes (if necessary)
1170 if ( aTextObj.ParagraphCount() )
1172 pPara = aTextObj.GetParagraph(0);
1173 sal_uInt32 nParaFlags = 0x1f;
1174 sal_Int16 nMask, nNumberingRule[ 10 ];
1175 const sal_uInt32 nTabs = pPara->maTabStop.getLength();
1176 const auto& rTabStops = pPara->maTabStop;
1178 for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount(); ++i )
1180 pPara = aTextObj.GetParagraph(i);
1181 if ( pPara->bExtendedParameters )
1183 nMask = 1 << pPara->nDepth;
1184 if ( nParaFlags & nMask )
1186 nParaFlags &=~ nMask;
1187 if ( ( rParaSheet.maParaLevel[ pPara->nDepth ].mnTextOfs != pPara->nTextOfs ) ||
1188 ( rParaSheet.maParaLevel[ pPara->nDepth ].mnBulletOfs != pPara->nBulletOfs ) )
1190 nParaFlags |= nMask << 16;
1191 nNumberingRule[ pPara->nDepth << 1 ] = pPara->nTextOfs;
1192 nNumberingRule[ ( pPara->nDepth << 1 ) + 1 ] = static_cast<sal_Int16>(pPara->nBulletOfs);
1197 nParaFlags >>= 16;
1199 sal_Int32 nDefaultTabSizeSrc = 2011; // I've no idea where this number came from, honestly
1200 const uno::Reference< beans::XPropertySet > xPropSet( mXModel, uno::UNO_QUERY );
1201 if ( xPropSet.is() )
1203 if(ImplGetPropertyValue( xPropSet, "TabStop" ))
1205 sal_Int32 nTabStop( 0 );
1206 if ( mAny >>= nTabStop )
1207 nDefaultTabSizeSrc = nTabStop;
1210 const sal_uInt32 nDefaultTabSize = MapSize( awt::Size( nDefaultTabSizeSrc, 1 ) ).Width;
1211 sal_uInt32 nDefaultTabs = std::abs( maRect.GetWidth() ) / nDefaultTabSize;
1212 if ( nTabs )
1213 nDefaultTabs -= static_cast<sal_Int32>( convertMm100ToMasterUnit(rTabStops[ nTabs - 1 ].Position) / nDefaultTabSize );
1214 if ( static_cast<sal_Int32>(nDefaultTabs) < 0 )
1215 nDefaultTabs = 0;
1217 sal_uInt32 nTabCount = nTabs + nDefaultTabs;
1218 sal_uInt32 i, nTextRulerAtomFlags = 0;
1220 if ( nTabCount )
1221 nTextRulerAtomFlags |= 4;
1222 if ( nParaFlags )
1223 nTextRulerAtomFlags |= ( ( nParaFlags << 3 ) | ( nParaFlags << 8 ) );
1225 if ( nTextRulerAtomFlags )
1227 SvStream* pRuleOut = &rOut;
1228 if ( pTextRule )
1230 pTextRule->pOut.reset( new SvMemoryStream( 0x100, 0x100 ) );
1231 pRuleOut = pTextRule->pOut.get();
1234 sal_uInt32 nRulePos = pRuleOut->Tell();
1235 pRuleOut->WriteUInt32( EPP_TextRulerAtom << 16 ).WriteUInt32( 0 );
1236 pRuleOut->WriteUInt32( nTextRulerAtomFlags );
1237 if ( nTextRulerAtomFlags & 4 )
1239 pRuleOut->WriteUInt16( nTabCount );
1240 for ( const css::style::TabStop& rTabStop : rTabStops )
1242 sal_uInt16 nPosition = static_cast<sal_uInt16>( convertMm100ToMasterUnit(rTabStop.Position) );
1243 sal_uInt16 nType;
1244 switch ( rTabStop.Alignment )
1246 case css::style::TabAlign_DECIMAL : nType = 3; break;
1247 case css::style::TabAlign_RIGHT : nType = 2; break;
1248 case css::style::TabAlign_CENTER : nType = 1; break;
1250 case css::style::TabAlign_LEFT :
1251 default: nType = 0;
1253 pRuleOut->WriteUInt16( nPosition )
1254 .WriteUInt16( nType );
1257 sal_uInt32 nWidth = 1;
1258 if ( nTabs )
1259 nWidth += static_cast<sal_Int32>( convertMm100ToMasterUnit(rTabStops[ nTabs - 1 ].Position) / nDefaultTabSize );
1260 nWidth *= nDefaultTabSize;
1261 for ( i = 0; i < nDefaultTabs; i++, nWidth += nDefaultTabSize )
1262 pRuleOut->WriteUInt32( nWidth );
1264 for ( i = 0; i < 5; i++ )
1266 if ( nTextRulerAtomFlags & ( 8 << i ) )
1267 pRuleOut->WriteInt16( nNumberingRule[ i << 1 ] );
1268 if ( nTextRulerAtomFlags & ( 256 << i ) )
1269 pRuleOut->WriteInt16( nNumberingRule[ ( i << 1 ) + 1 ] );
1271 sal_uInt32 nBufSize = pRuleOut->Tell() - nRulePos;
1272 pRuleOut->SeekRel( - ( static_cast<sal_Int32>(nBufSize) - 4 ) );
1273 pRuleOut->WriteUInt32( nBufSize - 8 );
1274 pRuleOut->SeekRel( nBufSize - 8 );
1277 if ( !aTextObj.HasExtendedBullets() )
1278 return;
1280 if ( !aTextObj.ParagraphCount() )
1281 return;
1283 sal_uInt32 nNumberingType = 0, nPos2 = rExtBuStr.Tell();
1285 rExtBuStr.WriteUInt32( EPP_PST_ExtendedParagraphAtom << 16 ).WriteUInt32( 0 );
1287 for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount(); ++i )
1289 ParagraphObj* pBulletPara = aTextObj.GetParagraph(i);
1290 sal_uInt32 nBulletFlags = 0;
1291 sal_uInt16 nBulletId = pBulletPara->nBulletId;
1293 if ( pBulletPara->bExtendedBulletsUsed )
1295 nBulletFlags = 0x800000;
1296 if ( pBulletPara->nNumberingType != SVX_NUM_BITMAP )
1297 nBulletFlags = 0x3000000;
1299 rExtBuStr.WriteUInt32( nBulletFlags );
1301 if ( nBulletFlags & 0x800000 )
1302 rExtBuStr.WriteUInt16( nBulletId );
1303 if ( nBulletFlags & 0x1000000 )
1305 switch( pBulletPara->nNumberingType )
1307 case SVX_NUM_NUMBER_NONE :
1308 case SVX_NUM_CHAR_SPECIAL :
1309 nNumberingType = 0;
1310 break;
1311 case SVX_NUM_CHARS_UPPER_LETTER :
1312 case SVX_NUM_CHARS_UPPER_LETTER_N :
1313 case SVX_NUM_CHARS_LOWER_LETTER :
1314 case SVX_NUM_CHARS_LOWER_LETTER_N :
1315 case SVX_NUM_ROMAN_UPPER :
1316 case SVX_NUM_ROMAN_LOWER :
1317 case SVX_NUM_ARABIC :
1318 case SVX_NUM_NUMBER_UPPER_ZH:
1319 case SVX_NUM_CIRCLE_NUMBER:
1320 case SVX_NUM_NUMBER_UPPER_ZH_TW:
1321 case SVX_NUM_NUMBER_LOWER_ZH:
1322 case SVX_NUM_FULL_WIDTH_ARABIC:
1323 nNumberingType = pBulletPara->nMappedNumType;
1324 break;
1326 case SVX_NUM_BITMAP :
1327 nNumberingType = 0;
1328 break;
1329 default: break;
1331 rExtBuStr.WriteUInt32( nNumberingType );
1333 if ( nBulletFlags & 0x2000000 )
1334 rExtBuStr.WriteUInt16( pBulletPara->nStartWith );
1335 rExtBuStr.WriteUInt32( 0 ).WriteUInt32( 0 );
1337 sal_uInt32 nBulletSize = ( rExtBuStr.Tell() - nPos2 ) - 8;
1338 rExtBuStr.SeekRel( - ( static_cast<sal_Int32>(nBulletSize) + 4 ) );
1339 rExtBuStr.WriteUInt32( nBulletSize );
1340 rExtBuStr.SeekRel( nBulletSize );
1343 void PPTWriter::ImplWriteClickAction( SvStream& rSt, css::presentation::ClickAction eCa, bool bMediaClickAction )
1345 sal_uInt32 nSoundRef = 0; // a reference to a sound in the sound collection, or NULL.
1346 sal_uInt32 nHyperLinkID = 0;// a persistent unique identifier to an external hyperlink object (only valid when action == HyperlinkAction).
1347 sal_uInt8 nAction = 0; // Action See Action Table
1348 sal_uInt8 const nOleVerb = 0; // OleVerb Only valid when action == OLEAction. OLE verb to use, 0 = first verb, 1 = second verb, etc.
1349 sal_uInt8 nJump = 0; // Jump See Jump Table
1350 sal_uInt8 const nFlags = 0; // Bit 1: Animated. If 1, then button is animated
1351 // Bit 2: Stop sound. If 1, then stop current sound when button is pressed.
1352 // Bit 3: CustomShowReturn. If 1, and this is a jump to custom show, then return to this slide after custom show.
1353 sal_uInt8 nHyperLinkType = 0;// HyperlinkType a value from the LinkTo enum, such as LT_URL (only valid when action == HyperlinkAction).
1355 OUString aFile;
1358 Action Table: Action Value
1359 NoAction 0
1360 MacroAction 1
1361 RunProgramAction 2
1362 JumpAction 3
1363 HyperlinkAction 4
1364 OLEAction 5
1365 MediaAction 6
1366 CustomShowAction 7
1368 Jump Table: Jump Value
1369 NoJump 0
1370 NextSlide, 1
1371 PreviousSlide, 2
1372 FirstSlide, 3
1373 LastSlide, 4
1374 LastSlideViewed 5
1375 EndShow 6
1378 if ( bMediaClickAction )
1379 nAction = 6;
1380 else switch( eCa )
1382 case css::presentation::ClickAction_STOPPRESENTATION :
1383 nJump += 2;
1384 [[fallthrough]];
1385 case css::presentation::ClickAction_LASTPAGE :
1386 nJump++;
1387 [[fallthrough]];
1388 case css::presentation::ClickAction_FIRSTPAGE :
1389 nJump++;
1390 [[fallthrough]];
1391 case css::presentation::ClickAction_PREVPAGE :
1392 nJump++;
1393 [[fallthrough]];
1394 case css::presentation::ClickAction_NEXTPAGE :
1396 nJump++;
1397 nAction = 3;
1399 break;
1400 case css::presentation::ClickAction_SOUND :
1402 if ( ImplGetPropertyValue( "Bookmark" ) )
1403 nSoundRef = maSoundCollection.GetId( *o3tl::doAccess<OUString>(mAny) );
1405 break;
1406 case css::presentation::ClickAction_PROGRAM :
1408 if ( ImplGetPropertyValue( "Bookmark" ) )
1410 INetURLObject aUrl( *o3tl::doAccess<OUString>(mAny) );
1411 if ( INetProtocol::File == aUrl.GetProtocol() )
1413 aFile = aUrl.PathToFileName();
1414 nAction = 2;
1418 break;
1420 case css::presentation::ClickAction_BOOKMARK :
1422 if ( ImplGetPropertyValue( "Bookmark" ) )
1424 OUString aBookmark( *o3tl::doAccess<OUString>(mAny) );
1425 sal_uInt32 nIndex = 0;
1426 for ( const auto& rSlideName : maSlideNameList )
1428 if ( rSlideName == aBookmark )
1430 // Bookmark is a link to a document page
1431 nAction = 4;
1432 nHyperLinkType = 7;
1434 OUString aHyperString = OUString::number(256 + nIndex) +
1435 "," +
1436 OUString::number(nIndex + 1) +
1437 ",Slide " +
1438 OUString::number(nIndex + 1);
1439 nHyperLinkID = ImplInsertBookmarkURL( aHyperString, 1 | ( nIndex << 8 ) | ( 1U << 31 ), aBookmark, "", "", aHyperString );
1441 nIndex++;
1445 break;
1447 case css::presentation::ClickAction_DOCUMENT :
1449 if ( ImplGetPropertyValue( "Bookmark" ) )
1451 OUString aBookmark( *o3tl::doAccess<OUString>(mAny) );
1452 if ( !aBookmark.isEmpty() )
1454 nAction = 4;
1455 nHyperLinkType = 8;
1457 OUString aBookmarkFile( aBookmark );
1458 INetURLObject aUrl( aBookmark );
1459 if ( INetProtocol::File == aUrl.GetProtocol() )
1460 aBookmarkFile = aUrl.PathToFileName();
1461 nHyperLinkID = ImplInsertBookmarkURL( aBookmark, sal_uInt32(2 | ( 1U << 31 )), aBookmarkFile, aBookmark, "", "" );
1465 break;
1467 case css::presentation::ClickAction_INVISIBLE :
1468 case css::presentation::ClickAction_VERB :
1469 case css::presentation::ClickAction_VANISH :
1470 case css::presentation::ClickAction_MACRO :
1471 default :
1472 break;
1475 sal_uInt32 nContainerSize = 24;
1476 if ( nAction == 2 )
1477 nContainerSize += ( aFile.getLength() * 2 ) + 8;
1478 rSt.WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0xf ).WriteUInt32( nContainerSize )
1479 .WriteUInt32( EPP_InteractiveInfoAtom << 16 ).WriteUInt32( 16 )
1480 .WriteUInt32( nSoundRef )
1481 .WriteUInt32( nHyperLinkID )
1482 .WriteUChar( nAction )
1483 .WriteUChar( nOleVerb )
1484 .WriteUChar( nJump )
1485 .WriteUChar( nFlags )
1486 .WriteUInt32( nHyperLinkType );
1488 if ( nAction == 2 ) // run program Action
1490 sal_Int32 nLen = aFile.getLength();
1491 rSt.WriteUInt32( ( EPP_CString << 16 ) | 0x20 ).WriteUInt32( nLen * 2 );
1492 for ( sal_Int32 i = 0; i < nLen; i++ )
1493 rSt.WriteUInt16( aFile[i] );
1496 rSt.WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0x1f ).WriteUInt32( 24 ) // Mouse Over Action
1497 .WriteUInt32( EPP_InteractiveInfo << 16 ).WriteUInt32( 16 );
1498 for ( int i = 0; i < 4; i++, rSt.WriteUInt32( 0 ) ) ;
1501 bool PPTWriter::ImplGetEffect( const css::uno::Reference< css::beans::XPropertySet > & rPropSet,
1502 css::presentation::AnimationEffect& eEffect,
1503 css::presentation::AnimationEffect& eTextEffect,
1504 bool& bIsSound )
1506 css::uno::Any aAny;
1507 if ( GetPropertyValue( aAny, rPropSet, "Effect" ) )
1508 aAny >>= eEffect;
1509 else
1510 eEffect = css::presentation::AnimationEffect_NONE;
1512 if ( GetPropertyValue( aAny, rPropSet, "TextEffect" ) )
1513 aAny >>= eTextEffect;
1514 else
1515 eTextEffect = css::presentation::AnimationEffect_NONE;
1516 if ( GetPropertyValue( aAny, rPropSet, "SoundOn" ) )
1517 aAny >>= bIsSound;
1518 else
1519 bIsSound = false;
1521 bool bHasEffect = ( ( eEffect != css::presentation::AnimationEffect_NONE )
1522 || ( eTextEffect != css::presentation::AnimationEffect_NONE )
1523 || bIsSound );
1524 return bHasEffect;
1527 bool PPTWriter::ImplCreatePresentationPlaceholder( const bool bMasterPage,
1528 const sal_uInt32 nStyleInstance, const sal_uInt8 nPlaceHolderId )
1530 bool bRet = ImplGetText();
1531 if ( bRet && bMasterPage )
1533 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1534 sal_uInt32 nPresShapeID = mpPptEscherEx->GenerateShapeId();
1535 mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
1536 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty, nPresShapeID );
1537 EscherPropertyContainer aPropOpt;
1538 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x50001 );
1539 mnTxId += 0x60;
1540 aPropOpt.AddOpt( ESCHER_Prop_lTxid, mnTxId );
1541 aPropOpt.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
1542 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110001 );
1543 aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x8000001 );
1544 aPropOpt.AddOpt( ESCHER_Prop_shadowColor, 0x8000002 );
1545 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
1546 sal_uInt32 nLineFlags = 0x90001;
1547 if ( aPropOpt.GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ) )
1548 nLineFlags |= 0x10001; // draw dashed line if no line
1549 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
1551 SvMemoryStream aExtBu( 0x200, 0x200 );
1552 SvMemoryStream aClientTextBox( 0x200, 0x200 );
1553 ImplWriteTextStyleAtom( aClientTextBox, nStyleInstance, 0, nullptr, aExtBu, &aPropOpt );
1555 mnTxId += 0x60;
1556 aPropOpt.CreateTextProperties( mXPropSet, mnTxId );
1557 aPropOpt.CreateShapeProperties( mXShape );
1558 aPropOpt.Commit( *mpStrm );
1559 mpPptEscherEx->AddAtom( 8, ESCHER_ClientAnchor );
1560 mpStrm->WriteInt16( maRect.Top() ).WriteInt16( maRect.Left() ).WriteInt16( maRect.Right() ).WriteInt16( maRect.Bottom() ); // top, left, right, bottom ????
1561 mpPptEscherEx->OpenContainer( ESCHER_ClientData );
1562 mpPptEscherEx->AddAtom( 8, EPP_OEPlaceholderAtom );
1563 mpStrm->WriteUInt32( 0 ) // PlacementID
1564 .WriteUChar( nPlaceHolderId ) // PlaceHolderID
1565 .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
1566 .WriteUInt16( 0 ); // padword
1567 mpPptEscherEx->CloseContainer(); // ESCHER_ClientData
1569 if ( aClientTextBox.Tell() )
1571 mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
1572 .WriteUInt32( aClientTextBox.Tell() );
1574 mpStrm->WriteBytes(aClientTextBox.GetData(), aClientTextBox.Tell());
1576 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
1578 else
1579 bRet = false;
1580 return bRet;
1583 void PPTWriter::ImplCreateShape( sal_uInt32 nType, ShapeFlag nFlags, EscherSolverContainer& rSolver )
1585 sal_uInt32 nId = mpPptEscherEx->GenerateShapeId();
1586 mpPptEscherEx->AddShape( nType, nFlags, nId );
1587 rSolver.AddShape( mXShape, nId );
1590 void PPTWriter::ImplCreateTextShape( EscherPropertyContainer& rPropOpt, EscherSolverContainer& rSolver, bool bFill )
1592 mnTextStyle = EPP_TEXTSTYLE_TEXT;
1593 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1594 ImplCreateShape( ESCHER_ShpInst_TextBox, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty, rSolver );
1595 if ( bFill )
1596 rPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
1597 if ( ImplGetText() )
1599 mnTxId += 0x60;
1600 rPropOpt.CreateTextProperties( mXPropSet, mnTxId );
1604 void PPTWriter::ImplWritePage( const PHLayout& rLayout, EscherSolverContainer& aSolverContainer, PageType ePageType, bool bMasterPage, int nPageNumber )
1606 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
1607 // sal_uInt32 nGroupLevel = 0;
1609 sal_uInt32 nGroups, nShapes, nShapeCount, nPer, nLastPer, nIndices, nOlePictureId;
1610 css::awt::Point aTextRefPoint;
1612 nShapes = mXShapes->getCount();
1613 ResetGroupTable( nShapes );
1615 nIndices = nLastPer = nShapeCount = 0;
1617 bool bIsTitlePossible = true; // powerpoint is not able to handle more than one title
1619 sal_uInt32 nOutlinerCount = 0; // the outline objects have to conform to the layout,
1620 sal_uInt32 nPrevTextStyle = 0; // there are no more than two allowed
1622 nOlePictureId = 0;
1624 bool bAdditionalText = false;
1626 bool bSecOutl = false;
1627 sal_uInt32 nPObjects = 0;
1629 std::unique_ptr<SvMemoryStream> pClientTextBox;
1630 std::unique_ptr<SvMemoryStream> pClientData;
1632 while( GetNextGroupEntry() )
1634 nShapeCount++;
1636 nPer = ( 5 * nShapeCount ) / nShapes;
1637 if ( nPer != nLastPer )
1639 nLastPer = nPer;
1640 sal_uInt32 nValue = mnPagesWritten * 5 + nPer;
1641 if ( nValue > mnStatMaxValue )
1642 nValue = mnStatMaxValue;
1643 if ( mbStatusIndicator && ( nValue > mnLatestStatValue ) )
1645 mXStatusIndicator->setValue( nValue );
1646 mnLatestStatValue = nValue;
1649 nGroups = GetGroupsClosed();
1650 for ( sal_uInt32 i = 0; i < nGroups; i++, mpPptEscherEx->LeaveGroup() ) ;
1652 if ( GetShapeByIndex( GetCurrentGroupIndex(), true ) )
1654 bool bIsSound;
1655 bool bMediaClickAction = false;
1656 css::presentation::AnimationEffect eAe;
1657 css::presentation::AnimationEffect eTe;
1659 bool bEffect = ImplGetEffect( mXPropSet, eAe, eTe, bIsSound );
1660 css::presentation::ClickAction eCa = css::presentation::ClickAction_NONE;
1661 if ( ImplGetPropertyValue( "OnClick" ) )
1662 mAny >>= eCa;
1664 bool bGroup = mType == "drawing.Group";
1665 bool bOpenBezier = mType == "drawing.OpenBezier";
1666 bool bClosedBezier = mType == "drawing.ClosedBezier";
1667 bool bPolyPolygon = mType == "drawing.PolyPolygon";
1668 bool bPolyLine = mType == "drawing.PolyLine";
1669 OUString aGraphicPropertyName("Graphic");
1671 const css::awt::Size aSize100thmm( mXShape->getSize() );
1672 const css::awt::Point aPoint100thmm( mXShape->getPosition() );
1673 ::tools::Rectangle aRect100thmm( Point( aPoint100thmm.X, aPoint100thmm.Y ), Size( aSize100thmm.Width, aSize100thmm.Height ) );
1674 EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect100thmm );
1676 if ( bGroup )
1678 css::uno::Reference< css::container::XIndexAccess >
1679 aXIndexAccess( mXShape, css::uno::UNO_QUERY );
1680 if ( EnterGroup( aXIndexAccess ) )
1682 std::unique_ptr<SvMemoryStream> pTmp;
1683 if ( eCa != css::presentation::ClickAction_NONE )
1685 pTmp.reset(new SvMemoryStream(0x200, 0x200));
1686 ImplWriteClickAction( *pTmp, eCa, bMediaClickAction );
1688 sal_uInt32 nShapeId = mpPptEscherEx->EnterGroup(&maRect, pTmp.get());
1689 aSolverContainer.AddShape( mXShape, nShapeId );
1692 else
1694 bool bIsFontwork = false;
1695 bool bIsHatching = false;
1696 css::uno::Any aAny;
1697 if ( GetPropertyValue( aAny, mXPropSet, "IsFontwork", true ) )
1698 aAny >>= bIsFontwork;
1699 if ( GetPropertyValue( aAny, mXPropSet, "FillStyle", true ) )
1701 css::drawing::FillStyle eFS;
1702 aAny >>= eFS;
1703 bIsHatching = eFS == css::drawing::FillStyle_HATCH;
1704 if (mType == "drawing.Custom" && eFS == drawing::FillStyle_BITMAP)
1706 ShapeFlag nMirrorFlags;
1707 OUString sCustomShapeType;
1708 MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType(
1709 mXShape, nMirrorFlags, sCustomShapeType);
1710 if (eShapeType == mso_sptMax)
1712 // We can't map this custom shape to a PPT preset and it has a bitmap
1713 // fill. Make sure that at least the bitmap fill is not lost.
1714 mType = "drawing.GraphicObject";
1715 aGraphicPropertyName = "Bitmap";
1719 if ( bIsHatching || bIsFontwork || ( mType == "drawing.Measure" ) || ( mType == "drawing.Caption" ) )
1721 if ( ImplGetPropertyValue( "BoundRect" ) )
1723 auto aRect = o3tl::doAccess<css::awt::Rectangle>(mAny);
1724 maPosition = MapPoint( css::awt::Point( aRect->X, aRect->Y ) );
1725 maSize = MapSize( css::awt::Size( aRect->Width, aRect->Height ) );
1726 maRect = ::tools::Rectangle( Point( maPosition.X, maPosition.Y ), Size( maSize.Width, maSize.Height ) );
1728 mType = "drawing.dontknow";
1731 sal_uInt8 nPlaceHolderAtom = EPP_PLACEHOLDER_NONE;
1733 mnTextSize = 0;
1734 mnTextStyle = EPP_TEXTSTYLE_NORMAL;
1736 if ( mType == "drawing.Custom" )
1738 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1739 ShapeFlag nMirrorFlags;
1740 OUString sCustomShapeType;
1741 MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType( mXShape, nMirrorFlags, sCustomShapeType );
1742 if ( sCustomShapeType == "col-502ad400" || sCustomShapeType == "col-60da8460" )
1743 { // sj: creating metafile for customshapes that can't be saved to ms format properly
1744 ImplCreateShape( ESCHER_ShpInst_PictureFrame,
1745 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1746 aSolverContainer );
1747 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "MetaFile", false ) )
1749 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
1750 SdrObject* pObj = GetSdrObjectFromXShape( mXShape );
1751 if ( pObj )
1753 ::tools::Rectangle aBound = pObj->GetCurrentBoundRect();
1754 maPosition = MapPoint( css::awt::Point( aBound.Left(), aBound.Top() ) );
1755 maSize = MapSize( css::awt::Size ( aBound.GetWidth(), aBound.GetHeight() ) );
1756 maRect = ::tools::Rectangle( Point( maPosition.X, maPosition.Y ), Size( maSize.Width, maSize.Height ) );
1757 mnAngle = 0;
1761 else
1763 ImplCreateShape( eShapeType,
1764 nMirrorFlags | ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1765 aSolverContainer );
1766 aPropOpt.CreateCustomShapeProperties( eShapeType, mXShape );
1767 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape);
1768 if ( ImplGetText() )
1770 if ( !aPropOpt.IsFontWork() )
1772 mnTxId += 0x60;
1773 aPropOpt.CreateTextProperties( mXPropSet, mnTxId, true );
1778 else if ( mType == "drawing.Rectangle" )
1780 sal_Int32 nRadius = 0;
1781 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1782 if ( ImplGetPropertyValue( "CornerRadius" ) )
1784 mAny >>= nRadius;
1785 nRadius = MapSize( css::awt::Size( nRadius, 0 ) ).Width;
1787 if ( nRadius )
1789 ImplCreateShape( ESCHER_ShpInst_RoundRectangle,
1790 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1791 aSolverContainer );
1792 sal_Int32 nLength = maRect.GetWidth();
1793 if ( nLength > maRect.GetHeight() )
1794 nLength = maRect.GetHeight();
1795 nLength >>= 1;
1796 if ( nRadius >= nLength )
1797 nRadius = 0x2a30; // 0x2a30 is PPTs maximum radius
1798 else
1800 if (nLength != 0)
1801 nRadius = ( 0x2a30 * nRadius ) / nLength;
1802 else
1803 nRadius = 0x2a30; // 0x2a30 is PPTs maximum radius
1805 aPropOpt.AddOpt( ESCHER_Prop_adjustValue, nRadius );
1807 else
1809 ImplCreateShape( ESCHER_ShpInst_Rectangle,
1810 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1811 aSolverContainer );
1813 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
1814 if ( ImplGetText() )
1816 mnTxId += 0x60;
1817 aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
1820 else if ( mType == "drawing.Ellipse" )
1822 css::drawing::CircleKind eCircleKind( css::drawing::CircleKind_FULL );
1823 PolyStyle ePolyKind = PolyStyle::Chord;
1824 if ( ImplGetPropertyValue( "CircleKind" ) )
1826 mAny >>= eCircleKind;
1827 switch ( eCircleKind )
1829 case css::drawing::CircleKind_SECTION :
1831 ePolyKind = PolyStyle::Pie;
1833 break;
1834 case css::drawing::CircleKind_ARC :
1836 ePolyKind = PolyStyle::Arc;
1838 break;
1840 case css::drawing::CircleKind_CUT :
1842 ePolyKind = PolyStyle::Chord;
1844 break;
1846 default:
1847 eCircleKind = css::drawing::CircleKind_FULL;
1850 if ( eCircleKind == css::drawing::CircleKind_FULL )
1852 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1853 ImplCreateShape( ESCHER_ShpInst_Ellipse,
1854 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1855 aSolverContainer );
1856 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
1857 if ( ImplGetText() )
1859 mnTxId += 0x60;
1860 aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
1863 else
1865 sal_Int32 nStartAngle, nEndAngle;
1866 if ( !ImplGetPropertyValue( "CircleStartAngle" ) )
1867 continue;
1868 nStartAngle = *o3tl::doAccess<sal_Int32>(mAny);
1869 if( !ImplGetPropertyValue( "CircleEndAngle" ) )
1870 continue;
1871 nEndAngle = *o3tl::doAccess<sal_Int32>(mAny);
1872 css::awt::Point aPoint( mXShape->getPosition() );
1873 css::awt::Size aSize( mXShape->getSize() );
1874 css::awt::Point aStart, aEnd, aCenter;
1875 ::tools::Rectangle aRect( Point( aPoint.X, aPoint.Y ), Size( aSize.Width, aSize.Height ) );
1876 aStart.X = static_cast<sal_Int32>( cos( nStartAngle * F_PI18000 ) * 100.0 );
1877 aStart.Y = - static_cast<sal_Int32>( sin( nStartAngle * F_PI18000 ) * 100.0 );
1878 aEnd.X = static_cast<sal_Int32>( cos( nEndAngle * F_PI18000 ) * 100.0 );
1879 aEnd.Y = - static_cast<sal_Int32>( sin( nEndAngle * F_PI18000 ) * 100.0 ) ;
1880 aCenter.X = aPoint.X + ( aSize.Width / 2 );
1881 aCenter.Y = aPoint.Y + ( aSize.Height / 2 );
1882 aStart.X += aCenter.X;
1883 aStart.Y += aCenter.Y;
1884 aEnd.X += aCenter.X;
1885 aEnd.Y += aCenter.Y;
1886 tools::Polygon aPolygon( aRect, Point( aStart.X, aStart.Y ), Point( aEnd.X, aEnd.Y ), ePolyKind );
1887 bool bNeedText = true;
1888 if ( mnAngle )
1890 aPolygon.Rotate( aRect.TopLeft(), Degree10(static_cast<sal_Int16>( mnAngle / 10 )) );
1891 if ( ImplGetText() )
1893 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
1894 // mpPptEscherEx->EnterGroup( 0,0 );
1895 // nGroupLevel = mpPptEscherEx->GetGroupLevel();
1896 bNeedText = false;
1897 bAdditionalText = true;
1898 mnTextSize = 0;
1900 mnAngle = 0;
1902 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1903 ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
1904 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1905 aSolverContainer );
1906 css::awt::Rectangle aNewRect;
1907 switch ( ePolyKind )
1909 case PolyStyle::Pie :
1910 case PolyStyle::Chord :
1912 if ( aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect, &aPolygon ) )
1913 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
1915 break;
1917 case PolyStyle::Arc :
1919 if ( aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect, &aPolygon ) )
1920 aPropOpt.CreateLineProperties( mXPropSet, false );
1922 break;
1924 maRect = MapRectangle( aNewRect );
1925 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
1926 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
1927 if ( bNeedText && ImplGetText() )
1929 mnTxId += 0x60;
1930 aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
1934 else if ( mType == "drawing.Control" )
1936 css::uno::Reference< css::drawing::XControlShape > aXControlShape( mXShape, css::uno::UNO_QUERY );
1937 if ( !aXControlShape.is() )
1938 continue;
1939 css::uno::Reference< css::awt::XControlModel > aXControlModel( aXControlShape->getControl() );
1940 if ( !aXControlModel.is() )
1941 continue;
1943 sal_Int64 nAspect = css::embed::Aspects::MSOLE_CONTENT;
1946 // try to get the aspect when available
1947 css::uno::Reference< css::beans::XPropertySet > xShapeProps( mXShape, css::uno::UNO_QUERY_THROW );
1948 xShapeProps->getPropertyValue("Aspect") >>= nAspect;
1950 catch( css::uno::Exception& )
1953 mpExEmbed->WriteUInt32( 0xf | ( EPP_ExControl << 16 ) )
1954 .WriteUInt32( 0 ); // Size of this container
1956 sal_uInt32 nSize, nOldPos = mpExEmbed->Tell();
1958 sal_uInt32 nPageId = nPageNumber;
1959 if ( ePageType == MASTER )
1960 nPageId |= 0x80000000;
1961 else
1962 nPageId += 0x100;
1963 mpExEmbed->WriteUInt32( EPP_ExControlAtom << 16 )
1964 .WriteUInt32( 4 )
1965 .WriteUInt32( nPageId );
1966 std::unique_ptr<PPTExOleObjEntry> pEntry( new PPTExOleObjEntry( OCX_CONTROL, mpExEmbed->Tell() ) );
1967 pEntry->xControlModel = aXControlModel;
1968 pEntry->xShape = mXShape;
1969 maExOleObj.push_back( std::move(pEntry) );
1971 mnExEmbed++;
1973 mpExEmbed->WriteUInt32( 1 | ( EPP_ExOleObjAtom << 16 ) )
1974 .WriteUInt32( 24 )
1975 .WriteUInt32( nAspect )
1976 .WriteUInt32( 2 )
1977 .WriteUInt32( mnExEmbed )
1978 .WriteUInt32( 0 )
1979 .WriteUInt32( 4 ) // index to the persist table
1980 .WriteUInt32( 0x0012de00 );
1982 css::awt::Size aSize;
1983 OUString aControlName;
1984 tools::SvRef<SotStorage> xTemp( new SotStorage( new SvMemoryStream(), true ) );
1985 if ( oox::ole::MSConvertOCXControls::WriteOCXStream( mXModel, xTemp, aXControlModel, aSize, aControlName ) )
1987 OUString aUserName( xTemp->GetUserName() );
1988 OUString aOleIdentifier;
1989 if ( !aUserName.isEmpty() )
1991 tools::SvRef<SotStorageStream> xCompObj = xTemp->OpenSotStream(
1992 "\1CompObj",
1993 StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYALL );
1994 sal_uInt32 const nStreamLen = xCompObj->remainingSize();
1995 sal_Int16 nVersion, nByteOrder;
1996 sal_Int32 nWinVersion, nVal, nStringLen;
1997 xCompObj->ReadInt16( nVersion )
1998 .ReadInt16( nByteOrder )
1999 .ReadInt32( nWinVersion )
2000 .ReadInt32( nVal );
2001 xCompObj->SeekRel( 16 ); // skipping clsid
2002 xCompObj->ReadInt32( nStringLen );
2003 if ( ( xCompObj->Tell() + nStringLen ) < nStreamLen )
2005 xCompObj->SeekRel( nStringLen ); // now skipping the UserName;
2006 xCompObj->ReadInt32( nStringLen );
2007 if ( ( xCompObj->Tell() + nStringLen ) < nStreamLen )
2009 xCompObj->SeekRel( nStringLen ); // now skipping the clipboard formatname
2010 xCompObj->ReadInt32( nStringLen );
2011 if ( ( nStringLen > 1 ) && ( ( xCompObj->Tell() + nStringLen ) < nStreamLen ) )
2012 { // i think that the OleIdentifier will follow
2013 OString aTemp = read_uInt8s_ToOString(*xCompObj, nStringLen - 1);
2014 aOleIdentifier = OStringToOUString(aTemp, RTL_TEXTENCODING_MS_1252);
2020 PPTWriter::WriteCString( *mpExEmbed, aControlName, 1 );
2021 PPTWriter::WriteCString( *mpExEmbed, aOleIdentifier, 2 );
2022 PPTWriter::WriteCString( *mpExEmbed, aUserName, 3 );
2024 nSize = mpExEmbed->Tell() - nOldPos;
2025 mpExEmbed->Seek( nOldPos - 4 );
2026 mpExEmbed->WriteUInt32( nSize );
2027 mpExEmbed->Seek( STREAM_SEEK_TO_END );
2028 nOlePictureId = mnExEmbed;
2030 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2031 ShapeFlag const nSpFlags = ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor | ShapeFlag::OLEShape;
2032 ImplCreateShape( ESCHER_ShpInst_HostControl, nSpFlags, aSolverContainer );
2033 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "MetaFile", false ) )
2034 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2035 //export form control graphic
2036 else if ( aPropOpt.CreateBlipPropertiesforOLEControl(mXPropSet,mXShape))
2037 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2038 aPropOpt.AddOpt( ESCHER_Prop_pictureId, mnExEmbed );
2039 aPropOpt.AddOpt( ESCHER_Prop_pictureActive, 0x10000 );
2041 if ( !aControlName.isEmpty() )
2043 aPropOpt.AddOpt(ESCHER_Prop_wzName, aControlName);
2046 else if ( mType == "drawing.Connector" )
2048 sal_uInt16 nSpType;
2049 ShapeFlag nSpFlags;
2050 css::awt::Rectangle aNewRect;
2051 if ( !aPropOpt.CreateConnectorProperties( mXShape, aSolverContainer, aNewRect, nSpType, nSpFlags ) )
2052 continue;
2054 maRect = MapRectangle( aNewRect );
2055 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2056 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2058 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2059 ImplCreateShape( nSpType, nSpFlags, aSolverContainer );
2061 // #119459# for connector shape, the start point and end point is fixed, and should not be rotated.
2062 mnAngle = 0;
2064 else if ( mType == "drawing.Measure" )
2066 continue;
2068 else if ( mType == "drawing.Line" )
2070 css::awt::Rectangle aNewRect;
2071 aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_LINE, false, aNewRect );
2072 maRect = MapRectangle( aNewRect );
2073 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2074 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2075 if ( ImplGetText() )
2077 aTextRefPoint = css::awt::Point( maRect.Left(), maRect.Top() );
2078 mnTextSize = 0;
2079 bAdditionalText = true;
2080 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2081 // mpPptEscherEx->EnterGroup( &maRect,0 );
2083 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2084 ShapeFlag nFlags = ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty;
2086 if ( maRect.Top() > maRect.Bottom() )
2087 nFlags |= ShapeFlag::FlipV;
2088 if ( maRect.Left() > maRect.Right() )
2089 nFlags |= ShapeFlag::FlipH;
2091 ImplCreateShape( ESCHER_ShpInst_Line, nFlags, aSolverContainer );
2092 aPropOpt.AddOpt( ESCHER_Prop_shapePath, ESCHER_ShapeComplex );
2093 aPropOpt.CreateLineProperties( mXPropSet, false );
2094 mnAngle = 0;
2096 else if ( bPolyPolygon )
2098 if ( ImplGetText() )
2100 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2101 // mpPptEscherEx->EnterGroup( 0,0 );
2102 // nGroupLevel = mpPptEscherEx->GetGroupLevel();
2103 bAdditionalText = true;
2104 mnTextSize = 0;
2106 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2107 ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
2108 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2109 aSolverContainer );
2110 css::awt::Rectangle aNewRect;
2111 aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect );
2112 maRect = MapRectangle( aNewRect );
2113 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2114 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2115 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
2116 mnAngle = 0;
2118 else if ( bPolyLine )
2120 if ( ImplGetText() )
2122 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2123 // mpPptEscherEx->EnterGroup( 0,0 );
2124 // nGroupLevel = mpPptEscherEx->GetGroupLevel();
2125 bAdditionalText = true;
2126 mnTextSize = 0;
2128 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2129 ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
2130 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2131 aSolverContainer );
2132 css::awt::Rectangle aNewRect;
2133 aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect );
2134 maRect = MapRectangle( aNewRect );
2135 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2136 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2137 aPropOpt.CreateLineProperties( mXPropSet, false );
2138 mnAngle = 0;
2140 else if ( bOpenBezier )
2142 if ( ImplGetText() )
2144 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2145 // mpPptEscherEx->EnterGroup( 0,0 );
2146 // nGroupLevel = mpPptEscherEx->GetGroupLevel();
2147 bAdditionalText = true;
2148 mnTextSize = 0;
2150 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2151 ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
2152 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2153 aSolverContainer );
2154 css::awt::Rectangle aNewRect;
2155 aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, true, aNewRect );
2156 maRect = MapRectangle( aNewRect );
2157 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2158 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2159 aPropOpt.CreateLineProperties( mXPropSet, false );
2160 mnAngle = 0;
2162 else if ( bClosedBezier )
2164 if ( ImplGetText() )
2166 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2167 // mpPptEscherEx->EnterGroup( 0,0 );
2168 // nGroupLevel = mpPptEscherEx->GetGroupLevel();
2169 bAdditionalText = true;
2170 mnTextSize = 0;
2172 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2173 ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
2174 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2175 aSolverContainer );
2176 css::awt::Rectangle aNewRect;
2177 aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, true, aNewRect );
2178 maRect = MapRectangle( aNewRect );
2179 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2180 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2181 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
2182 mnAngle = 0;
2184 else if ( ( mType == "drawing.GraphicObject" ) || ( mType == "presentation.GraphicObject" ) )
2186 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2188 // a GraphicObject can also be a ClickMe element
2189 if ( mbEmptyPresObj && ( ePageType == NORMAL ) )
2191 nPlaceHolderAtom = rLayout.nUsedObjectPlaceHolder;
2192 ImplCreateShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster, aSolverContainer );
2193 mnTxId += 0x60;
2194 aPropOpt.AddOpt( ESCHER_Prop_lTxid, mnTxId );
2195 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
2196 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 );
2197 aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
2199 else
2201 mXText.set( mXShape, css::uno::UNO_QUERY );
2203 if ( mXText.is() )
2204 mnTextSize = mXText->getString().getLength();
2206 if ( mnTextSize ) // graphic object or area fill
2208 /* SJ #i34951#: because M. documents are not allowing GraphicObjects containing text, we
2209 have to create a simple Rectangle with fill bitmap instead (while not allowing BitmapMode_Repeat).
2211 ImplCreateShape( ESCHER_ShpInst_Rectangle,
2212 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2213 aSolverContainer );
2214 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "Graphic", true, true, false ) )
2216 aPropOpt.AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapNone );
2217 aPropOpt.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
2218 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x140014 );
2219 aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x8000000 );
2220 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
2221 if ( ImplGetText() )
2223 mnTxId += 0x60;
2224 aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
2228 else
2230 ImplCreateShape( ESCHER_ShpInst_PictureFrame,
2231 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2232 aSolverContainer );
2234 if (aPropOpt.CreateGraphicProperties(mXPropSet, aGraphicPropertyName, false,
2235 true))
2237 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2242 else if ( ( mType == "drawing.Text" ) || ( mType == "presentation.Notes" ) )
2244 if ( ( ePageType == NOTICE ) && mbPresObj )
2246 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Notes, EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE ) )
2247 continue;
2248 else
2249 nPlaceHolderAtom = EPP_PLACEHOLDER_NOTESBODY;
2251 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2253 else if ( mType == "presentation.TitleText" )
2255 if ( mbPresObj )
2257 if ( ( ePageType == NOTICE ) && mbEmptyPresObj )
2259 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2260 nPlaceHolderAtom = EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE;
2261 ImplCreateShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveAnchor, aSolverContainer );
2262 aPropOpt.CreateLineProperties( mXPropSet, false );
2263 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
2265 else if ( rLayout.bTitlePossible && bIsTitlePossible )
2267 bIsTitlePossible = false;
2269 ImplGetText();
2270 TextObjBinary aTextObj( mXText, EPP_TEXTTYPE_Title, maFontCollection, static_cast<PPTExBulletProvider&>(*this) );
2271 if ( ePageType == MASTER )
2273 if ( mnTextSize )
2275 OUString aUString( mXText->getString() );
2276 sal_uInt16 nChar;
2278 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2279 mnShapeMasterTitle = mpPptEscherEx->GenerateShapeId();
2280 mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
2281 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2282 mnShapeMasterTitle );
2283 EscherPropertyContainer aPropertyOptions;
2284 aPropertyOptions.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x50001 );
2285 mnTxId += 0x60;
2286 aPropertyOptions.AddOpt( ESCHER_Prop_lTxid, mnTxId );
2287 aPropertyOptions.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
2288 aPropertyOptions.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110001 );
2289 aPropertyOptions.AddOpt( ESCHER_Prop_lineColor, 0x8000001 );
2290 aPropertyOptions.AddOpt( ESCHER_Prop_shadowColor, 0x8000002 );
2291 aPropertyOptions.CreateFillProperties( mXPropSet, true, mXShape );
2292 sal_uInt32 nLineFlags = 0x90001;
2293 if ( aPropertyOptions.GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ) )
2294 nLineFlags |= 0x10001; // draw dashed line if no line
2295 aPropertyOptions.AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
2296 mnTxId += 0x60;
2297 aPropertyOptions.CreateTextProperties( mXPropSet, mnTxId );
2298 ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt );
2299 aPropertyOptions.Commit( *mpStrm );
2300 mpPptEscherEx->AddAtom( 8, ESCHER_ClientAnchor );
2301 mpStrm->WriteInt16( maRect.Top() ).WriteInt16( maRect.Left() ).WriteInt16( maRect.Right() ).WriteInt16( maRect.Bottom() ); // top, left, right, bottom ????
2302 mpPptEscherEx->OpenContainer( ESCHER_ClientData );
2303 mpPptEscherEx->AddAtom( 8, EPP_OEPlaceholderAtom );
2304 mpStrm->WriteUInt32( 0 ) // PlacementID
2305 .WriteUChar( EPP_PLACEHOLDER_MASTERTITLE ) // PlaceHolderID
2306 .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
2307 .WriteUInt16( 0 ); // padword
2308 mpPptEscherEx->CloseContainer(); // ESCHER_ClientData
2309 mpPptEscherEx->OpenContainer( ESCHER_ClientTextbox );
2310 mpPptEscherEx->AddAtom( 4, EPP_TextHeaderAtom );
2311 mpStrm->WriteUInt32( EPP_TEXTTYPE_Title );
2312 mpPptEscherEx->AddAtom( mnTextSize << 1, EPP_TextCharsAtom );
2313 const sal_Unicode* pString = aUString.getStr();
2314 for ( sal_uInt32 i = 0; i < mnTextSize; i++ )
2316 nChar = pString[ i ]; // 0xa -> 0xb soft newline
2317 if ( nChar == 0xa )
2318 nChar++; // 0xd -> 0xd hard newline
2319 mpStrm->WriteUInt16( nChar );
2321 mpPptEscherEx->AddAtom( 6, EPP_BaseTextPropAtom );
2322 mpStrm->WriteUInt32( mnTextSize + 1 ).WriteUInt16( 0 );
2323 mpPptEscherEx->AddAtom( 10, EPP_TextSpecInfoAtom );
2324 mpStrm->WriteUInt32( mnTextSize + 1 ).WriteUInt32( 1 ).WriteUInt16( 0 );
2325 mpPptEscherEx->CloseContainer(); // ESCHER_ClientTextBox
2326 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
2328 continue;
2330 else
2332 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2333 mnTextStyle = EPP_TEXTSTYLE_TITLE;
2334 nPlaceHolderAtom = rLayout.nTypeOfTitle;
2335 ImplCreateShape( ESCHER_ShpInst_Rectangle,
2336 ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster,
2337 aSolverContainer );
2338 aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterTitle );
2339 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
2340 mnTxId += 0x60;
2341 aPropOpt.CreateTextProperties( mXPropSet, mnTxId );
2342 ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt );
2343 if ( mbEmptyPresObj )
2345 sal_uInt32 nNoLineDrawDash = 0;
2346 aPropOpt.GetOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
2347 nNoLineDrawDash |= 0x10001;
2348 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
2352 else
2353 mbPresObj = false;
2355 if ( !mbPresObj )
2357 mType = "drawing.Text";
2358 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2361 else if ( ( mType == "presentation.Outliner" ) || ( mType == "presentation.Subtitle" ) )
2363 if ( mbPresObj )
2365 nOutlinerCount++;
2366 if ( (rLayout.bOutlinerPossible && ( nOutlinerCount == 1 )) ||
2367 (( rLayout.bSecOutlinerPossible && ( nOutlinerCount == 2 ) ) && ( nPrevTextStyle == EPP_TEXTSTYLE_BODY ))
2370 ImplGetText();
2371 TextObjBinary aTextObj( mXText, EPP_TEXTTYPE_Body, maFontCollection, static_cast<PPTExBulletProvider&>(*this) );
2372 if ( ePageType == MASTER )
2374 nPrevTextStyle = EPP_TEXTSTYLE_TITLE;
2375 if ( mnTextSize )
2377 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2378 mnShapeMasterBody = mpPptEscherEx->GenerateShapeId();
2379 mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
2380 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2381 mnShapeMasterBody );
2382 EscherPropertyContainer aPropOpt2;
2383 aPropOpt2.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x50001 );
2384 mnTxId += 0x60;
2385 aPropOpt2.AddOpt( ESCHER_Prop_lTxid, mnTxId );
2386 aPropOpt2.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110001 );
2387 aPropOpt2.AddOpt( ESCHER_Prop_lineColor, 0x8000001 );
2388 aPropOpt2.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90001 );
2389 aPropOpt2.AddOpt( ESCHER_Prop_shadowColor, 0x8000002 );
2390 aPropOpt2.CreateFillProperties( mXPropSet, true, mXShape );
2391 sal_uInt32 nLineFlags = 0x90001;
2392 if ( aPropOpt2.GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ) )
2393 nLineFlags |= 0x10001; // draw dashed line if no line
2394 aPropOpt2.AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
2395 mnTxId += 0x60;
2396 aPropOpt2.CreateTextProperties( mXPropSet, mnTxId );
2397 ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt2 );
2398 aPropOpt2.Commit( *mpStrm );
2399 mpPptEscherEx->AddAtom( 8, ESCHER_ClientAnchor );
2400 mpStrm->WriteInt16( maRect.Top() ).WriteInt16( maRect.Left() ).WriteInt16( maRect.Right() ).WriteInt16( maRect.Bottom() ); // top, left, right, bottom ????
2401 mpPptEscherEx->OpenContainer( ESCHER_ClientData );
2402 mpPptEscherEx->AddAtom( 8, EPP_OEPlaceholderAtom );
2403 sal_uInt8 PlaceHolderID = ( mType == "presentation.Subtitle") ? EPP_PLACEHOLDER_MASTERSUBTITLE:EPP_PLACEHOLDER_MASTERBODY;
2404 mpStrm->WriteUInt32( 1 ) // PlacementID
2405 .WriteUChar( PlaceHolderID )/*(sal_uInt8)EPP_PLACEHOLDER_MASTERBODY */ // PlaceHolderID
2406 .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
2407 .WriteUInt16( 0 ); // padword
2408 mpPptEscherEx->CloseContainer(); // ESCHER_ClientData
2409 mpPptEscherEx->OpenContainer( ESCHER_ClientTextbox ); // printf
2410 mpPptEscherEx->AddAtom( 4, EPP_TextHeaderAtom );
2411 if ( mType == "presentation.Subtitle")
2412 mpStrm->WriteUInt32( EPP_TEXTTYPE_CenterBody );
2413 else
2414 mpStrm->WriteUInt32( EPP_TEXTTYPE_Body );
2415 mnTextSize = aTextObj.Count();
2416 aTextObj.Write( mpStrm.get() );
2417 mpPptEscherEx->BeginAtom();
2418 for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount() ; ++i )
2420 ParagraphObj* pPara = aTextObj.GetParagraph(i);
2421 mpStrm->WriteUInt32( pPara->CharacterCount() )
2422 .WriteUInt16( pPara->nDepth );
2424 mpPptEscherEx->EndAtom( EPP_BaseTextPropAtom );
2425 mpPptEscherEx->AddAtom( 10, EPP_TextSpecInfoAtom );
2426 mpStrm->WriteUInt32( mnTextSize ).WriteUInt32( 1 ).WriteUInt16( 0 );
2428 mpPptEscherEx->CloseContainer(); // ESCHER_ClientTextBox
2429 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
2431 continue;
2433 else
2435 mnTextStyle = EPP_TEXTSTYLE_BODY;
2436 nPlaceHolderAtom = rLayout.nTypeOfOutliner;
2437 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2438 ImplCreateShape( ESCHER_ShpInst_Rectangle,
2439 ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster,
2440 aSolverContainer );
2441 aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
2442 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
2443 mnTxId += 0x60;
2444 aPropOpt.CreateTextProperties( mXPropSet, mnTxId );
2445 ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt );
2446 if ( mbEmptyPresObj )
2448 sal_uInt32 nNoLineDrawDash = 0;
2449 aPropOpt.GetOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
2450 nNoLineDrawDash |= 0x10001;
2451 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
2455 else
2456 mbPresObj = false;
2458 if ( !mbPresObj )
2460 if (ePageType == MASTER )
2462 SdrObject* pObj = GetSdrObjectFromXShape( mXShape );
2463 if (pObj && pObj->IsNotVisibleAsMaster())
2464 continue;
2467 mType = "drawing.Text";
2468 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2471 else if ( ( mType == "drawing.Page" ) || ( mType == "presentation.Page" ) )
2473 if ( ( ePageType == NOTICE ) && mbPresObj )
2475 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Notes, EPP_PLACEHOLDER_MASTERNOTESSLIDEIMAGE ) )
2476 continue;
2477 else
2478 nPlaceHolderAtom = EPP_PLACEHOLDER_NOTESSLIDEIMAGE;
2480 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2482 else if ( mType == "drawing.Frame" )
2484 continue;
2486 else if ( ( mType == "drawing.OLE2" ) || ( mType == "presentation.OLE2" )
2487 || ( mType == "presentation.Chart" ) || ( mType == "presentation.Calc" )
2488 || ( mType == "presentation.OrgChart" ) )
2490 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2491 if ( mbEmptyPresObj && ( ePageType == NORMAL ) )
2493 nPlaceHolderAtom = rLayout.nUsedObjectPlaceHolder;
2494 ImplCreateShape( ESCHER_ShpInst_Rectangle,
2495 ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster,
2496 aSolverContainer );
2497 mnTxId += 0x60;
2498 aPropOpt.AddOpt( ESCHER_Prop_lTxid, mnTxId );
2499 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
2500 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 );
2501 aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
2503 else
2505 mpExEmbed->WriteUInt32( 0xf | ( EPP_ExEmbed << 16 ) )
2506 .WriteUInt32( 0 ); // Size of this container
2508 sal_uInt32 nSize, nOldPos = mpExEmbed->Tell();
2510 mpExEmbed->WriteUInt32( EPP_ExEmbedAtom << 16 )
2511 .WriteUInt32( 8 )
2512 .WriteUInt32( 0 ) // follow colorscheme : 0->do not follow
2513 // 1->follow colorscheme
2514 // 2->follow text and background scheme
2515 .WriteUChar( 1 ) // (bool)set if embedded server can not be locked
2516 .WriteUChar( 0 ) // (bool)do not need to send dimension
2517 .WriteUChar( 0 ) // (bool)is object a world table
2518 .WriteUChar( 0 ); // pad byte
2520 std::unique_ptr<PPTExOleObjEntry> pE( new PPTExOleObjEntry( NORMAL_OLE_OBJECT, mpExEmbed->Tell() ) );
2521 pE->xShape = mXShape;
2522 maExOleObj.push_back( std::move(pE) );
2524 mnExEmbed++;
2526 sal_Int64 nAspect = css::embed::Aspects::MSOLE_CONTENT;
2529 // try to get the aspect when available
2530 css::uno::Reference< css::beans::XPropertySet > xShapeProps( mXShape, css::uno::UNO_QUERY_THROW );
2531 xShapeProps->getPropertyValue("Aspect") >>= nAspect;
2533 catch( css::uno::Exception& )
2536 mpExEmbed->WriteUInt32( 1 | ( EPP_ExOleObjAtom << 16 ) )
2537 .WriteUInt32( 24 )
2538 .WriteUInt32( nAspect ) // Aspect
2539 .WriteUInt32( 0 )
2540 .WriteUInt32( mnExEmbed ) // index to the persist table
2541 .WriteUInt32( 0 ) // subtype
2542 .WriteUInt32( 0 )
2543 .WriteUInt32( 0x0012b600 );
2545 nSize = mpExEmbed->Tell() - nOldPos;
2546 mpExEmbed->Seek( nOldPos - 4 );
2547 mpExEmbed->WriteUInt32( nSize );
2548 mpExEmbed->Seek( STREAM_SEEK_TO_END );
2549 nOlePictureId = mnExEmbed;
2551 ShapeFlag nSpFlags = ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty;
2552 if ( nOlePictureId )
2553 nSpFlags |= ShapeFlag::OLEShape;
2554 ImplCreateShape( ESCHER_ShpInst_PictureFrame, nSpFlags, aSolverContainer );
2555 if ( aPropOpt.CreateOLEGraphicProperties( mXShape ) )
2556 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2557 if ( nOlePictureId )
2558 aPropOpt.AddOpt( ESCHER_Prop_pictureId, nOlePictureId );
2561 else if ( mType == "presentation.Header" )
2563 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERHEADER ) )
2564 continue;
2565 else
2567 mbPresObj = false;
2568 mType = "drawing.Text";
2569 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2572 else if ( mType == "presentation.Footer" )
2574 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERFOOTER ) )
2575 continue;
2576 else
2578 mbPresObj = false;
2579 mType = "drawing.Text";
2580 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2583 else if ( mType == "presentation.DateTime" )
2585 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERDATE ) )
2586 continue;
2587 else
2589 mbPresObj = false;
2590 mType = "drawing.Text";
2591 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2594 else if ( mType == "presentation.SlideNumber" )
2596 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERSLIDENUMBER ) )
2597 continue;
2598 else
2600 mbPresObj = false;
2601 mType = "drawing.Text";
2602 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2605 else if ( (mType.getLength() > 9) && (mType[8] == '3') && (mType[9] == 'D') ) // drawing.3D
2607 // SceneObject, CubeObject, SphereObject, LatheObject, ExtrudeObject, PolygonObject
2608 if ( !ImplGetPropertyValue( "Bitmap" ) )
2609 continue;
2611 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2612 ImplCreateShape( ESCHER_ShpInst_PictureFrame,
2613 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2614 aSolverContainer );
2616 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "Bitmap", false ) )
2617 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2619 else if ( mType == "drawing.Media" )
2621 mnAngle = 0;
2622 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2623 ImplCreateShape( ESCHER_ShpInst_PictureFrame,
2624 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2625 aSolverContainer );
2626 if ( aPropOpt.CreateMediaGraphicProperties( mXShape ) )
2627 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2628 css::uno::Any aAny;
2629 if ( PropValue::GetPropertyValue( aAny, mXPropSet, "MediaURL", true ) )
2631 OUString aMediaURL;
2632 if ( (aAny >>= aMediaURL ) && !aMediaURL.isEmpty() )
2634 // SJ: creating the Media RefObj
2635 sal_uInt32 nRefId = ++mnExEmbed;
2637 mpExEmbed->WriteUInt16( 0xf )
2638 .WriteUInt16( EPP_ExMCIMovie ) // PPT_PST_ExAviMovie
2639 .WriteUInt32( 0 );
2640 sal_uInt32 nSize, nStart = mpExEmbed->Tell();
2641 mpExEmbed->WriteUInt16( 0 )
2642 .WriteUInt16( EPP_ExObjRefAtom )
2643 .WriteUInt32( 4 )
2644 .WriteUInt32( nRefId );
2645 mpExEmbed->WriteUInt16( 0xf )
2646 .WriteUInt16( EPP_ExVideo )
2647 .WriteUInt32( 0 );
2649 mpExEmbed->WriteUInt16( 0 )
2650 .WriteUInt16( EPP_ExMediaAtom )
2651 .WriteUInt32( 8 )
2652 .WriteUInt32( nRefId )
2653 .WriteUInt16( 0 )
2654 .WriteUInt16( 0x435 );
2656 sal_uInt16 i, nStringLen = static_cast<sal_uInt16>(aMediaURL.getLength());
2657 mpExEmbed->WriteUInt32( EPP_CString << 16 ).WriteUInt32( nStringLen * 2 );
2658 for ( i = 0; i < nStringLen; i++ )
2660 sal_Unicode nChar = aMediaURL[ i ];
2661 mpExEmbed->WriteUInt16( nChar );
2663 nSize = mpExEmbed->Tell() - nStart;
2664 mpExEmbed->SeekRel( - ( static_cast<sal_Int32>(nSize) + 4 ) );
2665 mpExEmbed->WriteUInt32( nSize ); // size of PPT_PST_ExMCIMovie
2666 mpExEmbed->SeekRel( 0x10 );
2667 nSize -= 20;
2668 mpExEmbed->WriteUInt32( nSize ); // PPT_PST_ExMediaAtom
2669 mpExEmbed->SeekRel( nSize );
2671 if ( !pClientData )
2672 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2673 pClientData->WriteUInt16( 0 )
2674 .WriteUInt16( EPP_ExObjRefAtom )
2675 .WriteUInt32( 4 )
2676 .WriteUInt32( nRefId );
2677 // write EPP_InteractiveInfo container for no_action
2678 pClientData->WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0xf ).WriteUInt32( 24 );
2679 pClientData->WriteUInt16( 0 )
2680 .WriteUInt16( EPP_InteractiveInfoAtom )
2681 .WriteUInt32( 16 )
2682 .WriteUInt32( 0 )
2683 .WriteUInt32( 0 )
2684 .WriteUChar( 6 )
2685 .WriteUChar( 0 )
2686 .WriteUChar( 0 )
2687 .WriteUChar( 0 )
2688 .WriteUInt32( 0 );
2692 else if ( (mType == "drawing.Table") || (mType == "presentation.Table") )
2694 if ( eCa != css::presentation::ClickAction_NONE )
2696 SvMemoryStream aTmp(0x200, 0x200);
2697 ImplWriteClickAction( aTmp, eCa, bMediaClickAction );
2699 ImplCreateTable( mXShape, aSolverContainer, aPropOpt );
2700 continue;
2702 else if ( mType == "drawing.dontknow" )
2704 mnAngle = 0;
2705 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2706 ImplCreateShape( ESCHER_ShpInst_PictureFrame,
2707 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2708 aSolverContainer );
2709 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "MetaFile", false ) )
2710 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2712 else
2714 continue;
2717 bool bClientData = ( bEffect || ( eCa != css::presentation::ClickAction_NONE ) ||
2718 nPlaceHolderAtom || nOlePictureId );
2719 if ( bClientData )
2721 if ( nPlaceHolderAtom )
2723 sal_Int32 nPlacementID = -1;
2724 if ( ( mnTextStyle == EPP_TEXTSTYLE_TITLE ) || ( mnTextStyle == EPP_TEXTSTYLE_BODY ) )
2725 nPlacementID = nIndices++;
2726 else
2728 switch ( nPlaceHolderAtom )
2730 default :
2732 if ( nPlaceHolderAtom < 19 )
2733 break;
2734 [[fallthrough]];
2736 case EPP_PLACEHOLDER_NOTESBODY :
2737 case EPP_PLACEHOLDER_MASTERDATE :
2738 case EPP_PLACEHOLDER_NOTESSLIDEIMAGE :
2739 case EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE :
2740 nPlacementID = nIndices++;
2743 if ( !pClientData )
2744 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2746 pClientData->WriteUInt32( EPP_OEPlaceholderAtom << 16 ).WriteUInt32( 8 )
2747 .WriteInt32( nPlacementID ) // PlacementID
2748 .WriteUChar( nPlaceHolderAtom ) // PlaceHolderID
2749 .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
2750 .WriteUInt16( 0 ); // padword
2752 if ( nOlePictureId )
2754 if ( !pClientData )
2755 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2757 pClientData->WriteUInt32( EPP_ExObjRefAtom << 16 ).WriteUInt32( 4 )
2758 .WriteUInt32( nOlePictureId );
2759 nOlePictureId = 0;
2761 if ( bEffect && !pClientData )
2763 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2766 if ( eCa != css::presentation::ClickAction_NONE )
2768 if ( !pClientData )
2769 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2770 ImplWriteClickAction( *pClientData, eCa, bMediaClickAction );
2773 if ( ( mnTextStyle == EPP_TEXTSTYLE_TITLE ) || ( mnTextStyle == EPP_TEXTSTYLE_BODY ) )
2775 if ( !pClientTextBox )
2776 pClientTextBox.reset(new SvMemoryStream( 0x200, 0x200 ));
2778 if ( !mbEmptyPresObj )
2780 if ( ( ePageType == NORMAL ) && !bMasterPage )
2782 sal_uInt32 nTextType = EPP_TEXTTYPE_Body;
2783 if ( mnTextStyle == EPP_TEXTSTYLE_BODY )
2785 if ( bSecOutl )
2786 nTextType = EPP_TEXTTYPE_HalfBody;
2787 else if ( mType == "presentation.Subtitle" )
2788 nTextType = EPP_TEXTTYPE_CenterBody;
2789 bSecOutl = true;
2791 else
2792 nTextType = EPP_TEXTTYPE_Title;
2794 TextRuleEntry aTextRule;
2795 SvMemoryStream aExtBu( 0x200, 0x200 );
2796 ImplGetText();
2797 ImplWriteTextStyleAtom( *pClientTextBox, nTextType, nPObjects, &aTextRule, aExtBu, nullptr );
2798 ImplWriteExtParaHeader( aExtBu, nPObjects++, nTextType, nPageNumber + 0x100 );
2799 SvMemoryStream* pOut = aTextRule.pOut.get();
2800 if ( pOut )
2802 pClientTextBox->WriteBytes(pOut->GetData(), pOut->Tell());
2803 aTextRule.pOut.reset();
2805 if ( aExtBu.Tell() )
2807 if ( !pClientData )
2808 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2809 ImplProgTagContainer( pClientData.get(), &aExtBu );
2814 else
2816 if ( !aPropOpt.IsFontWork() )
2818 if ( mnTextSize || ( nPlaceHolderAtom == EPP_PLACEHOLDER_MASTERDATE ) || ( nPlaceHolderAtom == EPP_PLACEHOLDER_NOTESBODY ) )
2820 int nInstance2;
2821 if ( ( nPlaceHolderAtom == EPP_PLACEHOLDER_MASTERDATE ) || ( nPlaceHolderAtom == EPP_PLACEHOLDER_NOTESBODY ) )
2822 nInstance2 = 2;
2823 else
2824 nInstance2 = EPP_TEXTTYPE_Other; // Text in a Shape
2826 if ( !pClientTextBox )
2827 pClientTextBox.reset(new SvMemoryStream( 0x200, 0x200 ));
2829 SvMemoryStream aExtBu( 0x200, 0x200 );
2830 ImplWriteTextStyleAtom( *pClientTextBox, nInstance2, 0, nullptr, aExtBu, &aPropOpt );
2831 if ( aExtBu.Tell() )
2833 if ( !pClientData )
2834 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2835 ImplProgTagContainer( pClientData.get(), &aExtBu );
2838 else if ( nPlaceHolderAtom >= 19 )
2840 if ( !pClientTextBox )
2841 pClientTextBox.reset(new SvMemoryStream( 12 ));
2843 pClientTextBox->WriteUInt32( EPP_TextHeaderAtom << 16 ).WriteUInt32( 4 )
2844 .WriteUInt32( 7 );
2849 aPropOpt.CreateShadowProperties( mXPropSet );
2850 maRect.Justify();
2851 if ( mnAngle )
2852 ImplFlipBoundingBox( aPropOpt );
2853 aPropOpt.CreateShapeProperties( mXShape );
2854 aPropOpt.Commit( *mpStrm );
2855 if ( GetCurrentGroupLevel() > 0 )
2856 mpPptEscherEx->AddChildAnchor( maRect );
2857 else
2858 mpPptEscherEx->AddClientAnchor( maRect );
2860 if ( pClientData )
2862 mpStrm->WriteUInt32( ( ESCHER_ClientData << 16 ) | 0xf )
2863 .WriteUInt32( pClientData->Tell() );
2865 mpStrm->WriteBytes(pClientData->GetData(), pClientData->Tell());
2866 pClientData.reset();
2868 if ( pClientTextBox )
2870 mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
2871 .WriteUInt32( pClientTextBox->Tell() );
2873 mpStrm->WriteBytes(pClientTextBox->GetData(), pClientTextBox->Tell());
2874 pClientTextBox.reset();
2876 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
2878 nPrevTextStyle = mnTextStyle;
2880 if ( bAdditionalText )
2882 bAdditionalText = false;
2884 css::uno::Any aAny;
2885 EscherPropertyContainer aPropOpt;
2886 mnAngle = ( PropValue::GetPropertyValue( aAny,
2887 mXPropSet, "RotateAngle", true ) )
2888 ? *o3tl::doAccess<sal_Int32>(aAny)
2889 : 0;
2891 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 );
2892 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 );
2893 if ( mType == "drawing.Line" )
2895 double fDist = hypot( maRect.GetWidth(), maRect.GetHeight() );
2896 maRect = ::tools::Rectangle( Point( aTextRefPoint.X, aTextRefPoint.Y ),
2897 Point( static_cast<sal_Int32>( aTextRefPoint.X + fDist ), aTextRefPoint.Y - 1 ) );
2898 ImplCreateTextShape( aPropOpt, aSolverContainer, false );
2899 aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x60006 ); // Size Shape To Fit Text
2900 if ( mnAngle < 0 )
2901 mnAngle = ( 36000 + mnAngle ) % 36000;
2902 if ( mnAngle )
2903 ImplFlipBoundingBox( aPropOpt );
2905 else
2907 ImplCreateTextShape( aPropOpt, aSolverContainer, false );
2908 if ( mnAngle < 0 )
2909 mnAngle = ( 36000 + mnAngle ) % 36000;
2910 else
2911 mnAngle = ( 36000 - ( mnAngle % 36000 ) );
2913 mnAngle *= 655;
2914 mnAngle += 0x8000;
2915 mnAngle &=~0xffff; // round nAngle to full grad
2916 aPropOpt.AddOpt( ESCHER_Prop_Rotation, mnAngle );
2918 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2919 // mpPptEscherEx->SetGroupSnapRect( nGroupLevel, maRect );
2920 // mpPptEscherEx->SetGroupLogicRect( nGroupLevel, maRect );
2922 if ( !pClientTextBox )
2923 pClientTextBox.reset(new SvMemoryStream( 0x200, 0x200 ));
2925 SvMemoryStream aExtBu( 0x200, 0x200 );
2926 ImplWriteTextStyleAtom( *pClientTextBox, EPP_TEXTTYPE_Other, 0, nullptr, aExtBu, &aPropOpt );
2928 aPropOpt.CreateShapeProperties( mXShape );
2929 aPropOpt.Commit( *mpStrm );
2930 if ( GetCurrentGroupLevel() > 0 )
2931 mpPptEscherEx->AddChildAnchor( maRect );
2932 else
2933 mpPptEscherEx->AddClientAnchor( maRect );
2935 mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
2936 .WriteUInt32( pClientTextBox->Tell() );
2938 mpStrm->WriteBytes(pClientTextBox->GetData(), pClientTextBox->Tell());
2939 pClientTextBox.reset();
2941 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
2943 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2944 // mpPptEscherEx->LeaveGroup();
2947 ClearGroupTable(); // storing groups if any are still open, which should not be the case
2948 nGroups = GetGroupsClosed();
2949 for ( sal_uInt32 i = 0; i < nGroups; i++, mpPptEscherEx->LeaveGroup() ) ;
2950 mnPagesWritten++;
2953 struct CellBorder
2955 sal_Int32 mnPos; // specifies the distance to the top/left position of the table
2956 table::BorderLine maCellBorder;
2958 CellBorder() : mnPos ( 0 ) {};
2961 bool PPTWriter::ImplCreateCellBorder( const CellBorder* pCellBorder, sal_Int32 nX1, sal_Int32 nY1, sal_Int32 nX2, sal_Int32 nY2)
2963 sal_Int32 nLineWidth = pCellBorder->maCellBorder.OuterLineWidth + pCellBorder->maCellBorder.InnerLineWidth;
2964 if ( nLineWidth )
2966 nLineWidth *= 2;
2967 mnAngle = 0;
2968 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2969 EscherPropertyContainer aPropOptSp;
2971 sal_uInt32 nId = mpPptEscherEx->GenerateShapeId();
2972 mpPptEscherEx->AddShape( ESCHER_ShpInst_Line,
2973 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty | ShapeFlag::Child,
2974 nId );
2975 aPropOptSp.AddOpt( ESCHER_Prop_shapePath, ESCHER_ShapeComplex );
2976 aPropOptSp.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0xa0008 );
2977 aPropOptSp.AddOpt( ESCHER_Prop_fshadowObscured, 0x20000 );
2979 sal_uInt32 nBorderColor = pCellBorder->maCellBorder.Color & 0xff00; // green
2980 nBorderColor |= static_cast< sal_uInt8 >( pCellBorder->maCellBorder.Color ) << 16; // red
2981 nBorderColor |= static_cast< sal_uInt8 >( pCellBorder->maCellBorder.Color >> 16 ); // blue
2982 aPropOptSp.AddOpt( ESCHER_Prop_lineColor, nBorderColor );
2984 aPropOptSp.AddOpt( ESCHER_Prop_lineWidth, nLineWidth * 360 );
2985 aPropOptSp.AddOpt( ESCHER_Prop_fc3DLightFace, 0x80000 );
2986 aPropOptSp.Commit( *mpStrm );
2987 mpPptEscherEx->AddAtom( 16, ESCHER_ChildAnchor );
2988 mpStrm ->WriteInt32( nX1 )
2989 .WriteInt32( nY1 )
2990 .WriteInt32( nX2 )
2991 .WriteInt32( nY2 );
2992 mpPptEscherEx->CloseContainer();
2993 return true;
2995 return false;
2998 //get merged cell's width
2999 static sal_Int32 GetCellRight( sal_Int32 nColumn,
3000 ::tools::Rectangle const & rect,
3001 std::vector< std::pair< sal_Int32, sal_Int32 > >& aColumns,
3002 uno::Reference< table::XMergeableCell > const & xCell )
3004 sal_Int32 nRight = aColumns[ nColumn ].first + aColumns[ nColumn ].second;
3005 for ( sal_Int32 nColumnSpan = 1; nColumnSpan < xCell->getColumnSpan(); nColumnSpan++ )
3007 sal_uInt32 nC = nColumnSpan + nColumn;
3008 if ( nC < aColumns.size() )
3009 nRight += aColumns[ nC ].second;
3010 else
3011 nRight = rect.Right();
3013 return nRight;
3015 //get merged cell's height
3016 static sal_Int32 GetCellBottom( sal_Int32 nRow,
3017 ::tools::Rectangle const & rect,
3018 std::vector< std::pair< sal_Int32, sal_Int32 > >& aRows,
3019 uno::Reference< table::XMergeableCell > const & xCell )
3021 sal_Int32 nBottom = aRows[nRow].first + aRows[nRow].second;
3022 for ( sal_Int32 nRowSpan = 1; nRowSpan < xCell->getRowSpan(); nRowSpan++ )
3024 sal_uInt32 nR = nRowSpan + nRow;
3025 if ( nR < aRows.size() )
3026 nBottom += aRows[ nR ].second;
3027 else
3028 nBottom = rect.Bottom();
3030 return nBottom;
3033 void PPTWriter::WriteCString( SvStream& rSt, const OUString& rString, sal_uInt32 nInstance )
3035 sal_Int32 nLen = rString.getLength();
3036 if ( nLen )
3038 rSt.WriteUInt32( ( nInstance << 4 ) | ( EPP_CString << 16 ) )
3039 .WriteUInt32( nLen << 1 );
3040 for ( sal_Int32 i = 0; i < nLen; i++ )
3041 rSt.WriteUInt16( rString[i] );
3045 namespace {
3047 class ContainerGuard
3049 private:
3050 PptEscherEx* m_pPptEscherEx;
3051 public:
3052 ContainerGuard(PptEscherEx* pPptEscherEx, sal_uInt16 nRecord)
3053 : m_pPptEscherEx(pPptEscherEx)
3055 m_pPptEscherEx->OpenContainer(nRecord);
3057 ~ContainerGuard()
3059 m_pPptEscherEx->CloseContainer();
3065 void PPTWriter::ImplCreateTable( uno::Reference< drawing::XShape > const & rXShape, EscherSolverContainer& aSolverContainer,
3066 EscherPropertyContainer& aPropOpt )
3070 uno::Reference< table::XTable > xTable;
3071 if ( mXPropSet->getPropertyValue( "Model" ) >>= xTable )
3073 uno::Reference< table::XColumnRowRange > xColumnRowRange( xTable, uno::UNO_QUERY_THROW );
3074 uno::Reference< container::XIndexAccess > xColumns( xColumnRowRange->getColumns(), uno::UNO_QUERY_THROW );
3075 uno::Reference< container::XIndexAccess > xRows( xColumnRowRange->getRows(), uno::UNO_QUERY_THROW );
3076 sal_uInt16 nRowCount = static_cast< sal_uInt16 >( xRows->getCount() );
3077 sal_uInt16 nColumnCount = static_cast< sal_uInt16 >( xColumns->getCount() );
3079 std::vector< std::pair< sal_Int32, sal_Int32 > > aColumns;
3080 std::vector< std::pair< sal_Int32, sal_Int32 > > aRows;
3082 awt::Point aPosition( MapPoint( rXShape->getPosition() ) );
3083 sal_Int32 nPosition = aPosition.X;
3084 for ( sal_Int32 x = 0; x < nColumnCount; x++ )
3086 uno::Reference< beans::XPropertySet > xPropSet( xColumns->getByIndex( x ), uno::UNO_QUERY_THROW );
3087 awt::Size aS( 0, 0 );
3088 xPropSet->getPropertyValue( "Width" ) >>= aS.Width;
3089 awt::Size aM( MapSize( aS ) );
3090 aColumns.emplace_back( nPosition, aM.Width );
3091 nPosition += aM.Width;
3092 if ( x == nColumnCount - 1 && nPosition != maRect.Right() )
3093 maRect.SetRight( nPosition );
3096 nPosition = aPosition.Y;
3097 for ( sal_Int32 y = 0; y < nRowCount; y++ )
3099 uno::Reference< beans::XPropertySet > xPropSet( xRows->getByIndex( y ), uno::UNO_QUERY_THROW );
3100 awt::Size aS( 0, 0 );
3101 xPropSet->getPropertyValue( "Height" ) >>= aS.Height;
3102 awt::Size aM( MapSize( aS ) );
3103 aRows.emplace_back( nPosition, aM.Height );
3104 nPosition += aM.Height;
3105 if ( y == nRowCount - 1 && nPosition != maRect.Bottom())
3106 maRect.SetBottom( nPosition );
3108 std::unique_ptr<ContainerGuard> xSpgrContainer(new ContainerGuard(mpPptEscherEx.get(), ESCHER_SpgrContainer));
3109 std::unique_ptr<ContainerGuard> xSpContainer(new ContainerGuard(mpPptEscherEx.get(), ESCHER_SpContainer));
3110 mpPptEscherEx->AddAtom( 16, ESCHER_Spgr, 1 );
3111 mpStrm ->WriteInt32( maRect.Left() ) // Bounding box for the grouped shapes to which they are attached
3112 .WriteInt32( maRect.Top() )
3113 .WriteInt32( maRect.Right() )
3114 .WriteInt32( maRect.Bottom() );
3116 sal_uInt32 nShapeId = mpPptEscherEx->GenerateShapeId();
3117 mpPptEscherEx->AddShape( ESCHER_ShpInst_Min, ShapeFlag::HaveAnchor | ShapeFlag::Group, nShapeId );
3118 // TODO: check flags, comment does not match code // Flags: Group | Patriarch
3119 aSolverContainer.AddShape( rXShape, nShapeId );
3120 EscherPropertyContainer aPropOpt2;
3122 SvMemoryStream aMemStrm;
3123 aMemStrm.WriteUInt16( nRowCount )
3124 .WriteUInt16( nRowCount )
3125 .WriteUInt16( 4 );
3127 for( const auto& rRow : aRows )
3128 aMemStrm.WriteInt32( rRow.second );
3130 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x1000100 );
3131 aPropOpt2.AddOpt( ESCHER_Prop_tableProperties, 1 );
3132 aPropOpt2.AddOpt(ESCHER_Prop_tableRowProperties, true, 0, aMemStrm);
3133 aPropOpt.CreateShapeProperties( rXShape );
3134 aPropOpt.Commit( *mpStrm );
3135 aPropOpt2.Commit( *mpStrm, 3, ESCHER_UDefProp );
3136 if ( GetCurrentGroupLevel() > 0 )
3137 mpPptEscherEx->AddChildAnchor( maRect );
3138 else
3139 mpPptEscherEx->AddClientAnchor( maRect );
3140 xSpContainer.reset(); //ESCHER_SpContainer
3142 uno::Reference< table::XCellRange > xCellRange( xTable, uno::UNO_QUERY_THROW );
3143 for( sal_Int32 nRow = 0; nRow < xRows->getCount(); nRow++ )
3145 for( sal_Int32 nColumn = 0; nColumn < xColumns->getCount(); nColumn++ )
3147 uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn, nRow ), uno::UNO_QUERY_THROW );
3148 if ( !xCell->isMerged() )
3150 sal_Int32 nLeft = aColumns[ nColumn ].first;
3151 sal_Int32 nTop = aRows[ nRow ].first;
3152 sal_Int32 nRight = GetCellRight( nColumn, maRect,aColumns,xCell );
3153 sal_Int32 nBottom = GetCellBottom( nRow, maRect,aRows,xCell );
3155 mbFontIndependentLineSpacing = false;
3156 mXPropSet.set( xCell, uno::UNO_QUERY_THROW );
3157 mXText.set( xCell, uno::UNO_QUERY_THROW );
3158 mnTextSize = mXText->getString().getLength();
3160 css::uno::Any aAny;
3161 if ( GetPropertyValue( aAny, mXPropSet, "FontIndependentLineSpacing", true ) )
3162 aAny >>= mbFontIndependentLineSpacing;
3164 EscherPropertyContainer aPropOptSp;
3165 std::unique_ptr<ContainerGuard> xCellContainer(new ContainerGuard(mpPptEscherEx.get(), ESCHER_SpContainer));
3166 ImplCreateShape( ESCHER_ShpInst_Rectangle,
3167 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty | ShapeFlag::Child,
3168 aSolverContainer );
3169 aPropOptSp.CreateFillProperties( mXPropSet, true );
3170 aPropOptSp.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 );
3171 mnTxId += 0x60;
3172 aPropOptSp.CreateTextProperties( mXPropSet, mnTxId );
3173 aPropOptSp.AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapSquare );
3175 SvMemoryStream aClientTextBox( 0x200, 0x200 );
3176 SvMemoryStream aExtBu( 0x200, 0x200 );
3178 ImplWriteTextStyleAtom( aClientTextBox, EPP_TEXTTYPE_Other, 0, nullptr, aExtBu, &aPropOptSp );
3180 // need write client data for extend bullet
3181 if ( aExtBu.Tell() )
3183 std::unique_ptr<SvMemoryStream> pClientData(new SvMemoryStream( 0x200, 0x200 ));
3184 ImplProgTagContainer( pClientData.get(), &aExtBu );
3185 mpStrm->WriteUInt32( ( ESCHER_ClientData << 16 ) | 0xf )
3186 .WriteUInt32( pClientData->Tell() );
3188 mpStrm->WriteBytes(pClientData->GetData(), pClientData->Tell());
3191 aPropOptSp.Commit( *mpStrm );
3192 mpPptEscherEx->AddAtom( 16, ESCHER_ChildAnchor );
3193 mpStrm ->WriteInt32( nLeft )
3194 .WriteInt32( nTop )
3195 .WriteInt32( nRight )
3196 .WriteInt32( nBottom );
3198 mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
3199 .WriteUInt32( aClientTextBox.Tell() );
3201 mpStrm->WriteBytes(aClientTextBox.GetData(), aClientTextBox.Tell());
3202 xCellContainer.reset();
3207 // creating horz lines
3208 for( sal_Int32 nLine = 0; nLine < ( xRows->getCount() + 1 ); nLine++ )
3210 for( sal_Int32 nColumn = 0; nColumn < xColumns->getCount(); nColumn++ )
3212 CellBorder aCellBorder;
3213 aCellBorder.mnPos = aColumns[ nColumn ].first;
3214 bool bTop = false;
3215 //write nLine*nColumn cell's top border
3216 if ( nLine < xRows->getCount() )
3217 { // top border
3218 uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn, nLine ), uno::UNO_QUERY_THROW );
3219 if ( !xCell->isMerged() )
3221 uno::Reference< beans::XPropertySet > xPropSet2( xCell, uno::UNO_QUERY_THROW );
3222 table::BorderLine aBorderLine;
3223 if ( xPropSet2->getPropertyValue( "TopBorder" ) >>= aBorderLine )
3224 aCellBorder.maCellBorder = aBorderLine;
3225 sal_Int32 nRight = GetCellRight( nColumn, maRect,aColumns,xCell );
3226 bTop = ImplCreateCellBorder( &aCellBorder, aCellBorder.mnPos,
3227 aRows[ nLine ].first, nRight, aRows[ nLine ].first );
3231 //if nLine*nColumn cell's top border is empty, check (nLine-1)*nColumn cell's bottom border
3232 //and write the last row's bottom border
3233 if (( nLine && !bTop ) || (nLine == xRows->getCount()))
3234 { // bottom border
3235 sal_Int32 nRow = nLine;
3237 while( nRow )
3238 { //find last no merged cell
3239 uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn, nRow - 1 ), uno::UNO_QUERY_THROW );
3240 if ( !xCell->isMerged() )
3242 sal_Int32 nRight = GetCellRight( nColumn, maRect,aColumns,xCell );
3243 sal_Int32 nBottom = GetCellBottom( nRow - 1, maRect,aRows,xCell );
3244 if ( nBottom == ( aRows[ nLine-1 ].first + aRows[ nLine-1 ].second ) )
3246 uno::Reference< table::XMergeableCell > xCellOwn( xCellRange->getCellByPosition( nColumn, nRow - 1 ), uno::UNO_QUERY_THROW );
3247 uno::Reference< beans::XPropertySet > xPropSet2( xCellOwn, uno::UNO_QUERY_THROW );
3248 table::BorderLine aBorderLine;
3249 if ( xPropSet2->getPropertyValue( "BottomBorder" ) >>= aBorderLine )
3250 aCellBorder.maCellBorder = aBorderLine;
3251 ImplCreateCellBorder( &aCellBorder, aCellBorder.mnPos,
3252 nBottom, nRight, nBottom);
3254 nRow=0;
3256 else
3257 nRow--;
3263 // creating vertical lines
3264 for( sal_Int32 nLine = 0; nLine < ( xColumns->getCount() + 1 ); nLine++ )
3266 for( sal_Int32 nRow = 0; nRow < xRows->getCount(); nRow++ )
3269 CellBorder aCellBorder;
3270 aCellBorder.mnPos = aRows[ nRow].first;
3271 bool bLeft = false;
3272 if ( nLine < xColumns->getCount() )
3273 { // left border
3274 uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nLine, nRow ), uno::UNO_QUERY_THROW );
3275 if (!xCell->isMerged() )
3277 uno::Reference< beans::XPropertySet > xCellSet( xCell, uno::UNO_QUERY_THROW );
3278 table::BorderLine aBorderLine;
3279 if ( xCellSet->getPropertyValue( "LeftBorder" ) >>= aBorderLine )
3280 aCellBorder.maCellBorder = aBorderLine;
3281 sal_Int32 nBottom = GetCellBottom( nRow, maRect, aRows,xCell );
3282 bLeft = ImplCreateCellBorder( &aCellBorder, aColumns[nLine].first, aCellBorder.mnPos,
3283 aColumns[nLine].first, nBottom );
3286 if ( ( nLine && !bLeft )||(nLine == xColumns->getCount()))
3287 { // right border
3288 sal_Int32 nColumn = nLine;
3289 while ( nColumn )
3291 uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn - 1, nRow ), uno::UNO_QUERY_THROW );
3292 if (!xCell->isMerged() )
3294 sal_Int32 nRight = GetCellRight( nColumn-1, maRect, aColumns,xCell );
3295 sal_Int32 nBottom = GetCellBottom( nRow, maRect, aRows, xCell );
3296 if ( nRight == (aColumns[nLine-1].first + aColumns[nLine-1].second) )
3298 uno::Reference< table::XMergeableCell > xCellOwn( xCellRange->getCellByPosition( nColumn - 1, nRow ), uno::UNO_QUERY_THROW );
3299 uno::Reference< beans::XPropertySet > xCellSet( xCellOwn, uno::UNO_QUERY_THROW );
3300 table::BorderLine aBorderLine;
3301 if ( xCellSet->getPropertyValue( "RightBorder" ) >>= aBorderLine )
3302 aCellBorder.maCellBorder = aBorderLine;
3303 ImplCreateCellBorder( &aCellBorder, nRight, aCellBorder.mnPos,
3304 nRight, nBottom );
3306 nColumn = 0;
3308 else
3309 nColumn --;
3315 xSpgrContainer.reset(); //ESCHER_SpgrContainer
3318 catch( uno::Exception& )
3323 void TextObjBinary::Write( SvStream* pStrm )
3325 sal_uInt32 nSize, nPos = pStrm->Tell();
3326 pStrm->WriteUInt32( EPP_TextCharsAtom << 16 ).WriteUInt32( 0 );
3327 for ( sal_uInt32 i = 0; i < ParagraphCount(); ++i )
3328 GetParagraph(i)->Write( pStrm );
3329 nSize = pStrm->Tell() - nPos;
3330 pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
3331 pStrm->WriteUInt32( nSize - 8 );
3332 pStrm->SeekRel( nSize - 8 );
3335 void TextObjBinary::WriteTextSpecInfo( SvStream* pStrm )
3337 sal_uInt32 nCharactersLeft( Count() );
3338 if ( nCharactersLeft < 1 )
3339 return;
3341 EscherExAtom aAnimationInfoAtom( *pStrm, EPP_TextSpecInfoAtom, 0, 0 );
3342 for ( sal_uInt32 i = 0; nCharactersLeft && i < ParagraphCount(); ++i )
3344 ParagraphObj* pPtr = GetParagraph(i);
3345 for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = pPtr->begin(); nCharactersLeft && it != pPtr->end(); ++it )
3347 const PortionObj& rPortion = **it;
3348 sal_Int32 nPortionSize = rPortion.mnTextSize >= nCharactersLeft ? nCharactersLeft : rPortion.mnTextSize;
3349 sal_Int32 const nFlags = 7;
3350 nCharactersLeft -= nPortionSize;
3351 pStrm ->WriteUInt32( nPortionSize )
3352 .WriteInt32( nFlags )
3353 .WriteInt16( 1 ) // spellinfo -> needs rechecking
3354 .WriteInt16( static_cast<sal_uInt16>(LanguageTag( rPortion.meCharLocale ).makeFallback().getLanguageType()) )
3355 .WriteInt16( 0 ); // alt language
3358 if ( nCharactersLeft )
3359 pStrm->WriteUInt32( nCharactersLeft ).WriteInt32( 1 ).WriteInt16( 1 );
3362 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */