LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sd / source / filter / eppt / epptso.cxx
bloba85af722f0f3e37cd5a7596ca704484a5d9c0856
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include <sal/config.h>
23 #include <basegfx/numeric/ftools.hxx>
24 #include <o3tl/any.hxx>
25 #include "eppt.hxx"
26 #include "text.hxx"
27 #include "epptdef.hxx"
28 #include "escherex.hxx"
29 #include <tools/poly.hxx>
30 #include <tools/stream.hxx>
31 #include <tools/fontenum.hxx>
32 #include <tools/UnitConversion.hxx>
33 #include <sot/storage.hxx>
34 #include <vcl/graph.hxx>
35 #include <editeng/svxenum.hxx>
36 #include <svx/svdobj.hxx>
37 #include <svx/unoapi.hxx>
38 #include <com/sun/star/awt/FontFamily.hpp>
39 #include <com/sun/star/awt/FontPitch.hpp>
40 #include <com/sun/star/awt/Rectangle.hpp>
41 #include <com/sun/star/awt/FontDescriptor.hpp>
42 #include <com/sun/star/frame/XModel.hpp>
43 #include <com/sun/star/style/TabStop.hpp>
44 #include <com/sun/star/drawing/CircleKind.hpp>
45 #include <com/sun/star/drawing/FillStyle.hpp>
46 #include <com/sun/star/beans/XPropertyState.hpp>
47 #include <com/sun/star/drawing/XControlShape.hpp>
48 #include <com/sun/star/embed/Aspects.hpp>
49 #include <tools/urlobj.hxx>
50 #include <com/sun/star/text/XSimpleText.hpp>
51 #include <com/sun/star/task/XStatusIndicator.hpp>
52 #include <com/sun/star/table/XTable.hpp>
53 #include <com/sun/star/table/XMergeableCell.hpp>
54 #include <com/sun/star/table/BorderLine.hpp>
55 #include <com/sun/star/table/XColumnRowRange.hpp>
56 #include <com/sun/star/table/XCellRange.hpp>
57 #include <oox/ole/olehelper.hxx>
58 #include <i18nlangtag/languagetag.hxx>
60 using namespace ::com::sun::star;
62 #define ANSI_CHARSET 0
63 #define SYMBOL_CHARSET 2
65 /* Font Families */
66 #define FF_ROMAN 0x10
67 #define FF_SWISS 0x20
68 #define FF_MODERN 0x30
69 #define FF_SCRIPT 0x40
70 #define FF_DECORATIVE 0x50
72 #define DEFAULT_PITCH 0x00
73 #define FIXED_PITCH 0x01
75 PPTExBulletProvider::PPTExBulletProvider()
76 : pGraphicProv( new EscherGraphicProvider( EscherGraphicProviderFlags::UseInstances ) )
80 PPTExBulletProvider::~PPTExBulletProvider()
84 sal_uInt16 PPTExBulletProvider::GetId(Graphic const & rGraphic, Size& rGraphicSize )
86 sal_uInt16 nRetValue = 0xffff;
88 if (!rGraphic.IsNone())
90 Graphic aMappedGraphic, aGraphic(rGraphic);
91 GraphicObject aGraphicObject(aGraphic);
92 Size aPrefSize( aGraphic.GetPrefSize() );
93 BitmapEx aBmpEx( aGraphic.GetBitmapEx() );
95 if ( rGraphicSize.Width() && rGraphicSize.Height() )
97 if (aPrefSize.IsEmpty())
99 aBmpEx.Scale(aPrefSize);
101 else
103 double fQ1 = static_cast<double>(aPrefSize.Width()) / static_cast<double>(aPrefSize.Height());
104 double fQ2 = static_cast<double>(rGraphicSize.Width()) / static_cast<double>(rGraphicSize.Height());
105 double fXScale = 1;
106 double fYScale = 1;
108 if ( fQ1 > fQ2 )
109 fYScale = fQ1 / fQ2;
110 else if ( fQ1 < fQ2 )
111 fXScale = fQ2 / fQ1;
113 if ( ( fXScale != 1.0 ) || ( fYScale != 1.0 ) )
115 aBmpEx.Scale( fXScale, fYScale );
116 rGraphicSize = Size( static_cast<sal_Int32>(static_cast<double>(rGraphicSize.Width()) / fXScale + 0.5 ),
117 static_cast<sal_Int32>(static_cast<double>(rGraphicSize.Height()) / fYScale + 0.5 ) );
119 aMappedGraphic = Graphic( aBmpEx );
120 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 const OUString& rStringVer0, const OUString& rStringVer1, const OUString& rStringVer2, const OUString& rStringVer3 )
342 sal_uInt32 nHyperId = ++mnExEmbed;
344 OUString sBookmarkURL( rBookmarkURL );
345 INetURLObject aBaseURI( maBaseURI );
346 INetURLObject aBookmarkURI( rBookmarkURL );
347 if( aBaseURI.GetProtocol() == aBookmarkURI.GetProtocol() )
349 OUString aRelUrl( INetURLObject::GetRelURL( maBaseURI, rBookmarkURL ) );
350 if ( !aRelUrl.isEmpty() )
351 sBookmarkURL = aRelUrl;
353 maHyperlink.emplace_back( sBookmarkURL, nType );
355 mpExEmbed->WriteUInt16( 0xf )
356 .WriteUInt16( EPP_ExHyperlink )
357 .WriteUInt32( 0 );
358 sal_uInt32 nHyperSize, nHyperStart = mpExEmbed->Tell();
359 mpExEmbed->WriteUInt16( 0 )
360 .WriteUInt16( EPP_ExHyperlinkAtom )
361 .WriteUInt32( 4 )
362 .WriteUInt32( nHyperId );
364 PPTWriter::WriteCString( *mpExEmbed, rStringVer0 );
365 PPTWriter::WriteCString( *mpExEmbed, rStringVer1, 1 );
366 PPTWriter::WriteCString( *mpExEmbed, rStringVer2, 2 );
367 PPTWriter::WriteCString( *mpExEmbed, rStringVer3, 3 );
369 nHyperSize = mpExEmbed->Tell() - nHyperStart;
370 mpExEmbed->SeekRel( - ( static_cast<sal_Int32>(nHyperSize) + 4 ) );
371 mpExEmbed->WriteUInt32( nHyperSize );
372 mpExEmbed->SeekRel( nHyperSize );
373 return nHyperId;
376 bool PPTWriter::ImplCloseDocument()
378 sal_uInt32 nOfs = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_Document );
379 if ( nOfs )
381 mpPptEscherEx->PtReplaceOrInsert( EPP_Persist_CurrentPos, mpStrm->Tell() );
382 mpStrm->Seek( nOfs );
384 // creating the TxMasterStyleAtom
385 SvMemoryStream aTxMasterStyleAtomStrm( 0x200, 0x200 );
387 EscherExAtom aTxMasterStyleAtom( aTxMasterStyleAtomStrm, EPP_TxMasterStyleAtom, EPP_TEXTTYPE_Other );
388 aTxMasterStyleAtomStrm.WriteUInt16( 5 ); // paragraph count
389 sal_uInt16 nLev;
390 for ( nLev = 0; nLev < 5; nLev++ )
392 mpStyleSheet->mpParaSheet[ EPP_TEXTTYPE_Other ]->Write( aTxMasterStyleAtomStrm, nLev, false, mXPagePropSet );
393 mpStyleSheet->mpCharSheet[ EPP_TEXTTYPE_Other ]->Write( aTxMasterStyleAtomStrm, nLev, false, mXPagePropSet );
397 sal_uInt32 nExEmbedSize = mpExEmbed->TellEnd();
399 // nEnvironment : whole size of the environment container
400 sal_uInt32 nEnvironment = maFontCollection.GetCount() * 76 // 68 bytes per Fontenityatom and 8 Bytes per header
401 + 8 // 1 FontCollection container
402 + 20 // SrKinsoku container
403 + 18 // 1 TxSiStyleAtom
404 + aTxMasterStyleAtomStrm.Tell() // 1 TxMasterStyleAtom;
405 + PPTExStyleSheet::SizeOfTxCFStyleAtom();
407 sal_uInt32 nBytesToInsert = nEnvironment + 8;
409 if ( nExEmbedSize )
410 nBytesToInsert += nExEmbedSize + 8 + 12;
412 nBytesToInsert += maSoundCollection.GetSize();
413 nBytesToInsert += mpPptEscherEx->DrawingGroupContainerSize();
414 nBytesToInsert += ImplMasterSlideListContainer(nullptr);
415 nBytesToInsert += ImplDocumentListContainer(nullptr);
417 // insert nBytes into stream and adjust depending container
418 mpPptEscherEx->InsertAtCurrentPos( nBytesToInsert );
420 // CREATE HYPERLINK CONTAINER
421 if ( nExEmbedSize )
423 mpStrm->WriteUInt16( 0xf )
424 .WriteUInt16( EPP_ExObjList )
425 .WriteUInt32( nExEmbedSize + 12 )
426 .WriteUInt16( 0 )
427 .WriteUInt16( EPP_ExObjListAtom )
428 .WriteUInt32( 4 )
429 .WriteUInt32( mnExEmbed );
430 mpPptEscherEx->InsertPersistOffset( EPP_Persist_ExObj, mpStrm->Tell() );
431 mpStrm->WriteBytes(mpExEmbed->GetData(), nExEmbedSize);
434 // CREATE ENVIRONMENT
435 mpStrm->WriteUInt16( 0xf ).WriteUInt16( EPP_Environment ).WriteUInt32( nEnvironment );
437 // Open Container ( EPP_SrKinsoku )
438 mpStrm->WriteUInt16( 0x2f ).WriteUInt16( EPP_SrKinsoku ).WriteUInt32( 12 );
439 mpPptEscherEx->AddAtom( 4, EPP_SrKinsokuAtom, 0, 3 );
440 mpStrm->WriteInt32( 0 ); // SrKinsoku Level 0
442 // Open Container ( EPP_FontCollection )
443 mpStrm->WriteUInt16( 0xf ).WriteUInt16( EPP_FontCollection ).WriteUInt32( maFontCollection.GetCount() * 76 );
445 for ( sal_uInt32 i = 0; i < maFontCollection.GetCount(); i++ )
447 mpPptEscherEx->AddAtom( 68, EPP_FontEnityAtom, 0, i );
448 const FontCollectionEntry* pDesc = maFontCollection.GetById( i );
449 sal_Int32 nFontLen = pDesc->Name.getLength();
450 if ( nFontLen > 31 )
451 nFontLen = 31;
452 for ( sal_Int32 n = 0; n < 32; n++ )
454 sal_Unicode nUniCode = 0;
455 if ( n < nFontLen )
456 nUniCode = pDesc->Name[n];
457 mpStrm->WriteUInt16( nUniCode );
459 sal_uInt8 lfCharSet = ANSI_CHARSET;
460 sal_uInt8 const lfClipPrecision = 0;
461 sal_uInt8 const lfQuality = 6;
462 sal_uInt8 lfPitchAndFamily = 0;
464 if ( pDesc->CharSet == RTL_TEXTENCODING_SYMBOL )
465 lfCharSet = SYMBOL_CHARSET;
467 switch( pDesc->Family )
469 case css::awt::FontFamily::ROMAN :
470 lfPitchAndFamily |= FF_ROMAN;
471 break;
473 case css::awt::FontFamily::SWISS :
474 lfPitchAndFamily |= FF_SWISS;
475 break;
477 case css::awt::FontFamily::MODERN :
478 lfPitchAndFamily |= FF_MODERN;
479 break;
481 case css::awt::FontFamily::SCRIPT:
482 lfPitchAndFamily |= FF_SCRIPT;
483 break;
485 case css::awt::FontFamily::DECORATIVE:
486 lfPitchAndFamily |= FF_DECORATIVE;
487 break;
489 default:
490 lfPitchAndFamily |= FAMILY_DONTKNOW;
491 break;
493 switch( pDesc->Pitch )
495 case css::awt::FontPitch::FIXED:
496 lfPitchAndFamily |= FIXED_PITCH;
497 break;
499 default:
500 lfPitchAndFamily |= DEFAULT_PITCH;
501 break;
503 mpStrm->WriteUChar( lfCharSet )
504 .WriteUChar( lfClipPrecision )
505 .WriteUChar( lfQuality )
506 .WriteUChar( lfPitchAndFamily );
508 mpStyleSheet->WriteTxCFStyleAtom( *mpStrm ); // create style that is used for new standard objects
509 mpPptEscherEx->AddAtom( 10, EPP_TxSIStyleAtom );
510 mpStrm->WriteUInt32( 7 ) // ?
511 .WriteInt16( 2 ) // ?
512 .WriteUChar( 9 ) // ?
513 .WriteUChar( 8 ) // ?
514 .WriteInt16( 0 ); // ?
516 mpStrm->WriteBytes(aTxMasterStyleAtomStrm.GetData(), aTxMasterStyleAtomStrm.Tell());
517 maSoundCollection.Write( *mpStrm );
518 mpPptEscherEx->WriteDrawingGroupContainer( *mpStrm );
519 ImplMasterSlideListContainer( mpStrm.get() );
520 ImplDocumentListContainer( mpStrm.get() );
522 sal_uInt32 nOldPos = mpPptEscherEx->PtGetOffsetByID( EPP_Persist_CurrentPos );
523 if ( nOldPos )
525 mpStrm->Seek( nOldPos );
526 return true;
529 return false;
532 bool PropValue::GetPropertyValue(
533 css::uno::Any& rAny,
534 const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
535 const OUString& rString,
536 bool bTestPropertyAvailability )
538 bool bRetValue = true;
539 if ( bTestPropertyAvailability )
541 bRetValue = false;
544 css::uno::Reference< css::beans::XPropertySetInfo > aXPropSetInfo( rXPropSet->getPropertySetInfo() );
545 if ( aXPropSetInfo.is() )
546 bRetValue = aXPropSetInfo->hasPropertyByName( rString );
548 catch( css::uno::Exception& )
550 bRetValue = false;
553 if ( bRetValue )
557 rAny = rXPropSet->getPropertyValue( rString );
558 if ( !rAny.hasValue() )
559 bRetValue = false;
561 catch( css::uno::Exception& )
563 bRetValue = false;
566 return bRetValue;
569 css::beans::PropertyState PropValue::GetPropertyState(
570 const css::uno::Reference< css::beans::XPropertySet > & rXPropSet,
571 const OUString& rPropertyName )
573 css::beans::PropertyState eRetValue = css::beans::PropertyState_AMBIGUOUS_VALUE;
576 css::uno::Reference< css::beans::XPropertyState > aXPropState( rXPropSet, css::uno::UNO_QUERY );
577 if ( aXPropState.is() )
578 eRetValue = aXPropState->getPropertyState( rPropertyName );
580 catch( css::uno::Exception& )
584 return eRetValue;
587 bool PropValue::ImplGetPropertyValue( const OUString& rString )
589 return GetPropertyValue( mAny, mXPropSet, rString );
592 bool PropValue::ImplGetPropertyValue( const css::uno::Reference< css::beans::XPropertySet > & aXPropSet, const OUString& rString )
594 return GetPropertyValue( mAny, aXPropSet, rString );
597 bool PropStateValue::ImplGetPropertyValue( const OUString& rString, bool bGetPropertyState )
599 ePropState = css::beans::PropertyState_AMBIGUOUS_VALUE;
600 bool bRetValue = true;
601 #ifdef UNX
602 css::uno::Reference< css::beans::XPropertySetInfo >
603 aXPropSetInfo( mXPropSet->getPropertySetInfo() );
604 if ( !aXPropSetInfo.is() )
605 return false;
606 #endif
609 mAny = mXPropSet->getPropertyValue( rString );
610 if ( !mAny.hasValue() )
611 bRetValue = false;
612 else if ( bGetPropertyState )
613 ePropState = mXPropState->getPropertyState( rString );
614 else
615 ePropState = css::beans::PropertyState_DIRECT_VALUE;
617 catch( css::uno::Exception& )
619 bRetValue = false;
621 return bRetValue;
624 void PPTWriter::ImplWriteParagraphs( SvStream& rOut, TextObj& rTextObj )
626 bool bFirstParagraph = true;
627 sal_uInt32 nCharCount;
628 sal_uInt32 nPropertyFlags = 0;
629 sal_Int16 nLineSpacing;
630 int nInstance = rTextObj.GetInstance();
632 for ( sal_uInt32 i = 0; i < rTextObj.ParagraphCount(); ++i, bFirstParagraph = false )
634 ParagraphObj* pPara = rTextObj.GetParagraph(i);
635 const PortionObj& rPortion = pPara->front();
636 nCharCount = pPara->CharacterCount();
638 if ( ( pPara->meTextAdjust == css::beans::PropertyState_DIRECT_VALUE ) ||
639 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_Adjust, pPara->mnTextAdjust ) ) )
640 nPropertyFlags |= 0x00000800;
641 nLineSpacing = pPara->mnLineSpacing;
643 const FontCollectionEntry* pDesc = maFontCollection.GetById( rPortion.mnFont );
644 sal_Int16 nNormalSpacing = 100;
645 if ( !mbFontIndependentLineSpacing && pDesc )
647 double fN = 100.0;
648 fN *= pDesc->Scaling;
649 nNormalSpacing = static_cast<sal_Int16>( fN + 0.5 );
651 if ( !mbFontIndependentLineSpacing && bFirstParagraph && ( nLineSpacing > nNormalSpacing ) ) // sj: i28747, no replacement for fixed linespacing
653 nLineSpacing = nNormalSpacing;
654 nPropertyFlags |= 0x00001000;
656 else
658 if ( nLineSpacing > 0 )
660 if ( !mbFontIndependentLineSpacing && pDesc )
661 nLineSpacing = static_cast<sal_Int16>( static_cast<double>(nLineSpacing) * pDesc->Scaling + 0.5 );
663 else
665 if ( !pPara->mbFixedLineSpacing && rPortion.mnCharHeight > static_cast<sal_uInt16>( static_cast<double>(-nLineSpacing) * 0.001 * 72.0 / 2.54 ) ) // 1/100mm to point
666 nLineSpacing = nNormalSpacing;
667 else
668 nLineSpacing = static_cast<sal_Int16>( convertMm100ToMasterUnit(nLineSpacing) );
670 if ( ( pPara->meLineSpacing == css::beans::PropertyState_DIRECT_VALUE ) ||
671 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_LineFeed, nLineSpacing ) ) )
672 nPropertyFlags |= 0x00001000;
674 if ( ( pPara->meLineSpacingTop == css::beans::PropertyState_DIRECT_VALUE ) ||
675 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_UpperDist, pPara->mnLineSpacingTop ) ) )
676 nPropertyFlags |= 0x00002000;
677 if ( ( pPara->meLineSpacingBottom == css::beans::PropertyState_DIRECT_VALUE ) ||
678 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_LowerDist, pPara->mnLineSpacingBottom ) ) )
679 nPropertyFlags |= 0x00004000;
680 if ( ( pPara->meForbiddenRules == css::beans::PropertyState_DIRECT_VALUE ) ||
681 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_UpperDist, pPara->mbForbiddenRules ? 1 : 0 ) ) )
682 nPropertyFlags |= 0x00020000;
683 if ( ( pPara->meParagraphPunctation == css::beans::PropertyState_DIRECT_VALUE ) ||
684 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_UpperDist, pPara->mbParagraphPunctation ? 1 : 0 ) ) )
685 nPropertyFlags |= 0x00080000;
686 if ( ( pPara->meBiDi == css::beans::PropertyState_DIRECT_VALUE ) ||
687 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_BiDi, pPara->mnBiDi ) ) )
688 nPropertyFlags |= 0x00200000;
690 sal_Int32 nBuRealSize = pPara->nBulletRealSize;
691 sal_Int16 nBulletFlags = pPara->nBulletFlags;
693 if ( pPara->bExtendedParameters )
694 nPropertyFlags |= pPara->nParaFlags;
695 else
697 nPropertyFlags |= 1; // turn off bullet explicit
698 nBulletFlags = 0;
701 // Write nTextOfs and nBullets
702 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_TextOfs, pPara->nTextOfs ) )
703 nPropertyFlags |= 0x100;
704 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, ParaAttr_BulletOfs, pPara->nBulletOfs ))
705 nPropertyFlags |= 0x400;
707 FontCollectionEntry aFontDescEntry( pPara->aFontDesc.Name, pPara->aFontDesc.Family, pPara->aFontDesc.Pitch, pPara->aFontDesc.CharSet );
708 sal_uInt16 nFontId = static_cast<sal_uInt16>(maFontCollection.GetId( aFontDescEntry ));
710 rOut.WriteUInt32( nCharCount )
711 .WriteUInt16( pPara->nDepth ) // Level
712 .WriteUInt32( nPropertyFlags ); // Paragraph 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, "IsBackgroundDark", true ) )
730 aAny >>= bIsDark;
731 nBulletColor = bIsDark ? 0xffffff : 0x000000;
733 nBulletColor &= 0xffffff;
734 nBulletColor |= 0xfe000000;
735 rOut.WriteUInt32( nBulletColor );
737 if ( nPropertyFlags & 0x00000800 )
738 rOut.WriteUInt16( pPara->mnTextAdjust );
739 if ( nPropertyFlags & 0x00001000 )
740 rOut.WriteUInt16( nLineSpacing );
741 if ( nPropertyFlags & 0x00002000 )
742 rOut.WriteUInt16( pPara->mnLineSpacingTop );
743 if ( nPropertyFlags & 0x00004000 )
744 rOut.WriteUInt16( pPara->mnLineSpacingBottom );
745 if ( nPropertyFlags & 0x100 )
746 rOut.WriteUInt16( pPara->nTextOfs );
747 if ( nPropertyFlags & 0x400 )
748 rOut.WriteUInt16( pPara->nBulletOfs );
749 if ( nPropertyFlags & 0x000e0000 )
751 sal_uInt16 nAsianSettings = 0;
752 if ( pPara->mbForbiddenRules )
753 nAsianSettings |= 1;
754 if ( pPara->mbParagraphPunctation )
755 nAsianSettings |= 4;
756 rOut.WriteUInt16( nAsianSettings );
758 if ( nPropertyFlags & 0x200000 )
759 rOut.WriteUInt16( pPara->mnBiDi );
763 void PPTWriter::ImplWritePortions( SvStream& rOut, TextObj& rTextObj )
765 sal_uInt32 nPropertyFlags;
766 int nInstance = rTextObj.GetInstance();
768 for ( sal_uInt32 i = 0; i < rTextObj.ParagraphCount(); ++i )
770 ParagraphObj* pPara = rTextObj.GetParagraph(i);
771 for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = pPara->begin(); it != pPara->end(); ++it )
773 const PortionObj& rPortion = **it;
774 nPropertyFlags = 0;
775 sal_uInt32 nCharAttr = rPortion.mnCharAttr;
776 sal_uInt32 nCharColor = rPortion.mnCharColor;
778 if ( nCharColor == sal_uInt32(COL_AUTO) ) // nCharColor depends to the background color
780 bool bIsDark = false;
781 css::uno::Any aAny;
782 if ( PropValue::GetPropertyValue( aAny, mXPagePropSet, "IsBackgroundDark", true ) )
783 aAny >>= bIsDark;
784 nCharColor = bIsDark ? 0xffffff : 0x000000;
787 nCharColor &= 0xffffff;
789 /* the portion is using the embossed or engraved attribute, which we want to map to the relief feature of PPT.
790 Because the relief feature of PPT is dependent to the background color, such a mapping can not always be used. */
791 if ( nCharAttr & 0x200 )
793 sal_uInt32 nBackgroundColor = 0xffffff;
795 if ( !nCharColor ) // special treatment for
796 nCharColor = 0xffffff; // black fontcolor
798 css::uno::Any aAny;
799 css::drawing::FillStyle aFS( css::drawing::FillStyle_NONE );
800 if ( PropValue::GetPropertyValue( aAny, mXPropSet, "FillStyle" ) )
801 aAny >>= aFS;
802 switch( aFS )
804 case css::drawing::FillStyle_GRADIENT :
806 ::tools::Rectangle aRect( Point(), Size( 28000, 21000 ) );
807 EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect );
808 aPropOpt.CreateGradientProperties( mXPropSet );
809 aPropOpt.GetOpt( ESCHER_Prop_fillColor, nBackgroundColor );
811 break;
812 case css::drawing::FillStyle_SOLID :
814 if ( PropValue::GetPropertyValue( aAny, mXPropSet, "FillColor" ) )
815 nBackgroundColor = EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(aAny) );
817 break;
818 case css::drawing::FillStyle_NONE :
820 css::uno::Any aBackAny;
821 css::drawing::FillStyle aBackFS( css::drawing::FillStyle_NONE );
822 if ( PropValue::GetPropertyValue( aBackAny, mXBackgroundPropSet, "FillStyle" ) )
823 aBackAny >>= aBackFS;
824 switch( aBackFS )
826 case css::drawing::FillStyle_GRADIENT :
828 ::tools::Rectangle aRect( Point(), Size( 28000, 21000 ) );
829 EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect );
830 aPropOpt.CreateGradientProperties( mXBackgroundPropSet );
831 aPropOpt.GetOpt( ESCHER_Prop_fillColor, nBackgroundColor );
833 break;
834 case css::drawing::FillStyle_SOLID :
836 if ( PropValue::GetPropertyValue( aAny, mXBackgroundPropSet, "FillColor" ) )
837 nBackgroundColor = EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(aAny) );
839 break;
840 default:
841 break;
844 break;
845 default:
846 break;
849 sal_Int32 nB = nBackgroundColor & 0xff;
850 nB += static_cast<sal_uInt8>( nBackgroundColor >> 8 );
851 nB += static_cast<sal_uInt8>( nBackgroundColor >> 16 );
852 // if the background color is nearly black, relief can't been used, because the text would not be visible
853 if ( nB < 0x60 || ( nBackgroundColor != nCharColor ) )
855 nCharAttr &=~ 0x200;
857 // now check if the text is part of a group, and if the previous object has the same color than the fontcolor
858 // ( and if fillcolor is not available the background color ), it is sometimes
859 // not possible to export the 'embossed' flag
860 if ( ( GetCurrentGroupLevel() > 0 ) && ( GetCurrentGroupIndex() >= 1 ) )
862 css::uno::Reference< css::drawing::XShape > aGroupedShape( GetCurrentGroupAccess()->getByIndex( GetCurrentGroupIndex() - 1 ), uno::UNO_QUERY );
863 if( aGroupedShape.is() )
865 css::uno::Reference< css::beans::XPropertySet > aPropSetOfNextShape
866 ( aGroupedShape, css::uno::UNO_QUERY );
867 if ( aPropSetOfNextShape.is() )
869 if ( PropValue::GetPropertyValue( aAny, aPropSetOfNextShape,
870 "FillColor", true ) )
872 if ( nCharColor == EscherEx::GetColor( *o3tl::doAccess<sal_uInt32>(aAny) ) )
874 nCharAttr |= 0x200;
882 nCharColor |= 0xfe000000;
883 if ( nInstance == 4 ) // special handling for normal textobjects:
884 nPropertyFlags |= nCharAttr & 0x217; // not all attributes are inherited
885 else
887 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Bold, nCharAttr ) )
888 nPropertyFlags |= 1;
889 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Italic, nCharAttr ) )
890 nPropertyFlags |= 2;
891 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Underline, nCharAttr ) )
892 nPropertyFlags |= 4;
893 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Shadow, nCharAttr ) )
894 nPropertyFlags |= 0x10;
895 if ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Embossed, nCharAttr ) )
896 nPropertyFlags |= 512;
898 if ( rTextObj.HasExtendedBullets() )
900 nPropertyFlags |= ( i & 0x3f ) << 10 ;
901 nCharAttr |= ( i & 0x3f ) << 10;
903 if ( ( rPortion.meFontName == css::beans::PropertyState_DIRECT_VALUE ) ||
904 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Font, rPortion.mnFont ) ) )
905 nPropertyFlags |= 0x00010000;
906 if ( ( rPortion.meAsianOrComplexFont == css::beans::PropertyState_DIRECT_VALUE ) ||
907 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_AsianOrComplexFont, rPortion.mnAsianOrComplexFont ) ) )
908 nPropertyFlags |= 0x00200000;
909 if ( ( rPortion.meCharHeight == css::beans::PropertyState_DIRECT_VALUE ) ||
910 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_FontHeight, rPortion.mnCharHeight ) ) )
911 nPropertyFlags |= 0x00020000;
912 if ( ( rPortion.meCharColor == css::beans::PropertyState_DIRECT_VALUE ) ||
913 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_FontColor, nCharColor & 0xffffff ) ) )
914 nPropertyFlags |= 0x00040000;
915 if ( ( rPortion.meCharEscapement == css::beans::PropertyState_DIRECT_VALUE ) ||
916 ( mpStyleSheet->IsHardAttribute( nInstance, pPara->nDepth, CharAttr_Escapement, rPortion.mnCharEscapement ) ) )
917 nPropertyFlags |= 0x00080000;
919 sal_uInt32 nCharCount = rPortion.Count();
921 rOut.WriteUInt32( nCharCount )
922 .WriteUInt32( nPropertyFlags ); //PropertyFlags
924 if ( nPropertyFlags & 0xffff )
925 rOut.WriteUInt16( nCharAttr );
926 if ( nPropertyFlags & 0x00010000 )
927 rOut.WriteUInt16( rPortion.mnFont );
928 if ( nPropertyFlags & 0x00200000 )
929 rOut.WriteUInt16( rPortion.mnAsianOrComplexFont );
930 if ( nPropertyFlags & 0x00020000 )
931 rOut.WriteUInt16( rPortion.mnCharHeight );
932 if ( nPropertyFlags & 0x00040000 )
933 rOut.WriteUInt32( nCharColor );
934 if ( nPropertyFlags & 0x00080000 )
935 rOut.WriteInt16( rPortion.mnCharEscapement );
941 * Loads and converts text from shape, value is stored in mnTextSize.
943 bool PPTWriter::ImplGetText()
945 mnTextSize = 0;
946 mbFontIndependentLineSpacing = false;
947 mXText.set( mXShape, css::uno::UNO_QUERY );
949 if ( mXText.is() )
951 mnTextSize = mXText->getString().getLength();
952 css::uno::Any aAny;
953 if ( GetPropertyValue( aAny, mXPropSet, "FontIndependentLineSpacing", true ) )
954 aAny >>= mbFontIndependentLineSpacing;
956 return ( mnTextSize != 0 );
959 void PPTWriter::ImplFlipBoundingBox( EscherPropertyContainer& rPropOpt )
961 if ( mnAngle < 0 )
962 mnAngle = ( 36000 + mnAngle ) % 36000;
963 else
964 mnAngle = ( 36000 - ( mnAngle % 36000 ) );
966 double fCos = cos( 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_uInt32 nSize, nPos = rOut.Tell();
1051 rOut.WriteUInt32( EPP_StyleTextPropAtom << 16 ).WriteUInt32( 0 );
1052 ImplWriteParagraphs( rOut, aTextObj );
1053 ImplWritePortions( rOut, aTextObj );
1054 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, "", "", aPageUrl );
1123 else
1124 nHyperId = ImplInsertBookmarkURL( pFieldEntry->aFieldUrl, 2 | ( nHyperId << 8 ), aFile, aTarget, "", "" );
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, "TabStop" ))
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_uInt32 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, nPos2 = rExtBuStr.Tell();
1284 rExtBuStr.WriteUInt32( EPP_PST_ExtendedParagraphAtom << 16 ).WriteUInt32( 0 );
1286 for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount(); ++i )
1288 ParagraphObj* pBulletPara = aTextObj.GetParagraph(i);
1289 sal_uInt32 nBulletFlags = 0;
1290 sal_uInt16 nBulletId = pBulletPara->nBulletId;
1292 if ( pBulletPara->bExtendedBulletsUsed )
1294 nBulletFlags = 0x800000;
1295 if ( pBulletPara->nNumberingType != SVX_NUM_BITMAP )
1296 nBulletFlags = 0x3000000;
1298 rExtBuStr.WriteUInt32( nBulletFlags );
1300 if ( nBulletFlags & 0x800000 )
1301 rExtBuStr.WriteUInt16( nBulletId );
1302 if ( nBulletFlags & 0x1000000 )
1304 switch( pBulletPara->nNumberingType )
1306 case SVX_NUM_NUMBER_NONE :
1307 case SVX_NUM_CHAR_SPECIAL :
1308 nNumberingType = 0;
1309 break;
1310 case SVX_NUM_CHARS_UPPER_LETTER :
1311 case SVX_NUM_CHARS_UPPER_LETTER_N :
1312 case SVX_NUM_CHARS_LOWER_LETTER :
1313 case SVX_NUM_CHARS_LOWER_LETTER_N :
1314 case SVX_NUM_ROMAN_UPPER :
1315 case SVX_NUM_ROMAN_LOWER :
1316 case SVX_NUM_ARABIC :
1317 case SVX_NUM_NUMBER_UPPER_ZH:
1318 case SVX_NUM_CIRCLE_NUMBER:
1319 case SVX_NUM_NUMBER_UPPER_ZH_TW:
1320 case SVX_NUM_NUMBER_LOWER_ZH:
1321 case SVX_NUM_FULL_WIDTH_ARABIC:
1322 nNumberingType = pBulletPara->nMappedNumType;
1323 break;
1325 case SVX_NUM_BITMAP :
1326 nNumberingType = 0;
1327 break;
1328 default: break;
1330 rExtBuStr.WriteUInt32( nNumberingType );
1332 if ( nBulletFlags & 0x2000000 )
1333 rExtBuStr.WriteUInt16( pBulletPara->nStartWith );
1334 rExtBuStr.WriteUInt32( 0 ).WriteUInt32( 0 );
1336 sal_uInt32 nBulletSize = ( rExtBuStr.Tell() - nPos2 ) - 8;
1337 rExtBuStr.SeekRel( - ( static_cast<sal_Int32>(nBulletSize) + 4 ) );
1338 rExtBuStr.WriteUInt32( nBulletSize );
1339 rExtBuStr.SeekRel( nBulletSize );
1342 void PPTWriter::ImplWriteClickAction( SvStream& rSt, css::presentation::ClickAction eCa, bool bMediaClickAction )
1344 sal_uInt32 nSoundRef = 0; // a reference to a sound in the sound collection, or NULL.
1345 sal_uInt32 nHyperLinkID = 0;// a persistent unique identifier to an external hyperlink object (only valid when action == HyperlinkAction).
1346 sal_uInt8 nAction = 0; // Action See Action Table
1347 sal_uInt8 const nOleVerb = 0; // OleVerb Only valid when action == OLEAction. OLE verb to use, 0 = first verb, 1 = second verb, etc.
1348 sal_uInt8 nJump = 0; // Jump See Jump Table
1349 sal_uInt8 const nFlags = 0; // Bit 1: Animated. If 1, then button is animated
1350 // Bit 2: Stop sound. If 1, then stop current sound when button is pressed.
1351 // Bit 3: CustomShowReturn. If 1, and this is a jump to custom show, then return to this slide after custom show.
1352 sal_uInt8 nHyperLinkType = 0;// HyperlinkType a value from the LinkTo enum, such as LT_URL (only valid when action == HyperlinkAction).
1354 OUString aFile;
1357 Action Table: Action Value
1358 NoAction 0
1359 MacroAction 1
1360 RunProgramAction 2
1361 JumpAction 3
1362 HyperlinkAction 4
1363 OLEAction 5
1364 MediaAction 6
1365 CustomShowAction 7
1367 Jump Table: Jump Value
1368 NoJump 0
1369 NextSlide, 1
1370 PreviousSlide, 2
1371 FirstSlide, 3
1372 LastSlide, 4
1373 LastSlideViewed 5
1374 EndShow 6
1377 if ( bMediaClickAction )
1378 nAction = 6;
1379 else switch( eCa )
1381 case css::presentation::ClickAction_STOPPRESENTATION :
1382 nJump += 2;
1383 [[fallthrough]];
1384 case css::presentation::ClickAction_LASTPAGE :
1385 nJump++;
1386 [[fallthrough]];
1387 case css::presentation::ClickAction_FIRSTPAGE :
1388 nJump++;
1389 [[fallthrough]];
1390 case css::presentation::ClickAction_PREVPAGE :
1391 nJump++;
1392 [[fallthrough]];
1393 case css::presentation::ClickAction_NEXTPAGE :
1395 nJump++;
1396 nAction = 3;
1398 break;
1399 case css::presentation::ClickAction_SOUND :
1401 if ( ImplGetPropertyValue( "Bookmark" ) )
1402 nSoundRef = maSoundCollection.GetId( *o3tl::doAccess<OUString>(mAny) );
1404 break;
1405 case css::presentation::ClickAction_PROGRAM :
1407 if ( ImplGetPropertyValue( "Bookmark" ) )
1409 INetURLObject aUrl( *o3tl::doAccess<OUString>(mAny) );
1410 if ( INetProtocol::File == aUrl.GetProtocol() )
1412 aFile = aUrl.PathToFileName();
1413 nAction = 2;
1417 break;
1419 case css::presentation::ClickAction_BOOKMARK :
1421 if ( ImplGetPropertyValue( "Bookmark" ) )
1423 OUString aBookmark( *o3tl::doAccess<OUString>(mAny) );
1424 sal_uInt32 nIndex = 0;
1425 for ( const auto& rSlideName : maSlideNameList )
1427 if ( rSlideName == aBookmark )
1429 // Bookmark is a link to a document page
1430 nAction = 4;
1431 nHyperLinkType = 7;
1433 OUString aHyperString = OUString::number(256 + nIndex) +
1434 "," +
1435 OUString::number(nIndex + 1) +
1436 ",Slide " +
1437 OUString::number(nIndex + 1);
1438 nHyperLinkID = ImplInsertBookmarkURL( aHyperString, 1 | ( nIndex << 8 ) | ( 1U << 31 ), aBookmark, "", "", aHyperString );
1440 nIndex++;
1444 break;
1446 case css::presentation::ClickAction_DOCUMENT :
1448 if ( ImplGetPropertyValue( "Bookmark" ) )
1450 OUString aBookmark( *o3tl::doAccess<OUString>(mAny) );
1451 if ( !aBookmark.isEmpty() )
1453 nAction = 4;
1454 nHyperLinkType = 8;
1456 OUString aBookmarkFile( aBookmark );
1457 INetURLObject aUrl( aBookmark );
1458 if ( INetProtocol::File == aUrl.GetProtocol() )
1459 aBookmarkFile = aUrl.PathToFileName();
1460 nHyperLinkID = ImplInsertBookmarkURL( aBookmark, sal_uInt32(2 | ( 1U << 31 )), aBookmarkFile, aBookmark, "", "" );
1464 break;
1466 case css::presentation::ClickAction_INVISIBLE :
1467 case css::presentation::ClickAction_VERB :
1468 case css::presentation::ClickAction_VANISH :
1469 case css::presentation::ClickAction_MACRO :
1470 default :
1471 break;
1474 sal_uInt32 nContainerSize = 24;
1475 if ( nAction == 2 )
1476 nContainerSize += ( aFile.getLength() * 2 ) + 8;
1477 rSt.WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0xf ).WriteUInt32( nContainerSize )
1478 .WriteUInt32( EPP_InteractiveInfoAtom << 16 ).WriteUInt32( 16 )
1479 .WriteUInt32( nSoundRef )
1480 .WriteUInt32( nHyperLinkID )
1481 .WriteUChar( nAction )
1482 .WriteUChar( nOleVerb )
1483 .WriteUChar( nJump )
1484 .WriteUChar( nFlags )
1485 .WriteUInt32( nHyperLinkType );
1487 if ( nAction == 2 ) // run program Action
1489 sal_Int32 nLen = aFile.getLength();
1490 rSt.WriteUInt32( ( EPP_CString << 16 ) | 0x20 ).WriteUInt32( nLen * 2 );
1491 for ( sal_Int32 i = 0; i < nLen; i++ )
1492 rSt.WriteUInt16( aFile[i] );
1495 rSt.WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0x1f ).WriteUInt32( 24 ) // Mouse Over Action
1496 .WriteUInt32( EPP_InteractiveInfo << 16 ).WriteUInt32( 16 );
1497 for ( int i = 0; i < 4; i++, rSt.WriteUInt32( 0 ) ) ;
1500 bool PPTWriter::ImplGetEffect( const css::uno::Reference< css::beans::XPropertySet > & rPropSet,
1501 css::presentation::AnimationEffect& eEffect,
1502 css::presentation::AnimationEffect& eTextEffect,
1503 bool& bIsSound )
1505 css::uno::Any aAny;
1506 if ( GetPropertyValue( aAny, rPropSet, "Effect" ) )
1507 aAny >>= eEffect;
1508 else
1509 eEffect = css::presentation::AnimationEffect_NONE;
1511 if ( GetPropertyValue( aAny, rPropSet, "TextEffect" ) )
1512 aAny >>= eTextEffect;
1513 else
1514 eTextEffect = css::presentation::AnimationEffect_NONE;
1515 if ( GetPropertyValue( aAny, rPropSet, "SoundOn" ) )
1516 aAny >>= bIsSound;
1517 else
1518 bIsSound = false;
1520 bool bHasEffect = ( ( eEffect != css::presentation::AnimationEffect_NONE )
1521 || ( eTextEffect != css::presentation::AnimationEffect_NONE )
1522 || bIsSound );
1523 return bHasEffect;
1526 bool PPTWriter::ImplCreatePresentationPlaceholder( const bool bMasterPage,
1527 const sal_uInt32 nStyleInstance, const sal_uInt8 nPlaceHolderId )
1529 bool bRet = ImplGetText();
1530 if ( bRet && bMasterPage )
1532 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1533 sal_uInt32 nPresShapeID = mpPptEscherEx->GenerateShapeId();
1534 mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
1535 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty, nPresShapeID );
1536 EscherPropertyContainer aPropOpt;
1537 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x50001 );
1538 mnTxId += 0x60;
1539 aPropOpt.AddOpt( ESCHER_Prop_lTxid, mnTxId );
1540 aPropOpt.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
1541 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110001 );
1542 aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x8000001 );
1543 aPropOpt.AddOpt( ESCHER_Prop_shadowColor, 0x8000002 );
1544 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
1545 sal_uInt32 nLineFlags = 0x90001;
1546 if ( aPropOpt.GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ) )
1547 nLineFlags |= 0x10001; // draw dashed line if no line
1548 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
1550 SvMemoryStream aExtBu( 0x200, 0x200 );
1551 SvMemoryStream aClientTextBox( 0x200, 0x200 );
1552 ImplWriteTextStyleAtom( aClientTextBox, nStyleInstance, 0, nullptr, aExtBu, &aPropOpt );
1554 mnTxId += 0x60;
1555 aPropOpt.CreateTextProperties( mXPropSet, mnTxId );
1556 aPropOpt.CreateShapeProperties( mXShape );
1557 aPropOpt.Commit( *mpStrm );
1558 mpPptEscherEx->AddAtom( 8, ESCHER_ClientAnchor );
1559 mpStrm->WriteInt16( maRect.Top() ).WriteInt16( maRect.Left() ).WriteInt16( maRect.Right() ).WriteInt16( maRect.Bottom() ); // top, left, right, bottom ????
1560 mpPptEscherEx->OpenContainer( ESCHER_ClientData );
1561 mpPptEscherEx->AddAtom( 8, EPP_OEPlaceholderAtom );
1562 mpStrm->WriteUInt32( 0 ) // PlacementID
1563 .WriteUChar( nPlaceHolderId ) // PlaceHolderID
1564 .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
1565 .WriteUInt16( 0 ); // padword
1566 mpPptEscherEx->CloseContainer(); // ESCHER_ClientData
1568 if ( aClientTextBox.Tell() )
1570 mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
1571 .WriteUInt32( aClientTextBox.Tell() );
1573 mpStrm->WriteBytes(aClientTextBox.GetData(), aClientTextBox.Tell());
1575 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
1577 else
1578 bRet = false;
1579 return bRet;
1582 void PPTWriter::ImplCreateShape( sal_uInt32 nType, ShapeFlag nFlags, EscherSolverContainer& rSolver )
1584 sal_uInt32 nId = mpPptEscherEx->GenerateShapeId();
1585 mpPptEscherEx->AddShape( nType, nFlags, nId );
1586 rSolver.AddShape( mXShape, nId );
1589 void PPTWriter::ImplCreateTextShape( EscherPropertyContainer& rPropOpt, EscherSolverContainer& rSolver, bool bFill )
1591 mnTextStyle = EPP_TEXTSTYLE_TEXT;
1592 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1593 ImplCreateShape( ESCHER_ShpInst_TextBox, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty, rSolver );
1594 if ( bFill )
1595 rPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
1596 if ( ImplGetText() )
1598 mnTxId += 0x60;
1599 rPropOpt.CreateTextProperties( mXPropSet, mnTxId );
1603 void PPTWriter::ImplWritePage( const PHLayout& rLayout, EscherSolverContainer& aSolverContainer, PageType ePageType, bool bMasterPage, int nPageNumber )
1605 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
1606 // sal_uInt32 nGroupLevel = 0;
1608 sal_uInt32 nGroups, nShapes, nShapeCount, nPer, nLastPer, nIndices, nOlePictureId;
1609 css::awt::Point aTextRefPoint;
1611 nShapes = mXShapes->getCount();
1612 ResetGroupTable( nShapes );
1614 nIndices = nLastPer = nShapeCount = 0;
1616 bool bIsTitlePossible = true; // powerpoint is not able to handle more than one title
1618 sal_uInt32 nOutlinerCount = 0; // the outline objects have to conform to the layout,
1619 sal_uInt32 nPrevTextStyle = 0; // there are no more than two allowed
1621 nOlePictureId = 0;
1623 bool bAdditionalText = false;
1625 bool bSecOutl = false;
1626 sal_uInt32 nPObjects = 0;
1628 std::unique_ptr<SvMemoryStream> pClientTextBox;
1629 std::unique_ptr<SvMemoryStream> pClientData;
1631 while( GetNextGroupEntry() )
1633 nShapeCount++;
1635 nPer = ( 5 * nShapeCount ) / nShapes;
1636 if ( nPer != nLastPer )
1638 nLastPer = nPer;
1639 sal_uInt32 nValue = mnPagesWritten * 5 + nPer;
1640 if ( nValue > mnStatMaxValue )
1641 nValue = mnStatMaxValue;
1642 if ( mbStatusIndicator && ( nValue > mnLatestStatValue ) )
1644 mXStatusIndicator->setValue( nValue );
1645 mnLatestStatValue = nValue;
1648 nGroups = GetGroupsClosed();
1649 for ( sal_uInt32 i = 0; i < nGroups; i++, mpPptEscherEx->LeaveGroup() ) ;
1651 if ( GetShapeByIndex( GetCurrentGroupIndex(), true ) )
1653 bool bIsSound;
1654 bool bMediaClickAction = false;
1655 css::presentation::AnimationEffect eAe;
1656 css::presentation::AnimationEffect eTe;
1658 bool bEffect = ImplGetEffect( mXPropSet, eAe, eTe, bIsSound );
1659 css::presentation::ClickAction eCa = css::presentation::ClickAction_NONE;
1660 if ( ImplGetPropertyValue( "OnClick" ) )
1661 mAny >>= eCa;
1663 bool bGroup = mType == "drawing.Group";
1664 bool bOpenBezier = mType == "drawing.OpenBezier";
1665 bool bClosedBezier = mType == "drawing.ClosedBezier";
1666 bool bPolyPolygon = mType == "drawing.PolyPolygon";
1667 bool bPolyLine = mType == "drawing.PolyLine";
1668 OUString aGraphicPropertyName("Graphic");
1670 const css::awt::Size aSize100thmm( mXShape->getSize() );
1671 const css::awt::Point aPoint100thmm( mXShape->getPosition() );
1672 ::tools::Rectangle aRect100thmm( Point( aPoint100thmm.X, aPoint100thmm.Y ), Size( aSize100thmm.Width, aSize100thmm.Height ) );
1673 EscherPropertyContainer aPropOpt( mpPptEscherEx->GetGraphicProvider(), mpPicStrm.get(), aRect100thmm );
1675 if ( bGroup )
1677 css::uno::Reference< css::container::XIndexAccess >
1678 aXIndexAccess( mXShape, css::uno::UNO_QUERY );
1679 if ( EnterGroup( aXIndexAccess ) )
1681 std::unique_ptr<SvMemoryStream> pTmp;
1682 if ( eCa != css::presentation::ClickAction_NONE )
1684 pTmp.reset(new SvMemoryStream(0x200, 0x200));
1685 ImplWriteClickAction( *pTmp, eCa, bMediaClickAction );
1687 sal_uInt32 nShapeId = mpPptEscherEx->EnterGroup(&maRect, pTmp.get());
1688 aSolverContainer.AddShape( mXShape, nShapeId );
1691 else
1693 bool bIsFontwork = false;
1694 bool bIsHatching = false;
1695 css::uno::Any aAny;
1696 if ( GetPropertyValue( aAny, mXPropSet, "IsFontwork", true ) )
1697 aAny >>= bIsFontwork;
1698 if ( GetPropertyValue( aAny, mXPropSet, "FillStyle", true ) )
1700 css::drawing::FillStyle eFS;
1701 aAny >>= eFS;
1702 bIsHatching = eFS == css::drawing::FillStyle_HATCH;
1703 if (mType == "drawing.Custom" && eFS == drawing::FillStyle_BITMAP)
1705 ShapeFlag nMirrorFlags;
1706 OUString sCustomShapeType;
1707 MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType(
1708 mXShape, nMirrorFlags, sCustomShapeType);
1709 if (eShapeType == mso_sptMax)
1711 // We can't map this custom shape to a PPT preset and it has a bitmap
1712 // fill. Make sure that at least the bitmap fill is not lost.
1713 mType = "drawing.GraphicObject";
1714 aGraphicPropertyName = "Bitmap";
1718 if ( bIsHatching || bIsFontwork || ( mType == "drawing.Measure" ) || ( mType == "drawing.Caption" ) )
1720 if ( ImplGetPropertyValue( "BoundRect" ) )
1722 auto aRect = o3tl::doAccess<css::awt::Rectangle>(mAny);
1723 maPosition = MapPoint( css::awt::Point( aRect->X, aRect->Y ) );
1724 maSize = MapSize( css::awt::Size( aRect->Width, aRect->Height ) );
1725 maRect = ::tools::Rectangle( Point( maPosition.X, maPosition.Y ), Size( maSize.Width, maSize.Height ) );
1727 mType = "drawing.dontknow";
1730 sal_uInt8 nPlaceHolderAtom = EPP_PLACEHOLDER_NONE;
1732 mnTextSize = 0;
1733 mnTextStyle = EPP_TEXTSTYLE_NORMAL;
1735 if ( mType == "drawing.Custom" )
1737 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1738 ShapeFlag nMirrorFlags;
1739 OUString sCustomShapeType;
1740 MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType( mXShape, nMirrorFlags, sCustomShapeType );
1741 if ( sCustomShapeType == "col-502ad400" || sCustomShapeType == "col-60da8460" )
1742 { // sj: creating metafile for customshapes that can't be saved to ms format properly
1743 ImplCreateShape( ESCHER_ShpInst_PictureFrame,
1744 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1745 aSolverContainer );
1746 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "MetaFile", false ) )
1748 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
1749 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mXShape);
1750 if ( pObj )
1752 ::tools::Rectangle aBound = pObj->GetCurrentBoundRect();
1753 maPosition = MapPoint( css::awt::Point( aBound.Left(), aBound.Top() ) );
1754 maSize = MapSize( css::awt::Size ( aBound.GetWidth(), aBound.GetHeight() ) );
1755 maRect = ::tools::Rectangle( Point( maPosition.X, maPosition.Y ), Size( maSize.Width, maSize.Height ) );
1756 mnAngle = 0;
1760 else
1762 ImplCreateShape( eShapeType,
1763 nMirrorFlags | ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1764 aSolverContainer );
1765 aPropOpt.CreateCustomShapeProperties( eShapeType, mXShape );
1766 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape);
1767 if ( ImplGetText() )
1769 if ( !aPropOpt.IsFontWork() )
1771 mnTxId += 0x60;
1772 aPropOpt.CreateTextProperties( mXPropSet, mnTxId, true );
1777 else if ( mType == "drawing.Rectangle" )
1779 sal_Int32 nRadius = 0;
1780 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1781 if ( ImplGetPropertyValue( "CornerRadius" ) )
1783 mAny >>= nRadius;
1784 nRadius = MapSize( css::awt::Size( nRadius, 0 ) ).Width;
1786 if ( nRadius )
1788 ImplCreateShape( ESCHER_ShpInst_RoundRectangle,
1789 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1790 aSolverContainer );
1791 sal_Int32 nLength = maRect.GetWidth();
1792 if ( nLength > maRect.GetHeight() )
1793 nLength = maRect.GetHeight();
1794 nLength >>= 1;
1795 if ( nRadius >= nLength )
1796 nRadius = 0x2a30; // 0x2a30 is PPTs maximum radius
1797 else
1799 if (nLength != 0)
1800 nRadius = ( 0x2a30 * nRadius ) / nLength;
1801 else
1802 nRadius = 0x2a30; // 0x2a30 is PPTs maximum radius
1804 aPropOpt.AddOpt( ESCHER_Prop_adjustValue, nRadius );
1806 else
1808 ImplCreateShape( ESCHER_ShpInst_Rectangle,
1809 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1810 aSolverContainer );
1812 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
1813 if ( ImplGetText() )
1815 mnTxId += 0x60;
1816 aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
1819 else if ( mType == "drawing.Ellipse" )
1821 css::drawing::CircleKind eCircleKind( css::drawing::CircleKind_FULL );
1822 PolyStyle ePolyKind = PolyStyle::Chord;
1823 if ( ImplGetPropertyValue( "CircleKind" ) )
1825 mAny >>= eCircleKind;
1826 switch ( eCircleKind )
1828 case css::drawing::CircleKind_SECTION :
1830 ePolyKind = PolyStyle::Pie;
1832 break;
1833 case css::drawing::CircleKind_ARC :
1835 ePolyKind = PolyStyle::Arc;
1837 break;
1839 case css::drawing::CircleKind_CUT :
1841 ePolyKind = PolyStyle::Chord;
1843 break;
1845 default:
1846 eCircleKind = css::drawing::CircleKind_FULL;
1849 if ( eCircleKind == css::drawing::CircleKind_FULL )
1851 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1852 ImplCreateShape( ESCHER_ShpInst_Ellipse,
1853 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1854 aSolverContainer );
1855 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
1856 if ( ImplGetText() )
1858 mnTxId += 0x60;
1859 aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
1862 else
1864 sal_Int32 nStartAngle, nEndAngle;
1865 if ( !ImplGetPropertyValue( "CircleStartAngle" ) )
1866 continue;
1867 nStartAngle = *o3tl::doAccess<sal_Int32>(mAny);
1868 if( !ImplGetPropertyValue( "CircleEndAngle" ) )
1869 continue;
1870 nEndAngle = *o3tl::doAccess<sal_Int32>(mAny);
1871 css::awt::Point aPoint( mXShape->getPosition() );
1872 css::awt::Size aSize( mXShape->getSize() );
1873 css::awt::Point aStart, aEnd, aCenter;
1874 ::tools::Rectangle aRect( Point( aPoint.X, aPoint.Y ), Size( aSize.Width, aSize.Height ) );
1875 aStart.X = static_cast<sal_Int32>( cos( basegfx::deg2rad<100>(nStartAngle) ) * 100.0 );
1876 aStart.Y = - static_cast<sal_Int32>( sin( basegfx::deg2rad<100>(nStartAngle) ) * 100.0 );
1877 aEnd.X = static_cast<sal_Int32>( cos( basegfx::deg2rad<100>(nEndAngle) ) * 100.0 );
1878 aEnd.Y = - static_cast<sal_Int32>( sin( basegfx::deg2rad<100>(nEndAngle) ) * 100.0 );
1879 aCenter.X = aPoint.X + ( aSize.Width / 2 );
1880 aCenter.Y = aPoint.Y + ( aSize.Height / 2 );
1881 aStart.X += aCenter.X;
1882 aStart.Y += aCenter.Y;
1883 aEnd.X += aCenter.X;
1884 aEnd.Y += aCenter.Y;
1885 tools::Polygon aPolygon( aRect, Point( aStart.X, aStart.Y ), Point( aEnd.X, aEnd.Y ), ePolyKind );
1886 bool bNeedText = true;
1887 if ( mnAngle )
1889 aPolygon.Rotate( aRect.TopLeft(), Degree10(static_cast<sal_Int16>( mnAngle / 10 )) );
1890 if ( ImplGetText() )
1892 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
1893 // mpPptEscherEx->EnterGroup( 0,0 );
1894 // nGroupLevel = mpPptEscherEx->GetGroupLevel();
1895 bNeedText = false;
1896 bAdditionalText = true;
1897 mnTextSize = 0;
1899 mnAngle = 0;
1901 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
1902 ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
1903 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
1904 aSolverContainer );
1905 css::awt::Rectangle aNewRect;
1906 switch ( ePolyKind )
1908 case PolyStyle::Pie :
1909 case PolyStyle::Chord :
1911 if ( aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect, &aPolygon ) )
1912 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
1914 break;
1916 case PolyStyle::Arc :
1918 if ( aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect, &aPolygon ) )
1919 aPropOpt.CreateLineProperties( mXPropSet, false );
1921 break;
1923 maRect = MapRectangle( aNewRect );
1924 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
1925 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
1926 if ( bNeedText && ImplGetText() )
1928 mnTxId += 0x60;
1929 aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
1933 else if ( mType == "drawing.Control" )
1935 css::uno::Reference< css::drawing::XControlShape > aXControlShape( mXShape, css::uno::UNO_QUERY );
1936 if ( !aXControlShape.is() )
1937 continue;
1938 css::uno::Reference< css::awt::XControlModel > aXControlModel( aXControlShape->getControl() );
1939 if ( !aXControlModel.is() )
1940 continue;
1942 sal_Int64 nAspect = css::embed::Aspects::MSOLE_CONTENT;
1945 // try to get the aspect when available
1946 css::uno::Reference< css::beans::XPropertySet > xShapeProps( mXShape, css::uno::UNO_QUERY_THROW );
1947 xShapeProps->getPropertyValue("Aspect") >>= nAspect;
1949 catch( css::uno::Exception& )
1952 mpExEmbed->WriteUInt32( 0xf | ( EPP_ExControl << 16 ) )
1953 .WriteUInt32( 0 ); // Size of this container
1955 sal_uInt32 nSize, nOldPos = mpExEmbed->Tell();
1957 sal_uInt32 nPageId = nPageNumber;
1958 if ( ePageType == MASTER )
1959 nPageId |= 0x80000000;
1960 else
1961 nPageId += 0x100;
1962 mpExEmbed->WriteUInt32( EPP_ExControlAtom << 16 )
1963 .WriteUInt32( 4 )
1964 .WriteUInt32( nPageId );
1965 std::unique_ptr<PPTExOleObjEntry> pEntry( new PPTExOleObjEntry( OCX_CONTROL, mpExEmbed->Tell() ) );
1966 pEntry->xControlModel = aXControlModel;
1967 pEntry->xShape = mXShape;
1968 maExOleObj.push_back( std::move(pEntry) );
1970 mnExEmbed++;
1972 mpExEmbed->WriteUInt32( 1 | ( EPP_ExOleObjAtom << 16 ) )
1973 .WriteUInt32( 24 )
1974 .WriteUInt32( nAspect )
1975 .WriteUInt32( 2 )
1976 .WriteUInt32( mnExEmbed )
1977 .WriteUInt32( 0 )
1978 .WriteUInt32( 4 ) // index to the persist table
1979 .WriteUInt32( 0x0012de00 );
1981 css::awt::Size aSize;
1982 OUString aControlName;
1983 tools::SvRef<SotStorage> xTemp( new SotStorage( new SvMemoryStream(), true ) );
1984 if ( oox::ole::MSConvertOCXControls::WriteOCXStream( mXModel, xTemp, aXControlModel, aSize, aControlName ) )
1986 OUString aUserName( xTemp->GetUserName() );
1987 OUString aOleIdentifier;
1988 if ( !aUserName.isEmpty() )
1990 tools::SvRef<SotStorageStream> xCompObj = xTemp->OpenSotStream(
1991 "\1CompObj",
1992 StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYALL );
1993 sal_uInt32 const nStreamLen = xCompObj->remainingSize();
1994 sal_Int16 nVersion, nByteOrder;
1995 sal_Int32 nWinVersion, nVal, nStringLen;
1996 xCompObj->ReadInt16( nVersion )
1997 .ReadInt16( nByteOrder )
1998 .ReadInt32( nWinVersion )
1999 .ReadInt32( nVal );
2000 xCompObj->SeekRel( 16 ); // skipping clsid
2001 xCompObj->ReadInt32( nStringLen );
2002 if ( ( xCompObj->Tell() + nStringLen ) < nStreamLen )
2004 xCompObj->SeekRel( nStringLen ); // now skipping the UserName;
2005 xCompObj->ReadInt32( nStringLen );
2006 if ( ( xCompObj->Tell() + nStringLen ) < nStreamLen )
2008 xCompObj->SeekRel( nStringLen ); // now skipping the clipboard formatname
2009 xCompObj->ReadInt32( nStringLen );
2010 if ( ( nStringLen > 1 ) && ( ( xCompObj->Tell() + nStringLen ) < nStreamLen ) )
2011 { // i think that the OleIdentifier will follow
2012 OString aTemp = read_uInt8s_ToOString(*xCompObj, nStringLen - 1);
2013 aOleIdentifier = OStringToOUString(aTemp, RTL_TEXTENCODING_MS_1252);
2019 PPTWriter::WriteCString( *mpExEmbed, aControlName, 1 );
2020 PPTWriter::WriteCString( *mpExEmbed, aOleIdentifier, 2 );
2021 PPTWriter::WriteCString( *mpExEmbed, aUserName, 3 );
2023 nSize = mpExEmbed->Tell() - nOldPos;
2024 mpExEmbed->Seek( nOldPos - 4 );
2025 mpExEmbed->WriteUInt32( nSize );
2026 mpExEmbed->Seek( STREAM_SEEK_TO_END );
2027 nOlePictureId = mnExEmbed;
2029 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2030 ShapeFlag const nSpFlags = ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor | ShapeFlag::OLEShape;
2031 ImplCreateShape( ESCHER_ShpInst_HostControl, nSpFlags, aSolverContainer );
2032 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "MetaFile", false ) )
2033 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2034 //export form control graphic
2035 else if ( aPropOpt.CreateBlipPropertiesforOLEControl(mXPropSet,mXShape))
2036 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2037 aPropOpt.AddOpt( ESCHER_Prop_pictureId, mnExEmbed );
2038 aPropOpt.AddOpt( ESCHER_Prop_pictureActive, 0x10000 );
2040 if ( !aControlName.isEmpty() )
2042 aPropOpt.AddOpt(ESCHER_Prop_wzName, aControlName);
2045 else if ( mType == "drawing.Connector" )
2047 sal_uInt16 nSpType;
2048 ShapeFlag nSpFlags;
2049 css::awt::Rectangle aNewRect;
2050 if ( !aPropOpt.CreateConnectorProperties( mXShape, aSolverContainer, aNewRect, nSpType, nSpFlags ) )
2051 continue;
2053 maRect = MapRectangle( aNewRect );
2054 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2055 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2057 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2058 ImplCreateShape( nSpType, nSpFlags, aSolverContainer );
2060 // #119459# for connector shape, the start point and end point is fixed, and should not be rotated.
2061 mnAngle = 0;
2063 else if ( mType == "drawing.Measure" )
2065 continue;
2067 else if ( mType == "drawing.Line" )
2069 css::awt::Rectangle aNewRect;
2070 aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_LINE, false, aNewRect );
2071 maRect = MapRectangle( aNewRect );
2072 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2073 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2074 if ( ImplGetText() )
2076 aTextRefPoint = css::awt::Point( maRect.Left(), maRect.Top() );
2077 mnTextSize = 0;
2078 bAdditionalText = true;
2079 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2080 // mpPptEscherEx->EnterGroup( &maRect,0 );
2082 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2083 ShapeFlag nFlags = ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty;
2085 if ( maRect.Top() > maRect.Bottom() )
2086 nFlags |= ShapeFlag::FlipV;
2087 if ( maRect.Left() > maRect.Right() )
2088 nFlags |= ShapeFlag::FlipH;
2090 ImplCreateShape( ESCHER_ShpInst_Line, nFlags, aSolverContainer );
2091 aPropOpt.AddOpt( ESCHER_Prop_shapePath, ESCHER_ShapeComplex );
2092 aPropOpt.CreateLineProperties( mXPropSet, false );
2093 mnAngle = 0;
2095 else if ( bPolyPolygon )
2097 if ( ImplGetText() )
2099 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2100 // mpPptEscherEx->EnterGroup( 0,0 );
2101 // nGroupLevel = mpPptEscherEx->GetGroupLevel();
2102 bAdditionalText = true;
2103 mnTextSize = 0;
2105 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2106 ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
2107 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2108 aSolverContainer );
2109 css::awt::Rectangle aNewRect;
2110 aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect );
2111 maRect = MapRectangle( aNewRect );
2112 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2113 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2114 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
2115 mnAngle = 0;
2117 else if ( bPolyLine )
2119 if ( ImplGetText() )
2121 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2122 // mpPptEscherEx->EnterGroup( 0,0 );
2123 // nGroupLevel = mpPptEscherEx->GetGroupLevel();
2124 bAdditionalText = true;
2125 mnTextSize = 0;
2127 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2128 ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
2129 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2130 aSolverContainer );
2131 css::awt::Rectangle aNewRect;
2132 aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect );
2133 maRect = MapRectangle( aNewRect );
2134 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2135 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2136 aPropOpt.CreateLineProperties( mXPropSet, false );
2137 mnAngle = 0;
2139 else if ( bOpenBezier )
2141 if ( ImplGetText() )
2143 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2144 // mpPptEscherEx->EnterGroup( 0,0 );
2145 // nGroupLevel = mpPptEscherEx->GetGroupLevel();
2146 bAdditionalText = true;
2147 mnTextSize = 0;
2149 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2150 ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
2151 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2152 aSolverContainer );
2153 css::awt::Rectangle aNewRect;
2154 aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, true, aNewRect );
2155 maRect = MapRectangle( aNewRect );
2156 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2157 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2158 aPropOpt.CreateLineProperties( mXPropSet, false );
2159 mnAngle = 0;
2161 else if ( bClosedBezier )
2163 if ( ImplGetText() )
2165 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2166 // mpPptEscherEx->EnterGroup( 0,0 );
2167 // nGroupLevel = mpPptEscherEx->GetGroupLevel();
2168 bAdditionalText = true;
2169 mnTextSize = 0;
2171 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2172 ImplCreateShape( ESCHER_ShpInst_NotPrimitive,
2173 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2174 aSolverContainer );
2175 css::awt::Rectangle aNewRect;
2176 aPropOpt.CreatePolygonProperties( mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, true, aNewRect );
2177 maRect = MapRectangle( aNewRect );
2178 maPosition = css::awt::Point( maRect.Left(), maRect.Top() );
2179 maSize = css::awt::Size( maRect.GetWidth(), maRect.GetHeight() );
2180 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
2181 mnAngle = 0;
2183 else if ( ( mType == "drawing.GraphicObject" ) || ( mType == "presentation.GraphicObject" ) )
2185 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2187 // a GraphicObject can also be a ClickMe element
2188 if ( mbEmptyPresObj && ( ePageType == NORMAL ) )
2190 nPlaceHolderAtom = rLayout.nUsedObjectPlaceHolder;
2191 ImplCreateShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster, aSolverContainer );
2192 mnTxId += 0x60;
2193 aPropOpt.AddOpt( ESCHER_Prop_lTxid, mnTxId );
2194 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
2195 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 );
2196 aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
2198 else
2200 mXText.set( mXShape, css::uno::UNO_QUERY );
2202 if ( mXText.is() )
2203 mnTextSize = mXText->getString().getLength();
2205 if ( mnTextSize ) // graphic object or area fill
2207 /* SJ #i34951#: because M. documents are not allowing GraphicObjects containing text, we
2208 have to create a simple Rectangle with fill bitmap instead (while not allowing BitmapMode_Repeat).
2210 ImplCreateShape( ESCHER_ShpInst_Rectangle,
2211 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2212 aSolverContainer );
2213 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "Graphic", true, true, false ) )
2215 aPropOpt.AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapNone );
2216 aPropOpt.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
2217 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x140014 );
2218 aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x8000000 );
2219 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
2220 if ( ImplGetText() )
2222 mnTxId += 0x60;
2223 aPropOpt.CreateTextProperties( mXPropSet, mnTxId, false, false );
2227 else
2229 ImplCreateShape( ESCHER_ShpInst_PictureFrame,
2230 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2231 aSolverContainer );
2233 if (aPropOpt.CreateGraphicProperties(mXPropSet, aGraphicPropertyName, false,
2234 true))
2236 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2241 else if ( ( mType == "drawing.Text" ) || ( mType == "presentation.Notes" ) )
2243 if ( ( ePageType == NOTICE ) && mbPresObj )
2245 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Notes, EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE ) )
2246 continue;
2247 else
2248 nPlaceHolderAtom = EPP_PLACEHOLDER_NOTESBODY;
2250 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2252 else if ( mType == "presentation.TitleText" )
2254 if ( mbPresObj )
2256 if ( ( ePageType == NOTICE ) && mbEmptyPresObj )
2258 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2259 nPlaceHolderAtom = EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE;
2260 ImplCreateShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveAnchor, aSolverContainer );
2261 aPropOpt.CreateLineProperties( mXPropSet, false );
2262 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
2264 else if ( rLayout.bTitlePossible && bIsTitlePossible )
2266 bIsTitlePossible = false;
2268 ImplGetText();
2269 TextObjBinary aTextObj( mXText, EPP_TEXTTYPE_Title, maFontCollection, static_cast<PPTExBulletProvider&>(*this) );
2270 if ( ePageType == MASTER )
2272 if ( mnTextSize )
2274 OUString aUString( mXText->getString() );
2275 sal_uInt16 nChar;
2277 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2278 mnShapeMasterTitle = mpPptEscherEx->GenerateShapeId();
2279 mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
2280 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2281 mnShapeMasterTitle );
2282 EscherPropertyContainer aPropertyOptions;
2283 aPropertyOptions.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x50001 );
2284 mnTxId += 0x60;
2285 aPropertyOptions.AddOpt( ESCHER_Prop_lTxid, mnTxId );
2286 aPropertyOptions.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
2287 aPropertyOptions.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110001 );
2288 aPropertyOptions.AddOpt( ESCHER_Prop_lineColor, 0x8000001 );
2289 aPropertyOptions.AddOpt( ESCHER_Prop_shadowColor, 0x8000002 );
2290 aPropertyOptions.CreateFillProperties( mXPropSet, true, mXShape );
2291 sal_uInt32 nLineFlags = 0x90001;
2292 if ( aPropertyOptions.GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ) )
2293 nLineFlags |= 0x10001; // draw dashed line if no line
2294 aPropertyOptions.AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
2295 mnTxId += 0x60;
2296 aPropertyOptions.CreateTextProperties( mXPropSet, mnTxId );
2297 ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt );
2298 aPropertyOptions.Commit( *mpStrm );
2299 mpPptEscherEx->AddAtom( 8, ESCHER_ClientAnchor );
2300 mpStrm->WriteInt16( maRect.Top() ).WriteInt16( maRect.Left() ).WriteInt16( maRect.Right() ).WriteInt16( maRect.Bottom() ); // top, left, right, bottom ????
2301 mpPptEscherEx->OpenContainer( ESCHER_ClientData );
2302 mpPptEscherEx->AddAtom( 8, EPP_OEPlaceholderAtom );
2303 mpStrm->WriteUInt32( 0 ) // PlacementID
2304 .WriteUChar( EPP_PLACEHOLDER_MASTERTITLE ) // PlaceHolderID
2305 .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
2306 .WriteUInt16( 0 ); // padword
2307 mpPptEscherEx->CloseContainer(); // ESCHER_ClientData
2308 mpPptEscherEx->OpenContainer( ESCHER_ClientTextbox );
2309 mpPptEscherEx->AddAtom( 4, EPP_TextHeaderAtom );
2310 mpStrm->WriteUInt32( EPP_TEXTTYPE_Title );
2311 mpPptEscherEx->AddAtom( mnTextSize << 1, EPP_TextCharsAtom );
2312 const sal_Unicode* pString = aUString.getStr();
2313 for ( sal_uInt32 i = 0; i < mnTextSize; i++ )
2315 nChar = pString[ i ]; // 0xa -> 0xb soft newline
2316 if ( nChar == 0xa )
2317 nChar++; // 0xd -> 0xd hard newline
2318 mpStrm->WriteUInt16( nChar );
2320 mpPptEscherEx->AddAtom( 6, EPP_BaseTextPropAtom );
2321 mpStrm->WriteUInt32( mnTextSize + 1 ).WriteUInt16( 0 );
2322 mpPptEscherEx->AddAtom( 10, EPP_TextSpecInfoAtom );
2323 mpStrm->WriteUInt32( mnTextSize + 1 ).WriteUInt32( 1 ).WriteUInt16( 0 );
2324 mpPptEscherEx->CloseContainer(); // ESCHER_ClientTextBox
2325 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
2327 continue;
2329 else
2331 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2332 mnTextStyle = EPP_TEXTSTYLE_TITLE;
2333 nPlaceHolderAtom = rLayout.nTypeOfTitle;
2334 ImplCreateShape( ESCHER_ShpInst_Rectangle,
2335 ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster,
2336 aSolverContainer );
2337 aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterTitle );
2338 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
2339 mnTxId += 0x60;
2340 aPropOpt.CreateTextProperties( mXPropSet, mnTxId );
2341 ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt );
2342 if ( mbEmptyPresObj )
2344 sal_uInt32 nNoLineDrawDash = 0;
2345 aPropOpt.GetOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
2346 nNoLineDrawDash |= 0x10001;
2347 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
2351 else
2352 mbPresObj = false;
2354 if ( !mbPresObj )
2356 mType = "drawing.Text";
2357 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2360 else if ( ( mType == "presentation.Outliner" ) || ( mType == "presentation.Subtitle" ) )
2362 if ( mbPresObj )
2364 nOutlinerCount++;
2365 if ( (rLayout.bOutlinerPossible && ( nOutlinerCount == 1 )) ||
2366 (( rLayout.bSecOutlinerPossible && ( nOutlinerCount == 2 ) ) && ( nPrevTextStyle == EPP_TEXTSTYLE_BODY ))
2369 ImplGetText();
2370 TextObjBinary aTextObj( mXText, EPP_TEXTTYPE_Body, maFontCollection, static_cast<PPTExBulletProvider&>(*this) );
2371 if ( ePageType == MASTER )
2373 nPrevTextStyle = EPP_TEXTSTYLE_TITLE;
2374 if ( mnTextSize )
2376 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2377 mnShapeMasterBody = mpPptEscherEx->GenerateShapeId();
2378 mpPptEscherEx->AddShape( ESCHER_ShpInst_Rectangle,
2379 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2380 mnShapeMasterBody );
2381 EscherPropertyContainer aPropOpt2;
2382 aPropOpt2.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x50001 );
2383 mnTxId += 0x60;
2384 aPropOpt2.AddOpt( ESCHER_Prop_lTxid, mnTxId );
2385 aPropOpt2.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110001 );
2386 aPropOpt2.AddOpt( ESCHER_Prop_lineColor, 0x8000001 );
2387 aPropOpt2.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90001 );
2388 aPropOpt2.AddOpt( ESCHER_Prop_shadowColor, 0x8000002 );
2389 aPropOpt2.CreateFillProperties( mXPropSet, true, mXShape );
2390 sal_uInt32 nLineFlags = 0x90001;
2391 if ( aPropOpt2.GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags ) )
2392 nLineFlags |= 0x10001; // draw dashed line if no line
2393 aPropOpt2.AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
2394 mnTxId += 0x60;
2395 aPropOpt2.CreateTextProperties( mXPropSet, mnTxId );
2396 ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt2 );
2397 aPropOpt2.Commit( *mpStrm );
2398 mpPptEscherEx->AddAtom( 8, ESCHER_ClientAnchor );
2399 mpStrm->WriteInt16( maRect.Top() ).WriteInt16( maRect.Left() ).WriteInt16( maRect.Right() ).WriteInt16( maRect.Bottom() ); // top, left, right, bottom ????
2400 mpPptEscherEx->OpenContainer( ESCHER_ClientData );
2401 mpPptEscherEx->AddAtom( 8, EPP_OEPlaceholderAtom );
2402 sal_uInt8 PlaceHolderID = ( mType == "presentation.Subtitle") ? EPP_PLACEHOLDER_MASTERSUBTITLE:EPP_PLACEHOLDER_MASTERBODY;
2403 mpStrm->WriteUInt32( 1 ) // PlacementID
2404 .WriteUChar( PlaceHolderID )/*(sal_uInt8)EPP_PLACEHOLDER_MASTERBODY */ // PlaceHolderID
2405 .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
2406 .WriteUInt16( 0 ); // padword
2407 mpPptEscherEx->CloseContainer(); // ESCHER_ClientData
2408 mpPptEscherEx->OpenContainer( ESCHER_ClientTextbox ); // printf
2409 mpPptEscherEx->AddAtom( 4, EPP_TextHeaderAtom );
2410 if ( mType == "presentation.Subtitle")
2411 mpStrm->WriteUInt32( EPP_TEXTTYPE_CenterBody );
2412 else
2413 mpStrm->WriteUInt32( EPP_TEXTTYPE_Body );
2414 mnTextSize = aTextObj.Count();
2415 aTextObj.Write( mpStrm.get() );
2416 mpPptEscherEx->BeginAtom();
2417 for ( sal_uInt32 i = 0; i < aTextObj.ParagraphCount() ; ++i )
2419 ParagraphObj* pPara = aTextObj.GetParagraph(i);
2420 mpStrm->WriteUInt32( pPara->CharacterCount() )
2421 .WriteUInt16( pPara->nDepth );
2423 mpPptEscherEx->EndAtom( EPP_BaseTextPropAtom );
2424 mpPptEscherEx->AddAtom( 10, EPP_TextSpecInfoAtom );
2425 mpStrm->WriteUInt32( mnTextSize ).WriteUInt32( 1 ).WriteUInt16( 0 );
2427 mpPptEscherEx->CloseContainer(); // ESCHER_ClientTextBox
2428 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
2430 continue;
2432 else
2434 mnTextStyle = EPP_TEXTSTYLE_BODY;
2435 nPlaceHolderAtom = rLayout.nTypeOfOutliner;
2436 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2437 ImplCreateShape( ESCHER_ShpInst_Rectangle,
2438 ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster,
2439 aSolverContainer );
2440 aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
2441 aPropOpt.CreateFillProperties( mXPropSet, true, mXShape );
2442 mnTxId += 0x60;
2443 aPropOpt.CreateTextProperties( mXPropSet, mnTxId );
2444 ImplAdjustFirstLineLineSpacing( aTextObj, aPropOpt );
2445 if ( mbEmptyPresObj )
2447 sal_uInt32 nNoLineDrawDash = 0;
2448 aPropOpt.GetOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
2449 nNoLineDrawDash |= 0x10001;
2450 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, nNoLineDrawDash );
2454 else
2455 mbPresObj = false;
2457 if ( !mbPresObj )
2459 if (ePageType == MASTER )
2461 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(mXShape);
2462 if (pObj && pObj->IsNotVisibleAsMaster())
2463 continue;
2466 mType = "drawing.Text";
2467 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2470 else if ( ( mType == "drawing.Page" ) || ( mType == "presentation.Page" ) )
2472 if ( ( ePageType == NOTICE ) && mbPresObj )
2474 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Notes, EPP_PLACEHOLDER_MASTERNOTESSLIDEIMAGE ) )
2475 continue;
2476 else
2477 nPlaceHolderAtom = EPP_PLACEHOLDER_NOTESSLIDEIMAGE;
2479 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2481 else if ( mType == "drawing.Frame" )
2483 continue;
2485 else if ( ( mType == "drawing.OLE2" ) || ( mType == "presentation.OLE2" )
2486 || ( mType == "presentation.Chart" ) || ( mType == "presentation.Calc" )
2487 || ( mType == "presentation.OrgChart" ) )
2489 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2490 if ( mbEmptyPresObj && ( ePageType == NORMAL ) )
2492 nPlaceHolderAtom = rLayout.nUsedObjectPlaceHolder;
2493 ImplCreateShape( ESCHER_ShpInst_Rectangle,
2494 ShapeFlag::HaveAnchor | ShapeFlag::HaveMaster,
2495 aSolverContainer );
2496 mnTxId += 0x60;
2497 aPropOpt.AddOpt( ESCHER_Prop_lTxid, mnTxId );
2498 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
2499 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 );
2500 aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
2502 else
2504 mpExEmbed->WriteUInt32( 0xf | ( EPP_ExEmbed << 16 ) )
2505 .WriteUInt32( 0 ); // Size of this container
2507 sal_uInt32 nSize, nOldPos = mpExEmbed->Tell();
2509 mpExEmbed->WriteUInt32( EPP_ExEmbedAtom << 16 )
2510 .WriteUInt32( 8 )
2511 .WriteUInt32( 0 ) // follow colorscheme : 0->do not follow
2512 // 1->follow colorscheme
2513 // 2->follow text and background scheme
2514 .WriteUChar( 1 ) // (bool)set if embedded server can not be locked
2515 .WriteUChar( 0 ) // (bool)do not need to send dimension
2516 .WriteUChar( 0 ) // (bool)is object a world table
2517 .WriteUChar( 0 ); // pad byte
2519 std::unique_ptr<PPTExOleObjEntry> pE( new PPTExOleObjEntry( NORMAL_OLE_OBJECT, mpExEmbed->Tell() ) );
2520 pE->xShape = mXShape;
2521 maExOleObj.push_back( std::move(pE) );
2523 mnExEmbed++;
2525 sal_Int64 nAspect = css::embed::Aspects::MSOLE_CONTENT;
2528 // try to get the aspect when available
2529 css::uno::Reference< css::beans::XPropertySet > xShapeProps( mXShape, css::uno::UNO_QUERY_THROW );
2530 xShapeProps->getPropertyValue("Aspect") >>= nAspect;
2532 catch( css::uno::Exception& )
2535 mpExEmbed->WriteUInt32( 1 | ( EPP_ExOleObjAtom << 16 ) )
2536 .WriteUInt32( 24 )
2537 .WriteUInt32( nAspect ) // Aspect
2538 .WriteUInt32( 0 )
2539 .WriteUInt32( mnExEmbed ) // index to the persist table
2540 .WriteUInt32( 0 ) // subtype
2541 .WriteUInt32( 0 )
2542 .WriteUInt32( 0x0012b600 );
2544 nSize = mpExEmbed->Tell() - nOldPos;
2545 mpExEmbed->Seek( nOldPos - 4 );
2546 mpExEmbed->WriteUInt32( nSize );
2547 mpExEmbed->Seek( STREAM_SEEK_TO_END );
2548 nOlePictureId = mnExEmbed;
2550 ShapeFlag nSpFlags = ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty;
2551 if ( nOlePictureId )
2552 nSpFlags |= ShapeFlag::OLEShape;
2553 ImplCreateShape( ESCHER_ShpInst_PictureFrame, nSpFlags, aSolverContainer );
2554 if ( aPropOpt.CreateOLEGraphicProperties( mXShape ) )
2555 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2556 if ( nOlePictureId )
2557 aPropOpt.AddOpt( ESCHER_Prop_pictureId, nOlePictureId );
2560 else if ( mType == "presentation.Header" )
2562 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERHEADER ) )
2563 continue;
2564 else
2566 mbPresObj = false;
2567 mType = "drawing.Text";
2568 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2571 else if ( mType == "presentation.Footer" )
2573 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERFOOTER ) )
2574 continue;
2575 else
2577 mbPresObj = false;
2578 mType = "drawing.Text";
2579 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2582 else if ( mType == "presentation.DateTime" )
2584 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERDATE ) )
2585 continue;
2586 else
2588 mbPresObj = false;
2589 mType = "drawing.Text";
2590 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2593 else if ( mType == "presentation.SlideNumber" )
2595 if ( ImplCreatePresentationPlaceholder( bMasterPage, EPP_TEXTTYPE_Other, EPP_PLACEHOLDER_MASTERSLIDENUMBER ) )
2596 continue;
2597 else
2599 mbPresObj = false;
2600 mType = "drawing.Text";
2601 ImplCreateTextShape( aPropOpt, aSolverContainer, true );
2604 else if ( (mType.getLength() > 9) && (mType[8] == '3') && (mType[9] == 'D') ) // drawing.3D
2606 // SceneObject, CubeObject, SphereObject, LatheObject, ExtrudeObject, PolygonObject
2607 if ( !ImplGetPropertyValue( "Bitmap" ) )
2608 continue;
2610 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2611 ImplCreateShape( ESCHER_ShpInst_PictureFrame,
2612 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2613 aSolverContainer );
2615 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "Bitmap", false ) )
2616 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2618 else if ( mType == "drawing.Media" )
2620 mnAngle = 0;
2621 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2622 ImplCreateShape( ESCHER_ShpInst_PictureFrame,
2623 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2624 aSolverContainer );
2625 if ( aPropOpt.CreateMediaGraphicProperties( mXShape ) )
2626 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2627 css::uno::Any aAny;
2628 if ( PropValue::GetPropertyValue( aAny, mXPropSet, "MediaURL", true ) )
2630 OUString aMediaURL;
2631 if ( (aAny >>= aMediaURL ) && !aMediaURL.isEmpty() )
2633 // SJ: creating the Media RefObj
2634 sal_uInt32 nRefId = ++mnExEmbed;
2636 mpExEmbed->WriteUInt16( 0xf )
2637 .WriteUInt16( EPP_ExMCIMovie ) // PPT_PST_ExAviMovie
2638 .WriteUInt32( 0 );
2639 sal_uInt32 nSize, nStart = mpExEmbed->Tell();
2640 mpExEmbed->WriteUInt16( 0 )
2641 .WriteUInt16( EPP_ExObjRefAtom )
2642 .WriteUInt32( 4 )
2643 .WriteUInt32( nRefId );
2644 mpExEmbed->WriteUInt16( 0xf )
2645 .WriteUInt16( EPP_ExVideo )
2646 .WriteUInt32( 0 );
2648 mpExEmbed->WriteUInt16( 0 )
2649 .WriteUInt16( EPP_ExMediaAtom )
2650 .WriteUInt32( 8 )
2651 .WriteUInt32( nRefId )
2652 .WriteUInt16( 0 )
2653 .WriteUInt16( 0x435 );
2655 sal_uInt16 i, nStringLen = static_cast<sal_uInt16>(aMediaURL.getLength());
2656 mpExEmbed->WriteUInt32( EPP_CString << 16 ).WriteUInt32( nStringLen * 2 );
2657 for ( i = 0; i < nStringLen; i++ )
2659 sal_Unicode nChar = aMediaURL[ i ];
2660 mpExEmbed->WriteUInt16( nChar );
2662 nSize = mpExEmbed->Tell() - nStart;
2663 mpExEmbed->SeekRel( - ( static_cast<sal_Int32>(nSize) + 4 ) );
2664 mpExEmbed->WriteUInt32( nSize ); // size of PPT_PST_ExMCIMovie
2665 mpExEmbed->SeekRel( 0x10 );
2666 nSize -= 20;
2667 mpExEmbed->WriteUInt32( nSize ); // PPT_PST_ExMediaAtom
2668 mpExEmbed->SeekRel( nSize );
2670 if ( !pClientData )
2671 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2672 pClientData->WriteUInt16( 0 )
2673 .WriteUInt16( EPP_ExObjRefAtom )
2674 .WriteUInt32( 4 )
2675 .WriteUInt32( nRefId );
2676 // write EPP_InteractiveInfo container for no_action
2677 pClientData->WriteUInt32( ( EPP_InteractiveInfo << 16 ) | 0xf ).WriteUInt32( 24 );
2678 pClientData->WriteUInt16( 0 )
2679 .WriteUInt16( EPP_InteractiveInfoAtom )
2680 .WriteUInt32( 16 )
2681 .WriteUInt32( 0 )
2682 .WriteUInt32( 0 )
2683 .WriteUChar( 6 )
2684 .WriteUChar( 0 )
2685 .WriteUChar( 0 )
2686 .WriteUChar( 0 )
2687 .WriteUInt32( 0 );
2691 else if ( (mType == "drawing.Table") || (mType == "presentation.Table") )
2693 if ( eCa != css::presentation::ClickAction_NONE )
2695 SvMemoryStream aTmp(0x200, 0x200);
2696 ImplWriteClickAction( aTmp, eCa, bMediaClickAction );
2698 ImplCreateTable( mXShape, aSolverContainer, aPropOpt );
2699 continue;
2701 else if ( mType == "drawing.dontknow" )
2703 mnAngle = 0;
2704 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2705 ImplCreateShape( ESCHER_ShpInst_PictureFrame,
2706 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty,
2707 aSolverContainer );
2708 if ( aPropOpt.CreateGraphicProperties( mXPropSet, "MetaFile", false ) )
2709 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
2711 else
2713 continue;
2716 bool bClientData = ( bEffect || ( eCa != css::presentation::ClickAction_NONE ) ||
2717 nPlaceHolderAtom || nOlePictureId );
2718 if ( bClientData )
2720 if ( nPlaceHolderAtom )
2722 sal_Int32 nPlacementID = -1;
2723 if ( ( mnTextStyle == EPP_TEXTSTYLE_TITLE ) || ( mnTextStyle == EPP_TEXTSTYLE_BODY ) )
2724 nPlacementID = nIndices++;
2725 else
2727 switch ( nPlaceHolderAtom )
2729 default :
2731 if ( nPlaceHolderAtom < 19 )
2732 break;
2733 [[fallthrough]];
2735 case EPP_PLACEHOLDER_NOTESBODY :
2736 case EPP_PLACEHOLDER_MASTERDATE :
2737 case EPP_PLACEHOLDER_NOTESSLIDEIMAGE :
2738 case EPP_PLACEHOLDER_MASTERNOTESBODYIMAGE :
2739 nPlacementID = nIndices++;
2742 if ( !pClientData )
2743 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2745 pClientData->WriteUInt32( EPP_OEPlaceholderAtom << 16 ).WriteUInt32( 8 )
2746 .WriteInt32( nPlacementID ) // PlacementID
2747 .WriteUChar( nPlaceHolderAtom ) // PlaceHolderID
2748 .WriteUChar( 0 ) // Size of PlaceHolder ( 0 = FULL, 1 = HALF, 2 = QUARTER )
2749 .WriteUInt16( 0 ); // padword
2751 if ( nOlePictureId )
2753 if ( !pClientData )
2754 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2756 pClientData->WriteUInt32( EPP_ExObjRefAtom << 16 ).WriteUInt32( 4 )
2757 .WriteUInt32( nOlePictureId );
2758 nOlePictureId = 0;
2760 if ( bEffect && !pClientData )
2762 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2765 if ( eCa != css::presentation::ClickAction_NONE )
2767 if ( !pClientData )
2768 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2769 ImplWriteClickAction( *pClientData, eCa, bMediaClickAction );
2772 if ( ( mnTextStyle == EPP_TEXTSTYLE_TITLE ) || ( mnTextStyle == EPP_TEXTSTYLE_BODY ) )
2774 if ( !pClientTextBox )
2775 pClientTextBox.reset(new SvMemoryStream( 0x200, 0x200 ));
2777 if ( !mbEmptyPresObj )
2779 if ( ( ePageType == NORMAL ) && !bMasterPage )
2781 sal_uInt32 nTextType = EPP_TEXTTYPE_Body;
2782 if ( mnTextStyle == EPP_TEXTSTYLE_BODY )
2784 if ( bSecOutl )
2785 nTextType = EPP_TEXTTYPE_HalfBody;
2786 else if ( mType == "presentation.Subtitle" )
2787 nTextType = EPP_TEXTTYPE_CenterBody;
2788 bSecOutl = true;
2790 else
2791 nTextType = EPP_TEXTTYPE_Title;
2793 TextRuleEntry aTextRule;
2794 SvMemoryStream aExtBu( 0x200, 0x200 );
2795 ImplGetText();
2796 ImplWriteTextStyleAtom( *pClientTextBox, nTextType, nPObjects, &aTextRule, aExtBu, nullptr );
2797 ImplWriteExtParaHeader( aExtBu, nPObjects++, nTextType, nPageNumber + 0x100 );
2798 SvMemoryStream* pOut = aTextRule.pOut.get();
2799 if ( pOut )
2801 pClientTextBox->WriteBytes(pOut->GetData(), pOut->Tell());
2802 aTextRule.pOut.reset();
2804 if ( aExtBu.Tell() )
2806 if ( !pClientData )
2807 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2808 ImplProgTagContainer( pClientData.get(), &aExtBu );
2813 else
2815 if ( !aPropOpt.IsFontWork() )
2817 if ( mnTextSize || ( nPlaceHolderAtom == EPP_PLACEHOLDER_MASTERDATE ) || ( nPlaceHolderAtom == EPP_PLACEHOLDER_NOTESBODY ) )
2819 int nInstance2;
2820 if ( ( nPlaceHolderAtom == EPP_PLACEHOLDER_MASTERDATE ) || ( nPlaceHolderAtom == EPP_PLACEHOLDER_NOTESBODY ) )
2821 nInstance2 = 2;
2822 else
2823 nInstance2 = EPP_TEXTTYPE_Other; // Text in a Shape
2825 if ( !pClientTextBox )
2826 pClientTextBox.reset(new SvMemoryStream( 0x200, 0x200 ));
2828 SvMemoryStream aExtBu( 0x200, 0x200 );
2829 ImplWriteTextStyleAtom( *pClientTextBox, nInstance2, 0, nullptr, aExtBu, &aPropOpt );
2830 if ( aExtBu.Tell() )
2832 if ( !pClientData )
2833 pClientData.reset(new SvMemoryStream( 0x200, 0x200 ));
2834 ImplProgTagContainer( pClientData.get(), &aExtBu );
2837 else if ( nPlaceHolderAtom >= 19 )
2839 if ( !pClientTextBox )
2840 pClientTextBox.reset(new SvMemoryStream( 12 ));
2842 pClientTextBox->WriteUInt32( EPP_TextHeaderAtom << 16 ).WriteUInt32( 4 )
2843 .WriteUInt32( 7 );
2848 aPropOpt.CreateShadowProperties( mXPropSet );
2849 maRect.Justify();
2850 if ( mnAngle )
2851 ImplFlipBoundingBox( aPropOpt );
2852 aPropOpt.CreateShapeProperties( mXShape );
2853 aPropOpt.Commit( *mpStrm );
2854 if ( GetCurrentGroupLevel() > 0 )
2855 mpPptEscherEx->AddChildAnchor( maRect );
2856 else
2857 mpPptEscherEx->AddClientAnchor( maRect );
2859 if ( pClientData )
2861 mpStrm->WriteUInt32( ( ESCHER_ClientData << 16 ) | 0xf )
2862 .WriteUInt32( pClientData->Tell() );
2864 mpStrm->WriteBytes(pClientData->GetData(), pClientData->Tell());
2865 pClientData.reset();
2867 if ( pClientTextBox )
2869 mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
2870 .WriteUInt32( pClientTextBox->Tell() );
2872 mpStrm->WriteBytes(pClientTextBox->GetData(), pClientTextBox->Tell());
2873 pClientTextBox.reset();
2875 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
2877 nPrevTextStyle = mnTextStyle;
2879 if ( bAdditionalText )
2881 bAdditionalText = false;
2883 css::uno::Any aAny;
2884 EscherPropertyContainer aPropOpt;
2885 mnAngle = ( PropValue::GetPropertyValue( aAny,
2886 mXPropSet, "RotateAngle", true ) )
2887 ? *o3tl::doAccess<sal_Int32>(aAny)
2888 : 0;
2890 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 );
2891 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 );
2892 if ( mType == "drawing.Line" )
2894 double fDist = hypot( maRect.GetWidth(), maRect.GetHeight() );
2895 maRect = ::tools::Rectangle( Point( aTextRefPoint.X, aTextRefPoint.Y ),
2896 Point( static_cast<sal_Int32>( aTextRefPoint.X + fDist ), aTextRefPoint.Y - 1 ) );
2897 ImplCreateTextShape( aPropOpt, aSolverContainer, false );
2898 aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x60006 ); // Size Shape To Fit Text
2899 if ( mnAngle < 0 )
2900 mnAngle = ( 36000 + mnAngle ) % 36000;
2901 if ( mnAngle )
2902 ImplFlipBoundingBox( aPropOpt );
2904 else
2906 ImplCreateTextShape( aPropOpt, aSolverContainer, false );
2907 if ( mnAngle < 0 )
2908 mnAngle = ( 36000 + mnAngle ) % 36000;
2909 else
2910 mnAngle = ( 36000 - ( mnAngle % 36000 ) );
2912 mnAngle *= 655;
2913 mnAngle += 0x8000;
2914 mnAngle &=~0xffff; // round nAngle to full grad
2915 aPropOpt.AddOpt( ESCHER_Prop_Rotation, mnAngle );
2917 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2918 // mpPptEscherEx->SetGroupSnapRect( nGroupLevel, maRect );
2919 // mpPptEscherEx->SetGroupLogicRect( nGroupLevel, maRect );
2921 if ( !pClientTextBox )
2922 pClientTextBox.reset(new SvMemoryStream( 0x200, 0x200 ));
2924 SvMemoryStream aExtBu( 0x200, 0x200 );
2925 ImplWriteTextStyleAtom( *pClientTextBox, EPP_TEXTTYPE_Other, 0, nullptr, aExtBu, &aPropOpt );
2927 aPropOpt.CreateShapeProperties( mXShape );
2928 aPropOpt.Commit( *mpStrm );
2929 if ( GetCurrentGroupLevel() > 0 )
2930 mpPptEscherEx->AddChildAnchor( maRect );
2931 else
2932 mpPptEscherEx->AddClientAnchor( maRect );
2934 mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
2935 .WriteUInt32( pClientTextBox->Tell() );
2937 mpStrm->WriteBytes(pClientTextBox->GetData(), pClientTextBox->Tell());
2938 pClientTextBox.reset();
2940 mpPptEscherEx->CloseContainer(); // ESCHER_SpContainer
2942 // #i119551# PPT does not support groups of polygons and text (MS patch KB2289187)
2943 // mpPptEscherEx->LeaveGroup();
2946 ClearGroupTable(); // storing groups if any are still open, which should not be the case
2947 nGroups = GetGroupsClosed();
2948 for ( sal_uInt32 i = 0; i < nGroups; i++, mpPptEscherEx->LeaveGroup() ) ;
2949 mnPagesWritten++;
2952 struct CellBorder
2954 sal_Int32 mnPos; // specifies the distance to the top/left position of the table
2955 table::BorderLine maCellBorder;
2957 CellBorder() : mnPos ( 0 ) {};
2960 bool PPTWriter::ImplCreateCellBorder( const CellBorder* pCellBorder, sal_Int32 nX1, sal_Int32 nY1, sal_Int32 nX2, sal_Int32 nY2)
2962 sal_Int32 nLineWidth = pCellBorder->maCellBorder.OuterLineWidth + pCellBorder->maCellBorder.InnerLineWidth;
2963 if ( nLineWidth )
2965 nLineWidth *= 2;
2966 mnAngle = 0;
2967 mpPptEscherEx->OpenContainer( ESCHER_SpContainer );
2968 EscherPropertyContainer aPropOptSp;
2970 sal_uInt32 nId = mpPptEscherEx->GenerateShapeId();
2971 mpPptEscherEx->AddShape( ESCHER_ShpInst_Line,
2972 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty | ShapeFlag::Child,
2973 nId );
2974 aPropOptSp.AddOpt( ESCHER_Prop_shapePath, ESCHER_ShapeComplex );
2975 aPropOptSp.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0xa0008 );
2976 aPropOptSp.AddOpt( ESCHER_Prop_fshadowObscured, 0x20000 );
2978 sal_uInt32 nBorderColor = pCellBorder->maCellBorder.Color & 0xff00; // green
2979 nBorderColor |= static_cast< sal_uInt8 >( pCellBorder->maCellBorder.Color ) << 16; // red
2980 nBorderColor |= static_cast< sal_uInt8 >( pCellBorder->maCellBorder.Color >> 16 ); // blue
2981 aPropOptSp.AddOpt( ESCHER_Prop_lineColor, nBorderColor );
2983 aPropOptSp.AddOpt( ESCHER_Prop_lineWidth, nLineWidth * 360 );
2984 aPropOptSp.AddOpt( ESCHER_Prop_fc3DLightFace, 0x80000 );
2985 aPropOptSp.Commit( *mpStrm );
2986 mpPptEscherEx->AddAtom( 16, ESCHER_ChildAnchor );
2987 mpStrm ->WriteInt32( nX1 )
2988 .WriteInt32( nY1 )
2989 .WriteInt32( nX2 )
2990 .WriteInt32( nY2 );
2991 mpPptEscherEx->CloseContainer();
2992 return true;
2994 return false;
2997 //get merged cell's width
2998 static sal_Int32 GetCellRight( sal_Int32 nColumn,
2999 ::tools::Rectangle const & rect,
3000 std::vector< std::pair< sal_Int32, sal_Int32 > >& aColumns,
3001 uno::Reference< table::XMergeableCell > const & xCell )
3003 sal_Int32 nRight = aColumns[ nColumn ].first + aColumns[ nColumn ].second;
3004 for ( sal_Int32 nColumnSpan = 1; nColumnSpan < xCell->getColumnSpan(); nColumnSpan++ )
3006 sal_uInt32 nC = nColumnSpan + nColumn;
3007 if ( nC < aColumns.size() )
3008 nRight += aColumns[ nC ].second;
3009 else
3010 nRight = rect.Right();
3012 return nRight;
3014 //get merged cell's height
3015 static sal_Int32 GetCellBottom( sal_Int32 nRow,
3016 ::tools::Rectangle const & rect,
3017 std::vector< std::pair< sal_Int32, sal_Int32 > >& aRows,
3018 uno::Reference< table::XMergeableCell > const & xCell )
3020 sal_Int32 nBottom = aRows[nRow].first + aRows[nRow].second;
3021 for ( sal_Int32 nRowSpan = 1; nRowSpan < xCell->getRowSpan(); nRowSpan++ )
3023 sal_uInt32 nR = nRowSpan + nRow;
3024 if ( nR < aRows.size() )
3025 nBottom += aRows[ nR ].second;
3026 else
3027 nBottom = rect.Bottom();
3029 return nBottom;
3032 void PPTWriter::WriteCString( SvStream& rSt, const OUString& rString, sal_uInt32 nInstance )
3034 sal_Int32 nLen = rString.getLength();
3035 if ( nLen )
3037 rSt.WriteUInt32( ( nInstance << 4 ) | ( EPP_CString << 16 ) )
3038 .WriteUInt32( nLen << 1 );
3039 for ( sal_Int32 i = 0; i < nLen; i++ )
3040 rSt.WriteUInt16( rString[i] );
3044 namespace {
3046 class ContainerGuard
3048 private:
3049 PptEscherEx* m_pPptEscherEx;
3050 public:
3051 ContainerGuard(PptEscherEx* pPptEscherEx, sal_uInt16 nRecord)
3052 : m_pPptEscherEx(pPptEscherEx)
3054 m_pPptEscherEx->OpenContainer(nRecord);
3056 ~ContainerGuard()
3058 m_pPptEscherEx->CloseContainer();
3064 void PPTWriter::ImplCreateTable( uno::Reference< drawing::XShape > const & rXShape, EscherSolverContainer& aSolverContainer,
3065 EscherPropertyContainer& aPropOpt )
3069 uno::Reference< table::XTable > xTable;
3070 if ( mXPropSet->getPropertyValue( "Model" ) >>= xTable )
3072 uno::Reference< table::XColumnRowRange > xColumnRowRange( xTable, uno::UNO_QUERY_THROW );
3073 uno::Reference< container::XIndexAccess > xColumns( xColumnRowRange->getColumns(), uno::UNO_QUERY_THROW );
3074 uno::Reference< container::XIndexAccess > xRows( xColumnRowRange->getRows(), uno::UNO_QUERY_THROW );
3075 sal_uInt16 nRowCount = static_cast< sal_uInt16 >( xRows->getCount() );
3076 sal_uInt16 nColumnCount = static_cast< sal_uInt16 >( xColumns->getCount() );
3078 std::vector< std::pair< sal_Int32, sal_Int32 > > aColumns;
3079 std::vector< std::pair< sal_Int32, sal_Int32 > > aRows;
3081 awt::Point aPosition( MapPoint( rXShape->getPosition() ) );
3082 sal_Int32 nPosition = aPosition.X;
3083 for ( sal_Int32 x = 0; x < nColumnCount; x++ )
3085 uno::Reference< beans::XPropertySet > xPropSet( xColumns->getByIndex( x ), uno::UNO_QUERY_THROW );
3086 awt::Size aS( 0, 0 );
3087 xPropSet->getPropertyValue( "Width" ) >>= aS.Width;
3088 awt::Size aM( MapSize( aS ) );
3089 aColumns.emplace_back( nPosition, aM.Width );
3090 nPosition += aM.Width;
3091 if ( x == nColumnCount - 1 && nPosition != maRect.Right() )
3092 maRect.SetRight( nPosition );
3095 nPosition = aPosition.Y;
3096 for ( sal_Int32 y = 0; y < nRowCount; y++ )
3098 uno::Reference< beans::XPropertySet > xPropSet( xRows->getByIndex( y ), uno::UNO_QUERY_THROW );
3099 awt::Size aS( 0, 0 );
3100 xPropSet->getPropertyValue( "Height" ) >>= aS.Height;
3101 awt::Size aM( MapSize( aS ) );
3102 aRows.emplace_back( nPosition, aM.Height );
3103 nPosition += aM.Height;
3104 if ( y == nRowCount - 1 && nPosition != maRect.Bottom())
3105 maRect.SetBottom( nPosition );
3107 std::optional<ContainerGuard> xSpgrContainer(std::in_place, mpPptEscherEx.get(), ESCHER_SpgrContainer);
3108 std::optional<ContainerGuard> xSpContainer(std::in_place, mpPptEscherEx.get(), ESCHER_SpContainer);
3109 mpPptEscherEx->AddAtom( 16, ESCHER_Spgr, 1 );
3110 mpStrm ->WriteInt32( maRect.Left() ) // Bounding box for the grouped shapes to which they are attached
3111 .WriteInt32( maRect.Top() )
3112 .WriteInt32( maRect.Right() )
3113 .WriteInt32( maRect.Bottom() );
3115 sal_uInt32 nShapeId = mpPptEscherEx->GenerateShapeId();
3116 mpPptEscherEx->AddShape( ESCHER_ShpInst_Min, ShapeFlag::HaveAnchor | ShapeFlag::Group, nShapeId );
3117 // TODO: check flags, comment does not match code // Flags: Group | Patriarch
3118 aSolverContainer.AddShape( rXShape, nShapeId );
3119 EscherPropertyContainer aPropOpt2;
3121 SvMemoryStream aMemStrm;
3122 aMemStrm.WriteUInt16( nRowCount )
3123 .WriteUInt16( nRowCount )
3124 .WriteUInt16( 4 );
3126 for( const auto& rRow : aRows )
3127 aMemStrm.WriteInt32( rRow.second );
3129 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x1000100 );
3130 aPropOpt2.AddOpt( ESCHER_Prop_tableProperties, 1 );
3131 aPropOpt2.AddOpt(ESCHER_Prop_tableRowProperties, true, 0, aMemStrm);
3132 aPropOpt.CreateShapeProperties( rXShape );
3133 aPropOpt.Commit( *mpStrm );
3134 aPropOpt2.Commit( *mpStrm, 3, ESCHER_UDefProp );
3135 if ( GetCurrentGroupLevel() > 0 )
3136 mpPptEscherEx->AddChildAnchor( maRect );
3137 else
3138 mpPptEscherEx->AddClientAnchor( maRect );
3139 xSpContainer.reset(); //ESCHER_SpContainer
3141 uno::Reference< table::XCellRange > xCellRange( xTable, uno::UNO_QUERY_THROW );
3142 for( sal_Int32 nRow = 0; nRow < xRows->getCount(); nRow++ )
3144 for( sal_Int32 nColumn = 0; nColumn < xColumns->getCount(); nColumn++ )
3146 uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn, nRow ), uno::UNO_QUERY_THROW );
3147 if ( !xCell->isMerged() )
3149 sal_Int32 nLeft = aColumns[ nColumn ].first;
3150 sal_Int32 nTop = aRows[ nRow ].first;
3151 sal_Int32 nRight = GetCellRight( nColumn, maRect,aColumns,xCell );
3152 sal_Int32 nBottom = GetCellBottom( nRow, maRect,aRows,xCell );
3154 mbFontIndependentLineSpacing = false;
3155 mXPropSet.set( xCell, uno::UNO_QUERY_THROW );
3156 mXText.set( xCell, uno::UNO_QUERY_THROW );
3157 mnTextSize = mXText->getString().getLength();
3159 css::uno::Any aAny;
3160 if ( GetPropertyValue( aAny, mXPropSet, "FontIndependentLineSpacing", true ) )
3161 aAny >>= mbFontIndependentLineSpacing;
3163 EscherPropertyContainer aPropOptSp;
3164 std::optional<ContainerGuard> xCellContainer(std::in_place, mpPptEscherEx.get(), ESCHER_SpContainer);
3165 ImplCreateShape( ESCHER_ShpInst_Rectangle,
3166 ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty | ShapeFlag::Child,
3167 aSolverContainer );
3168 aPropOptSp.CreateFillProperties( mXPropSet, true );
3169 aPropOptSp.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 );
3170 mnTxId += 0x60;
3171 aPropOptSp.CreateTextProperties( mXPropSet, mnTxId );
3172 aPropOptSp.AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapSquare );
3174 SvMemoryStream aClientTextBox( 0x200, 0x200 );
3175 SvMemoryStream aExtBu( 0x200, 0x200 );
3177 ImplWriteTextStyleAtom( aClientTextBox, EPP_TEXTTYPE_Other, 0, nullptr, aExtBu, &aPropOptSp );
3179 // need write client data for extend bullet
3180 if ( aExtBu.Tell() )
3182 SvMemoryStream aClientData( 0x200, 0x200 );
3183 ImplProgTagContainer( &aClientData, &aExtBu );
3184 mpStrm->WriteUInt32( ( ESCHER_ClientData << 16 ) | 0xf )
3185 .WriteUInt32( aClientData.Tell() );
3187 mpStrm->WriteBytes(aClientData.GetData(), aClientData.Tell());
3190 aPropOptSp.Commit( *mpStrm );
3191 mpPptEscherEx->AddAtom( 16, ESCHER_ChildAnchor );
3192 mpStrm ->WriteInt32( nLeft )
3193 .WriteInt32( nTop )
3194 .WriteInt32( nRight )
3195 .WriteInt32( nBottom );
3197 mpStrm->WriteUInt32( ( ESCHER_ClientTextbox << 16 ) | 0xf )
3198 .WriteUInt32( aClientTextBox.Tell() );
3200 mpStrm->WriteBytes(aClientTextBox.GetData(), aClientTextBox.Tell());
3201 xCellContainer.reset();
3206 // creating horz lines
3207 for( sal_Int32 nLine = 0; nLine < ( xRows->getCount() + 1 ); nLine++ )
3209 for( sal_Int32 nColumn = 0; nColumn < xColumns->getCount(); nColumn++ )
3211 CellBorder aCellBorder;
3212 aCellBorder.mnPos = aColumns[ nColumn ].first;
3213 bool bTop = false;
3214 //write nLine*nColumn cell's top border
3215 if ( nLine < xRows->getCount() )
3216 { // top border
3217 uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn, nLine ), uno::UNO_QUERY_THROW );
3218 if ( !xCell->isMerged() )
3220 uno::Reference< beans::XPropertySet > xPropSet2( xCell, uno::UNO_QUERY_THROW );
3221 table::BorderLine aBorderLine;
3222 if ( xPropSet2->getPropertyValue( "TopBorder" ) >>= aBorderLine )
3223 aCellBorder.maCellBorder = aBorderLine;
3224 sal_Int32 nRight = GetCellRight( nColumn, maRect,aColumns,xCell );
3225 bTop = ImplCreateCellBorder( &aCellBorder, aCellBorder.mnPos,
3226 aRows[ nLine ].first, nRight, aRows[ nLine ].first );
3230 //if nLine*nColumn cell's top border is empty, check (nLine-1)*nColumn cell's bottom border
3231 //and write the last row's bottom border
3232 if (( nLine && !bTop ) || (nLine == xRows->getCount()))
3233 { // bottom border
3234 sal_Int32 nRow = nLine;
3236 while( nRow )
3237 { //find last no merged cell
3238 uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn, nRow - 1 ), uno::UNO_QUERY_THROW );
3239 if ( !xCell->isMerged() )
3241 sal_Int32 nRight = GetCellRight( nColumn, maRect,aColumns,xCell );
3242 sal_Int32 nBottom = GetCellBottom( nRow - 1, maRect,aRows,xCell );
3243 if ( nBottom == ( aRows[ nLine-1 ].first + aRows[ nLine-1 ].second ) )
3245 uno::Reference< table::XMergeableCell > xCellOwn( xCellRange->getCellByPosition( nColumn, nRow - 1 ), uno::UNO_QUERY_THROW );
3246 uno::Reference< beans::XPropertySet > xPropSet2( xCellOwn, uno::UNO_QUERY_THROW );
3247 table::BorderLine aBorderLine;
3248 if ( xPropSet2->getPropertyValue( "BottomBorder" ) >>= aBorderLine )
3249 aCellBorder.maCellBorder = aBorderLine;
3250 ImplCreateCellBorder( &aCellBorder, aCellBorder.mnPos,
3251 nBottom, nRight, nBottom);
3253 nRow=0;
3255 else
3256 nRow--;
3262 // creating vertical lines
3263 for( sal_Int32 nLine = 0; nLine < ( xColumns->getCount() + 1 ); nLine++ )
3265 for( sal_Int32 nRow = 0; nRow < xRows->getCount(); nRow++ )
3268 CellBorder aCellBorder;
3269 aCellBorder.mnPos = aRows[ nRow].first;
3270 bool bLeft = false;
3271 if ( nLine < xColumns->getCount() )
3272 { // left border
3273 uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nLine, nRow ), uno::UNO_QUERY_THROW );
3274 if (!xCell->isMerged() )
3276 uno::Reference< beans::XPropertySet > xCellSet( xCell, uno::UNO_QUERY_THROW );
3277 table::BorderLine aBorderLine;
3278 if ( xCellSet->getPropertyValue( "LeftBorder" ) >>= aBorderLine )
3279 aCellBorder.maCellBorder = aBorderLine;
3280 sal_Int32 nBottom = GetCellBottom( nRow, maRect, aRows,xCell );
3281 bLeft = ImplCreateCellBorder( &aCellBorder, aColumns[nLine].first, aCellBorder.mnPos,
3282 aColumns[nLine].first, nBottom );
3285 if ( ( nLine && !bLeft )||(nLine == xColumns->getCount()))
3286 { // right border
3287 sal_Int32 nColumn = nLine;
3288 while ( nColumn )
3290 uno::Reference< table::XMergeableCell > xCell( xCellRange->getCellByPosition( nColumn - 1, nRow ), uno::UNO_QUERY_THROW );
3291 if (!xCell->isMerged() )
3293 sal_Int32 nRight = GetCellRight( nColumn-1, maRect, aColumns,xCell );
3294 sal_Int32 nBottom = GetCellBottom( nRow, maRect, aRows, xCell );
3295 if ( nRight == (aColumns[nLine-1].first + aColumns[nLine-1].second) )
3297 uno::Reference< table::XMergeableCell > xCellOwn( xCellRange->getCellByPosition( nColumn - 1, nRow ), uno::UNO_QUERY_THROW );
3298 uno::Reference< beans::XPropertySet > xCellSet( xCellOwn, uno::UNO_QUERY_THROW );
3299 table::BorderLine aBorderLine;
3300 if ( xCellSet->getPropertyValue( "RightBorder" ) >>= aBorderLine )
3301 aCellBorder.maCellBorder = aBorderLine;
3302 ImplCreateCellBorder( &aCellBorder, nRight, aCellBorder.mnPos,
3303 nRight, nBottom );
3305 nColumn = 0;
3307 else
3308 nColumn --;
3314 xSpgrContainer.reset(); //ESCHER_SpgrContainer
3317 catch( uno::Exception& )
3322 void TextObjBinary::Write( SvStream* pStrm )
3324 sal_uInt32 nSize, nPos = pStrm->Tell();
3325 pStrm->WriteUInt32( EPP_TextCharsAtom << 16 ).WriteUInt32( 0 );
3326 for ( sal_uInt32 i = 0; i < ParagraphCount(); ++i )
3327 GetParagraph(i)->Write( pStrm );
3328 nSize = pStrm->Tell() - nPos;
3329 pStrm->SeekRel( - ( static_cast<sal_Int32>(nSize) - 4 ) );
3330 pStrm->WriteUInt32( nSize - 8 );
3331 pStrm->SeekRel( nSize - 8 );
3334 void TextObjBinary::WriteTextSpecInfo( SvStream* pStrm )
3336 sal_uInt32 nCharactersLeft( Count() );
3337 if ( nCharactersLeft < 1 )
3338 return;
3340 EscherExAtom aAnimationInfoAtom( *pStrm, EPP_TextSpecInfoAtom, 0, 0 );
3341 for ( sal_uInt32 i = 0; nCharactersLeft && i < ParagraphCount(); ++i )
3343 ParagraphObj* pPtr = GetParagraph(i);
3344 for ( std::vector<std::unique_ptr<PortionObj> >::const_iterator it = pPtr->begin(); nCharactersLeft && it != pPtr->end(); ++it )
3346 const PortionObj& rPortion = **it;
3347 sal_Int32 nPortionSize = rPortion.mnTextSize >= nCharactersLeft ? nCharactersLeft : rPortion.mnTextSize;
3348 sal_Int32 const nFlags = 7;
3349 nCharactersLeft -= nPortionSize;
3350 pStrm ->WriteUInt32( nPortionSize )
3351 .WriteInt32( nFlags )
3352 .WriteInt16( 1 ) // spellinfo -> needs rechecking
3353 .WriteInt16( static_cast<sal_uInt16>(LanguageTag( rPortion.meCharLocale ).makeFallback().getLanguageType()) )
3354 .WriteInt16( 0 ); // alt language
3357 if ( nCharactersLeft )
3358 pStrm->WriteUInt32( nCharactersLeft ).WriteInt32( 1 ).WriteInt16( 1 );
3361 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */