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