bump product version to 6.4.0.3
[LibreOffice.git] / sd / source / filter / eppt / epptso.cxx
blobe03db4c9ddd3a1bdee04c6de6ededfca689236c7
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 <sot/storage.hxx>
33 #include <vcl/graph.hxx>
34 #include <editeng/svxenum.hxx>
35 #include <svx/svdobj.hxx>
36 #include <svx/unoapi.hxx>
37 #include <com/sun/star/awt/FontFamily.hpp>
38 #include <com/sun/star/awt/FontPitch.hpp>
39 #include <com/sun/star/awt/Rectangle.hpp>
40 #include <com/sun/star/awt/FontDescriptor.hpp>
41 #include <com/sun/star/style/TabStop.hpp>
42 #include <com/sun/star/drawing/CircleKind.hpp>
43 #include <com/sun/star/drawing/FillStyle.hpp>
44 #include <com/sun/star/beans/XPropertyState.hpp>
45 #include <com/sun/star/drawing/XControlShape.hpp>
46 #include <com/sun/star/embed/Aspects.hpp>
47 #include <tools/urlobj.hxx>
48 #include <com/sun/star/text/XSimpleText.hpp>
49 #include <com/sun/star/task/XStatusIndicator.hpp>
50 #include <com/sun/star/table/XTable.hpp>
51 #include <com/sun/star/table/XMergeableCell.hpp>
52 #include <com/sun/star/table/BorderLine.hpp>
53 #include <com/sun/star/table/XColumnRowRange.hpp>
54 #include <com/sun/star/table/XCellRange.hpp>
55 #include <oox/ole/olehelper.hxx>
56 #include <i18nlangtag/languagetag.hxx>
58 using namespace ::com::sun::star;
60 #define ANSI_CHARSET 0
61 #define SYMBOL_CHARSET 2
63 /* Font Families */
64 #define FF_ROMAN 0x10
65 #define FF_SWISS 0x20
66 #define FF_MODERN 0x30
67 #define FF_SCRIPT 0x40
68 #define FF_DECORATIVE 0x50
70 #define DEFAULT_PITCH 0x00
71 #define FIXED_PITCH 0x01
73 PPTExBulletProvider::PPTExBulletProvider()
74 : pGraphicProv( new EscherGraphicProvider( EscherGraphicProviderFlags::UseInstances ) )
78 PPTExBulletProvider::~PPTExBulletProvider()
82 sal_uInt16 PPTExBulletProvider::GetId(Graphic const & rGraphic, Size& rGraphicSize )
84 sal_uInt16 nRetValue = 0xffff;
86 if (!rGraphic.IsNone())
88 Graphic aMappedGraphic, aGraphic(rGraphic);
89 std::unique_ptr<GraphicObject> xGraphicObject(new GraphicObject(aGraphic));
90 Size aPrefSize( aGraphic.GetPrefSize() );
91 BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
93 if ( rGraphicSize.Width() && rGraphicSize.Height() )
95 Size aNewSize;
96 bool changed = false;
97 if (aPrefSize.Width() == 0 || aPrefSize.Height() == 0)
99 aBmpEx.Scale(aPrefSize);
100 aNewSize = aPrefSize;
101 changed = true;
103 else
105 double fQ1 = static_cast<double>(aPrefSize.Width()) / static_cast<double>(aPrefSize.Height());
106 double fQ2 = static_cast<double>(rGraphicSize.Width()) / static_cast<double>(rGraphicSize.Height());
107 double fXScale = 1;
108 double fYScale = 1;
110 if ( fQ1 > fQ2 )
111 fYScale = fQ1 / fQ2;
112 else if ( fQ1 < fQ2 )
113 fXScale = fQ2 / fQ1;
115 if ( ( fXScale != 1.0 ) || ( fYScale != 1.0 ) )
117 aBmpEx.Scale( fXScale, fYScale );
118 aNewSize = Size( static_cast<sal_Int32>(static_cast<double>(rGraphicSize.Width()) / fXScale + 0.5 ),
119 static_cast<sal_Int32>(static_cast<double>(rGraphicSize.Height()) / fYScale + 0.5 ) );
120 changed = true;
123 if (changed)
125 rGraphicSize = aNewSize;
127 aMappedGraphic = Graphic( aBmpEx );
128 xGraphicObject.reset(new GraphicObject(aMappedGraphic));
132 sal_uInt32 nId = pGraphicProv->GetBlibID(aBuExPictureStream, *xGraphicObject);
134 if ( nId && ( nId < 0x10000 ) )
135 nRetValue = static_cast<sal_uInt16>(nId) - 1;
137 return nRetValue;
140 sal_uInt32 PPTWriter::ImplVBAInfoContainer( SvStream* pStrm )
142 sal_uInt32 nSize = 28;
143 if ( pStrm )
145 pStrm->WriteUInt32( 0x1f | ( EPP_VBAInfo << 16 ) )
146 .WriteUInt32( nSize - 8 )
147 .WriteUInt32( 2 | ( EPP_VBAInfoAtom << 16 ) )
148 .WriteUInt32( 12 );
149 mpPptEscherEx->InsertPersistOffset( EPP_Persist_VBAInfoAtom, pStrm->Tell() );
150 pStrm->WriteUInt32( 0 )
151 .WriteUInt32( 0 )
152 .WriteUInt32( 1 );
154 return nSize;
157 sal_uInt32 PPTWriter::ImplSlideViewInfoContainer( sal_uInt32 nInstance, SvStream* pStrm )
159 sal_uInt32 nSize = 111;
160 if ( pStrm )
162 sal_uInt8 bShowGuides = 0;
163 sal_uInt8 const bSnapToGrid = 1;
164 sal_uInt8 const bSnapToShape = 0;
166 sal_Int32 nScaling = 85;
167 sal_Int32 nMasterCoordinate = 0xdda;
168 sal_Int32 nXOrigin = -780;
169 sal_Int32 nYOrigin = -84;
171 sal_Int32 nPosition1 = 0x870;
172 sal_Int32 nPosition2 = 0xb40;
174 if ( nInstance )
176 bShowGuides = 1;
177 nScaling = 0x3b;
178 nMasterCoordinate = 0xf0c;
179 nXOrigin = -1752;
180 nYOrigin = -72;
181 nPosition1 = 0xb40;
182 nPosition2 = 0x870;
184 pStrm->WriteUInt32( 0xf | ( EPP_SlideViewInfo << 16 ) | ( nInstance << 4 ) )
185 .WriteUInt32( nSize - 8 )
186 .WriteUInt32( EPP_SlideViewInfoAtom << 16 ).WriteUInt32( 3 )
187 .WriteUChar( bShowGuides ).WriteUChar( bSnapToGrid ).WriteUChar( bSnapToShape )
188 .WriteUInt32( EPP_ViewInfoAtom << 16 ).WriteUInt32( 52 )
189 .WriteInt32( nScaling ).WriteInt32( 100 ).WriteInt32( nScaling ).WriteInt32( 100 ) // scaling atom - Keeps the current scale
190 .WriteInt32( nScaling ).WriteInt32( 100 ).WriteInt32( nScaling ).WriteInt32( 100 ) // scaling atom - Keeps the previous scale
191 .WriteInt32( 0x17ac ).WriteInt32( nMasterCoordinate )// Origin - Keeps the origin in master coordinates
192 .WriteInt32( nXOrigin ).WriteInt32( nYOrigin ) // Origin
193 .WriteUChar( 1 ) // Bool1 varScale - Set if zoom to fit is set
194 .WriteUChar( 0 ) // bool1 draftMode - Not used
195 .WriteUInt16( 0 ) // padword
196 .WriteUInt32( ( 7 << 4 ) | ( EPP_GuideAtom << 16 ) ).WriteUInt32( 8 )
197 .WriteUInt32( 0 ) // Type of the guide. If the guide is horizontal this value is zero. If it's vertical, it's one.
198 .WriteInt32( nPosition1 ) // Position of the guide in master coordinates. X coordinate if it's vertical, and Y coordinate if it's horizontal.
199 .WriteUInt32( ( 7 << 4 ) | ( EPP_GuideAtom << 16 ) ).WriteUInt32( 8 )
200 .WriteInt32( 1 ) // Type of the guide. If the guide is horizontal this value is zero. If it's vertical, it's one.
201 .WriteInt32( nPosition2 ); // Position of the guide in master coordinates. X coordinate if it's vertical, and Y coordinate if it's horizontal.
203 return nSize;
206 sal_uInt32 PPTWriter::ImplOutlineViewInfoContainer( SvStream* pStrm )
208 sal_uInt32 nSize = 68;
209 if ( pStrm )
211 pStrm->WriteUInt32( 0xf | ( EPP_OutlineViewInfo << 16 ) ).WriteUInt32( nSize - 8 )
212 .WriteUInt32( EPP_ViewInfoAtom << 16 ).WriteUInt32( 52 )
213 .WriteInt32( 170 ).WriteInt32( 200 ).WriteInt32( 170 ).WriteInt32( 200 ) // scaling atom - Keeps the current scale
214 .WriteInt32( 170 ).WriteInt32( 200 ).WriteInt32( 170 ).WriteInt32( 200 ) // scaling atom - Keeps the previous scale
215 .WriteInt32( 0x17ac ).WriteInt32( 0xdda ) // Origin - Keeps the origin in master coordinates
216 .WriteInt32( -780 ).WriteInt32( -84 ) // Origin
217 .WriteUChar( 1 ) // bool1 varScale - Set if zoom to fit is set
218 .WriteUChar( 0 ) // bool1 draftMode - Not used
219 .WriteUInt16( 0 ); // padword
221 return nSize;
224 sal_uInt32 PPTWriter::ImplProgBinaryTag( SvStream* pStrm )
226 sal_uInt32 nPictureStreamSize, nOutlineStreamSize, nSize = 8;
228 nPictureStreamSize = aBuExPictureStream.Tell();
229 if ( nPictureStreamSize )
230 nSize += nPictureStreamSize + 8;
232 nOutlineStreamSize = aBuExOutlineStream.Tell();
233 if ( nOutlineStreamSize )
234 nSize += nOutlineStreamSize + 8;
236 if ( pStrm )
238 pStrm->WriteUInt32( EPP_BinaryTagData << 16 ).WriteUInt32( nSize - 8 );
239 if ( nPictureStreamSize )
241 pStrm->WriteUInt32( 0xf | ( EPP_PST_ExtendedBuGraContainer << 16 ) ).WriteUInt32( nPictureStreamSize );
242 pStrm->WriteBytes(aBuExPictureStream.GetData(), nPictureStreamSize);
244 if ( nOutlineStreamSize )
246 pStrm->WriteUInt32( 0xf | ( EPP_PST_ExtendedPresRuleContainer << 16 ) ).WriteUInt32( nOutlineStreamSize );
247 pStrm->WriteBytes(aBuExOutlineStream.GetData(), nOutlineStreamSize);
250 return nSize;
253 sal_uInt32 PPTWriter::ImplProgBinaryTagContainer( SvStream* pStrm, SvMemoryStream* pBinTagStrm )
255 sal_uInt32 nSize = 8 + 8 + 14;
256 if ( pStrm )
258 pStrm->WriteUInt32( 0xf | ( EPP_ProgBinaryTag << 16 ) ).WriteUInt32( 0 )
259 .WriteUInt32( EPP_CString << 16 ).WriteUInt32( 14 )
260 .WriteUInt32( 0x5f005f ).WriteUInt32( 0x50005f )
261 .WriteUInt32( 0x540050 ).WriteUInt16( 0x39 );
263 if ( pStrm && pBinTagStrm )
265 sal_uInt32 nLen = pBinTagStrm->Tell();
266 nSize += nLen + 8;
267 pStrm->WriteUInt32( EPP_BinaryTagData << 16 ).WriteUInt32( nLen );
268 pStrm->WriteBytes(pBinTagStrm->GetData(), nLen);
270 else
271 nSize += ImplProgBinaryTag( pStrm );
273 if ( pStrm )
275 pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
276 pStrm->WriteUInt32( nSize - 8 );
277 pStrm->SeekRel( nSize - 8 );
279 return nSize;
282 sal_uInt32 PPTWriter::ImplProgTagContainer( SvStream* pStrm, SvMemoryStream* pBinTagStrm )
284 sal_uInt32 nSize = 0;
285 if ( aBuExPictureStream.Tell() || aBuExOutlineStream.Tell() || pBinTagStrm )
287 nSize = 8;
288 if ( pStrm )
290 pStrm->WriteUInt32( 0xf | ( EPP_ProgTags << 16 ) ).WriteUInt32( 0 );
292 nSize += ImplProgBinaryTagContainer( pStrm, pBinTagStrm );
293 if ( pStrm )
295 pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
296 pStrm->WriteUInt32( nSize - 8 );
297 pStrm->SeekRel( nSize - 8 );
300 return nSize;
303 sal_uInt32 PPTWriter::ImplDocumentListContainer( SvStream* pStrm )
305 sal_uInt32 nSize = 8;
306 if ( pStrm )
308 pStrm->WriteUInt32( ( EPP_List << 16 ) | 0xf ).WriteUInt32( 0 );
311 nSize += ImplVBAInfoContainer( pStrm );
312 nSize += ImplSlideViewInfoContainer( 0, pStrm );
313 nSize += ImplOutlineViewInfoContainer( pStrm );
314 nSize += ImplSlideViewInfoContainer( 1, pStrm );
315 nSize += ImplProgTagContainer( pStrm );
317 if ( pStrm )
319 pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
320 pStrm->WriteUInt32( nSize - 8 );
321 pStrm->SeekRel( nSize - 8 );
323 return nSize;
326 sal_uInt32 PPTWriter::ImplMasterSlideListContainer( SvStream* pStrm )
328 sal_uInt32 i, nSize = 28 * mnMasterPages + 8;
329 if ( pStrm )
331 pStrm->WriteUInt32( 0x1f | ( EPP_SlideListWithText << 16 ) ).WriteUInt32( nSize - 8 );
333 for ( i = 0; i < mnMasterPages; i++ )
335 pStrm->WriteUInt32( EPP_SlidePersistAtom << 16 ).WriteUInt32( 20 );
336 mpPptEscherEx->InsertPersistOffset( EPP_MAINMASTER_PERSIST_KEY | i, pStrm->Tell() );
337 pStrm->WriteUInt32( 0 ) // psrReference - logical reference to the slide persist object ( EPP_MAINMASTER_PERSIST_KEY )
338 .WriteUInt32( 0 ) // flags - only bit 3 used, if set then slide contains shapes other than placeholders
339 .WriteInt32( 0 ) // numberTexts - number of placeholder texts stored with the persist object. Allows to display outline view without loading the slide persist objects
340 .WriteInt32( 0x80000000 | i ) // slideId - Unique slide identifier, used for OLE link monikers for example
341 .WriteUInt32( 0 ); // reserved, usually 0
344 return nSize;
347 sal_uInt32 PPTWriter::ImplInsertBookmarkURL( const OUString& rBookmarkURL, const sal_uInt32 nType,
348 const OUString& rStringVer0, const OUString& rStringVer1, const OUString& rStringVer2, const OUString& rStringVer3 )
350 sal_uInt32 nHyperId = ++mnExEmbed;
352 OUString sBookmarkURL( rBookmarkURL );
353 INetURLObject aBaseURI( maBaseURI );
354 INetURLObject aBookmarkURI( rBookmarkURL );
355 if( aBaseURI.GetProtocol() == aBookmarkURI.GetProtocol() )
357 OUString aRelUrl( INetURLObject::GetRelURL( maBaseURI, rBookmarkURL ) );
358 if ( !aRelUrl.isEmpty() )
359 sBookmarkURL = aRelUrl;
361 maHyperlink.emplace_back( sBookmarkURL, nType );
363 mpExEmbed->WriteUInt16( 0xf )
364 .WriteUInt16( EPP_ExHyperlink )
365 .WriteUInt32( 0 );
366 sal_uInt32 nHyperSize, nHyperStart = mpExEmbed->Tell();
367 mpExEmbed->WriteUInt16( 0 )
368 .WriteUInt16( EPP_ExHyperlinkAtom )
369 .WriteUInt32( 4 )
370 .WriteUInt32( nHyperId );
372 PPTWriter::WriteCString( *mpExEmbed, rStringVer0 );
373 PPTWriter::WriteCString( *mpExEmbed, rStringVer1, 1 );
374 PPTWriter::WriteCString( *mpExEmbed, rStringVer2, 2 );
375 PPTWriter::WriteCString( *mpExEmbed, rStringVer3, 3 );
377 nHyperSize = mpExEmbed->Tell() - nHyperStart;
378 mpExEmbed->SeekRel( - ( static_cast<sal_Int32>(nHyperSize) + 4 ) );
379 mpExEmbed->WriteUInt32( nHyperSize );
380 mpExEmbed->SeekRel( nHyperSize );
381 return nHyperId;
384 bool PPTWriter::ImplCloseDocument()
386 sal_uInt32 nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_Document );
387 if ( nOfs )
389 mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_CurrentPos, mpStrm->Tell() );
390 mpStrm->Seek( nOfs );
392 // creating the TxMasterStyleAtom
393 SvMemoryStream aTxMasterStyleAtomStrm( 0x200, 0x200 );
395 EscherExAtom aTxMasterStyleAtom( aTxMasterStyleAtomStrm, EPP_TxMasterStyleAtom, EPP_TEXTTYPE_Other );
396 aTxMasterStyleAtomStrm.WriteUInt16( 5 ); // paragraph count
397 sal_uInt16 nLev;
398 for ( nLev = 0; nLev < 5; nLev++ )
400 mpStyleSheet->mpParaSheet[ EPP_TEXTTYPE_Other ]->Write( aTxMasterStyleAtomStrm, nLev, false, mXPagePropSet );
401 mpStyleSheet->mpCharSheet[ EPP_TEXTTYPE_Other ]->Write( aTxMasterStyleAtomStrm, nLev, false, mXPagePropSet );
405 sal_uInt32 nExEmbedSize = mpExEmbed->TellEnd();
407 // nEnvironment : whole size of the environment container
408 sal_uInt32 nEnvironment = maFontCollection.GetCount() * 76 // 68 bytes per Fontenityatom and 8 Bytes per header
409 + 8 // 1 FontCollection container
410 + 20 // SrKinsoku container
411 + 18 // 1 TxSiStyleAtom
412 + aTxMasterStyleAtomStrm.Tell() // 1 TxMasterStyleAtom;
413 + PPTExStyleSheet::SizeOfTxCFStyleAtom();
415 sal_uInt32 nBytesToInsert = nEnvironment + 8;
417 if ( nExEmbedSize )
418 nBytesToInsert += nExEmbedSize + 8 + 12;
420 nBytesToInsert += maSoundCollection.GetSize();
421 nBytesToInsert += mpPptEscherEx->DrawingGroupContainerSize();
422 nBytesToInsert += ImplMasterSlideListContainer(nullptr);
423 nBytesToInsert += ImplDocumentListContainer(nullptr);
425 // insert nBytes into stream and adjust depending container
426 mpPptEscherEx->InsertAtCurrentPos( nBytesToInsert );
428 // CREATE HYPERLINK CONTAINER
429 if ( nExEmbedSize )
431 mpStrm->WriteUInt16( 0xf )
432 .WriteUInt16( EPP_ExObjList )
433 .WriteUInt32( nExEmbedSize + 12 )
434 .WriteUInt16( 0 )
435 .WriteUInt16( EPP_ExObjListAtom )
436 .WriteUInt32( 4 )
437 .WriteUInt32( mnExEmbed );
438 mpPptEscherEx->InsertPersistOffset( EPP_Persist_ExObj, mpStrm->Tell() );
439 mpStrm->WriteBytes(mpExEmbed->GetData(), nExEmbedSize);
442 // CREATE ENVIRONMENT
443 mpStrm->WriteUInt16( 0xf ).WriteUInt16( EPP_Environment ).WriteUInt32( nEnvironment );
445 // Open Container ( EPP_SrKinsoku )
446 mpStrm->WriteUInt16( 0x2f ).WriteUInt16( EPP_SrKinsoku ).WriteUInt32( 12 );
447 mpPptEscherEx->AddAtom( 4, EPP_SrKinsokuAtom, 0, 3 );
448 mpStrm->WriteInt32( 0 ); // SrKinsoku Level 0
450 // Open Container ( EPP_FontCollection )
451 mpStrm->WriteUInt16( 0xf ).WriteUInt16( EPP_FontCollection ).WriteUInt32( maFontCollection.GetCount() * 76 );
453 for ( sal_uInt32 i = 0; i < maFontCollection.GetCount(); i++ )
455 mpPptEscherEx->AddAtom( 68, EPP_FontEnityAtom, 0, i );
456 const FontCollectionEntry* pDesc = maFontCollection.GetById( i );
457 sal_Int32 nFontLen = pDesc->Name.getLength();
458 if ( nFontLen > 31 )
459 nFontLen = 31;
460 for ( sal_Int32 n = 0; n < 32; n++ )
462 sal_Unicode nUniCode = 0;
463 if ( n < nFontLen )
464 nUniCode = pDesc->Name[n];
465 mpStrm->WriteUInt16( nUniCode );
467 sal_uInt8 lfCharSet = ANSI_CHARSET;
468 sal_uInt8 const lfClipPrecision = 0;
469 sal_uInt8 const lfQuality = 6;
470 sal_uInt8 lfPitchAndFamily = 0;
472 if ( pDesc->CharSet == RTL_TEXTENCODING_SYMBOL )
473 lfCharSet = SYMBOL_CHARSET;
475 switch( pDesc->Family )
477 case css::awt::FontFamily::ROMAN :
478 lfPitchAndFamily |= FF_ROMAN;
479 break;
481 case css::awt::FontFamily::SWISS :
482 lfPitchAndFamily |= FF_SWISS;
483 break;
485 case css::awt::FontFamily::MODERN :
486 lfPitchAndFamily |= FF_MODERN;
487 break;
489 case css::awt::FontFamily::SCRIPT:
490 lfPitchAndFamily |= FF_SCRIPT;
491 break;
493 case css::awt::FontFamily::DECORATIVE:
494 lfPitchAndFamily |= FF_DECORATIVE;
495 break;
497 default:
498 lfPitchAndFamily |= FAMILY_DONTKNOW;
499 break;
501 switch( pDesc->Pitch )
503 case css::awt::FontPitch::FIXED:
504 lfPitchAndFamily |= FIXED_PITCH;
505 break;
507 default:
508 lfPitchAndFamily |= DEFAULT_PITCH;
509 break;
511 mpStrm->WriteUChar( lfCharSet )
512 .WriteUChar( lfClipPrecision )
513 .WriteUChar( lfQuality )
514 .WriteUChar( lfPitchAndFamily );
516 mpStyleSheet->WriteTxCFStyleAtom( *mpStrm ); // create style that is used for new standard objects
517 mpPptEscherEx->AddAtom( 10, EPP_TxSIStyleAtom );
518 mpStrm->WriteUInt32( 7 ) // ?
519 .WriteInt16( 2 ) // ?
520 .WriteUChar( 9 ) // ?
521 .WriteUChar( 8 ) // ?
522 .WriteInt16( 0 ); // ?
524 mpStrm->WriteBytes(aTxMasterStyleAtomStrm.GetData(), aTxMasterStyleAtomStrm.Tell());
525 maSoundCollection.Write( *mpStrm );
526 mpPptEscherEx->WriteDrawingGroupContainer( *mpStrm );
527 ImplMasterSlideListContainer( mpStrm.get() );
528 ImplDocumentListContainer( mpStrm.get() );
530 sal_uInt32 nOldPos = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_CurrentPos );
531 if ( nOldPos )
533 mpStrm->Seek( nOldPos );
534 return true;
537 return false;
540 bool PropValue::GetPropertyValue(
541 css::uno::Any& rAny,
542 const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
543 const OUString& rString,
544 bool bTestPropertyAvailability )
546 bool bRetValue = true;
547 if ( bTestPropertyAvailability )
549 bRetValue = false;
552 css::uno::Reference< css::beans::XPropertySetInfo > aXPropSetInfo( rXPropSet->getPropertySetInfo() );
553 if ( aXPropSetInfo.is() )
554 bRetValue = aXPropSetInfo->hasPropertyByName( rString );
556 catch( css::uno::Exception& )
558 bRetValue = false;
561 if ( bRetValue )
565 rAny = rXPropSet->getPropertyValue( rString );
566 if ( !rAny.hasValue() )
567 bRetValue = false;
569 catch( css::uno::Exception& )
571 bRetValue = false;
574 return bRetValue;
577 css::beans::PropertyState PropValue::GetPropertyState(
578 const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
579 const OUString& rPropertyName )
581 css::beans::PropertyState eRetValue = css::beans::PropertyState_AMBIGUOUS_VALUE;
584 css::uno::Reference< css::beans::XPropertyState > aXPropState( rXPropSet, css::uno::UNO_QUERY );
585 if ( aXPropState.is() )
586 eRetValue = aXPropState->getPropertyState( rPropertyName );
588 catch( css::uno::Exception& )
592 return eRetValue;
595 bool PropValue::ImplGetPropertyValue( const OUString& rString )
597 return GetPropertyValue( mAny, mXPropSet, rString );
600 bool PropValue::ImplGetPropertyValue( const css::uno::Reference< css::beans::XPropertySet > & aXPropSet, const OUString& rString )
602 return GetPropertyValue( mAny, aXPropSet, rString );
605 bool PropStateValue::ImplGetPropertyValue( const OUString& rString, bool bGetPropertyState )
607 ePropState = css::beans::PropertyState_AMBIGUOUS_VALUE;
608 bool bRetValue = true;
609 #ifdef UNX
610 css::uno::Reference< css::beans::XPropertySetInfo >
611 aXPropSetInfo( mXPropSet->getPropertySetInfo() );
612 if ( !aXPropSetInfo.is() )
613 return false;
614 #endif
617 mAny = mXPropSet->getPropertyValue( rString );
618 if ( !mAny.hasValue() )
619 bRetValue = false;
620 else if ( bGetPropertyState )
621 ePropState = mXPropState->getPropertyState( rString );
622 else
623 ePropState = css::beans::PropertyState_DIRECT_VALUE;
625 catch( css::uno::Exception& )
627 bRetValue = false;
629 return bRetValue;
632 void PPTWriter::ImplWriteParagraphs( SvStream& rOut, TextObj& rTextObj )
634 bool bFirstParagraph = true;
635 sal_uInt32 nCharCount;
636 sal_uInt32 nPropertyFlags = 0;
637 sal_Int16 nLineSpacing;
638 int nInstance = rTextObj.GetInstance();
640 for ( sal_uInt32 i = 0; i < rTextObj.ParagraphCount(); ++i, bFirstParagraph = false )
642 ParagraphObj* pPara = rTextObj.GetParagraph(i);
643 const PortionObj& rPortion = pPara->front();
644 nCharCount = pPara->CharacterCount();
646 if ( ( pPara->meTextAdjust == css::beans::PropertyState_DIRECT_VALUE ) ||
647 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_Adjust, pPara->mnTextAdjust ) ) )
648 nPropertyFlags |= 0x00000800;
649 nLineSpacing = pPara->mnLineSpacing;
651 const FontCollectionEntry* pDesc = maFontCollection.GetById( rPortion.mnFont );
652 sal_Int16 nNormalSpacing = 100;
653 if ( !mbFontIndependentLineSpacing && pDesc )
655 double fN = 100.0;
656 fN *= pDesc->Scaling;
657 nNormalSpacing = static_cast<sal_Int16>( fN + 0.5 );
659 if ( !mbFontIndependentLineSpacing && bFirstParagraph && ( nLineSpacing > nNormalSpacing ) ) // sj: i28747, no replacement for fixed linespacing
661 nLineSpacing = nNormalSpacing;
662 nPropertyFlags |= 0x00001000;
664 else
666 if ( nLineSpacing > 0 )
668 if ( !mbFontIndependentLineSpacing && pDesc )
669 nLineSpacing = static_cast<sal_Int16>( static_cast<double>(nLineSpacing) * pDesc->Scaling + 0.5 );
671 else
673 if ( !pPara->mbFixedLineSpacing && rPortion.mnCharHeight > static_cast<sal_uInt16>( static_cast<double>(-nLineSpacing) * 0.001 * 72.0 / 2.54 ) ) // 1/100mm to point
674 nLineSpacing = nNormalSpacing;
675 else
676 nLineSpacing = static_cast<sal_Int16>( static_cast<double>(nLineSpacing) / 4.40972 );
678 if ( ( pPara->meLineSpacing == css::beans::PropertyState_DIRECT_VALUE ) ||
679 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_LineFeed, nLineSpacing ) ) )
680 nPropertyFlags |= 0x00001000;
682 if ( ( pPara->meLineSpacingTop == css::beans::PropertyState_DIRECT_VALUE ) ||
683 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_UpperDist, pPara->mnLineSpacingTop ) ) )
684 nPropertyFlags |= 0x00002000;
685 if ( ( pPara->meLineSpacingBottom == css::beans::PropertyState_DIRECT_VALUE ) ||
686 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_LowerDist, pPara->mnLineSpacingBottom ) ) )
687 nPropertyFlags |= 0x00004000;
688 if ( ( pPara->meForbiddenRules == css::beans::PropertyState_DIRECT_VALUE ) ||
689 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_UpperDist, pPara->mbForbiddenRules ? 1 : 0 ) ) )
690 nPropertyFlags |= 0x00020000;
691 if ( ( pPara->meParagraphPunctation == css::beans::PropertyState_DIRECT_VALUE ) ||
692 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_UpperDist, pPara->mbParagraphPunctation ? 1 : 0 ) ) )
693 nPropertyFlags |= 0x00080000;
694 if ( ( pPara->meBiDi == css::beans::PropertyState_DIRECT_VALUE ) ||
695 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_BiDi, pPara->mnBiDi ) ) )
696 nPropertyFlags |= 0x00200000;
698 sal_Int32 nBuRealSize = pPara->nBulletRealSize;
699 sal_Int16 nBulletFlags = pPara->nBulletFlags;
701 if ( pPara->bExtendedParameters )
702 nPropertyFlags |= pPara->nParaFlags;
703 else
705 nPropertyFlags |= 1; // turn off bullet explicit
706 nBulletFlags = 0;
709 // Write nTextOfs and nBullets
710 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_TextOfs, pPara->nTextOfs ) )
711 nPropertyFlags |= 0x100;
712 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_BulletOfs, pPara->nBulletOfs ))
713 nPropertyFlags |= 0x400;
715 FontCollectionEntry aFontDescEntry( pPara->aFontDesc.Name, pPara->aFontDesc.Family, pPara->aFontDesc.Pitch, pPara->aFontDesc.CharSet );
716 sal_uInt16 nFontId = static_cast<sal_uInt16>(maFontCollection.GetId( aFontDescEntry ));
718 rOut.WriteUInt32( nCharCount )
719 .WriteUInt16( pPara->nDepth ) // Level
720 .WriteUInt32( nPropertyFlags ); // Paragraph Attribut Set
722 if ( nPropertyFlags & 0xf )
723 rOut.WriteInt16( nBulletFlags );
724 if ( nPropertyFlags & 0x80 )
725 rOut.WriteUInt16( pPara->cBulletId );
726 if ( nPropertyFlags & 0x10 )
727 rOut.WriteUInt16( nFontId );
728 if ( nPropertyFlags & 0x40 )
729 rOut.WriteInt16( nBuRealSize );
730 if ( nPropertyFlags & 0x20 )
732 sal_uInt32 nBulletColor = pPara->nBulletColor;
733 if ( nBulletColor == sal_uInt32(COL_AUTO) )
735 bool bIsDark = false;
736 css::uno::Any aAny;
737 if ( PropValue::GetPropertyValue( aAny, mXPagePropSet, "IsBackgroundDark", true ) )
738 aAny >>= bIsDark;
739 nBulletColor = bIsDark ? 0xffffff : 0x000000;
741 nBulletColor &= 0xffffff;
742 nBulletColor |= 0xfe000000;
743 rOut.WriteUInt32( nBulletColor );
745 if ( nPropertyFlags & 0x00000800 )
746 rOut.WriteUInt16( pPara->mnTextAdjust );
747 if ( nPropertyFlags & 0x00001000 )
748 rOut.WriteUInt16( nLineSpacing );
749 if ( nPropertyFlags & 0x00002000 )
750 rOut.WriteUInt16( pPara->mnLineSpacingTop );
751 if ( nPropertyFlags & 0x00004000 )
752 rOut.WriteUInt16( pPara->mnLineSpacingBottom );
753 if ( nPropertyFlags & 0x100 )
754 rOut.WriteUInt16( pPara->nTextOfs );
755 if ( nPropertyFlags & 0x400 )
756 rOut.WriteUInt16( pPara->nBulletOfs );
757 if ( nPropertyFlags & 0x000e0000 )
759 sal_uInt16 nAsianSettings = 0;
760 if ( pPara->mbForbiddenRules )
761 nAsianSettings |= 1;
762 if ( pPara->mbParagraphPunctation )
763 nAsianSettings |= 4;
764 rOut.WriteUInt16( nAsianSettings );
766 if ( nPropertyFlags & 0x200000 )
767 rOut.WriteUInt16( pPara->mnBiDi );
771 void PPTWriter::ImplWritePortions( SvStream& rOut, TextObj& rTextObj )
773 sal_uInt32 nPropertyFlags;
774 int nInstance = rTextObj.GetInstance();
776 for ( sal_uInt32 i = 0; i < rTextObj.ParagraphCount(); ++i )
778 ParagraphObj* pPara = rTextObj.GetParagraph(i);
779 for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = pPara->begin(); it != pPara->end(); ++it )
781 const PortionObj& rPortion = **it;
782 nPropertyFlags = 0;
783 sal_uInt32 nCharAttr = rPortion.mnCharAttr;
784 sal_uInt32 nCharColor = rPortion.mnCharColor;
786 if ( nCharColor == sal_uInt32(COL_AUTO) ) // nCharColor depends to the background color
788 bool bIsDark = false;
789 css::uno::Any aAny;
790 if ( PropValue::GetPropertyValue( aAny, mXPagePropSet, "IsBackgroundDark", true ) )
791 aAny >>= bIsDark;
792 nCharColor = bIsDark ? 0xffffff : 0x000000;
795 nCharColor &= 0xffffff;
797 /* the portion is using the embossed or engraved attribute, which we want to map to the relief feature of PPT.
798 Because the relief feature of PPT is dependent to the background color, such a mapping can not always be used. */
799 if ( nCharAttr & 0x200 )
801 sal_uInt32 nBackgroundColor = 0xffffff;
803 if ( !nCharColor ) // special treatment for
804 nCharColor = 0xffffff; // black fontcolor
806 css::uno::Any aAny;
807 css::drawing::FillStyle aFS( css::drawing::FillStyle_NONE );
808 if ( PropValue::GetPropertyValue( aAny, mXPropSet, "FillStyle" ) )
809 aAny >>= aFS;
810 switch( aFS )
812 case css::drawing::FillStyle_GRADIENT :
814 ::tools::Rectangle aRect( Point(), Size( 28000, 21000 ) );
815 EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect );
816 aPropOpt.CreateGradientProperties( mXPropSet );
817 aPropOpt.GetOpt( ESCHER_Prop_fillColor, nBackgroundColor );
819 break;
820 case css::drawing::FillStyle_SOLID :
822 if ( PropValue::GetPropertyValue( aAny, mXPropSet, "FillColor" ) )
823 nBackgroundColor = EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(aAny) );
825 break;
826 case css::drawing::FillStyle_NONE :
828 css::uno::Any aBackAny;
829 css::drawing::FillStyle aBackFS( css::drawing::FillStyle_NONE );
830 if ( PropValue::GetPropertyValue( aBackAny, mXBackgroundPropSet, "FillStyle" ) )
831 aBackAny >>= aBackFS;
832 switch( aBackFS )
834 case css::drawing::FillStyle_GRADIENT :
836 ::tools::Rectangle aRect( Point(), Size( 28000, 21000 ) );
837 EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect );
838 aPropOpt.CreateGradientProperties( mXBackgroundPropSet );
839 aPropOpt.GetOpt( ESCHER_Prop_fillColor, nBackgroundColor );
841 break;
842 case css::drawing::FillStyle_SOLID :
844 if ( PropValue::GetPropertyValue( aAny, mXBackgroundPropSet, "FillColor" ) )
845 nBackgroundColor = EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(aAny) );
847 break;
848 default:
849 break;
852 break;
853 default:
854 break;
857 sal_Int32 nB = nBackgroundColor & 0xff;
858 nB += static_cast<sal_uInt8>( nBackgroundColor >> 8 );
859 nB += static_cast<sal_uInt8>( nBackgroundColor >> 16 );
860 // if the background color is nearly black, relief can't been used, because the text would not be visible
861 if ( nB < 0x60 || ( nBackgroundColor != nCharColor ) )
863 nCharAttr &=~ 0x200;
865 // now check if the text is part of a group, and if the previous object has the same color than the fontcolor
866 // ( and if fillcolor is not available the background color ), it is sometimes
867 // not possible to export the 'embossed' flag
868 if ( ( GetCurrentGroupLevel() > 0 ) && ( GetCurrentGroupIndex() >= 1 ) )
870 css::uno::Reference< css::drawing::XShape > aGroupedShape( GetCurrentGroupAccess()->getByIndex( GetCurrentGroupIndex() - 1 ), uno::UNO_QUERY );
871 if( aGroupedShape.is() )
873 css::uno::Reference< css::beans::XPropertySet > aPropSetOfNextShape
874 ( aGroupedShape, css::uno::UNO_QUERY );
875 if ( aPropSetOfNextShape.is() )
877 if ( PropValue::GetPropertyValue( aAny, aPropSetOfNextShape,
878 "FillColor", true ) )
880 if ( nCharColor == EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(aAny) ) )
882 nCharAttr |= 0x200;
890 nCharColor |= 0xfe000000;
891 if ( nInstance == 4 ) // special handling for normal textobjects:
892 nPropertyFlags |= nCharAttr & 0x217; // not all attributes are inherited
893 else
895 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Bold, nCharAttr ) )
896 nPropertyFlags |= 1;
897 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Italic, nCharAttr ) )
898 nPropertyFlags |= 2;
899 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Underline, nCharAttr ) )
900 nPropertyFlags |= 4;
901 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Shadow, nCharAttr ) )
902 nPropertyFlags |= 0x10;
903 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Embossed, nCharAttr ) )
904 nPropertyFlags |= 512;
906 if ( rTextObj.HasExtendedBullets() )
908 nPropertyFlags |= ( i & 0x3f ) << 10 ;
909 nCharAttr |= ( i & 0x3f ) << 10;
911 if ( ( rPortion.meFontName == css::beans::PropertyState_DIRECT_VALUE ) ||
912 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Font, rPortion.mnFont ) ) )
913 nPropertyFlags |= 0x00010000;
914 if ( ( rPortion.meAsianOrComplexFont == css::beans::PropertyState_DIRECT_VALUE ) ||
915 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_AsianOrComplexFont, rPortion.mnAsianOrComplexFont ) ) )
916 nPropertyFlags |= 0x00200000;
917 if ( ( rPortion.meCharHeight == css::beans::PropertyState_DIRECT_VALUE ) ||
918 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_FontHeight, rPortion.mnCharHeight ) ) )
919 nPropertyFlags |= 0x00020000;
920 if ( ( rPortion.meCharColor == css::beans::PropertyState_DIRECT_VALUE ) ||
921 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_FontColor, nCharColor & 0xffffff ) ) )
922 nPropertyFlags |= 0x00040000;
923 if ( ( rPortion.meCharEscapement == css::beans::PropertyState_DIRECT_VALUE ) ||
924 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Escapement, rPortion.mnCharEscapement ) ) )
925 nPropertyFlags |= 0x00080000;
927 sal_uInt32 nCharCount = rPortion.Count();
929 rOut.WriteUInt32( nCharCount )
930 .WriteUInt32( nPropertyFlags ); //PropertyFlags
932 if ( nPropertyFlags & 0xffff )
933 rOut.WriteUInt16( nCharAttr );
934 if ( nPropertyFlags & 0x00010000 )
935 rOut.WriteUInt16( rPortion.mnFont );
936 if ( nPropertyFlags & 0x00200000 )
937 rOut.WriteUInt16( rPortion.mnAsianOrComplexFont );
938 if ( nPropertyFlags & 0x00020000 )
939 rOut.WriteUInt16( rPortion.mnCharHeight );
940 if ( nPropertyFlags & 0x00040000 )
941 rOut.WriteUInt32( nCharColor );
942 if ( nPropertyFlags & 0x00080000 )
943 rOut.WriteInt16( rPortion.mnCharEscapement );
949 * Loads and converts text from shape, value is stored in mnTextSize.
951 bool PPTWriter::ImplGetText()
953 mnTextSize = 0;
954 mbFontIndependentLineSpacing = false;
955 mXText.set( mXShape, css::uno::UNO_QUERY );
957 if ( mXText.is() )
959 mnTextSize = mXText->getString().getLength();
960 css::uno::Any aAny;
961 if ( GetPropertyValue( aAny, mXPropSet, "FontIndependentLineSpacing", true ) )
962 aAny >>= mbFontIndependentLineSpacing;
964 return ( mnTextSize != 0 );
967 void PPTWriter::ImplFlipBoundingBox( EscherPropertyContainer& rPropOpt )
969 if ( mnAngle < 0 )
970 mnAngle = ( 36000 + mnAngle ) % 36000;
971 else
972 mnAngle = ( 36000 - ( mnAngle % 36000 ) );
974 double fCos = cos( static_cast<double>(mnAngle) * F_PI18000 );
975 double fSin = sin( static_cast<double>(mnAngle) * F_PI18000 );
977 double fWidthHalf = maRect.GetWidth() / 2.0;
978 double fHeightHalf = maRect.GetHeight() / 2.0;
980 double fXDiff = fCos * fWidthHalf + fSin * (-fHeightHalf);
981 double fYDiff = - ( fSin * fWidthHalf - fCos * ( -fHeightHalf ) );
983 maRect.Move( static_cast<sal_Int32>( -( fWidthHalf - fXDiff ) ), static_cast<sal_Int32>( - ( fHeightHalf + fYDiff ) ) );
984 mnAngle *= 655;
985 mnAngle += 0x8000;
986 mnAngle &=~0xffff; // round nAngle to full grads
987 rPropOpt.AddOpt( ESCHER_Prop_Rotation, mnAngle );
989 if ( ( mnAngle >= ( 45 << 16 ) && mnAngle < ( 135 << 16 ) ) ||
990 ( mnAngle >= ( 225 << 16 ) && mnAngle < ( 315 << 16 ) ) )
992 // Maddeningly, in those two areas of PPT is the BoundingBox already
993 // vertical. Therefore, we need to put down it BEFORE THE ROTATION.
994 css::awt::Point aTopLeft( static_cast<sal_Int32>( maRect.Left() + fWidthHalf - fHeightHalf ), static_cast<sal_Int32>( maRect.Top() + fHeightHalf - fWidthHalf ) );
995 const long nRotatedWidth(maRect.GetHeight());
996 const long nRotatedHeight(maRect.GetWidth());
997 const Size aNewSize(nRotatedWidth, nRotatedHeight);
998 maRect = ::tools::Rectangle( Point( aTopLeft.X, aTopLeft.Y ), aNewSize );
1002 void PPTWriter::ImplAdjustFirstLineLineSpacing( TextObj& rTextObj, EscherPropertyContainer& rPropOpt )
1004 if ( mbFontIndependentLineSpacing )
1005 return;
1007 if ( !rTextObj.ParagraphCount() )
1008 return;
1010 ParagraphObj* pPara = rTextObj.GetParagraph(0);
1011 if ( pPara->empty() )
1012 return;
1014 const PortionObj& rPortion = pPara->front();
1015 sal_Int16 nLineSpacing = pPara->mnLineSpacing;
1016 const FontCollectionEntry* pDesc = maFontCollection.GetById( rPortion.mnFont );
1017 if ( pDesc )
1018 nLineSpacing = static_cast<sal_Int16>( static_cast<double>(nLineSpacing) * pDesc->Scaling + 0.5 );
1020 if ( ( nLineSpacing > 0 ) && ( nLineSpacing < 100 ) )
1022 double fCharHeight = rPortion.mnCharHeight;
1023 fCharHeight *= 2540 / 72.0;
1024 fCharHeight *= 100 - nLineSpacing;
1025 fCharHeight /= 100;
1027 sal_uInt32 nUpperDistance = 0;
1028 rPropOpt.GetOpt( ESCHER_Prop_dyTextTop, nUpperDistance );
1029 nUpperDistance += static_cast< sal_uInt32 >( fCharHeight * 360.0 );
1030 rPropOpt.AddOpt( ESCHER_Prop_dyTextTop, nUpperDistance );
1034 void PPTWriter::ImplWriteTextStyleAtom( SvStream& rOut, int nTextInstance, sal_uInt32 nAtomInstance,
1035 TextRuleEntry* pTextRule, SvStream& rExtBuStr, EscherPropertyContainer* pPropOpt )
1037 PPTExParaSheet& rParaSheet = mpStyleSheet->GetParaSheet( nTextInstance );
1039 rOut.WriteUInt32( ( EPP_TextHeaderAtom << 16 ) | ( nAtomInstance << 4 ) ).WriteUInt32( 4 )
1040 .WriteInt32( nTextInstance );
1042 if ( mbEmptyPresObj )
1043 mnTextSize = 0;
1044 if ( mbEmptyPresObj )
1045 return;
1047 ParagraphObj* pPara;
1048 TextObjBinary aTextObj( mXText, nTextInstance, maFontCollection, static_cast<PPTExBulletProvider&>(*this) );
1050 // leaving out EPP_TextCharsAtom w/o text - still write out
1051 // attribute info though
1052 if ( mnTextSize )
1053 aTextObj.Write( &rOut );
1055 if ( pPropOpt && mType != "drawing.Table" )
1056 ImplAdjustFirstLineLineSpacing( aTextObj, *pPropOpt );
1058 sal_uInt32 nSize, nPos = rOut.Tell();
1060 rOut.WriteUInt32( EPP_StyleTextPropAtom << 16 ).WriteUInt32( 0 );
1061 ImplWriteParagraphs( rOut, aTextObj );
1062 ImplWritePortions( rOut, aTextObj );
1063 nSize = rOut.Tell() - nPos;
1064 rOut.SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
1065 rOut.WriteUInt32( nSize - 8 );
1066 rOut.SeekRel( nSize - 8 );
1068 for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount(); ++i )
1070 pPara = aTextObj.GetParagraph(i);
1071 for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = pPara->begin(); it != pPara->end(); ++it )
1073 const PortionObj& rPortion = **it;
1074 if ( rPortion.mpFieldEntry )
1076 const FieldEntry* pFieldEntry = rPortion.mpFieldEntry.get();
1078 switch ( pFieldEntry->nFieldType >> 28 )
1080 case 1 :
1081 case 2 :
1083 rOut.WriteUInt32( EPP_DateTimeMCAtom << 16 ).WriteUInt32( 8 )
1084 .WriteUInt32( pFieldEntry->nFieldStartPos ) // TxtOffset to TxtField;
1085 .WriteUChar( pFieldEntry->nFieldType & 0xff ) // Type
1086 .WriteUChar( 0 ).WriteUInt16( 0 ); // PadBytes
1088 break;
1089 case 3 :
1091 rOut.WriteUInt32( EPP_SlideNumberMCAtom << 16 ).WriteUInt32( 4 )
1092 .WriteUInt32( pFieldEntry->nFieldStartPos );
1094 break;
1095 case 4 :
1097 sal_uInt32 nPageIndex = 0;
1098 OUString aPageUrl;
1099 OUString aFile( pFieldEntry->aFieldUrl );
1100 OUString aTarget( pFieldEntry->aFieldUrl );
1101 INetURLObject aUrl( pFieldEntry->aFieldUrl );
1102 if ( INetProtocol::File == aUrl.GetProtocol() )
1103 aFile = aUrl.PathToFileName();
1104 else if ( INetProtocol::Smb == aUrl.GetProtocol() )
1106 // Convert smb notation to '\\' and skip the 'smb:' part
1107 aFile = aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE).copy(4);
1108 aFile = aFile.replaceAll( "/", "\\" );
1109 aTarget = aFile;
1111 else if ( pFieldEntry->aFieldUrl.startsWith("#") )
1113 OUString aPage( INetURLObject::decode( pFieldEntry->aFieldUrl, INetURLObject::DecodeMechanism::WithCharset ) );
1114 aPage = aPage.copy( 1 );
1116 std::vector<OUString>::const_iterator pIter = std::find(
1117 maSlideNameList.begin(),maSlideNameList.end(),aPage);
1119 if ( pIter != maSlideNameList.end() )
1121 nPageIndex = pIter - maSlideNameList.begin();
1122 aPageUrl = OUString::number(256 + nPageIndex) +
1123 "," +
1124 OUString::number(nPageIndex + 1) +
1125 ",Slide " +
1126 OUString::number(nPageIndex + 1);
1129 sal_uInt32 nHyperId(0);
1130 if ( !aPageUrl.isEmpty() )
1131 nHyperId = ImplInsertBookmarkURL( aPageUrl, 1 | ( nPageIndex << 8 ) | ( 1U << 31 ), pFieldEntry->aRepresentation, "", "", aPageUrl );
1132 else
1133 nHyperId = ImplInsertBookmarkURL( pFieldEntry->aFieldUrl, 2 | ( nHyperId << 8 ), aFile, aTarget, "", "" );
1135 rOut.WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0xf ).WriteUInt32( 24 )
1136 .WriteUInt32( EPP_InteractiveInfoAtom << 16 ).WriteUInt32( 16 )
1137 .WriteUInt32( 0 ) // soundref
1138 .WriteUInt32( nHyperId ) // hyperlink id
1139 .WriteUChar( 4 ) // hyperlink action
1140 .WriteUChar( 0 ) // ole verb
1141 .WriteUChar( 0 ) // jump
1142 .WriteUChar( 0 ) // flags
1143 .WriteUChar( 8 ) // hyperlink type ?
1144 .WriteUChar( 0 ).WriteUChar( 0 ).WriteUChar( 0 )
1145 .WriteUInt32( EPP_TxInteractiveInfoAtom << 16 ).WriteUInt32( 8 )
1146 .WriteUInt32( pFieldEntry->nFieldStartPos )
1147 .WriteUInt32( pFieldEntry->nFieldEndPos );
1149 break;
1150 case 5 :
1152 rOut.WriteUInt32( EPP_GenericDateMCAtom << 16 ).WriteUInt32( 4 )
1153 .WriteUInt32( pFieldEntry->nFieldStartPos );
1155 break;
1156 case 6 :
1158 rOut.WriteUInt32( EPP_HeaderMCAtom << 16 ).WriteUInt32( 4 )
1159 .WriteUInt32( pFieldEntry->nFieldStartPos );
1161 break;
1162 case 7 :
1164 rOut.WriteUInt32( EPP_FooterMCAtom << 16 ).WriteUInt32( 4 )
1165 .WriteUInt32( pFieldEntry->nFieldStartPos );
1167 break;
1168 default:
1169 break;
1175 aTextObj.WriteTextSpecInfo( &rOut );
1177 // write Star Office Default TabSizes (if necessary)
1178 if ( aTextObj.ParagraphCount() )
1180 pPara = aTextObj.GetParagraph(0);
1181 sal_uInt32 nParaFlags = 0x1f;
1182 sal_Int16 nMask, nNumberingRule[ 10 ];
1183 sal_uInt32 nTextOfs = pPara->nTextOfs;
1184 sal_uInt32 nTabs = pPara->maTabStop.getLength();
1185 const css::style::TabStop* pTabStop = pPara->maTabStop.getConstArray();
1187 for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount(); ++i )
1189 pPara = aTextObj.GetParagraph(i);
1190 if ( pPara->bExtendedParameters )
1192 nMask = 1 << pPara->nDepth;
1193 if ( nParaFlags & nMask )
1195 nParaFlags &=~ nMask;
1196 if ( ( rParaSheet.maParaLevel[ pPara->nDepth ].mnTextOfs != pPara->nTextOfs ) ||
1197 ( rParaSheet.maParaLevel[ pPara->nDepth ].mnBulletOfs != pPara->nBulletOfs ) )
1199 nParaFlags |= nMask << 16;
1200 nNumberingRule[ pPara->nDepth << 1 ] = pPara->nTextOfs;
1201 nNumberingRule[ ( pPara->nDepth << 1 ) + 1 ] = static_cast<sal_Int16>(pPara->nBulletOfs);
1206 nParaFlags >>= 16;
1208 sal_Int32 nDefaultTabSizeSrc = 2011; // I've no idea where this number came from, honestly
1209 const uno::Reference< beans::XPropertySet > xPropSet( mXModel, uno::UNO_QUERY );
1210 if ( xPropSet.is() )
1212 if(ImplGetPropertyValue( xPropSet, "TabStop" ))
1214 sal_Int32 nTabStop( 0 );
1215 if ( mAny >>= nTabStop )
1216 nDefaultTabSizeSrc = nTabStop;
1219 const sal_uInt32 nDefaultTabSize = MapSize( awt::Size( nDefaultTabSizeSrc, 1 ) ).Width;
1220 sal_uInt32 nDefaultTabs = std::abs( maRect.GetWidth() ) / nDefaultTabSize;
1221 if ( nTabs )
1222 nDefaultTabs -= static_cast<sal_Int32>( ( ( pTabStop[ nTabs - 1 ].Position / 4.40972 ) + nTextOfs ) / nDefaultTabSize );
1223 if ( static_cast<sal_Int32>(nDefaultTabs) < 0 )
1224 nDefaultTabs = 0;
1226 sal_uInt32 nTabCount = nTabs + nDefaultTabs;
1227 sal_uInt32 i, nTextRulerAtomFlags = 0;
1229 if ( nTabCount )
1230 nTextRulerAtomFlags |= 4;
1231 if ( nParaFlags )
1232 nTextRulerAtomFlags |= ( ( nParaFlags << 3 ) | ( nParaFlags << 8 ) );
1234 if ( nTextRulerAtomFlags )
1236 SvStream* pRuleOut = &rOut;
1237 if ( pTextRule )
1239 pTextRule->pOut.reset( new SvMemoryStream( 0x100, 0x100 ) );
1240 pRuleOut = pTextRule->pOut.get();
1243 sal_uInt32 nRulePos = pRuleOut->Tell();
1244 pRuleOut->WriteUInt32( EPP_TextRulerAtom << 16 ).WriteUInt32( 0 );
1245 pRuleOut->WriteUInt32( nTextRulerAtomFlags );
1246 if ( nTextRulerAtomFlags & 4 )
1248 pRuleOut->WriteUInt16( nTabCount );
1249 for ( const css::style::TabStop& rTabStop : std::as_const(pPara->maTabStop) )
1251 sal_uInt16 nPosition = static_cast<sal_uInt16>( ( rTabStop.Position / 4.40972 ) + nTextOfs );
1252 sal_uInt16 nType;
1253 switch ( rTabStop.Alignment )
1255 case css::style::TabAlign_DECIMAL : nType = 3; break;
1256 case css::style::TabAlign_RIGHT : nType = 2; break;
1257 case css::style::TabAlign_CENTER : nType = 1; break;
1259 case css::style::TabAlign_LEFT :
1260 default: nType = 0;
1262 pRuleOut->WriteUInt16( nPosition )
1263 .WriteUInt16( nType );
1266 sal_uInt32 nWidth = 1;
1267 if ( nTabs )
1268 nWidth += static_cast<sal_Int32>( ( pTabStop[ nTabs - 1 ].Position / 4.40972 + nTextOfs ) / nDefaultTabSize );
1269 nWidth *= nDefaultTabSize;
1270 for ( i = 0; i < nDefaultTabs; i++, nWidth += nDefaultTabSize )
1271 pRuleOut->WriteUInt32( nWidth );
1273 for ( i = 0; i < 5; i++ )
1275 if ( nTextRulerAtomFlags & ( 8 << i ) )
1276 pRuleOut->WriteInt16( nNumberingRule[ i << 1 ] );
1277 if ( nTextRulerAtomFlags & ( 256 << i ) )
1278 pRuleOut->WriteInt16( nNumberingRule[ ( i << 1 ) + 1 ] );
1280 sal_uInt32 nBufSize = pRuleOut->Tell() - nRulePos;
1281 pRuleOut->SeekRel( - ( static_cast<sal_Int32>(nBufSize) - 4 ) );
1282 pRuleOut->WriteUInt32( nBufSize - 8 );
1283 pRuleOut->SeekRel( nBufSize - 8 );
1286 if ( !aTextObj.HasExtendedBullets() )
1287 return;
1289 if ( !aTextObj.ParagraphCount() )
1290 return;
1292 sal_uInt32 nNumberingType = 0, nPos2 = rExtBuStr.Tell();
1294 rExtBuStr.WriteUInt32( EPP_PST_ExtendedParagraphAtom << 16 ).WriteUInt32( 0 );
1296 for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount(); ++i )
1298 ParagraphObj* pBulletPara = aTextObj.GetParagraph(i);
1299 sal_uInt32 nBulletFlags = 0;
1300 sal_uInt16 nBulletId = pBulletPara->nBulletId;
1302 if ( pBulletPara->bExtendedBulletsUsed )
1304 nBulletFlags = 0x800000;
1305 if ( pBulletPara->nNumberingType != SVX_NUM_BITMAP )
1306 nBulletFlags = 0x3000000;
1308 rExtBuStr.WriteUInt32( nBulletFlags );
1310 if ( nBulletFlags & 0x800000 )
1311 rExtBuStr.WriteUInt16( nBulletId );
1312 if ( nBulletFlags & 0x1000000 )
1314 switch( pBulletPara->nNumberingType )
1316 case SVX_NUM_NUMBER_NONE :
1317 case SVX_NUM_CHAR_SPECIAL :
1318 nNumberingType = 0;
1319 break;
1320 case SVX_NUM_CHARS_UPPER_LETTER :
1321 case SVX_NUM_CHARS_UPPER_LETTER_N :
1322 case SVX_NUM_CHARS_LOWER_LETTER :
1323 case SVX_NUM_CHARS_LOWER_LETTER_N :
1324 case SVX_NUM_ROMAN_UPPER :
1325 case SVX_NUM_ROMAN_LOWER :
1326 case SVX_NUM_ARABIC :
1327 case SVX_NUM_NUMBER_UPPER_ZH:
1328 case SVX_NUM_CIRCLE_NUMBER:
1329 case SVX_NUM_NUMBER_UPPER_ZH_TW:
1330 case SVX_NUM_NUMBER_LOWER_ZH:
1331 case SVX_NUM_FULL_WIDTH_ARABIC:
1332 nNumberingType = pBulletPara->nMappedNumType;
1333 break;
1335 case SVX_NUM_BITMAP :
1336 nNumberingType = 0;
1337 break;
1338 default: break;
1340 rExtBuStr.WriteUInt32( nNumberingType );
1342 if ( nBulletFlags & 0x2000000 )
1343 rExtBuStr.WriteUInt16( pBulletPara->nStartWith );
1344 rExtBuStr.WriteUInt32( 0 ).WriteUInt32( 0 );
1346 sal_uInt32 nBulletSize = ( rExtBuStr.Tell() - nPos2 ) - 8;
1347 rExtBuStr.SeekRel( - ( static_cast<sal_Int32>(nBulletSize) + 4 ) );
1348 rExtBuStr.WriteUInt32( nBulletSize );
1349 rExtBuStr.SeekRel( nBulletSize );
1352 void PPTWriter::ImplWriteClickAction( SvStream& rSt, css::presentation::ClickAction eCa, bool bMediaClickAction )
1354 sal_uInt32 nSoundRef = 0; // a reference to a sound in the sound collection, or NULL.
1355 sal_uInt32 nHyperLinkID = 0;// a persistent unique identifier to an external hyperlink object (only valid when action == HyperlinkAction).
1356 sal_uInt8 nAction = 0; // Action See Action Table
1357 sal_uInt8 const nOleVerb = 0; // OleVerb Only valid when action == OLEAction. OLE verb to use, 0 = first verb, 1 = second verb, etc.
1358 sal_uInt8 nJump = 0; // Jump See Jump Table
1359 sal_uInt8 const nFlags = 0; // Bit 1: Animated. If 1, then button is animated
1360 // Bit 2: Stop sound. If 1, then stop current sound when button is pressed.
1361 // Bit 3: CustomShowReturn. If 1, and this is a jump to custom show, then return to this slide after custom show.
1362 sal_uInt8 nHyperLinkType = 0;// HyperlinkType a value from the LinkTo enum, such as LT_URL (only valid when action == HyperlinkAction).
1364 OUString aFile;
1367 Action Table: Action Value
1368 NoAction 0
1369 MacroAction 1
1370 RunProgramAction 2
1371 JumpAction 3
1372 HyperlinkAction 4
1373 OLEAction 5
1374 MediaAction 6
1375 CustomShowAction 7
1377 Jump Table: Jump Value
1378 NoJump 0
1379 NextSlide, 1
1380 PreviousSlide, 2
1381 FirstSlide, 3
1382 LastSlide, 4
1383 LastSlideViewed 5
1384 EndShow 6
1387 if ( bMediaClickAction )
1388 nAction = 6;
1389 else switch( eCa )
1391 case css::presentation::ClickAction_STOPPRESENTATION :
1392 nJump += 2;
1393 [[fallthrough]];
1394 case css::presentation::ClickAction_LASTPAGE :
1395 nJump++;
1396 [[fallthrough]];
1397 case css::presentation::ClickAction_FIRSTPAGE :
1398 nJump++;
1399 [[fallthrough]];
1400 case css::presentation::ClickAction_PREVPAGE :
1401 nJump++;
1402 [[fallthrough]];
1403 case css::presentation::ClickAction_NEXTPAGE :
1405 nJump++;
1406 nAction = 3;
1408 break;
1409 case css::presentation::ClickAction_SOUND :
1411 if ( ImplGetPropertyValue( "Bookmark" ) )
1412 nSoundRef = maSoundCollection.GetId( *o3tl::doAccess<OUString>(mAny) );
1414 break;
1415 case css::presentation::ClickAction_PROGRAM :
1417 if ( ImplGetPropertyValue( "Bookmark" ) )
1419 INetURLObject aUrl( *o3tl::doAccess<OUString>(mAny) );
1420 if ( INetProtocol::File == aUrl.GetProtocol() )
1422 aFile = aUrl.PathToFileName();
1423 nAction = 2;
1427 break;
1429 case css::presentation::ClickAction_BOOKMARK :
1431 if ( ImplGetPropertyValue( "Bookmark" ) )
1433 OUString aBookmark( *o3tl::doAccess<OUString>(mAny) );
1434 sal_uInt32 nIndex = 0;
1435 for ( const auto& rSlideName : maSlideNameList )
1437 if ( rSlideName == aBookmark )
1439 // Bookmark is a link to a document page
1440 nAction = 4;
1441 nHyperLinkType = 7;
1443 OUString aHyperString = OUString::number(256 + nIndex) +
1444 "," +
1445 OUString::number(nIndex + 1) +
1446 ",Slide " +
1447 OUString::number(nIndex + 1);
1448 nHyperLinkID = ImplInsertBookmarkURL( aHyperString, 1 | ( nIndex << 8 ) | ( 1U << 31 ), aBookmark, "", "", aHyperString );
1450 nIndex++;
1454 break;
1456 case css::presentation::ClickAction_DOCUMENT :
1458 if ( ImplGetPropertyValue( "Bookmark" ) )
1460 OUString aBookmark( *o3tl::doAccess<OUString>(mAny) );
1461 if ( !aBookmark.isEmpty() )
1463 nAction = 4;
1464 nHyperLinkType = 8;
1466 OUString aBookmarkFile( aBookmark );
1467 INetURLObject aUrl( aBookmark );
1468 if ( INetProtocol::File == aUrl.GetProtocol() )
1469 aBookmarkFile = aUrl.PathToFileName();
1470 nHyperLinkID = ImplInsertBookmarkURL( aBookmark, sal_uInt32(2 | ( 1U << 31 )), aBookmarkFile, aBookmark, "", "" );
1474 break;
1476 case css::presentation::ClickAction_INVISIBLE :
1477 case css::presentation::ClickAction_VERB :
1478 case css::presentation::ClickAction_VANISH :
1479 case css::presentation::ClickAction_MACRO :
1480 default :
1481 break;
1484 sal_uInt32 nContainerSize = 24;
1485 if ( nAction == 2 )
1486 nContainerSize += ( aFile.getLength() * 2 ) + 8;
1487 rSt.WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0xf ).WriteUInt32( nContainerSize )
1488 .WriteUInt32( EPP_InteractiveInfoAtom << 16 ).WriteUInt32( 16 )
1489 .WriteUInt32( nSoundRef )
1490 .WriteUInt32( nHyperLinkID )
1491 .WriteUChar( nAction )
1492 .WriteUChar( nOleVerb )
1493 .WriteUChar( nJump )
1494 .WriteUChar( nFlags )
1495 .WriteUInt32( nHyperLinkType );
1497 if ( nAction == 2 ) // run program Action
1499 sal_Int32 nLen = aFile.getLength();
1500 rSt.WriteUInt32( ( EPP_CString << 16 ) | 0x20 ).WriteUInt32( nLen * 2 );
1501 for ( sal_Int32 i = 0; i < nLen; i++ )
1502 rSt.WriteUInt16( aFile[i] );
1505 rSt.WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0x1f ).WriteUInt32( 24 ) // Mouse Over Action
1506 .WriteUInt32( EPP_InteractiveInfo << 16 ).WriteUInt32( 16 );
1507 for ( int i = 0; i < 4; i++, rSt.WriteUInt32( 0 ) ) ;
1510 bool PPTWriter::ImplGetEffect( const css::uno::Reference< css::beans::XPropertySet > & rPropSet,
1511 css::presentation::AnimationEffect& eEffect,
1512 css::presentation::AnimationEffect& eTextEffect,
1513 bool& bIsSound )
1515 css::uno::Any aAny;
1516 if ( GetPropertyValue( aAny, rPropSet, "Effect" ) )
1517 aAny >>= eEffect;
1518 else
1519 eEffect = css::presentation::AnimationEffect_NONE;
1521 if ( GetPropertyValue( aAny, rPropSet, "TextEffect" ) )
1522 aAny >>= eTextEffect;
1523 else
1524 eTextEffect = css::presentation::AnimationEffect_NONE;
1525 if ( GetPropertyValue( aAny, rPropSet, "SoundOn" ) )
1526 aAny >>= bIsSound;
1527 else
1528 bIsSound = false;
1530 bool bHasEffect = ( ( eEffect != css::presentation::AnimationEffect_NONE )
1531 || ( eTextEffect != css::presentation::AnimationEffect_NONE )
1532 || bIsSound );
1533 return bHasEffect;
1536 bool PPTWriter::ImplCreatePresentationPlaceholder( const bool bMasterPage,
1537 const sal_uInt32 nStyleInstance, const sal_uInt8 nPlaceHolderId )
1539 bool bRet = ImplGetText();
1540 if ( bRet && bMasterPage )
1542 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1543 sal_uInt32 nPresShapeID = mpPptEscherEx->GenerateShapeId();
1544 mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
1545 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty, nPresShapeID );
1546 EscherPropertyContainer aPropOpt;
1547 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x50001 );
1548 mnTxId += 0x60;
1549 aPropOpt.AddOpt( ESCHER_Prop_lTxid, mnTxId );
1550 aPropOpt.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
1551 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110001 );
1552 aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x8000001 );
1553 aPropOpt.AddOpt( ESCHER_Prop_shadowColor, 0x8000002 );
1554 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
1555 sal_uInt32 nLineFlags = 0x90001;
1556 if ( aPropOpt.GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ) )
1557 nLineFlags |= 0x10001; // draw dashed line if no line
1558 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
1560 SvMemoryStream aExtBu( 0x200, 0x200 );
1561 SvMemoryStream aClientTextBox( 0x200, 0x200 );
1562 ImplWriteTextStyleAtom( aClientTextBox, nStyleInstance, 0, nullptr, aExtBu, &aPropOpt );
1564 mnTxId += 0x60;
1565 aPropOpt.CreateTextProperties( mXPropSet, mnTxId );
1566 aPropOpt.CreateShapeProperties( mXShape );
1567 aPropOpt.Commit( *mpStrm );
1568 mpPptEscherEx->AddAtom( 8, ESCHER_ClientAnchor );
1569 mpStrm->WriteInt16( maRect.Top() ).WriteInt16( maRect.Left() ).WriteInt16( maRect.Right() ).WriteInt16( maRect.Bottom() ); // top, left, right, bottom ????
1570 mpPptEscherEx->OpenContainer( ESCHER_ClientData );
1571 mpPptEscherEx->AddAtom( 8, EPP_OEPlaceholderAtom );
1572 mpStrm->WriteUInt32( 0 ) // PlacementID
1573 .WriteUChar( nPlaceHolderId ) // PlaceHolderID
1574 .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
1575 .WriteUInt16( 0 ); // padword
1576 mpPptEscherEx->CloseContainer(); // ESCHER_ClientData
1578 if ( aClientTextBox.Tell() )
1580 mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
1581 .WriteUInt32( aClientTextBox.Tell() );
1583 mpStrm->WriteBytes(aClientTextBox.GetData(), aClientTextBox.Tell());
1585 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
1587 else
1588 bRet = false;
1589 return bRet;
1592 void PPTWriter::ImplCreateShape( sal_uInt32 nType, ShapeFlag nFlags, EscherSolverContainer& rSolver )
1594 sal_uInt32 nId = mpPptEscherEx->GenerateShapeId();
1595 mpPptEscherEx->AddShape( nType, nFlags, nId );
1596 rSolver.AddShape( mXShape, nId );
1599 void PPTWriter::ImplCreateTextShape( EscherPropertyContainer& rPropOpt, EscherSolverContainer& rSolver, bool bFill )
1601 mnTextStyle = EPP_TEXTSTYLE_TEXT;
1602 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1603 ImplCreateShape( ESCHER_ShpInst_TextBox, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty, rSolver );
1604 if ( bFill )
1605 rPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
1606 if ( ImplGetText() )
1608 mnTxId += 0x60;
1609 rPropOpt.CreateTextProperties( mXPropSet, mnTxId );
1613 void PPTWriter::ImplWritePage( const PHLayout& rLayout, EscherSolverContainer& aSolverContainer, PageType ePageType, bool bMasterPage, int nPageNumber )
1615 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
1616 // sal_uInt32 nGroupLevel = 0;
1618 sal_uInt32 nGroups, nShapes, nShapeCount, nPer, nLastPer, nIndices, nOlePictureId;
1619 css::awt::Point aTextRefPoint;
1621 nShapes = mXShapes->getCount();
1622 ResetGroupTable( nShapes );
1624 nIndices = nLastPer = nShapeCount = 0;
1626 bool bIsTitlePossible = true; // powerpoint is not able to handle more than one title
1628 sal_uInt32 nOutlinerCount = 0; // the outline objects have to conform to the layout,
1629 sal_uInt32 nPrevTextStyle = 0; // there are no more than two allowed
1631 nOlePictureId = 0;
1633 bool bAdditionalText = false;
1635 bool bSecOutl = false;
1636 sal_uInt32 nPObjects = 0;
1638 std::unique_ptr<SvMemoryStream> pClientTextBox;
1639 std::unique_ptr<SvMemoryStream> pClientData;
1641 while( GetNextGroupEntry() )
1643 nShapeCount++;
1645 nPer = ( 5 * nShapeCount ) / nShapes;
1646 if ( nPer != nLastPer )
1648 nLastPer = nPer;
1649 sal_uInt32 nValue = mnPagesWritten * 5 + nPer;
1650 if ( nValue > mnStatMaxValue )
1651 nValue = mnStatMaxValue;
1652 if ( mbStatusIndicator && ( nValue > mnLatestStatValue ) )
1654 mXStatusIndicator->setValue( nValue );
1655 mnLatestStatValue = nValue;
1658 nGroups = GetGroupsClosed();
1659 for ( sal_uInt32 i = 0; i < nGroups; i++, mpPptEscherEx->LeaveGroup() ) ;
1661 if ( GetShapeByIndex( GetCurrentGroupIndex(), true ) )
1663 bool bIsSound;
1664 bool bMediaClickAction = false;
1665 css::presentation::AnimationEffect eAe;
1666 css::presentation::AnimationEffect eTe;
1668 bool bEffect = ImplGetEffect( mXPropSet, eAe, eTe, bIsSound );
1669 css::presentation::ClickAction eCa = css::presentation::ClickAction_NONE;
1670 if ( ImplGetPropertyValue( "OnClick" ) )
1671 mAny >>= eCa;
1673 bool bGroup = mType == "drawing.Group";
1674 bool bOpenBezier = mType == "drawing.OpenBezier";
1675 bool bClosedBezier = mType == "drawing.ClosedBezier";
1676 bool bPolyPolygon = mType == "drawing.PolyPolygon";
1677 bool bPolyLine = mType == "drawing.PolyLine";
1679 const css::awt::Size aSize100thmm( mXShape->getSize() );
1680 const css::awt::Point aPoint100thmm( mXShape->getPosition() );
1681 ::tools::Rectangle aRect100thmm( Point( aPoint100thmm.X, aPoint100thmm.Y ), Size( aSize100thmm.Width, aSize100thmm.Height ) );
1682 EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect100thmm );
1684 if ( bGroup )
1686 css::uno::Reference< css::container::XIndexAccess >
1687 aXIndexAccess( mXShape, css::uno::UNO_QUERY );
1688 if ( EnterGroup( aXIndexAccess ) )
1690 std::unique_ptr<SvMemoryStream> pTmp;
1691 if ( eCa != css::presentation::ClickAction_NONE )
1693 pTmp.reset(new SvMemoryStream(0x200, 0x200));
1694 ImplWriteClickAction( *pTmp, eCa, bMediaClickAction );
1696 sal_uInt32 nShapeId = mpPptEscherEx->EnterGroup(&maRect, pTmp.get());
1697 aSolverContainer.AddShape( mXShape, nShapeId );
1700 else
1702 bool bIsFontwork = false;
1703 bool bIsHatching = false;
1704 css::uno::Any aAny;
1705 css::drawing::FillStyle eFS;
1706 if ( GetPropertyValue( aAny, mXPropSet, "IsFontwork", true ) )
1707 aAny >>= bIsFontwork;
1708 if ( GetPropertyValue( aAny, mXPropSet, "FillStyle", true ) )
1710 aAny >>= eFS;
1711 bIsHatching = eFS == css::drawing::FillStyle_HATCH;
1713 if ( bIsHatching || bIsFontwork || ( mType == "drawing.Measure" ) || ( mType == "drawing.Caption" ) )
1715 if ( ImplGetPropertyValue( "BoundRect" ) )
1717 auto aRect = o3tl::doAccess<css::awt::Rectangle>(mAny);
1718 maPosition = MapPoint( css::awt::Point( aRect->X, aRect->Y ) );
1719 maSize = MapSize( css::awt::Size( aRect->Width, aRect->Height ) );
1720 maRect = ::tools::Rectangle( Point( maPosition.X, maPosition.Y ), Size( maSize.Width, maSize.Height ) );
1722 mType = "drawing.dontknow";
1725 sal_uInt8 nPlaceHolderAtom = EPP_PLACEHOLDER_NONE;
1727 mnTextSize = 0;
1728 mnTextStyle = EPP_TEXTSTYLE_NORMAL;
1730 if ( mType == "drawing.Custom" )
1732 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1733 ShapeFlag nMirrorFlags;
1734 OUString sCustomShapeType;
1735 MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType( mXShape, nMirrorFlags, sCustomShapeType );
1736 if ( sCustomShapeType == "col-502ad400" || sCustomShapeType == "col-60da8460" )
1737 { // sj: creating metafile for customshapes that can't be saved to ms format properly
1738 ImplCreateShape( ESCHER_ShpInst_PictureFrame,
1739 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1740 aSolverContainer );
1741 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "MetaFile", false ) )
1743 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
1744 SdrObject* pObj = GetSdrObjectFromXShape( mXShape );
1745 if ( pObj )
1747 ::tools::Rectangle aBound = pObj->GetCurrentBoundRect();
1748 maPosition = MapPoint( css::awt::Point( aBound.Left(), aBound.Top() ) );
1749 maSize = MapSize( css::awt::Size ( aBound.GetWidth(), aBound.GetHeight() ) );
1750 maRect = ::tools::Rectangle( Point( maPosition.X, maPosition.Y ), Size( maSize.Width, maSize.Height ) );
1751 mnAngle = 0;
1755 else
1757 ImplCreateShape( eShapeType,
1758 nMirrorFlags | ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1759 aSolverContainer );
1760 aPropOpt.CreateCustomShapeProperties( eShapeType, mXShape );
1761 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape);
1762 if ( ImplGetText() )
1764 if ( !aPropOpt.IsFontWork() )
1766 mnTxId += 0x60;
1767 aPropOpt.CreateTextProperties( mXPropSet, mnTxId, true );
1772 else if ( mType == "drawing.Rectangle" )
1774 sal_Int32 nRadius = 0;
1775 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1776 if ( ImplGetPropertyValue( "CornerRadius" ) )
1778 mAny >>= nRadius;
1779 nRadius = MapSize( css::awt::Size( nRadius, 0 ) ).Width;
1781 if ( nRadius )
1783 ImplCreateShape( ESCHER_ShpInst_RoundRectangle,
1784 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1785 aSolverContainer );
1786 sal_Int32 nLength = maRect.GetWidth();
1787 if ( nLength > maRect.GetHeight() )
1788 nLength = maRect.GetHeight();
1789 nLength >>= 1;
1790 if ( nRadius >= nLength )
1791 nRadius = 0x2a30; // 0x2a30 is PPTs maximum radius
1792 else
1794 if (nLength != 0)
1795 nRadius = ( 0x2a30 * nRadius ) / nLength;
1796 else
1797 nRadius = 0x2a30; // 0x2a30 is PPTs maximum radius
1799 aPropOpt.AddOpt( ESCHER_Prop_adjustValue, nRadius );
1801 else
1803 ImplCreateShape( ESCHER_ShpInst_Rectangle,
1804 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1805 aSolverContainer );
1807 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
1808 if ( ImplGetText() )
1810 mnTxId += 0x60;
1811 aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
1814 else if ( mType == "drawing.Ellipse" )
1816 css::drawing::CircleKind eCircleKind( css::drawing::CircleKind_FULL );
1817 PolyStyle ePolyKind = PolyStyle::Chord;
1818 if ( ImplGetPropertyValue( "CircleKind" ) )
1820 mAny >>= eCircleKind;
1821 switch ( eCircleKind )
1823 case css::drawing::CircleKind_SECTION :
1825 ePolyKind = PolyStyle::Pie;
1827 break;
1828 case css::drawing::CircleKind_ARC :
1830 ePolyKind = PolyStyle::Arc;
1832 break;
1834 case css::drawing::CircleKind_CUT :
1836 ePolyKind = PolyStyle::Chord;
1838 break;
1840 default:
1841 eCircleKind = css::drawing::CircleKind_FULL;
1844 if ( eCircleKind == css::drawing::CircleKind_FULL )
1846 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1847 ImplCreateShape( ESCHER_ShpInst_Ellipse,
1848 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1849 aSolverContainer );
1850 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
1851 if ( ImplGetText() )
1853 mnTxId += 0x60;
1854 aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
1857 else
1859 sal_Int32 nStartAngle, nEndAngle;
1860 if ( !ImplGetPropertyValue( "CircleStartAngle" ) )
1861 continue;
1862 nStartAngle = *o3tl::doAccess<sal_Int32>(mAny);
1863 if( !ImplGetPropertyValue( "CircleEndAngle" ) )
1864 continue;
1865 nEndAngle = *o3tl::doAccess<sal_Int32>(mAny);
1866 css::awt::Point aPoint( mXShape->getPosition() );
1867 css::awt::Size aSize( mXShape->getSize() );
1868 css::awt::Point aStart, aEnd, aCenter;
1869 ::tools::Rectangle aRect( Point( aPoint.X, aPoint.Y ), Size( aSize.Width, aSize.Height ) );
1870 aStart.X = static_cast<sal_Int32>( cos( nStartAngle * F_PI18000 ) * 100.0 );
1871 aStart.Y = - static_cast<sal_Int32>( sin( nStartAngle * F_PI18000 ) * 100.0 );
1872 aEnd.X = static_cast<sal_Int32>( cos( nEndAngle * F_PI18000 ) * 100.0 );
1873 aEnd.Y = - static_cast<sal_Int32>( sin( nEndAngle * F_PI18000 ) * 100.0 ) ;
1874 aCenter.X = aPoint.X + ( aSize.Width / 2 );
1875 aCenter.Y = aPoint.Y + ( aSize.Height / 2 );
1876 aStart.X += aCenter.X;
1877 aStart.Y += aCenter.Y;
1878 aEnd.X += aCenter.X;
1879 aEnd.Y += aCenter.Y;
1880 tools::Polygon aPolygon( aRect, Point( aStart.X, aStart.Y ), Point( aEnd.X, aEnd.Y ), ePolyKind );
1881 bool bNeedText = true;
1882 if ( mnAngle )
1884 aPolygon.Rotate( aRect.TopLeft(), static_cast<sal_uInt16>( mnAngle / 10 ) );
1885 if ( ImplGetText() )
1887 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
1888 // mpPptEscherEx->EnterGroup( 0,0 );
1889 // nGroupLevel = mpPptEscherEx->GetGroupLevel();
1890 bNeedText = false;
1891 bAdditionalText = true;
1892 mnTextSize = 0;
1894 mnAngle = 0;
1896 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1897 ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
1898 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1899 aSolverContainer );
1900 css::awt::Rectangle aNewRect;
1901 switch ( ePolyKind )
1903 case PolyStyle::Pie :
1904 case PolyStyle::Chord :
1906 if ( aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect, &aPolygon ) )
1907 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
1909 break;
1911 case PolyStyle::Arc :
1913 if ( aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect, &aPolygon ) )
1914 aPropOpt.CreateLineProperties( mXPropSet, false );
1916 break;
1918 maRect = MapRectangle( aNewRect );
1919 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
1920 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
1921 if ( bNeedText && ImplGetText() )
1923 mnTxId += 0x60;
1924 aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
1928 else if ( mType == "drawing.Control" )
1930 css::uno::Reference< css::drawing::XControlShape > aXControlShape( mXShape, css::uno::UNO_QUERY );
1931 if ( !aXControlShape.is() )
1932 continue;
1933 css::uno::Reference< css::awt::XControlModel > aXControlModel( aXControlShape->getControl() );
1934 if ( !aXControlModel.is() )
1935 continue;
1937 sal_Int64 nAspect = css::embed::Aspects::MSOLE_CONTENT;
1940 // try to get the aspect when available
1941 css::uno::Reference< css::beans::XPropertySet > xShapeProps( mXShape, css::uno::UNO_QUERY_THROW );
1942 xShapeProps->getPropertyValue("Aspect") >>= nAspect;
1944 catch( css::uno::Exception& )
1947 mpExEmbed->WriteUInt32( 0xf | ( EPP_ExControl << 16 ) )
1948 .WriteUInt32( 0 ); // Size of this container
1950 sal_uInt32 nSize, nOldPos = mpExEmbed->Tell();
1952 sal_uInt32 nPageId = nPageNumber;
1953 if ( ePageType == MASTER )
1954 nPageId |= 0x80000000;
1955 else
1956 nPageId += 0x100;
1957 mpExEmbed->WriteUInt32( EPP_ExControlAtom << 16 )
1958 .WriteUInt32( 4 )
1959 .WriteUInt32( nPageId );
1960 std::unique_ptr<PPTExOleObjEntry> pEntry( new PPTExOleObjEntry( OCX_CONTROL, mpExEmbed->Tell() ) );
1961 pEntry->xControlModel = aXControlModel;
1962 pEntry->xShape = mXShape;
1963 maExOleObj.push_back( std::move(pEntry) );
1965 mnExEmbed++;
1967 mpExEmbed->WriteUInt32( 1 | ( EPP_ExOleObjAtom << 16 ) )
1968 .WriteUInt32( 24 )
1969 .WriteUInt32( nAspect )
1970 .WriteUInt32( 2 )
1971 .WriteUInt32( mnExEmbed )
1972 .WriteUInt32( 0 )
1973 .WriteUInt32( 4 ) // index to the persist table
1974 .WriteUInt32( 0x0012de00 );
1976 css::awt::Size aSize;
1977 OUString aControlName;
1978 tools::SvRef<SotStorage> xTemp( new SotStorage( new SvMemoryStream(), true ) );
1979 if ( oox::ole::MSConvertOCXControls::WriteOCXStream( mXModel, xTemp, aXControlModel, aSize, aControlName ) )
1981 OUString aUserName( xTemp->GetUserName() );
1982 OUString aOleIdentifier;
1983 if ( !aUserName.isEmpty() )
1985 tools::SvRef<SotStorageStream> xCompObj = xTemp->OpenSotStream(
1986 "\1CompObj",
1987 StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYALL );
1988 sal_uInt32 const nStreamLen = xCompObj->remainingSize();
1989 sal_Int16 nVersion, nByteOrder;
1990 sal_Int32 nWinVersion, nVal, nStringLen;
1991 xCompObj->ReadInt16( nVersion )
1992 .ReadInt16( nByteOrder )
1993 .ReadInt32( nWinVersion )
1994 .ReadInt32( nVal );
1995 xCompObj->SeekRel( 16 ); // skipping clsid
1996 xCompObj->ReadInt32( nStringLen );
1997 if ( ( xCompObj->Tell() + nStringLen ) < nStreamLen )
1999 xCompObj->SeekRel( nStringLen ); // now skipping the UserName;
2000 xCompObj->ReadInt32( nStringLen );
2001 if ( ( xCompObj->Tell() + nStringLen ) < nStreamLen )
2003 xCompObj->SeekRel( nStringLen ); // now skipping the clipboard formatname
2004 xCompObj->ReadInt32( nStringLen );
2005 if ( ( nStringLen > 1 ) && ( ( xCompObj->Tell() + nStringLen ) < nStreamLen ) )
2006 { // i think that the OleIdentifier will follow
2007 OString aTemp = read_uInt8s_ToOString(*xCompObj, nStringLen - 1);
2008 aOleIdentifier = OStringToOUString(aTemp, RTL_TEXTENCODING_MS_1252);
2014 PPTWriter::WriteCString( *mpExEmbed, aControlName, 1 );
2015 PPTWriter::WriteCString( *mpExEmbed, aOleIdentifier, 2 );
2016 PPTWriter::WriteCString( *mpExEmbed, aUserName, 3 );
2018 nSize = mpExEmbed->Tell() - nOldPos;
2019 mpExEmbed->Seek( nOldPos - 4 );
2020 mpExEmbed->WriteUInt32( nSize );
2021 mpExEmbed->Seek( STREAM_SEEK_TO_END );
2022 nOlePictureId = mnExEmbed;
2024 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2025 ShapeFlag const nSpFlags = ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor | ShapeFlag::OLEShape;
2026 ImplCreateShape( ESCHER_ShpInst_HostControl, nSpFlags, aSolverContainer );
2027 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "MetaFile", false ) )
2028 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2029 //export form control graphic
2030 else if ( aPropOpt.CreateBlipPropertiesforOLEControl(mXPropSet,mXShape))
2031 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2032 aPropOpt.AddOpt( ESCHER_Prop_pictureId, mnExEmbed );
2033 aPropOpt.AddOpt( ESCHER_Prop_pictureActive, 0x10000 );
2035 if ( !aControlName.isEmpty() )
2037 aPropOpt.AddOpt(ESCHER_Prop_wzName, aControlName);
2040 else if ( mType == "drawing.Connector" )
2042 sal_uInt16 nSpType;
2043 ShapeFlag nSpFlags;
2044 css::awt::Rectangle aNewRect;
2045 if ( !aPropOpt.CreateConnectorProperties( mXShape, aSolverContainer, aNewRect, nSpType, nSpFlags ) )
2046 continue;
2048 maRect = MapRectangle( aNewRect );
2049 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2050 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2052 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2053 ImplCreateShape( nSpType, nSpFlags, aSolverContainer );
2055 // #119459# for connector shape, the start point and end point is fixed, and should not be rotated.
2056 mnAngle = 0;
2058 else if ( mType == "drawing.Measure" )
2060 continue;
2062 else if ( mType == "drawing.Line" )
2064 css::awt::Rectangle aNewRect;
2065 aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_LINE, false, aNewRect );
2066 maRect = MapRectangle( aNewRect );
2067 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2068 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2069 if ( ImplGetText() )
2071 aTextRefPoint = css::awt::Point( maRect.Left(), maRect.Top() );
2072 mnTextSize = 0;
2073 bAdditionalText = true;
2074 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2075 // mpPptEscherEx->EnterGroup( &maRect,0 );
2077 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2078 ShapeFlag nFlags = ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty;
2080 if ( maRect.Top() > maRect.Bottom() )
2081 nFlags |= ShapeFlag::FlipV;
2082 if ( maRect.Left() > maRect.Right() )
2083 nFlags |= ShapeFlag::FlipH;
2085 ImplCreateShape( ESCHER_ShpInst_Line, nFlags, aSolverContainer );
2086 aPropOpt.AddOpt( ESCHER_Prop_shapePath, ESCHER_ShapeComplex );
2087 aPropOpt.CreateLineProperties( mXPropSet, false );
2088 mnAngle = 0;
2090 else if ( bPolyPolygon )
2092 if ( ImplGetText() )
2094 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2095 // mpPptEscherEx->EnterGroup( 0,0 );
2096 // nGroupLevel = mpPptEscherEx->GetGroupLevel();
2097 bAdditionalText = true;
2098 mnTextSize = 0;
2100 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2101 ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
2102 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2103 aSolverContainer );
2104 css::awt::Rectangle aNewRect;
2105 aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect );
2106 maRect = MapRectangle( aNewRect );
2107 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2108 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2109 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
2110 mnAngle = 0;
2112 else if ( bPolyLine )
2114 if ( ImplGetText() )
2116 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2117 // mpPptEscherEx->EnterGroup( 0,0 );
2118 // nGroupLevel = mpPptEscherEx->GetGroupLevel();
2119 bAdditionalText = true;
2120 mnTextSize = 0;
2122 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2123 ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
2124 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2125 aSolverContainer );
2126 css::awt::Rectangle aNewRect;
2127 aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect );
2128 maRect = MapRectangle( aNewRect );
2129 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2130 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2131 aPropOpt.CreateLineProperties( mXPropSet, false );
2132 mnAngle = 0;
2134 else if ( bOpenBezier )
2136 if ( ImplGetText() )
2138 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2139 // mpPptEscherEx->EnterGroup( 0,0 );
2140 // nGroupLevel = mpPptEscherEx->GetGroupLevel();
2141 bAdditionalText = true;
2142 mnTextSize = 0;
2144 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2145 ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
2146 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2147 aSolverContainer );
2148 css::awt::Rectangle aNewRect;
2149 aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, true, aNewRect );
2150 maRect = MapRectangle( aNewRect );
2151 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2152 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2153 aPropOpt.CreateLineProperties( mXPropSet, false );
2154 mnAngle = 0;
2156 else if ( bClosedBezier )
2158 if ( ImplGetText() )
2160 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2161 // mpPptEscherEx->EnterGroup( 0,0 );
2162 // nGroupLevel = mpPptEscherEx->GetGroupLevel();
2163 bAdditionalText = true;
2164 mnTextSize = 0;
2166 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2167 ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
2168 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2169 aSolverContainer );
2170 css::awt::Rectangle aNewRect;
2171 aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, true, aNewRect );
2172 maRect = MapRectangle( aNewRect );
2173 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2174 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2175 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
2176 mnAngle = 0;
2178 else if ( ( mType == "drawing.GraphicObject" ) || ( mType == "presentation.GraphicObject" ) )
2180 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2182 // a GraphicObject can also be a ClickMe element
2183 if ( mbEmptyPresObj && ( ePageType == NORMAL ) )
2185 nPlaceHolderAtom = rLayout.nUsedObjectPlaceHolder;
2186 ImplCreateShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster, aSolverContainer );
2187 mnTxId += 0x60;
2188 aPropOpt.AddOpt( ESCHER_Prop_lTxid, mnTxId );
2189 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
2190 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 );
2191 aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
2193 else
2195 mXText.set( mXShape, css::uno::UNO_QUERY );
2197 if ( mXText.is() )
2198 mnTextSize = mXText->getString().getLength();
2200 if ( mnTextSize ) // graphic object or area fill
2202 /* SJ #i34951#: because M. documents are not allowing GraphicObjects containing text, we
2203 have to create a simple Rectangle with fill bitmap instead (while not allowing BitmapMode_Repeat).
2205 ImplCreateShape( ESCHER_ShpInst_Rectangle,
2206 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2207 aSolverContainer );
2208 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "Graphic", true, true, false ) )
2210 aPropOpt.AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapNone );
2211 aPropOpt.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
2212 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x140014 );
2213 aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x8000000 );
2214 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
2215 if ( ImplGetText() )
2217 mnTxId += 0x60;
2218 aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
2222 else
2224 ImplCreateShape( ESCHER_ShpInst_PictureFrame,
2225 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2226 aSolverContainer );
2228 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "Graphic", false, true ) )
2230 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2235 else if ( ( mType == "drawing.Text" ) || ( mType == "presentation.Notes" ) )
2237 if ( ( ePageType == NOTICE ) && mbPresObj )
2239 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Notes, EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE ) )
2240 continue;
2241 else
2242 nPlaceHolderAtom = EPP_PLACEHOLDER_NOTESBODY;
2244 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2246 else if ( mType == "presentation.TitleText" )
2248 if ( mbPresObj )
2250 if ( ( ePageType == NOTICE ) && mbEmptyPresObj )
2252 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2253 nPlaceHolderAtom = EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE;
2254 ImplCreateShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveAnchor, aSolverContainer );
2255 aPropOpt.CreateLineProperties( mXPropSet, false );
2256 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
2258 else if ( rLayout.bTitlePossible && bIsTitlePossible )
2260 bIsTitlePossible = false;
2262 ImplGetText();
2263 TextObjBinary aTextObj( mXText, EPP_TEXTTYPE_Title, maFontCollection, static_cast<PPTExBulletProvider&>(*this) );
2264 if ( ePageType == MASTER )
2266 if ( mnTextSize )
2268 OUString aUString( mXText->getString() );
2269 sal_uInt16 nChar;
2271 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2272 mnShapeMasterTitle = mpPptEscherEx->GenerateShapeId();
2273 mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
2274 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2275 mnShapeMasterTitle );
2276 EscherPropertyContainer aPropertyOptions;
2277 aPropertyOptions.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x50001 );
2278 mnTxId += 0x60;
2279 aPropertyOptions.AddOpt( ESCHER_Prop_lTxid, mnTxId );
2280 aPropertyOptions.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
2281 aPropertyOptions.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110001 );
2282 aPropertyOptions.AddOpt( ESCHER_Prop_lineColor, 0x8000001 );
2283 aPropertyOptions.AddOpt( ESCHER_Prop_shadowColor, 0x8000002 );
2284 aPropertyOptions.CreateFillProperties( mXPropSet, true, mXShape );
2285 sal_uInt32 nLineFlags = 0x90001;
2286 if ( aPropertyOptions.GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ) )
2287 nLineFlags |= 0x10001; // draw dashed line if no line
2288 aPropertyOptions.AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
2289 mnTxId += 0x60;
2290 aPropertyOptions.CreateTextProperties( mXPropSet, mnTxId );
2291 ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt );
2292 aPropertyOptions.Commit( *mpStrm );
2293 mpPptEscherEx->AddAtom( 8, ESCHER_ClientAnchor );
2294 mpStrm->WriteInt16( maRect.Top() ).WriteInt16( maRect.Left() ).WriteInt16( maRect.Right() ).WriteInt16( maRect.Bottom() ); // top, left, right, bottom ????
2295 mpPptEscherEx->OpenContainer( ESCHER_ClientData );
2296 mpPptEscherEx->AddAtom( 8, EPP_OEPlaceholderAtom );
2297 mpStrm->WriteUInt32( 0 ) // PlacementID
2298 .WriteUChar( EPP_PLACEHOLDER_MASTERTITLE ) // PlaceHolderID
2299 .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
2300 .WriteUInt16( 0 ); // padword
2301 mpPptEscherEx->CloseContainer(); // ESCHER_ClientData
2302 mpPptEscherEx->OpenContainer( ESCHER_ClientTextbox );
2303 mpPptEscherEx->AddAtom( 4, EPP_TextHeaderAtom );
2304 mpStrm->WriteUInt32( EPP_TEXTTYPE_Title );
2305 mpPptEscherEx->AddAtom( mnTextSize << 1, EPP_TextCharsAtom );
2306 const sal_Unicode* pString = aUString.getStr();
2307 for ( sal_uInt32 i = 0; i < mnTextSize; i++ )
2309 nChar = pString[ i ]; // 0xa -> 0xb soft newline
2310 if ( nChar == 0xa )
2311 nChar++; // 0xd -> 0xd hard newline
2312 mpStrm->WriteUInt16( nChar );
2314 mpPptEscherEx->AddAtom( 6, EPP_BaseTextPropAtom );
2315 mpStrm->WriteUInt32( mnTextSize + 1 ).WriteUInt16( 0 );
2316 mpPptEscherEx->AddAtom( 10, EPP_TextSpecInfoAtom );
2317 mpStrm->WriteUInt32( mnTextSize + 1 ).WriteUInt32( 1 ).WriteUInt16( 0 );
2318 mpPptEscherEx->CloseContainer(); // ESCHER_ClientTextBox
2319 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
2321 continue;
2323 else
2325 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2326 mnTextStyle = EPP_TEXTSTYLE_TITLE;
2327 nPlaceHolderAtom = rLayout.nTypeOfTitle;
2328 ImplCreateShape( ESCHER_ShpInst_Rectangle,
2329 ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster,
2330 aSolverContainer );
2331 aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterTitle );
2332 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
2333 mnTxId += 0x60;
2334 aPropOpt.CreateTextProperties( mXPropSet, mnTxId );
2335 ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt );
2336 if ( mbEmptyPresObj )
2338 sal_uInt32 nNoLineDrawDash = 0;
2339 aPropOpt.GetOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
2340 nNoLineDrawDash |= 0x10001;
2341 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
2345 else
2346 mbPresObj = false;
2348 if ( !mbPresObj )
2350 mType = "drawing.Text";
2351 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2354 else if ( ( mType == "presentation.Outliner" ) || ( mType == "presentation.Subtitle" ) )
2356 if ( mbPresObj )
2358 nOutlinerCount++;
2359 if ( (rLayout.bOutlinerPossible && ( nOutlinerCount == 1 )) ||
2360 (( rLayout.bSecOutlinerPossible && ( nOutlinerCount == 2 ) ) && ( nPrevTextStyle == EPP_TEXTSTYLE_BODY ))
2363 ImplGetText();
2364 TextObjBinary aTextObj( mXText, EPP_TEXTTYPE_Body, maFontCollection, static_cast<PPTExBulletProvider&>(*this) );
2365 if ( ePageType == MASTER )
2367 nPrevTextStyle = EPP_TEXTSTYLE_TITLE;
2368 if ( mnTextSize )
2370 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2371 mnShapeMasterBody = mpPptEscherEx->GenerateShapeId();
2372 mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
2373 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2374 mnShapeMasterBody );
2375 EscherPropertyContainer aPropOpt2;
2376 aPropOpt2.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x50001 );
2377 mnTxId += 0x60;
2378 aPropOpt2.AddOpt( ESCHER_Prop_lTxid, mnTxId );
2379 aPropOpt2.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110001 );
2380 aPropOpt2.AddOpt( ESCHER_Prop_lineColor, 0x8000001 );
2381 aPropOpt2.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90001 );
2382 aPropOpt2.AddOpt( ESCHER_Prop_shadowColor, 0x8000002 );
2383 aPropOpt2.CreateFillProperties( mXPropSet, true, mXShape );
2384 sal_uInt32 nLineFlags = 0x90001;
2385 if ( aPropOpt2.GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ) )
2386 nLineFlags |= 0x10001; // draw dashed line if no line
2387 aPropOpt2.AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
2388 mnTxId += 0x60;
2389 aPropOpt2.CreateTextProperties( mXPropSet, mnTxId );
2390 ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt2 );
2391 aPropOpt2.Commit( *mpStrm );
2392 mpPptEscherEx->AddAtom( 8, ESCHER_ClientAnchor );
2393 mpStrm->WriteInt16( maRect.Top() ).WriteInt16( maRect.Left() ).WriteInt16( maRect.Right() ).WriteInt16( maRect.Bottom() ); // top, left, right, bottom ????
2394 mpPptEscherEx->OpenContainer( ESCHER_ClientData );
2395 mpPptEscherEx->AddAtom( 8, EPP_OEPlaceholderAtom );
2396 sal_uInt8 PlaceHolderID = ( mType == "presentation.Subtitle") ? EPP_PLACEHOLDER_MASTERSUBTITLE:EPP_PLACEHOLDER_MASTERBODY;
2397 mpStrm->WriteUInt32( 1 ) // PlacementID
2398 .WriteUChar( PlaceHolderID )/*(sal_uInt8)EPP_PLACEHOLDER_MASTERBODY */ // PlaceHolderID
2399 .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
2400 .WriteUInt16( 0 ); // padword
2401 mpPptEscherEx->CloseContainer(); // ESCHER_ClientData
2402 mpPptEscherEx->OpenContainer( ESCHER_ClientTextbox ); // printf
2403 mpPptEscherEx->AddAtom( 4, EPP_TextHeaderAtom );
2404 if ( mType == "presentation.Subtitle")
2405 mpStrm->WriteUInt32( EPP_TEXTTYPE_CenterBody );
2406 else
2407 mpStrm->WriteUInt32( EPP_TEXTTYPE_Body );
2408 mnTextSize = aTextObj.Count();
2409 aTextObj.Write( mpStrm.get() );
2410 mpPptEscherEx->BeginAtom();
2411 for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount() ; ++i )
2413 ParagraphObj* pPara = aTextObj.GetParagraph(i);
2414 mpStrm->WriteUInt32( pPara->CharacterCount() )
2415 .WriteUInt16( pPara->nDepth );
2417 mpPptEscherEx->EndAtom( EPP_BaseTextPropAtom );
2418 mpPptEscherEx->AddAtom( 10, EPP_TextSpecInfoAtom );
2419 mpStrm->WriteUInt32( mnTextSize ).WriteUInt32( 1 ).WriteUInt16( 0 );
2421 mpPptEscherEx->CloseContainer(); // ESCHER_ClientTextBox
2422 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
2424 continue;
2426 else
2428 mnTextStyle = EPP_TEXTSTYLE_BODY;
2429 nPlaceHolderAtom = rLayout.nTypeOfOutliner;
2430 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2431 ImplCreateShape( ESCHER_ShpInst_Rectangle,
2432 ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster,
2433 aSolverContainer );
2434 aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
2435 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
2436 mnTxId += 0x60;
2437 aPropOpt.CreateTextProperties( mXPropSet, mnTxId );
2438 ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt );
2439 if ( mbEmptyPresObj )
2441 sal_uInt32 nNoLineDrawDash = 0;
2442 aPropOpt.GetOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
2443 nNoLineDrawDash |= 0x10001;
2444 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
2448 else
2449 mbPresObj = false;
2451 if ( !mbPresObj )
2453 if (ePageType == MASTER )
2455 SdrObject* pObj = GetSdrObjectFromXShape( mXShape );
2456 if (pObj && pObj->IsNotVisibleAsMaster())
2457 continue;
2460 mType = "drawing.Text";
2461 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2464 else if ( ( mType == "drawing.Page" ) || ( mType == "presentation.Page" ) )
2466 if ( ( ePageType == NOTICE ) && mbPresObj )
2468 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Notes, EPP_PLACEHOLDER_MASTERNOTESSLIDEIMAGE ) )
2469 continue;
2470 else
2471 nPlaceHolderAtom = EPP_PLACEHOLDER_NOTESSLIDEIMAGE;
2473 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2475 else if ( mType == "drawing.Frame" )
2477 continue;
2479 else if ( ( mType == "drawing.OLE2" ) || ( mType == "presentation.OLE2" )
2480 || ( mType == "presentation.Chart" ) || ( mType == "presentation.Calc" )
2481 || ( mType == "presentation.OrgChart" ) )
2483 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2484 if ( mbEmptyPresObj && ( ePageType == NORMAL ) )
2486 nPlaceHolderAtom = rLayout.nUsedObjectPlaceHolder;
2487 ImplCreateShape( ESCHER_ShpInst_Rectangle,
2488 ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster,
2489 aSolverContainer );
2490 mnTxId += 0x60;
2491 aPropOpt.AddOpt( ESCHER_Prop_lTxid, mnTxId );
2492 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
2493 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 );
2494 aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
2496 else
2498 mpExEmbed->WriteUInt32( 0xf | ( EPP_ExEmbed << 16 ) )
2499 .WriteUInt32( 0 ); // Size of this container
2501 sal_uInt32 nSize, nOldPos = mpExEmbed->Tell();
2503 mpExEmbed->WriteUInt32( EPP_ExEmbedAtom << 16 )
2504 .WriteUInt32( 8 )
2505 .WriteUInt32( 0 ) // follow colorscheme : 0->do not follow
2506 // 1->follow colorscheme
2507 // 2->follow text and background scheme
2508 .WriteUChar( 1 ) // (bool)set if embedded server can not be locked
2509 .WriteUChar( 0 ) // (bool)do not need to send dimension
2510 .WriteUChar( 0 ) // (bool)is object a world table
2511 .WriteUChar( 0 ); // pad byte
2513 std::unique_ptr<PPTExOleObjEntry> pE( new PPTExOleObjEntry( NORMAL_OLE_OBJECT, mpExEmbed->Tell() ) );
2514 pE->xShape = mXShape;
2515 maExOleObj.push_back( std::move(pE) );
2517 mnExEmbed++;
2519 sal_Int64 nAspect = css::embed::Aspects::MSOLE_CONTENT;
2522 // try to get the aspect when available
2523 css::uno::Reference< css::beans::XPropertySet > xShapeProps( mXShape, css::uno::UNO_QUERY_THROW );
2524 xShapeProps->getPropertyValue("Aspect") >>= nAspect;
2526 catch( css::uno::Exception& )
2529 mpExEmbed->WriteUInt32( 1 | ( EPP_ExOleObjAtom << 16 ) )
2530 .WriteUInt32( 24 )
2531 .WriteUInt32( nAspect ) // Aspect
2532 .WriteUInt32( 0 )
2533 .WriteUInt32( mnExEmbed ) // index to the persist table
2534 .WriteUInt32( 0 ) // subtype
2535 .WriteUInt32( 0 )
2536 .WriteUInt32( 0x0012b600 );
2538 nSize = mpExEmbed->Tell() - nOldPos;
2539 mpExEmbed->Seek( nOldPos - 4 );
2540 mpExEmbed->WriteUInt32( nSize );
2541 mpExEmbed->Seek( STREAM_SEEK_TO_END );
2542 nOlePictureId = mnExEmbed;
2544 ShapeFlag nSpFlags = ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty;
2545 if ( nOlePictureId )
2546 nSpFlags |= ShapeFlag::OLEShape;
2547 ImplCreateShape( ESCHER_ShpInst_PictureFrame, nSpFlags, aSolverContainer );
2548 if ( aPropOpt.CreateOLEGraphicProperties( mXShape ) )
2549 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2550 if ( nOlePictureId )
2551 aPropOpt.AddOpt( ESCHER_Prop_pictureId, nOlePictureId );
2554 else if ( mType == "presentation.Header" )
2556 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERHEADER ) )
2557 continue;
2558 else
2560 mbPresObj = false;
2561 mType = "drawing.Text";
2562 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2565 else if ( mType == "presentation.Footer" )
2567 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERFOOTER ) )
2568 continue;
2569 else
2571 mbPresObj = false;
2572 mType = "drawing.Text";
2573 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2576 else if ( mType == "presentation.DateTime" )
2578 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERDATE ) )
2579 continue;
2580 else
2582 mbPresObj = false;
2583 mType = "drawing.Text";
2584 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2587 else if ( mType == "presentation.SlideNumber" )
2589 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERSLIDENUMBER ) )
2590 continue;
2591 else
2593 mbPresObj = false;
2594 mType = "drawing.Text";
2595 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2598 else if ( (mType.getLength() > 9) && (mType[8] == '3') && (mType[9] == 'D') ) // drawing.3D
2600 // SceneObject, CubeObject, SphereObject, LatheObject, ExtrudeObject, PolygonObject
2601 if ( !ImplGetPropertyValue( "Bitmap" ) )
2602 continue;
2604 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2605 ImplCreateShape( ESCHER_ShpInst_PictureFrame,
2606 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2607 aSolverContainer );
2609 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "Bitmap", false ) )
2610 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2612 else if ( mType == "drawing.Media" )
2614 mnAngle = 0;
2615 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2616 ImplCreateShape( ESCHER_ShpInst_PictureFrame,
2617 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2618 aSolverContainer );
2619 if ( aPropOpt.CreateMediaGraphicProperties( mXShape ) )
2620 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2621 css::uno::Any aAny;
2622 if ( PropValue::GetPropertyValue( aAny, mXPropSet, "MediaURL", true ) )
2624 OUString aMediaURL;
2625 if ( (aAny >>= aMediaURL ) && !aMediaURL.isEmpty() )
2627 // SJ: creating the Media RefObj
2628 sal_uInt32 nRefId = ++mnExEmbed;
2630 mpExEmbed->WriteUInt16( 0xf )
2631 .WriteUInt16( EPP_ExMCIMovie ) // PPT_PST_ExAviMovie
2632 .WriteUInt32( 0 );
2633 sal_uInt32 nSize, nStart = mpExEmbed->Tell();
2634 mpExEmbed->WriteUInt16( 0 )
2635 .WriteUInt16( EPP_ExObjRefAtom )
2636 .WriteUInt32( 4 )
2637 .WriteUInt32( nRefId );
2638 mpExEmbed->WriteUInt16( 0xf )
2639 .WriteUInt16( EPP_ExVideo )
2640 .WriteUInt32( 0 );
2642 mpExEmbed->WriteUInt16( 0 )
2643 .WriteUInt16( EPP_ExMediaAtom )
2644 .WriteUInt32( 8 )
2645 .WriteUInt32( nRefId )
2646 .WriteUInt16( 0 )
2647 .WriteUInt16( 0x435 );
2649 sal_uInt16 i, nStringLen = static_cast<sal_uInt16>(aMediaURL.getLength());
2650 mpExEmbed->WriteUInt32( EPP_CString << 16 ).WriteUInt32( nStringLen * 2 );
2651 for ( i = 0; i < nStringLen; i++ )
2653 sal_Unicode nChar = aMediaURL[ i ];
2654 mpExEmbed->WriteUInt16( nChar );
2656 nSize = mpExEmbed->Tell() - nStart;
2657 mpExEmbed->SeekRel( - ( static_cast<sal_Int32>(nSize) + 4 ) );
2658 mpExEmbed->WriteUInt32( nSize ); // size of PPT_PST_ExMCIMovie
2659 mpExEmbed->SeekRel( 0x10 );
2660 nSize -= 20;
2661 mpExEmbed->WriteUInt32( nSize ); // PPT_PST_ExMediaAtom
2662 mpExEmbed->SeekRel( nSize );
2664 if ( !pClientData )
2665 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2666 pClientData->WriteUInt16( 0 )
2667 .WriteUInt16( EPP_ExObjRefAtom )
2668 .WriteUInt32( 4 )
2669 .WriteUInt32( nRefId );
2670 // write EPP_InteractiveInfo container for no_action
2671 pClientData->WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0xf ).WriteUInt32( 24 );
2672 pClientData->WriteUInt16( 0 )
2673 .WriteUInt16( EPP_InteractiveInfoAtom )
2674 .WriteUInt32( 16 )
2675 .WriteUInt32( 0 )
2676 .WriteUInt32( 0 )
2677 .WriteUChar( 6 )
2678 .WriteUChar( 0 )
2679 .WriteUChar( 0 )
2680 .WriteUChar( 0 )
2681 .WriteUInt32( 0 );
2685 else if ( (mType == "drawing.Table") || (mType == "presentation.Table") )
2687 if ( eCa != css::presentation::ClickAction_NONE )
2689 SvMemoryStream aTmp(0x200, 0x200);
2690 ImplWriteClickAction( aTmp, eCa, bMediaClickAction );
2692 ImplCreateTable( mXShape, aSolverContainer, aPropOpt );
2693 continue;
2695 else if ( mType == "drawing.dontknow" )
2697 mnAngle = 0;
2698 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2699 ImplCreateShape( ESCHER_ShpInst_PictureFrame,
2700 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2701 aSolverContainer );
2702 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "MetaFile", false ) )
2703 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2705 else
2707 continue;
2710 bool bClientData = ( bEffect || ( eCa != css::presentation::ClickAction_NONE ) ||
2711 nPlaceHolderAtom || nOlePictureId );
2712 if ( bClientData )
2714 if ( nPlaceHolderAtom )
2716 sal_Int32 nPlacementID = -1;
2717 if ( ( mnTextStyle == EPP_TEXTSTYLE_TITLE ) || ( mnTextStyle == EPP_TEXTSTYLE_BODY ) )
2718 nPlacementID = nIndices++;
2719 else
2721 switch ( nPlaceHolderAtom )
2723 default :
2725 if ( nPlaceHolderAtom < 19 )
2726 break;
2727 [[fallthrough]];
2729 case EPP_PLACEHOLDER_NOTESBODY :
2730 case EPP_PLACEHOLDER_MASTERDATE :
2731 case EPP_PLACEHOLDER_NOTESSLIDEIMAGE :
2732 case EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE :
2733 nPlacementID = nIndices++;
2736 if ( !pClientData )
2737 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2739 pClientData->WriteUInt32( EPP_OEPlaceholderAtom << 16 ).WriteUInt32( 8 )
2740 .WriteInt32( nPlacementID ) // PlacementID
2741 .WriteUChar( nPlaceHolderAtom ) // PlaceHolderID
2742 .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
2743 .WriteUInt16( 0 ); // padword
2745 if ( nOlePictureId )
2747 if ( !pClientData )
2748 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2750 pClientData->WriteUInt32( EPP_ExObjRefAtom << 16 ).WriteUInt32( 4 )
2751 .WriteUInt32( nOlePictureId );
2752 nOlePictureId = 0;
2754 if ( bEffect && !pClientData )
2756 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2759 if ( eCa != css::presentation::ClickAction_NONE )
2761 if ( !pClientData )
2762 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2763 ImplWriteClickAction( *pClientData, eCa, bMediaClickAction );
2766 if ( ( mnTextStyle == EPP_TEXTSTYLE_TITLE ) || ( mnTextStyle == EPP_TEXTSTYLE_BODY ) )
2768 if ( !pClientTextBox )
2769 pClientTextBox.reset(new SvMemoryStream( 0x200, 0x200 ));
2771 if ( !mbEmptyPresObj )
2773 if ( ( ePageType == NORMAL ) && !bMasterPage )
2775 sal_uInt32 nTextType = EPP_TEXTTYPE_Body;
2776 if ( mnTextStyle == EPP_TEXTSTYLE_BODY )
2778 if ( bSecOutl )
2779 nTextType = EPP_TEXTTYPE_HalfBody;
2780 else if ( mType == "presentation.Subtitle" )
2781 nTextType = EPP_TEXTTYPE_CenterBody;
2782 bSecOutl = true;
2784 else
2785 nTextType = EPP_TEXTTYPE_Title;
2787 TextRuleEntry aTextRule;
2788 SvMemoryStream aExtBu( 0x200, 0x200 );
2789 ImplGetText();
2790 ImplWriteTextStyleAtom( *pClientTextBox, nTextType, nPObjects, &aTextRule, aExtBu, nullptr );
2791 ImplWriteExtParaHeader( aExtBu, nPObjects++, nTextType, nPageNumber + 0x100 );
2792 SvMemoryStream* pOut = aTextRule.pOut.get();
2793 if ( pOut )
2795 pClientTextBox->WriteBytes(pOut->GetData(), pOut->Tell());
2796 aTextRule.pOut.reset();
2798 if ( aExtBu.Tell() )
2800 if ( !pClientData )
2801 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2802 ImplProgTagContainer( pClientData.get(), &aExtBu );
2807 else
2809 if ( !aPropOpt.IsFontWork() )
2811 if ( mnTextSize || ( nPlaceHolderAtom == EPP_PLACEHOLDER_MASTERDATE ) || ( nPlaceHolderAtom == EPP_PLACEHOLDER_NOTESBODY ) )
2813 int nInstance2;
2814 if ( ( nPlaceHolderAtom == EPP_PLACEHOLDER_MASTERDATE ) || ( nPlaceHolderAtom == EPP_PLACEHOLDER_NOTESBODY ) )
2815 nInstance2 = 2;
2816 else
2817 nInstance2 = EPP_TEXTTYPE_Other; // Text in a Shape
2819 if ( !pClientTextBox )
2820 pClientTextBox.reset(new SvMemoryStream( 0x200, 0x200 ));
2822 SvMemoryStream aExtBu( 0x200, 0x200 );
2823 ImplWriteTextStyleAtom( *pClientTextBox, nInstance2, 0, nullptr, aExtBu, &aPropOpt );
2824 if ( aExtBu.Tell() )
2826 if ( !pClientData )
2827 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2828 ImplProgTagContainer( pClientData.get(), &aExtBu );
2831 else if ( nPlaceHolderAtom >= 19 )
2833 if ( !pClientTextBox )
2834 pClientTextBox.reset(new SvMemoryStream( 12 ));
2836 pClientTextBox->WriteUInt32( EPP_TextHeaderAtom << 16 ).WriteUInt32( 4 )
2837 .WriteUInt32( 7 );
2842 aPropOpt.CreateShadowProperties( mXPropSet );
2843 maRect.Justify();
2844 if ( mnAngle )
2845 ImplFlipBoundingBox( aPropOpt );
2846 aPropOpt.CreateShapeProperties( mXShape );
2847 aPropOpt.Commit( *mpStrm );
2848 if ( GetCurrentGroupLevel() > 0 )
2849 mpPptEscherEx->AddChildAnchor( maRect );
2850 else
2851 mpPptEscherEx->AddClientAnchor( maRect );
2853 if ( pClientData )
2855 mpStrm->WriteUInt32( ( ESCHER_ClientData << 16 ) | 0xf )
2856 .WriteUInt32( pClientData->Tell() );
2858 mpStrm->WriteBytes(pClientData->GetData(), pClientData->Tell());
2859 pClientData.reset();
2861 if ( pClientTextBox )
2863 mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
2864 .WriteUInt32( pClientTextBox->Tell() );
2866 mpStrm->WriteBytes(pClientTextBox->GetData(), pClientTextBox->Tell());
2867 pClientTextBox.reset();
2869 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
2871 nPrevTextStyle = mnTextStyle;
2873 if ( bAdditionalText )
2875 bAdditionalText = false;
2877 css::uno::Any aAny;
2878 EscherPropertyContainer aPropOpt;
2879 mnAngle = ( PropValue::GetPropertyValue( aAny,
2880 mXPropSet, "RotateAngle", true ) )
2881 ? *o3tl::doAccess<sal_Int32>(aAny)
2882 : 0;
2884 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 );
2885 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 );
2886 if ( mType == "drawing.Line" )
2888 double fDist = hypot( maRect.GetWidth(), maRect.GetHeight() );
2889 maRect = ::tools::Rectangle( Point( aTextRefPoint.X, aTextRefPoint.Y ),
2890 Point( static_cast<sal_Int32>( aTextRefPoint.X + fDist ), aTextRefPoint.Y - 1 ) );
2891 ImplCreateTextShape( aPropOpt, aSolverContainer, false );
2892 aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x60006 ); // Size Shape To Fit Text
2893 if ( mnAngle < 0 )
2894 mnAngle = ( 36000 + mnAngle ) % 36000;
2895 if ( mnAngle )
2896 ImplFlipBoundingBox( aPropOpt );
2898 else
2900 ImplCreateTextShape( aPropOpt, aSolverContainer, false );
2901 if ( mnAngle < 0 )
2902 mnAngle = ( 36000 + mnAngle ) % 36000;
2903 else
2904 mnAngle = ( 36000 - ( mnAngle % 36000 ) );
2906 mnAngle *= 655;
2907 mnAngle += 0x8000;
2908 mnAngle &=~0xffff; // round nAngle to full grad
2909 aPropOpt.AddOpt( ESCHER_Prop_Rotation, mnAngle );
2911 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2912 // mpPptEscherEx->SetGroupSnapRect( nGroupLevel, maRect );
2913 // mpPptEscherEx->SetGroupLogicRect( nGroupLevel, maRect );
2915 if ( !pClientTextBox )
2916 pClientTextBox.reset(new SvMemoryStream( 0x200, 0x200 ));
2918 SvMemoryStream aExtBu( 0x200, 0x200 );
2919 ImplWriteTextStyleAtom( *pClientTextBox, EPP_TEXTTYPE_Other, 0, nullptr, aExtBu, &aPropOpt );
2921 aPropOpt.CreateShapeProperties( mXShape );
2922 aPropOpt.Commit( *mpStrm );
2923 if ( GetCurrentGroupLevel() > 0 )
2924 mpPptEscherEx->AddChildAnchor( maRect );
2925 else
2926 mpPptEscherEx->AddClientAnchor( maRect );
2928 mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
2929 .WriteUInt32( pClientTextBox->Tell() );
2931 mpStrm->WriteBytes(pClientTextBox->GetData(), pClientTextBox->Tell());
2932 pClientTextBox.reset();
2934 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
2936 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2937 // mpPptEscherEx->LeaveGroup();
2940 ClearGroupTable(); // storing groups if any are still open, which should not be the case
2941 nGroups = GetGroupsClosed();
2942 for ( sal_uInt32 i = 0; i < nGroups; i++, mpPptEscherEx->LeaveGroup() ) ;
2943 mnPagesWritten++;
2946 struct CellBorder
2948 sal_Int32 mnPos; // specifies the distance to the top/left position of the table
2949 table::BorderLine maCellBorder;
2951 CellBorder() : mnPos ( 0 ) {};
2954 bool PPTWriter::ImplCreateCellBorder( const CellBorder* pCellBorder, sal_Int32 nX1, sal_Int32 nY1, sal_Int32 nX2, sal_Int32 nY2)
2956 sal_Int32 nLineWidth = pCellBorder->maCellBorder.OuterLineWidth + pCellBorder->maCellBorder.InnerLineWidth;
2957 if ( nLineWidth )
2959 nLineWidth *= 2;
2960 mnAngle = 0;
2961 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2962 EscherPropertyContainer aPropOptSp;
2964 sal_uInt32 nId = mpPptEscherEx->GenerateShapeId();
2965 mpPptEscherEx->AddShape( ESCHER_ShpInst_Line,
2966 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty | ShapeFlag::Child,
2967 nId );
2968 aPropOptSp.AddOpt( ESCHER_Prop_shapePath, ESCHER_ShapeComplex );
2969 aPropOptSp.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0xa0008 );
2970 aPropOptSp.AddOpt( ESCHER_Prop_fshadowObscured, 0x20000 );
2972 sal_uInt32 nBorderColor = pCellBorder->maCellBorder.Color & 0xff00; // green
2973 nBorderColor |= static_cast< sal_uInt8 >( pCellBorder->maCellBorder.Color ) << 16; // red
2974 nBorderColor |= static_cast< sal_uInt8 >( pCellBorder->maCellBorder.Color >> 16 ); // blue
2975 aPropOptSp.AddOpt( ESCHER_Prop_lineColor, nBorderColor );
2977 aPropOptSp.AddOpt( ESCHER_Prop_lineWidth, nLineWidth * 360 );
2978 aPropOptSp.AddOpt( ESCHER_Prop_fc3DLightFace, 0x80000 );
2979 aPropOptSp.Commit( *mpStrm );
2980 mpPptEscherEx->AddAtom( 16, ESCHER_ChildAnchor );
2981 mpStrm ->WriteInt32( nX1 )
2982 .WriteInt32( nY1 )
2983 .WriteInt32( nX2 )
2984 .WriteInt32( nY2 );
2985 mpPptEscherEx->CloseContainer();
2986 return true;
2988 return false;
2991 //get merged cell's width
2992 static sal_Int32 GetCellRight( sal_Int32 nColumn,
2993 ::tools::Rectangle const & rect,
2994 std::vector< std::pair< sal_Int32, sal_Int32 > >& aColumns,
2995 uno::Reference< table::XMergeableCell > const & xCell )
2997 sal_Int32 nRight = aColumns[ nColumn ].first + aColumns[ nColumn ].second;
2998 for ( sal_Int32 nColumnSpan = 1; nColumnSpan < xCell->getColumnSpan(); nColumnSpan++ )
3000 sal_uInt32 nC = nColumnSpan + nColumn;
3001 if ( nC < aColumns.size() )
3002 nRight += aColumns[ nC ].second;
3003 else
3004 nRight = rect.Right();
3006 return nRight;
3008 //get merged cell's height
3009 static sal_Int32 GetCellBottom( sal_Int32 nRow,
3010 ::tools::Rectangle const & rect,
3011 std::vector< std::pair< sal_Int32, sal_Int32 > >& aRows,
3012 uno::Reference< table::XMergeableCell > const & xCell )
3014 sal_Int32 nBottom = aRows[nRow].first + aRows[nRow].second;
3015 for ( sal_Int32 nRowSpan = 1; nRowSpan < xCell->getRowSpan(); nRowSpan++ )
3017 sal_uInt32 nR = nRowSpan + nRow;
3018 if ( nR < aRows.size() )
3019 nBottom += aRows[ nR ].second;
3020 else
3021 nBottom = rect.Bottom();
3023 return nBottom;
3026 void PPTWriter::WriteCString( SvStream& rSt, const OUString& rString, sal_uInt32 nInstance )
3028 sal_Int32 nLen = rString.getLength();
3029 if ( nLen )
3031 rSt.WriteUInt32( ( nInstance << 4 ) | ( EPP_CString << 16 ) )
3032 .WriteUInt32( nLen << 1 );
3033 for ( sal_Int32 i = 0; i < nLen; i++ )
3034 rSt.WriteUInt16( rString[i] );
3038 class ContainerGuard
3040 private:
3041 PptEscherEx* m_pPptEscherEx;
3042 public:
3043 ContainerGuard(PptEscherEx* pPptEscherEx, sal_uInt16 nRecord)
3044 : m_pPptEscherEx(pPptEscherEx)
3046 m_pPptEscherEx->OpenContainer(nRecord);
3048 ~ContainerGuard()
3050 m_pPptEscherEx->CloseContainer();
3054 void PPTWriter::ImplCreateTable( uno::Reference< drawing::XShape > const & rXShape, EscherSolverContainer& aSolverContainer,
3055 EscherPropertyContainer& aPropOpt )
3059 uno::Reference< table::XTable > xTable;
3060 if ( mXPropSet->getPropertyValue( "Model" ) >>= xTable )
3062 uno::Reference< table::XColumnRowRange > xColumnRowRange( xTable, uno::UNO_QUERY_THROW );
3063 uno::Reference< container::XIndexAccess > xColumns( xColumnRowRange->getColumns(), uno::UNO_QUERY_THROW );
3064 uno::Reference< container::XIndexAccess > xRows( xColumnRowRange->getRows(), uno::UNO_QUERY_THROW );
3065 sal_uInt16 nRowCount = static_cast< sal_uInt16 >( xRows->getCount() );
3066 sal_uInt16 nColumnCount = static_cast< sal_uInt16 >( xColumns->getCount() );
3068 std::vector< std::pair< sal_Int32, sal_Int32 > > aColumns;
3069 std::vector< std::pair< sal_Int32, sal_Int32 > > aRows;
3071 awt::Point aPosition( MapPoint( rXShape->getPosition() ) );
3072 sal_Int32 nPosition = aPosition.X;
3073 for ( sal_Int32 x = 0; x < nColumnCount; x++ )
3075 uno::Reference< beans::XPropertySet > xPropSet( xColumns->getByIndex( x ), uno::UNO_QUERY_THROW );
3076 awt::Size aS( 0, 0 );
3077 xPropSet->getPropertyValue( "Width" ) >>= aS.Width;
3078 awt::Size aM( MapSize( aS ) );
3079 aColumns.emplace_back( nPosition, aM.Width );
3080 nPosition += aM.Width;
3081 if ( x == nColumnCount - 1 && nPosition != maRect.Right() )
3082 maRect.SetRight( nPosition );
3085 nPosition = aPosition.Y;
3086 for ( sal_Int32 y = 0; y < nRowCount; y++ )
3088 uno::Reference< beans::XPropertySet > xPropSet( xRows->getByIndex( y ), uno::UNO_QUERY_THROW );
3089 awt::Size aS( 0, 0 );
3090 xPropSet->getPropertyValue( "Height" ) >>= aS.Height;
3091 awt::Size aM( MapSize( aS ) );
3092 aRows.emplace_back( nPosition, aM.Height );
3093 nPosition += aM.Height;
3094 if ( y == nRowCount - 1 && nPosition != maRect.Bottom())
3095 maRect.SetBottom( nPosition );
3097 std::unique_ptr<ContainerGuard> xSpgrContainer(new ContainerGuard(mpPptEscherEx.get(), ESCHER_SpgrContainer));
3098 std::unique_ptr<ContainerGuard> xSpContainer(new ContainerGuard(mpPptEscherEx.get(), ESCHER_SpContainer));
3099 mpPptEscherEx->AddAtom( 16, ESCHER_Spgr, 1 );
3100 mpStrm ->WriteInt32( maRect.Left() ) // Bounding box for the grouped shapes to which they are attached
3101 .WriteInt32( maRect.Top() )
3102 .WriteInt32( maRect.Right() )
3103 .WriteInt32( maRect.Bottom() );
3105 sal_uInt32 nShapeId = mpPptEscherEx->GenerateShapeId();
3106 mpPptEscherEx->AddShape( ESCHER_ShpInst_Min, ShapeFlag::HaveAnchor | ShapeFlag::Group, nShapeId );
3107 // TODO: check flags, comment does not match code // Flags: Group | Patriarch
3108 aSolverContainer.AddShape( rXShape, nShapeId );
3109 EscherPropertyContainer aPropOpt2;
3111 SvMemoryStream aMemStrm;
3112 aMemStrm.WriteUInt16( nRowCount )
3113 .WriteUInt16( nRowCount )
3114 .WriteUInt16( 4 );
3116 for( const auto& rRow : aRows )
3117 aMemStrm.WriteInt32( rRow.second );
3119 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x1000100 );
3120 aPropOpt2.AddOpt( ESCHER_Prop_tableProperties, 1 );
3121 aPropOpt2.AddOpt(ESCHER_Prop_tableRowProperties, true, 0, aMemStrm);
3122 aPropOpt.CreateShapeProperties( rXShape );
3123 aPropOpt.Commit( *mpStrm );
3124 aPropOpt2.Commit( *mpStrm, 3, ESCHER_UDefProp );
3125 if ( GetCurrentGroupLevel() > 0 )
3126 mpPptEscherEx->AddChildAnchor( maRect );
3127 else
3128 mpPptEscherEx->AddClientAnchor( maRect );
3129 xSpContainer.reset(); //ESCHER_SpContainer
3131 uno::Reference< table::XCellRange > xCellRange( xTable, uno::UNO_QUERY_THROW );
3132 for( sal_Int32 nRow = 0; nRow < xRows->getCount(); nRow++ )
3134 for( sal_Int32 nColumn = 0; nColumn < xColumns->getCount(); nColumn++ )
3136 uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn, nRow ), uno::UNO_QUERY_THROW );
3137 if ( !xCell->isMerged() )
3139 sal_Int32 nLeft = aColumns[ nColumn ].first;
3140 sal_Int32 nTop = aRows[ nRow ].first;
3141 sal_Int32 nRight = GetCellRight( nColumn, maRect,aColumns,xCell );
3142 sal_Int32 nBottom = GetCellBottom( nRow, maRect,aRows,xCell );
3144 mbFontIndependentLineSpacing = false;
3145 mXPropSet.set( xCell, uno::UNO_QUERY_THROW );
3146 mXText.set( xCell, uno::UNO_QUERY_THROW );
3147 mnTextSize = mXText->getString().getLength();
3149 css::uno::Any aAny;
3150 if ( GetPropertyValue( aAny, mXPropSet, "FontIndependentLineSpacing", true ) )
3151 aAny >>= mbFontIndependentLineSpacing;
3153 EscherPropertyContainer aPropOptSp;
3154 std::unique_ptr<ContainerGuard> xCellContainer(new ContainerGuard(mpPptEscherEx.get(), ESCHER_SpContainer));
3155 ImplCreateShape( ESCHER_ShpInst_Rectangle,
3156 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty | ShapeFlag::Child,
3157 aSolverContainer );
3158 aPropOptSp.CreateFillProperties( mXPropSet, true );
3159 aPropOptSp.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 );
3160 mnTxId += 0x60;
3161 aPropOptSp.CreateTextProperties( mXPropSet, mnTxId );
3162 aPropOptSp.AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapSquare );
3164 SvMemoryStream aClientTextBox( 0x200, 0x200 );
3165 SvMemoryStream aExtBu( 0x200, 0x200 );
3167 ImplWriteTextStyleAtom( aClientTextBox, EPP_TEXTTYPE_Other, 0, nullptr, aExtBu, &aPropOptSp );
3169 // need write client data for extend bullet
3170 if ( aExtBu.Tell() )
3172 std::unique_ptr<SvMemoryStream> pClientData(new SvMemoryStream( 0x200, 0x200 ));
3173 ImplProgTagContainer( pClientData.get(), &aExtBu );
3174 mpStrm->WriteUInt32( ( ESCHER_ClientData << 16 ) | 0xf )
3175 .WriteUInt32( pClientData->Tell() );
3177 mpStrm->WriteBytes(pClientData->GetData(), pClientData->Tell());
3180 aPropOptSp.Commit( *mpStrm );
3181 mpPptEscherEx->AddAtom( 16, ESCHER_ChildAnchor );
3182 mpStrm ->WriteInt32( nLeft )
3183 .WriteInt32( nTop )
3184 .WriteInt32( nRight )
3185 .WriteInt32( nBottom );
3187 mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
3188 .WriteUInt32( aClientTextBox.Tell() );
3190 mpStrm->WriteBytes(aClientTextBox.GetData(), aClientTextBox.Tell());
3191 xCellContainer.reset();
3196 // creating horz lines
3197 for( sal_Int32 nLine = 0; nLine < ( xRows->getCount() + 1 ); nLine++ )
3199 for( sal_Int32 nColumn = 0; nColumn < xColumns->getCount(); nColumn++ )
3201 CellBorder aCellBorder;
3202 aCellBorder.mnPos = aColumns[ nColumn ].first;
3203 bool bTop = false;
3204 //write nLine*nColumn cell's top border
3205 if ( nLine < xRows->getCount() )
3206 { // top border
3207 uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn, nLine ), uno::UNO_QUERY_THROW );
3208 if ( !xCell->isMerged() )
3210 uno::Reference< beans::XPropertySet > xPropSet2( xCell, uno::UNO_QUERY_THROW );
3211 table::BorderLine aBorderLine;
3212 if ( xPropSet2->getPropertyValue( "TopBorder" ) >>= aBorderLine )
3213 aCellBorder.maCellBorder = aBorderLine;
3214 sal_Int32 nRight = GetCellRight( nColumn, maRect,aColumns,xCell );
3215 bTop = ImplCreateCellBorder( &aCellBorder, aCellBorder.mnPos,
3216 aRows[ nLine ].first, nRight, aRows[ nLine ].first );
3220 //if nLine*nColumn cell's top border is empty, check (nLine-1)*nColumn cell's bottom border
3221 //and write the last row's bottom border
3222 if (( nLine && !bTop ) || (nLine == xRows->getCount()))
3223 { // bottom border
3224 sal_Int32 nRow = nLine;
3226 while( nRow )
3227 { //find last no merged cell
3228 uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn, nRow - 1 ), uno::UNO_QUERY_THROW );
3229 if ( !xCell->isMerged() )
3231 sal_Int32 nRight = GetCellRight( nColumn, maRect,aColumns,xCell );
3232 sal_Int32 nBottom = GetCellBottom( nRow - 1, maRect,aRows,xCell );
3233 if ( nBottom == ( aRows[ nLine-1 ].first + aRows[ nLine-1 ].second ) )
3235 uno::Reference< table::XMergeableCell > xCellOwn( xCellRange->getCellByPosition( nColumn, nRow - 1 ), uno::UNO_QUERY_THROW );
3236 uno::Reference< beans::XPropertySet > xPropSet2( xCellOwn, uno::UNO_QUERY_THROW );
3237 table::BorderLine aBorderLine;
3238 if ( xPropSet2->getPropertyValue( "BottomBorder" ) >>= aBorderLine )
3239 aCellBorder.maCellBorder = aBorderLine;
3240 ImplCreateCellBorder( &aCellBorder, aCellBorder.mnPos,
3241 nBottom, nRight, nBottom);
3243 nRow=0;
3245 else
3246 nRow--;
3252 // creating vertical lines
3253 for( sal_Int32 nLine = 0; nLine < ( xColumns->getCount() + 1 ); nLine++ )
3255 for( sal_Int32 nRow = 0; nRow < xRows->getCount(); nRow++ )
3258 CellBorder aCellBorder;
3259 aCellBorder.mnPos = aRows[ nRow].first;
3260 bool bLeft = false;
3261 if ( nLine < xColumns->getCount() )
3262 { // left border
3263 uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nLine, nRow ), uno::UNO_QUERY_THROW );
3264 if (!xCell->isMerged() )
3266 uno::Reference< beans::XPropertySet > xCellSet( xCell, uno::UNO_QUERY_THROW );
3267 table::BorderLine aBorderLine;
3268 if ( xCellSet->getPropertyValue( "LeftBorder" ) >>= aBorderLine )
3269 aCellBorder.maCellBorder = aBorderLine;
3270 sal_Int32 nBottom = GetCellBottom( nRow, maRect, aRows,xCell );
3271 bLeft = ImplCreateCellBorder( &aCellBorder, aColumns[nLine].first, aCellBorder.mnPos,
3272 aColumns[nLine].first, nBottom );
3275 if ( ( nLine && !bLeft )||(nLine == xColumns->getCount()))
3276 { // right border
3277 sal_Int32 nColumn = nLine;
3278 while ( nColumn )
3280 uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn - 1, nRow ), uno::UNO_QUERY_THROW );
3281 if (!xCell->isMerged() )
3283 sal_Int32 nRight = GetCellRight( nColumn-1, maRect, aColumns,xCell );
3284 sal_Int32 nBottom = GetCellBottom( nRow, maRect, aRows, xCell );
3285 if ( nRight == (aColumns[nLine-1].first + aColumns[nLine-1].second) )
3287 uno::Reference< table::XMergeableCell > xCellOwn( xCellRange->getCellByPosition( nColumn - 1, nRow ), uno::UNO_QUERY_THROW );
3288 uno::Reference< beans::XPropertySet > xCellSet( xCellOwn, uno::UNO_QUERY_THROW );
3289 table::BorderLine aBorderLine;
3290 if ( xCellSet->getPropertyValue( "RightBorder" ) >>= aBorderLine )
3291 aCellBorder.maCellBorder = aBorderLine;
3292 ImplCreateCellBorder( &aCellBorder, nRight, aCellBorder.mnPos,
3293 nRight, nBottom );
3295 nColumn = 0;
3297 else
3298 nColumn --;
3304 xSpgrContainer.reset(); //ESCHER_SpgrContainer
3307 catch( uno::Exception& )
3312 void TextObjBinary::Write( SvStream* pStrm )
3314 sal_uInt32 nSize, nPos = pStrm->Tell();
3315 pStrm->WriteUInt32( EPP_TextCharsAtom << 16 ).WriteUInt32( 0 );
3316 for ( sal_uInt32 i = 0; i < ParagraphCount(); ++i )
3317 GetParagraph(i)->Write( pStrm );
3318 nSize = pStrm->Tell() - nPos;
3319 pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
3320 pStrm->WriteUInt32( nSize - 8 );
3321 pStrm->SeekRel( nSize - 8 );
3324 void TextObjBinary::WriteTextSpecInfo( SvStream* pStrm )
3326 sal_uInt32 nCharactersLeft( Count() );
3327 if ( nCharactersLeft < 1 )
3328 return;
3330 EscherExAtom aAnimationInfoAtom( *pStrm, EPP_TextSpecInfoAtom, 0, 0 );
3331 for ( sal_uInt32 i = 0; nCharactersLeft && i < ParagraphCount(); ++i )
3333 ParagraphObj* pPtr = GetParagraph(i);
3334 for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = pPtr->begin(); nCharactersLeft && it != pPtr->end(); ++it )
3336 const PortionObj& rPortion = **it;
3337 sal_Int32 nPortionSize = rPortion.mnTextSize >= nCharactersLeft ? nCharactersLeft : rPortion.mnTextSize;
3338 sal_Int32 const nFlags = 7;
3339 nCharactersLeft -= nPortionSize;
3340 pStrm ->WriteUInt32( nPortionSize )
3341 .WriteInt32( nFlags )
3342 .WriteInt16( 1 ) // spellinfo -> needs rechecking
3343 .WriteInt16( static_cast<sal_uInt16>(LanguageTag( rPortion.meCharLocale ).makeFallback().getLanguageType()) )
3344 .WriteInt16( 0 ); // alt language
3347 if ( nCharactersLeft )
3348 pStrm->WriteUInt32( nCharactersLeft ).WriteInt32( 1 ).WriteInt16( 1 );
3351 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */