1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_filter.hxx"
26 #include "eschesdo.hxx"
27 #include <svx/svdobj.hxx>
28 #include <svx/unoapi.hxx>
29 #include <svx/svdoashp.hxx>
30 #include <svx/unoshape.hxx>
31 #include <vcl/outdev.hxx>
32 #include <tools/poly.hxx>
33 #include <vcl/bitmapex.hxx>
34 #include <vcl/graph.hxx>
35 #include <tools/debug.hxx>
36 #include <svx/fmdpage.hxx>
37 #include <toolkit/helper/vclunohelper.hxx>
38 #include <com/sun/star/style/VerticalAlignment.hpp>
39 #include <com/sun/star/awt/Gradient.hpp>
40 #include <com/sun/star/drawing/PointSequence.hpp>
41 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
42 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
43 #include <com/sun/star/drawing/FlagSequence.hpp>
44 #include <com/sun/star/drawing/TextAdjust.hpp>
45 #include <com/sun/star/drawing/LineDash.hpp>
46 #include <com/sun/star/text/XText.hpp>
47 #include <com/sun/star/drawing/CircleKind.hpp>
48 #include <com/sun/star/drawing/FillStyle.hpp>
49 #include <com/sun/star/task/XStatusIndicator.hpp>
50 #include <comphelper/extract.hxx>
51 #include <svtools/fltcall.hxx>
52 #include <vcl/cvtgrf.hxx>
53 #include <com/sun/star/drawing/HomogenMatrix3.hpp>
54 #include <basegfx/matrix/b2dhommatrix.hxx>
55 #include <basegfx/polygon/b2dpolygontools.hxx>
56 #include <basegfx/polygon/b2dpolygon.hxx>
57 
58 using ::rtl::OUString;
59 using namespace ::com::sun::star;
60 using namespace ::com::sun::star::beans;
61 using namespace ::com::sun::star::container;
62 using namespace ::com::sun::star::uno;
63 using namespace ::com::sun::star::drawing;
64 using namespace ::com::sun::star::text;
65 using namespace ::com::sun::star::task;
66 using namespace ::com::sun::star::style;
67 
68 #define EES_MAP_FRACTION 1440	// 1440 dpi
69 
70 // ===================================================================
71 
ImplEESdrWriter(EscherEx & rEx)72 ImplEESdrWriter::ImplEESdrWriter( EscherEx& rEx )
73 		:
74 		mpEscherEx				( &rEx ),
75 		maMapModeSrc			( MAP_100TH_MM ),
76 		// PowerPoint: 576 dpi, WinWord: 1440 dpi, Excel: 1440 dpi
77 		maMapModeDest( MAP_INCH, Point(), Fraction( 1, EES_MAP_FRACTION ), Fraction( 1, EES_MAP_FRACTION ) ),
78 //		mXStatusIndicator		( rXStatInd ),
79 		mpPicStrm				( NULL ),
80 		mpHostAppData			( NULL ),
81 		mnPagesWritten			( 0 ),
82 		mnShapeMasterTitle		( 0 ),
83 		mnShapeMasterBody		( 0 ),
84 		mbStatusIndicator		( sal_False ),
85 		mbStatus				( sal_False )
86 {
87 }
88 
89 
90 // -------------------------------------------------------------------
91 
ImplMapPoint(const Point & rPoint)92 Point ImplEESdrWriter::ImplMapPoint( const Point& rPoint )
93 {
94 	return OutputDevice::LogicToLogic( rPoint, maMapModeSrc, maMapModeDest );
95 }
96 
97 
98 // -------------------------------------------------------------------
99 
ImplMapSize(const Size & rSize)100 Size ImplEESdrWriter::ImplMapSize( const Size& rSize )
101 {
102 	Size aRetSize( OutputDevice::LogicToLogic( rSize, maMapModeSrc, maMapModeDest ) );
103 
104 	if ( !aRetSize.Width() )
105 		aRetSize.Width()++;
106 	if ( !aRetSize.Height() )
107 		aRetSize.Height()++;
108 	return aRetSize;
109 }
110 
111 // -------------------------------------------------------------------
112 
ImplFlipBoundingBox(ImplEESdrObject & rObj,EscherPropertyContainer & rPropOpt)113 void ImplEESdrWriter::ImplFlipBoundingBox( ImplEESdrObject& rObj, EscherPropertyContainer& rPropOpt )
114 {
115 	sal_Int32 nAngle = rObj.GetAngle();
116 	Rectangle aRect( rObj.GetRect() );
117 
118 	if ( nAngle < 0 )
119 		nAngle = ( 36000 + nAngle ) % 36000;
120 	else
121 		nAngle = ( 36000 - ( nAngle % 36000 ) );
122 
123 	double fVal = (double)nAngle * F_PI18000;
124 	double	fCos = cos( fVal );
125 	double	fSin = sin( fVal );
126 
127 	double	nWidthHalf = (double) aRect.GetWidth() / 2;
128 	double	nHeightHalf = (double) aRect.GetHeight() / 2;
129 
130 	double nXDiff = fCos * nWidthHalf + fSin * (-nHeightHalf);
131 	double nYDiff = - ( fSin * nWidthHalf - fCos * ( -nHeightHalf ) );
132 
133 	aRect.Move( (sal_Int32)( -( nWidthHalf - nXDiff ) ), (sal_Int32)( - ( nHeightHalf + nYDiff ) ) );
134 
135 	nAngle *= 655;
136 	nAngle += 0x8000;
137 	nAngle &=~0xffff;									// nAngle auf volle Gradzahl runden
138 	rPropOpt.AddOpt( ESCHER_Prop_Rotation, nAngle );
139 
140 	rObj.SetAngle( nAngle );
141 	rObj.SetRect( aRect );
142 }
143 
144 //	-----------------------------------------------------------------------
145 
146 #define ADD_SHAPE( nType, nFlags )								\
147 {																\
148 	nShapeType = nType;											\
149     nShapeID = mpEscherEx->GenerateShapeId();                   \
150 	rObj.SetShapeId( nShapeID );								\
151 	mpEscherEx->AddShape( (sal_uInt32)nType, (sal_uInt32)nFlags, nShapeID );	\
152 	rSolverContainer.AddShape( rObj.GetShapeRef(), nShapeID );	\
153 }
154 
155 #define SHAPE_TEXT( bFill )											\
156 {																	\
157 	mpEscherEx->OpenContainer( ESCHER_SpContainer );				\
158 	ADD_SHAPE( ESCHER_ShpInst_TextBox, 0xa00 );						\
159 	if ( bFill )													\
160 		aPropOpt.CreateFillProperties( rObj.mXPropSet, sal_True );	\
161 	if( rObj.ImplGetText() )										\
162 		aPropOpt.CreateTextProperties( rObj.mXPropSet,				\
163 			mpEscherEx->QueryTextID( rObj.GetShapeRef(),			\
164 				rObj.GetShapeId() ) );								\
165 }
166 
167 //Map from twips to export units, generally twips as well, only excel and word
168 //export is happening here, so native units are export units, leave as
169 //placeholder if required in future
MapRect(ImplEESdrObject &)170 void ImplEESdrWriter::MapRect(ImplEESdrObject& /* rObj */ )
171 {
172 }
173 
ImplWriteShape(ImplEESdrObject & rObj,EscherSolverContainer & rSolverContainer,ImplEESdrPageType ePageType)174 sal_uInt32 ImplEESdrWriter::ImplWriteShape( ImplEESdrObject& rObj,
175 								EscherSolverContainer& rSolverContainer,
176 								ImplEESdrPageType ePageType )
177 {
178 	sal_uInt32 nShapeID = 0;
179 	sal_uInt16 nShapeType = 0;
180 	sal_Bool bDontWriteText = sal_False;		// if a metafile is written as shape replacement, then the text is already part of the metafile
181 	sal_Bool bAdditionalText = sal_False;
182 	sal_uInt32 nGrpShapeID = 0;
183 
184 	do {
185         mpHostAppData = mpEscherEx->StartShape( rObj.GetShapeRef(), (mpEscherEx->GetGroupLevel() > 1) ? &rObj.GetRect() : 0 );
186 		if ( mpHostAppData && mpHostAppData->DontWriteShape() )
187 			break;
188 
189         // #i51348# get shape name
190         String aShapeName;
191         if( const SdrObject* pSdrObj = rObj.GetSdrObject() )
192             if( pSdrObj->GetName().Len() > 0 )
193                 aShapeName = pSdrObj->GetName();
194 
195 		Point aTextRefPoint;
196 
197 		if( rObj.GetType().EqualsAscii( "drawing.Group" ))
198 		{
199 			Reference< XIndexAccess > xXIndexAccess( rObj.GetShapeRef(), UNO_QUERY );
200 
201 			if( xXIndexAccess.is() && 0 != xXIndexAccess->getCount() )
202 			{
203                 nShapeID = mpEscherEx->EnterGroup( aShapeName, &rObj.GetRect() );
204 				nShapeType = ESCHER_ShpInst_Min;
205 
206 				for( sal_uInt32 n = 0, nCnt = xXIndexAccess->getCount();
207 						n < nCnt; ++n )
208 				{
209 					ImplEESdrObject aObj( *this, *(Reference< XShape >*)
210 									xXIndexAccess->getByIndex( n ).getValue() );
211 					if( aObj.IsValid() )
212 						ImplWriteShape( aObj, rSolverContainer, ePageType );
213 				}
214 				mpEscherEx->LeaveGroup();
215 			}
216 			break;
217 		}
218 		rObj.SetAngle( rObj.ImplGetInt32PropertyValue( ::rtl::OUString::createFromAscii("RotateAngle") ));
219 
220 		if( ( rObj.ImplGetPropertyValue( ::rtl::OUString::createFromAscii("IsFontwork") ) &&
221 			::cppu::any2bool( rObj.GetUsrAny() ) ) ||
222 			rObj.GetType().EqualsAscii( "drawing.Measure" ) || rObj.GetType().EqualsAscii( "drawing.Caption" ) )
223 		{
224 /*
225 			if( rObj.ImplGetPropertyValue( ::rtl::OUString::createFromAscii("BoundRect") ) )
226 			{
227 				::com::sun::star::awt::Rectangle aRect( *(::com::sun::star::awt::Rectangle*)rObj.GetUsrAny().getValue() );
228 				rObj.SetRect( ImplMapPoint( Point( aRect.X, aRect.Y ) ),
229 								ImplMapSize( Size( aRect.Width, aRect.Height ) ) );
230 			}
231 */
232 			rObj.SetType( String( RTL_CONSTASCII_STRINGPARAM(
233 								"drawing.dontknow" ),
234 								RTL_TEXTENCODING_MS_1252 ));
235 		}
236 
237 		const ::com::sun::star::awt::Size	aSize100thmm( rObj.GetShapeRef()->getSize() );
238 		const ::com::sun::star::awt::Point	aPoint100thmm( rObj.GetShapeRef()->getPosition() );
239 		Rectangle	aRect100thmm( Point( aPoint100thmm.X, aPoint100thmm.Y ), Size( aSize100thmm.Width, aSize100thmm.Height ) );
240 		if ( !mpPicStrm )
241             mpPicStrm = mpEscherEx->QueryPictureStream();
242         EscherPropertyContainer aPropOpt( mpEscherEx->GetGraphicProvider(), mpPicStrm, aRect100thmm );
243 
244         // #i51348# shape name
245         if( aShapeName.Len() > 0 )
246             aPropOpt.AddOpt( ESCHER_Prop_wzName, aShapeName );
247 
248 		if ( rObj.GetType().EqualsAscii( "drawing.Custom" ) )
249 		{
250 			mpEscherEx->OpenContainer( ESCHER_SpContainer );
251 			sal_uInt32 nMirrorFlags;
252 
253 			rtl::OUString sCustomShapeType;
254 			MSO_SPT eShapeType = aPropOpt.GetCustomShapeType( rObj.GetShapeRef(), nMirrorFlags, sCustomShapeType );
255 			if ( sCustomShapeType.equalsAscii( "col-502ad400" ) || sCustomShapeType.equalsAscii( "col-60da8460" ) )
256 			{
257 				ADD_SHAPE( ESCHER_ShpInst_PictureFrame, 0xa00 );
258 				if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, String( RTL_CONSTASCII_USTRINGPARAM( "MetaFile" ) ), sal_False ) )
259 				{
260 					aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
261 					aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 );		// no fill
262 					aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 );		// no linestyle
263 						SdrObject* pObj = GetSdrObjectFromXShape( rObj.GetShapeRef() );
264 					if ( pObj )
265 					{
266 						Rectangle aBound = pObj->GetCurrentBoundRect();
267 						Point aPosition( ImplMapPoint( aBound.TopLeft() ) );
268 					    Size aSize( ImplMapSize( aBound.GetSize() ) );
269 						rObj.SetRect( Rectangle( aPosition, aSize ) );
270 						rObj.SetAngle( 0 );
271 						bDontWriteText = sal_True;
272 					}
273 				}
274 			}
275 			else
276 			{
277 				ADD_SHAPE(
278                     sal::static_int_cast< sal_uInt16 >(eShapeType),
279                     nMirrorFlags | 0xa00 );
280 				aPropOpt.CreateCustomShapeProperties( eShapeType, rObj.GetShapeRef() );
281 				aPropOpt.CreateFillProperties( rObj.mXPropSet, sal_True );
282 				if ( rObj.ImplGetText() )
283 				{
284 					if ( !aPropOpt.IsFontWork() )
285 						aPropOpt.CreateTextProperties( rObj.mXPropSet, mpEscherEx->QueryTextID(
286 							rObj.GetShapeRef(),	rObj.GetShapeId() ), sal_True, sal_False );
287 				}
288 			}
289 		}
290 		else if ( rObj.GetType().EqualsAscii( "drawing.Rectangle" ))
291 		{
292 			mpEscherEx->OpenContainer( ESCHER_SpContainer );
293 			sal_Int32 nRadius = (sal_Int32)rObj.ImplGetInt32PropertyValue(
294 											::rtl::OUString::createFromAscii("CornerRadius"));
295 			if( nRadius )
296 			{
297 				nRadius = ImplMapSize( Size( nRadius, 0 )).Width();
298 				ADD_SHAPE( ESCHER_ShpInst_RoundRectangle, 0xa00 );	// Flags: Connector | HasSpt
299 				sal_Int32 nLenght = rObj.GetRect().GetWidth();
300 				if ( nLenght > rObj.GetRect().GetHeight() )
301 					nLenght = rObj.GetRect().GetHeight();
302 				nLenght >>= 1;
303 				if ( nRadius >= nLenght )
304 					nRadius = 0x2a30;							// 0x2a30 ist PPTs maximum radius
305 				else
306 					nRadius = ( 0x2a30 * nRadius ) / nLenght;
307 				aPropOpt.AddOpt( ESCHER_Prop_adjustValue, nRadius );
308 			}
309 			else
310 			{
311 				ADD_SHAPE( ESCHER_ShpInst_Rectangle, 0xa00 );			// Flags: Connector | HasSpt
312 			}
313 			aPropOpt.CreateFillProperties( rObj.mXPropSet, sal_True );
314 			if( rObj.ImplGetText() )
315 				aPropOpt.CreateTextProperties( rObj.mXPropSet,
316 					mpEscherEx->QueryTextID( rObj.GetShapeRef(),
317 						rObj.GetShapeId() ), sal_False, sal_False );
318 		}
319 		else if ( rObj.GetType().EqualsAscii( "drawing.Ellipse" ))
320 		{
321 			CircleKind	eCircleKind = CircleKind_FULL;
322 			PolyStyle	ePolyKind = PolyStyle();
323 			if ( rObj.ImplGetPropertyValue( ::rtl::OUString::createFromAscii("CircleKind") ) )
324 			{
325 				eCircleKind = *( (CircleKind*)rObj.GetUsrAny().getValue() );
326 				switch ( eCircleKind )
327 				{
328 					case CircleKind_SECTION :
329 					{
330 						ePolyKind = POLY_PIE;
331 					}
332 					break;
333 					case CircleKind_ARC :
334 					{
335 						ePolyKind = POLY_ARC;
336 					}
337 					break;
338 
339 					case CircleKind_CUT :
340 					{
341 						ePolyKind = POLY_CHORD;
342 					}
343 					break;
344 
345 					default:
346 						eCircleKind = CircleKind_FULL;
347 				}
348 			}
349 			if ( eCircleKind == CircleKind_FULL )
350 			{
351 				mpEscherEx->OpenContainer( ESCHER_SpContainer );
352 				ADD_SHAPE( ESCHER_ShpInst_Ellipse, 0xa00 );			// Flags: Connector | HasSpt
353 				aPropOpt.CreateFillProperties( rObj.mXPropSet, sal_True );;
354 			}
355 			else
356 			{
357 				sal_Int32 nStartAngle, nEndAngle;
358 				if ( !rObj.ImplGetPropertyValue( ::rtl::OUString::createFromAscii("CircleStartAngle") ) )
359 					break;
360 				nStartAngle = *( (sal_Int32*)rObj.GetUsrAny().getValue() );
361 				if( !rObj.ImplGetPropertyValue( ::rtl::OUString::createFromAscii("CircleEndAngle") ) )
362 					break;
363 				nEndAngle = *( (sal_Int32*)rObj.GetUsrAny().getValue() );
364 
365 				Point aStart, aEnd, aCenter;
366 				aStart.X() = (sal_Int32)( ( cos( (double)( nStartAngle *
367 												F_PI18000 ) ) * 100.0 ) );
368 				aStart.Y() = - (sal_Int32)( ( sin( (double)( nStartAngle *
369 												F_PI18000 ) ) * 100.0 ) );
370 				aEnd.X() = (sal_Int32)( ( cos( (double)( nEndAngle *
371 												F_PI18000 ) ) * 100.0 ) );
372 				aEnd.Y() = - (sal_Int32)( ( sin( (double)( nEndAngle *
373 												F_PI18000 ) ) * 100.0 ) );
374 				const Rectangle& rRect = aRect100thmm;
375 				aCenter.X() = rRect.Left() + ( rRect.GetWidth() / 2 );
376 				aCenter.Y() = rRect.Top() + ( rRect.GetHeight() / 2 );
377 				aStart.X() += aCenter.X();
378 				aStart.Y() += aCenter.Y();
379 				aEnd.X() += aCenter.X();
380 				aEnd.Y() += aCenter.Y();
381 				Polygon aPolygon( rRect, aStart, aEnd, ePolyKind );
382 				if( rObj.GetAngle() )
383 				{
384 					aPolygon.Rotate( rRect.TopLeft(), (sal_uInt16)( rObj.GetAngle() / 10 ) );
385 					rObj.SetAngle( 0 );
386 				}
387 				mpEscherEx->OpenContainer( ESCHER_SpContainer );
388 				ADD_SHAPE( ESCHER_ShpInst_NotPrimitive, 0xa00 );		// Flags: Connector | HasSpt
389 				::com::sun::star::awt::Rectangle aNewRect;
390 				switch ( ePolyKind )
391 				{
392 					case POLY_PIE :
393 					case POLY_CHORD :
394 					{
395 						aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, sal_False, aNewRect, &aPolygon );
396 						aPropOpt.CreateFillProperties( rObj.mXPropSet, sal_True  );
397 					}
398 					break;
399 
400 					case POLY_ARC :
401 					{
402 						aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, sal_False, aNewRect, &aPolygon );
403 						aPropOpt.CreateLineProperties( rObj.mXPropSet, sal_False );
404 					}
405 					break;
406 				}
407 				rObj.SetRect( Rectangle( ImplMapPoint( Point( aNewRect.X, aNewRect.Y ) ),
408 											ImplMapSize( Size( aNewRect.Width, aNewRect.Height ) ) ) );
409 			}
410 			if ( rObj.ImplGetText() )
411 				aPropOpt.CreateTextProperties( rObj.mXPropSet,
412 					mpEscherEx->QueryTextID( rObj.GetShapeRef(),
413 						rObj.GetShapeId() ), sal_False, sal_False );
414 
415 		}
416 		else if ( rObj.GetType().EqualsAscii( "drawing.Control" ))
417 		{
418 			break;
419 		}
420 		else if ( rObj.GetType().EqualsAscii( "drawing.Connector" ))
421 		{
422 			sal_uInt16 nSpType, nSpFlags;
423 			::com::sun::star::awt::Rectangle aNewRect;
424 			if ( aPropOpt.CreateConnectorProperties( rObj.GetShapeRef(),
425 							rSolverContainer, aNewRect, nSpType, nSpFlags ) == sal_False )
426 				break;
427 			rObj.SetRect( Rectangle( ImplMapPoint( Point( aNewRect.X, aNewRect.Y ) ),
428 										ImplMapSize( Size( aNewRect.Width, aNewRect.Height ) ) ) );
429 
430             mpEscherEx->OpenContainer( ESCHER_SpContainer );
431 			ADD_SHAPE( nSpType, nSpFlags );
432 		}
433 		else if ( rObj.GetType().EqualsAscii( "drawing.Measure" ))
434 		{
435 /*
436 			if ( ImplGetPropertyValue( L"MeasureKind" ) )
437 			{
438 				mpEscherEx->EnterGroup( &maRect );
439 				mpEscherEx->OpenContainer( ESCHER_SpContainer );
440 				ImplWriteAny( ANY_FLAGS_LINE, sal_False );
441 				sal_uInt32 nFlags = 0xa00;											// Flags: Connector | HasSpt
442 				if ( maRect.Top() > maRect.Bottom() )
443 					nFlags |= 0x80;												// Flags: VertMirror
444 				if ( maRect.Left() > maRect.Right() )
445 					nFlags |= 0x40;												// Flags: HorzMirror
446 
447 				ADD_SHAPE( ESCHER_ShpInst_Line, nFlags );
448 				aPropOpt.AddOpt( ESCHER_Prop_shapePath, ESCHER_ShapeComplex );
449 				aPropOpt.CreateLineProperties( rObj.mXPropSet, sal_False );
450 				mpEscherEx->EndCount( ESCHER_OPT, 3 );
451 				maRect.Justify();
452 				mpEscherEx->AddClientAnchor( maRect );
453 				mpEscherEx->CloseContainer();			// ESCHER_SpContainer
454 
455 				if ( ImplGetPropertyValue( L"MeasureTextHorizontalPosition" ) )
456 				{
457 				}
458 				if ( ImplGetPropertyValue( L"MeasureTextVerticalPosition" ) )
459 				{
460 				}
461 				if ( ImplGetPropertyValue( L"MeasureLineDistance" ) )
462 				{
463 				}
464 				if ( ImplGetPropertyValue( L"MeasureHelpLineOverhang" ) )
465 				{
466 				}
467 				if ( ImplGetPropertyValue( L"MeasureHelpLineDistance" ) )
468 				{
469 				}
470 				if ( ImplGetPropertyValue( L"MeasureHelpLine1Length" ) )
471 				{
472 				}
473 				if ( ImplGetPropertyValue( L"MeasureHelpLine2Length" ) )
474 				{
475 				}
476 				if ( ImplGetPropertyValue( L"MeasureBelowReferenceEdge" ) )
477 				{
478 				}
479 				if ( ImplGetPropertyValue( L"MeasureTextRotate90" ) )
480 				{
481 				}
482 				if ( ImplGetPropertyValue( L"MeasureTextUpsideDown" ) )
483 				{
484 				}
485 				if ( ImplGetPropertyValue( L"MeasureOverhang" ) )
486 				{
487 				}
488 				if ( ImplGetPropertyValue( L"MeasureUnit" ) )
489 				{
490 				}
491 				if ( ImplGetPropertyValue( L"MeasureScale" ) )
492 				{
493 				}
494 				if ( ImplGetPropertyValue( L"MeasureShowUnit" ) )
495 				{
496 				}
497 				if ( ImplGetPropertyValue( L"MeasureFormatString" ) )
498 				{
499 				}
500 				if ( ImplGetPropertyValue( L"MeasureTextAutoAngle" ) )
501 				{
502 				}
503 				if ( ImplGetPropertyValue( L"MeasureTextAutoAngleView" ) )
504 				{
505 				}
506 				if ( ImplGetPropertyValue( L"MeasureTextIsFixedAngle" ) )
507 				{
508 				}
509 				if ( ImplGetPropertyValue( L"MeasureTextFixedAngle" ) )
510 				{
511 				}
512 				mpEscherEx->LeaveGroup();
513 			}
514 */
515 			break;
516 		}
517 		else if ( rObj.GetType().EqualsAscii( "drawing.Line" ))
518 		{
519 			::com::sun::star::awt::Rectangle aNewRect;
520 			aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_LINE, sal_False, aNewRect, NULL );
521             MapRect(rObj);
522 			//i27942: Poly/Lines/Bezier do not support text.
523 
524 			mpEscherEx->OpenContainer( ESCHER_SpContainer );
525 			sal_uInt32 nFlags = 0xa00;			// Flags: Connector | HasSpt
526             if( aNewRect.Height < 0 )
527 				nFlags |= 0x80;	  			// Flags: VertMirror
528 			if( aNewRect.Width < 0 )
529 				nFlags |= 0x40;				// Flags: HorzMirror
530 
531 			ADD_SHAPE( ESCHER_ShpInst_Line, nFlags );
532 			aPropOpt.AddOpt( ESCHER_Prop_shapePath, ESCHER_ShapeComplex );
533 			aPropOpt.CreateLineProperties( rObj.mXPropSet, sal_False );
534 			rObj.SetAngle( 0 );
535 		}
536 		else if ( rObj.GetType().EqualsAscii( "drawing.PolyPolygon" ))
537 		{
538 			if( rObj.ImplHasText() )
539 			{
540 				nGrpShapeID = ImplEnterAdditionalTextGroup(	rObj.GetShapeRef(), &rObj.GetRect() );
541 				bAdditionalText = sal_True;
542 			}
543 			mpEscherEx->OpenContainer( ESCHER_SpContainer );
544 			ADD_SHAPE( ESCHER_ShpInst_NotPrimitive, 0xa00 );		// Flags: Connector | HasSpt
545 			::com::sun::star::awt::Rectangle aNewRect;
546 			aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, sal_False, aNewRect, NULL );
547             MapRect(rObj);
548 			aPropOpt.CreateFillProperties( rObj.mXPropSet, sal_True );
549 			rObj.SetAngle( 0 );
550 		}
551 		else if ( rObj.GetType().EqualsAscii( "drawing.PolyLine" ))
552 		{
553 			//i27942: Poly/Lines/Bezier do not support text.
554 
555 			mpEscherEx->OpenContainer( ESCHER_SpContainer );
556 			ADD_SHAPE( ESCHER_ShpInst_NotPrimitive, 0xa00 );		// Flags: Connector | HasSpt
557 			::com::sun::star::awt::Rectangle aNewRect;
558 			aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, sal_False, aNewRect, NULL );
559             MapRect(rObj);
560 			aPropOpt.CreateLineProperties( rObj.mXPropSet, sal_False );
561 			rObj.SetAngle( 0 );
562 		}
563 		else if ( rObj.GetType().EqualsAscii( "drawing.OpenBezier" ) )
564 		{
565 			//i27942: Poly/Lines/Bezier do not support text.
566 
567 			mpEscherEx->OpenContainer( ESCHER_SpContainer );
568 			ADD_SHAPE( ESCHER_ShpInst_NotPrimitive, 0xa00 );		// Flags: Connector | HasSpt
569 			::com::sun::star::awt::Rectangle aNewRect;
570 			aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, sal_True, aNewRect, NULL );
571             MapRect(rObj);
572 			aPropOpt.CreateLineProperties( rObj.mXPropSet, sal_False );
573 			rObj.SetAngle( 0 );
574 		}
575 		else if ( rObj.GetType().EqualsAscii( "drawing.ClosedBezier" ) )
576 		{
577 			if ( rObj.ImplHasText() )
578 			{
579 				nGrpShapeID = ImplEnterAdditionalTextGroup(	rObj.GetShapeRef(), &rObj.GetRect() );
580 				bAdditionalText = sal_True;
581 			}
582 			mpEscherEx->OpenContainer( ESCHER_SpContainer );
583 			ADD_SHAPE( ESCHER_ShpInst_NotPrimitive, 0xa00 );		// Flags: Connector | HasSpt
584 			::com::sun::star::awt::Rectangle aNewRect;
585 			aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, sal_True, aNewRect, NULL );
586             MapRect(rObj);
587 			aPropOpt.CreateFillProperties( rObj.mXPropSet, sal_True );
588 			rObj.SetAngle( 0 );
589 		}
590 		else if ( rObj.GetType().EqualsAscii( "drawing.GraphicObject" ))
591 		{
592 			mpEscherEx->OpenContainer( ESCHER_SpContainer );
593 
594 			// ein GraphicObject kann auch ein ClickMe Element sein
595 			if( rObj.IsEmptyPresObj() && ( ePageType == NORMAL ) )
596 			{
597 				ADD_SHAPE( ESCHER_ShpInst_Rectangle, 0x220 );				// Flags: HaveAnchor | HaveMaster
598 				sal_uInt32 nTxtBxId = mpEscherEx->QueryTextID( rObj.GetShapeRef(),
599 														rObj.GetShapeId() );
600 				aPropOpt.AddOpt( ESCHER_Prop_lTxid, nTxtBxId );
601 				aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
602 				aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 );
603 				aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
604 			}
605 			else
606 			{
607 				if( rObj.ImplGetText() )
608 				{
609 					/* SJ #i34951#: because M. documents are not allowing GraphicObjects containing text, we
610 					   have to create a simpe Rectangle with fill bitmap instead (while not allowing BitmapMode_Repeat).
611 					*/
612 					ADD_SHAPE( ESCHER_ShpInst_Rectangle, 0xa00 );			// Flags: Connector | HasSpt
613 					if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, String( RTL_CONSTASCII_USTRINGPARAM( "GraphicURL" ) ), sal_True,  sal_True, sal_False ) )
614 					{
615 						aPropOpt.AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapNone );
616 						aPropOpt.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle );
617 						aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x140014 );
618 						aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x8000000 );
619 						aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 );
620 						if ( rObj.ImplGetText() )
621 							aPropOpt.CreateTextProperties( rObj.mXPropSet,
622 								mpEscherEx->QueryTextID( rObj.GetShapeRef(),
623 									rObj.GetShapeId() ), sal_False, sal_False );
624 					}
625 				}
626 				else
627 				{
628 					ADD_SHAPE( ESCHER_ShpInst_PictureFrame, 0xa00 );
629 					if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, String( RTL_CONSTASCII_USTRINGPARAM( "GraphicURL" ) ), sal_False, sal_True ) )
630 						aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
631 				}
632 			}
633 		}
634 		else if ( rObj.GetType().EqualsAscii(  "drawing.Text" ))
635 		{
636 			SHAPE_TEXT( sal_True );
637 		}
638 		else if ( rObj.GetType().EqualsAscii( "drawing.Page" ))
639 		{
640 			mpEscherEx->OpenContainer( ESCHER_SpContainer );
641 			ADD_SHAPE( ESCHER_ShpInst_Rectangle, 0xa00 );
642 			aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x40004 );
643 			aPropOpt.AddOpt( ESCHER_Prop_fFillOK, 0x100001 );
644 			aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110011 );
645 			aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90008 );
646 			aPropOpt.AddOpt( ESCHER_Prop_fshadowObscured, 0x10001 );
647 		}
648 		else if ( rObj.GetType().EqualsAscii( "drawing.Frame" ))
649 		{
650 			break;
651 		}
652 		else if ( rObj.GetType().EqualsAscii( "drawing.OLE2" ))
653 		{
654 			mpEscherEx->OpenContainer( ESCHER_SpContainer );
655 			if( rObj.IsEmptyPresObj() && ( ePageType == NORMAL ) )
656 			{
657 				ADD_SHAPE( ESCHER_ShpInst_Rectangle, 0x220 );				// Flags: HaveAnchor | HaveMaster
658 				sal_uInt32 nTxtBxId = mpEscherEx->QueryTextID( rObj.GetShapeRef(),
659 														rObj.GetShapeId() );
660 				aPropOpt.AddOpt( ESCHER_Prop_lTxid, nTxtBxId );
661 				aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 );
662 				aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 );
663 				aPropOpt.AddOpt( ESCHER_Prop_hspMaster, mnShapeMasterBody );
664 			}
665 			else
666 			{
667 				//2do: could be made an option in HostAppData whether OLE object should be written or not
668 				sal_Bool bAppOLE = sal_True;
669 				ADD_SHAPE( ESCHER_ShpInst_PictureFrame,
670 					0xa00 | (bAppOLE ? SHAPEFLAG_OLESHAPE : 0) );
671 				if ( aPropOpt.CreateOLEGraphicProperties( rObj.GetShapeRef() ) )
672 				{
673 					if ( bAppOLE )
674 					{	// snooped from Xcl hex dump, nobody knows the trouble I have seen
675 						aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape,	0x00080008 );
676 						aPropOpt.AddOpt( ESCHER_Prop_pictureId,		0x00000001 );
677 						aPropOpt.AddOpt( ESCHER_Prop_fillColor,		0x08000041 );
678 						aPropOpt.AddOpt( ESCHER_Prop_fillBackColor,	0x08000041 );
679 						aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest,	0x00110010 );
680 						aPropOpt.AddOpt( ESCHER_Prop_lineColor,		0x08000040 );
681 						aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash,0x00080008 );
682 //						aPropOpt.AddOpt( ESCHER_Prop_fshadowObscured,0x00020000 );
683 						aPropOpt.AddOpt( ESCHER_Prop_fPrint,			0x00080000 );
684 					}
685 					aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
686 				}
687 			}
688 		}
689 		else if( '3' == rObj.GetType().GetChar(8 ) &&
690 				 'D' == rObj.GetType().GetChar( 9 ) )	// drawing.3D
691 		{
692 			// SceneObject, CubeObject, SphereObject, LatheObject, ExtrudeObject, PolygonObject
693 			if ( !rObj.ImplGetPropertyValue( ::rtl::OUString::createFromAscii("Bitmap") ) )
694 				break;
695 
696 			mpEscherEx->OpenContainer( ESCHER_SpContainer );
697 			ADD_SHAPE( ESCHER_ShpInst_PictureFrame, 0xa00 );
698 
699                 if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, String( RTL_CONSTASCII_USTRINGPARAM( "Bitmap" ) ), sal_False ) )
700 				aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
701 		}
702 		else if ( rObj.GetType().EqualsAscii( "drawing.dontknow" ))
703 		{
704 			rObj.SetAngle( 0 );
705 			mpEscherEx->OpenContainer( ESCHER_SpContainer );
706 			ADD_SHAPE( ESCHER_ShpInst_PictureFrame, 0xa00 );
707 			if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, String( RTL_CONSTASCII_USTRINGPARAM( "MetaFile" ) ), sal_False ) )
708 				aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 );
709 		}
710 		else
711 		{
712 			break;
713 		}
714 		aPropOpt.CreateShadowProperties( rObj.mXPropSet );
715 
716 		if( USHRT_MAX != mpEscherEx->GetHellLayerId() &&
717 			rObj.ImplGetPropertyValue( ::rtl::OUString::createFromAscii("LayerID") ) &&
718 			(*((sal_uInt16*)rObj.GetUsrAny().getValue()) ) == mpEscherEx->GetHellLayerId() )
719 		{
720 			aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x200020 );
721 		}
722 
723 		{
724 			Rectangle aRect( rObj.GetRect() );
725 			aRect.Justify();
726 			rObj.SetRect( aRect );
727 		}
728 
729 		if( rObj.GetAngle() )
730 			ImplFlipBoundingBox( rObj, aPropOpt );
731 
732 		aPropOpt.CreateShapeProperties( rObj.GetShapeRef() );
733 		mpEscherEx->Commit( aPropOpt, rObj.GetRect() );
734 		if( mpEscherEx->GetGroupLevel() > 1 )
735             mpEscherEx->AddChildAnchor( rObj.GetRect() );
736 
737 		if ( mpHostAppData )
738 		{	//! with AdditionalText the App has to control whether these are written or not
739 			mpHostAppData->WriteClientAnchor( *mpEscherEx, rObj.GetRect() );
740 			mpHostAppData->WriteClientData( *mpEscherEx );
741 			if ( !bDontWriteText )
742 				mpHostAppData->WriteClientTextbox( *mpEscherEx );
743 		}
744 		mpEscherEx->CloseContainer();		// ESCHER_SpContainer
745 
746 		if( bAdditionalText )
747 		{
748 			mpEscherEx->EndShape( nShapeType, nShapeID );
749 			ImplWriteAdditionalText( rObj, aTextRefPoint );
750 		}
751 
752 	} while ( 0 );
753 
754 	if ( bAdditionalText )
755 		mpEscherEx->EndShape( ESCHER_ShpInst_Min, nGrpShapeID );
756 	else
757 		mpEscherEx->EndShape( nShapeType, nShapeID );
758 	return nShapeID;
759 }
760 
ImplWriteAdditionalText(ImplEESdrObject & rObj,const Point & rTextRefPoint)761 void ImplEESdrWriter::ImplWriteAdditionalText( ImplEESdrObject& rObj,
762 												const Point& rTextRefPoint )
763 {
764 	sal_uInt32 nShapeID = 0;
765 	sal_uInt16 nShapeType = 0;
766 	do
767 	{
768         mpHostAppData = mpEscherEx->StartShape( rObj.GetShapeRef(), (mpEscherEx->GetGroupLevel() > 1) ? &rObj.GetRect() : 0 );
769 		if ( mpHostAppData && mpHostAppData->DontWriteShape() )
770 			break;
771 
772 		const ::com::sun::star::awt::Size	aSize100thmm( rObj.GetShapeRef()->getSize() );
773 		const ::com::sun::star::awt::Point	aPoint100thmm( rObj.GetShapeRef()->getPosition() );
774 		Rectangle	aRect100thmm( Point( aPoint100thmm.X, aPoint100thmm.Y ), Size( aSize100thmm.Width, aSize100thmm.Height ) );
775 		if ( !mpPicStrm )
776             mpPicStrm = mpEscherEx->QueryPictureStream();
777         EscherPropertyContainer aPropOpt( mpEscherEx->GetGraphicProvider(), mpPicStrm, aRect100thmm );
778 		rObj.SetAngle( rObj.ImplGetInt32PropertyValue( ::rtl::OUString::createFromAscii("RotateAngle")));
779 		sal_Int32 nAngle = rObj.GetAngle();
780 		if( rObj.GetType().EqualsAscii( "drawing.Line" ))
781 		{
782 //2do: this does not work right
783 			double fDist = hypot( rObj.GetRect().GetWidth(),
784 									rObj.GetRect().GetHeight() );
785 			rObj.SetRect( Rectangle( rTextRefPoint,
786 							Point( (sal_Int32)( rTextRefPoint.X() + fDist ), rTextRefPoint.Y() - 1 ) ) );
787 
788 			mpEscherEx->OpenContainer( ESCHER_SpContainer );
789 			mpEscherEx->AddShape( ESCHER_ShpInst_TextBox, 0xa00 );
790 			if ( rObj.ImplGetText() )
791 				aPropOpt.CreateTextProperties( rObj.mXPropSet,
792 					mpEscherEx->QueryTextID( rObj.GetShapeRef(),
793 						rObj.GetShapeId() ) );
794 
795 			aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 );
796 			aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 );
797 			aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x60006 );		// Size Shape To Fit Text
798 			if ( nAngle < 0 )
799 				nAngle = ( 36000 + nAngle ) % 36000;
800 			if ( nAngle )
801 				ImplFlipBoundingBox( rObj, aPropOpt );
802 		}
803 		else
804 		{
805 			mpEscherEx->OpenContainer( ESCHER_SpContainer );
806             nShapeID = mpEscherEx->GenerateShapeId();
807 			mpEscherEx->AddShape( nShapeType = ESCHER_ShpInst_TextBox, 0xa00, nShapeID );
808 			if ( rObj.ImplGetText() )
809 				aPropOpt.CreateTextProperties( rObj.mXPropSet,
810 					mpEscherEx->QueryTextID( rObj.GetShapeRef(),
811 						rObj.GetShapeId() ) );
812 			aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 );
813 			aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 );
814 
815 			if( nAngle < 0 )
816 				nAngle = ( 36000 + nAngle ) % 36000;
817 			else
818 				nAngle = ( 36000 - ( nAngle % 36000 ) );
819 
820 			nAngle *= 655;
821 			nAngle += 0x8000;
822 			nAngle &=~0xffff;	// nAngle auf volle Gradzahl runden
823 			aPropOpt.AddOpt( ESCHER_Prop_Rotation, nAngle );
824 			mpEscherEx->SetGroupSnapRect( mpEscherEx->GetGroupLevel(),
825 											rObj.GetRect() );
826 			mpEscherEx->SetGroupLogicRect( mpEscherEx->GetGroupLevel(),
827 											rObj.GetRect() );
828 		}
829 		rObj.SetAngle( nAngle );
830 		aPropOpt.CreateShapeProperties( rObj.GetShapeRef() );
831 		mpEscherEx->Commit( aPropOpt, rObj.GetRect() );
832 
833 		// write the childanchor
834         mpEscherEx->AddChildAnchor( rObj.GetRect() );
835 
836 #if defined EES_WRITE_EPP
837 		// ClientAnchor
838 		mpEscherEx->AddClientAnchor( maRect );
839 		// ClientTextbox
840 		mpEscherEx->OpenContainer( ESCHER_ClientTextbox );
841 		mpEscherEx->AddAtom( 4, EPP_TextHeaderAtom );
842 		*mpStrm << (sal_uInt32)EPP_TEXTTYPE_Other;								// Text in a Shape
843 		ImplWriteTextStyleAtom();
844 		mpEscherEx->CloseContainer();	// ESCHER_ClientTextBox
845 #else // !EES_WRITE_EPP
846 		if ( mpHostAppData )
847 		{	//! the App has to control whether these are written or not
848 			mpHostAppData->WriteClientAnchor( *mpEscherEx, rObj.GetRect() );
849 			mpHostAppData->WriteClientData( *mpEscherEx );
850 			mpHostAppData->WriteClientTextbox( *mpEscherEx );
851 		}
852 #endif // EES_WRITE_EPP
853 		mpEscherEx->CloseContainer();	// ESCHER_SpContainer
854 	} while ( 0 );
855 	mpEscherEx->LeaveGroup();
856 	mpEscherEx->EndShape( nShapeType, nShapeID );
857 }
858 
859 
860 // -------------------------------------------------------------------
861 
ImplEnterAdditionalTextGroup(const Reference<XShape> & rShape,const Rectangle * pBoundRect)862 sal_uInt32 ImplEESdrWriter::ImplEnterAdditionalTextGroup( const Reference< XShape >& rShape,
863 			const Rectangle* pBoundRect )
864 {
865 	mpHostAppData = mpEscherEx->EnterAdditionalTextGroup();
866 	sal_uInt32 nGrpId = mpEscherEx->EnterGroup( pBoundRect );
867     mpHostAppData = mpEscherEx->StartShape( rShape, pBoundRect );
868 	return nGrpId;
869 }
870 
871 
872 // -------------------------------------------------------------------
873 
ImplInitPageValues()874 sal_Bool ImplEESdrWriter::ImplInitPageValues()
875 {
876 	mnIndices = 0;
877 	mnOutlinerCount = 0;				// die gliederungsobjekte muessen dem layout entsprechen,
878 	mnEffectCount = 0;
879 	mbIsTitlePossible = sal_True;			// bei mehr als einem title geht powerpoint in die knie
880 
881 	return sal_True;
882 }
883 
884 
885 // -------------------------------------------------------------------
886 
ImplWritePage(EscherSolverContainer & rSolverContainer,ImplEESdrPageType ePageType,sal_Bool)887 void ImplEESdrWriter::ImplWritePage(
888 			EscherSolverContainer& rSolverContainer,
889 			ImplEESdrPageType ePageType, sal_Bool /* bBackGround */ )
890 {
891 	ImplInitPageValues();
892 
893 	sal_uInt32 nLastPer = 0, nShapes = mXShapes->getCount();
894 	for( sal_uInt32 n = 0; n < nShapes; ++n )
895 	{
896 		sal_uInt32 nPer = ( 5 * n ) / nShapes;
897 		if( nPer != nLastPer )
898 		{
899 			nLastPer = nPer;
900 			sal_uInt32 nValue = mnPagesWritten * 5 + nPer;
901 			if( nValue > mnStatMaxValue )
902 				nValue = mnStatMaxValue;
903 			if( mbStatusIndicator )
904 				mXStatusIndicator->setValue( nValue );
905 		}
906 
907 		ImplEESdrObject aObj( *this, *(Reference< XShape >*)
908 									mXShapes->getByIndex( n ).getValue() );
909 		if( aObj.IsValid() )
910 		{
911 			ImplWriteShape( aObj, rSolverContainer, ePageType );
912 		}
913 	}
914 	mnPagesWritten++;
915 }
916 
917 // ===================================================================
918 
ImplEscherExSdr(EscherEx & rEx)919 ImplEscherExSdr::ImplEscherExSdr( EscherEx& rEx )
920 		:
921 		ImplEESdrWriter( rEx ),
922 		mpSdrPage( NULL ),
923 		mpSolverContainer( NULL )
924 {
925 }
926 
927 
928 // -------------------------------------------------------------------
929 
~ImplEscherExSdr()930 ImplEscherExSdr::~ImplEscherExSdr()
931 {
932 	DBG_ASSERT( !mpSolverContainer, "ImplEscherExSdr::~ImplEscherExSdr: unwritten SolverContainer" );
933 	delete mpSolverContainer;
934 }
935 
936 
937 // -------------------------------------------------------------------
938 
ImplInitPage(const SdrPage & rPage)939 bool ImplEscherExSdr::ImplInitPage( const SdrPage& rPage )
940 {
941 	do
942 	{
943 		SvxDrawPage* pSvxDrawPage;
944 		if ( mpSdrPage != &rPage || !mXDrawPage.is() )
945 		{
946 			// eventually write SolverContainer of current page, deletes the Solver
947 			ImplFlushSolverContainer();
948 
949 			mpSdrPage = NULL;
950 			// why not declare a const parameter if the object will not be modified?
951 //			mXDrawPage = pSvxDrawPage = new SvxDrawPage( (SdrPage*) &rPage );
952 			mXDrawPage = pSvxDrawPage = new SvxFmDrawPage( (SdrPage*) &rPage );
953 			mXShapes = Reference< XShapes >::query( mXDrawPage );
954 			if ( !mXShapes.is() )
955 				break;
956 			if ( !ImplInitPageValues() )	// ImplEESdrWriter
957 				break;
958 			mpSdrPage = &rPage;
959 
960 			mpSolverContainer = new EscherSolverContainer;
961 		}
962 		else
963 			pSvxDrawPage = SvxDrawPage::getImplementation(mXDrawPage);
964 
965         return pSvxDrawPage != 0;
966 	} while ( 0 );
967 
968     return false;
969 }
970 
971 // -------------------------------------------------------------------
972 
ImplInitUnoShapes(const Reference<XShapes> & rxShapes)973 bool ImplEscherExSdr::ImplInitUnoShapes( const Reference< XShapes >& rxShapes )
974 {
975     // eventually write SolverContainer of current page, deletes the Solver
976     ImplFlushSolverContainer();
977 
978     if( !rxShapes.is() )
979         return false;
980 
981     mpSdrPage = 0;
982     mXDrawPage.clear();
983     mXShapes = rxShapes;
984 
985     if( !ImplInitPageValues() )    // ImplEESdrWriter
986         return false;
987 
988     mpSolverContainer = new EscherSolverContainer;
989     return true;
990 }
991 
992 // -------------------------------------------------------------------
993 
ImplExitPage()994 void ImplEscherExSdr::ImplExitPage()
995 {
996     // close all groups before the solver container is written
997     while( mpEscherEx->GetGroupLevel() )
998         mpEscherEx->LeaveGroup();
999 
1000 	ImplFlushSolverContainer();
1001 	mpSdrPage = NULL;	// reset page for next init
1002 }
1003 
1004 
1005 // -------------------------------------------------------------------
1006 
ImplFlushSolverContainer()1007 void ImplEscherExSdr::ImplFlushSolverContainer()
1008 {
1009 	if ( mpSolverContainer )
1010 	{
1011 		mpSolverContainer->WriteSolver( mpEscherEx->GetStream() );
1012 		delete mpSolverContainer;
1013 		mpSolverContainer = NULL;
1014 	}
1015 }
1016 
1017 
1018 // -------------------------------------------------------------------
1019 
ImplWriteCurrentPage()1020 void ImplEscherExSdr::ImplWriteCurrentPage()
1021 {
1022 	DBG_ASSERT( mpSolverContainer, "ImplEscherExSdr::ImplWriteCurrentPage: no SolverContainer" );
1023 	ImplWritePage( *mpSolverContainer, NORMAL );
1024 	ImplExitPage();
1025 }
1026 
1027 
1028 // -------------------------------------------------------------------
1029 
ImplWriteTheShape(ImplEESdrObject & rObj)1030 sal_uInt32 ImplEscherExSdr::ImplWriteTheShape( ImplEESdrObject& rObj )
1031 {
1032 	DBG_ASSERT( mpSolverContainer, "ImplEscherExSdr::ImplWriteShape: no SolverContainer" );
1033 	return ImplWriteShape( rObj, *mpSolverContainer, NORMAL );
1034 }
1035 
1036 
1037 // ===================================================================
1038 
AddSdrPage(const SdrPage & rPage)1039 void EscherEx::AddSdrPage( const SdrPage& rPage )
1040 {
1041 	if ( mpImplEscherExSdr->ImplInitPage( rPage ) )
1042 		mpImplEscherExSdr->ImplWriteCurrentPage();
1043 }
1044 
1045 // -------------------------------------------------------------------
1046 
AddUnoShapes(const Reference<XShapes> & rxShapes)1047 void EscherEx::AddUnoShapes( const Reference< XShapes >& rxShapes )
1048 {
1049     if ( mpImplEscherExSdr->ImplInitUnoShapes( rxShapes ) )
1050         mpImplEscherExSdr->ImplWriteCurrentPage();
1051 }
1052 
1053 // -------------------------------------------------------------------
1054 
AddSdrObject(const SdrObject & rObj)1055 sal_uInt32 EscherEx::AddSdrObject( const SdrObject& rObj )
1056 {
1057 	ImplEESdrObject aObj( *mpImplEscherExSdr, rObj );
1058 	if( aObj.IsValid() )
1059 		return mpImplEscherExSdr->ImplWriteTheShape( aObj );
1060 	return 0;
1061 }
1062 
1063 
1064 // -------------------------------------------------------------------
1065 
EndSdrObjectPage()1066 void EscherEx::EndSdrObjectPage()
1067 {
1068 	mpImplEscherExSdr->ImplExitPage();
1069 }
1070 
1071 // -------------------------------------------------------------------
1072 
StartShape(const Reference<XShape> &,const Rectangle *)1073 EscherExHostAppData* EscherEx::StartShape( const Reference< XShape >& /* rShape */, const Rectangle* /*pChildAnchor*/ )
1074 {
1075 	return NULL;
1076 }
1077 
1078 // -------------------------------------------------------------------
1079 
EndShape(sal_uInt16,sal_uInt32)1080 void EscherEx::EndShape( sal_uInt16 /* nShapeType */, sal_uInt32 /* nShapeID */ )
1081 {
1082 }
1083 
1084 // -------------------------------------------------------------------
1085 
QueryTextID(const Reference<XShape> &,sal_uInt32)1086 sal_uInt32 EscherEx::QueryTextID( const Reference< XShape >&, sal_uInt32 )
1087 {
1088 	return 0;
1089 }
1090 
1091 // -------------------------------------------------------------------
1092 // add an dummy rectangle shape into the escher stream
AddDummyShape()1093 sal_uInt32 EscherEx::AddDummyShape()
1094 {
1095 	OpenContainer( ESCHER_SpContainer );
1096     sal_uInt32 nShapeID = GenerateShapeId();
1097 	AddShape( ESCHER_ShpInst_Rectangle, 0xa00, nShapeID );
1098 //??	aSolverContainer.AddShape( mXShape, nShapeID );
1099 	CloseContainer();
1100 
1101 	return nShapeID;
1102 }
1103 
1104 // -------------------------------------------------------------------
1105 
1106 // static
GetSdrObject(const Reference<XShape> & rShape)1107 const SdrObject* EscherEx::GetSdrObject( const Reference< XShape >& rShape )
1108 {
1109 	const SdrObject* pRet = 0;
1110 	const SvxShape* pSvxShape = SvxShape::getImplementation( rShape );
1111 	DBG_ASSERT( pSvxShape, "EscherEx::GetSdrObject: no SvxShape" );
1112 	if( pSvxShape )
1113 	{
1114 		pRet = pSvxShape->GetSdrObject();
1115 		DBG_ASSERT( pRet, "EscherEx::GetSdrObject: no SdrObj" );
1116 	}
1117 	return pRet;
1118 }
1119 
1120 
1121 // -------------------------------------------------------------------
1122 
ImplEESdrObject(ImplEscherExSdr & rEx,const SdrObject & rObj)1123 ImplEESdrObject::ImplEESdrObject( ImplEscherExSdr& rEx,
1124 									const SdrObject& rObj ) :
1125 	mnShapeId( 0 ),
1126 	mnTextSize( 0 ),
1127 	mnAngle( 0 ),
1128 	mbValid( sal_False ),
1129 	mbPresObj( sal_False ),
1130 	mbEmptyPresObj( sal_False )
1131 {
1132 	SdrPage* pPage = rObj.GetPage();
1133 	DBG_ASSERT( pPage, "ImplEESdrObject::ImplEESdrObject: no SdrPage" );
1134     if( pPage && rEx.ImplInitPage( *pPage ) )
1135     {
1136         // why not declare a const parameter if the object will
1137         // not be modified?
1138         mXShape = uno::Reference< drawing::XShape >::query( ((SdrObject*)&rObj)->getUnoShape() );;
1139         Init( rEx );
1140     }
1141 }
1142 
ImplEESdrObject(ImplEESdrWriter & rEx,const Reference<XShape> & rShape)1143 ImplEESdrObject::ImplEESdrObject( ImplEESdrWriter& rEx,
1144 									const Reference< XShape >& rShape ) :
1145 	mXShape( rShape ),
1146 	mnShapeId( 0 ),
1147 	mnTextSize( 0 ),
1148 	mnAngle( 0 ),
1149 	mbValid( sal_False ),
1150 	mbPresObj( sal_False ),
1151 	mbEmptyPresObj( sal_False )
1152 {
1153 	Init( rEx );
1154 }
1155 
1156 
~ImplEESdrObject()1157 ImplEESdrObject::~ImplEESdrObject()
1158 {
1159 }
1160 
getUnrotatedGroupBoundRange(const Reference<XShape> & rxShape)1161 basegfx::B2DRange getUnrotatedGroupBoundRange(const Reference< XShape >& rxShape)
1162 {
1163     basegfx::B2DRange aRetval;
1164 
1165     try
1166     {
1167         if(rxShape.is())
1168         {
1169             if(rxShape->getShapeType().equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("com.sun.star.drawing.GroupShape")))
1170             {
1171                 // it's a group shape, iterate over children
1172                 const Reference< XIndexAccess > xXIndexAccess(rxShape, UNO_QUERY);
1173 
1174                 if(xXIndexAccess.is())
1175                 {
1176                     for(sal_uInt32 n(0), nCnt = xXIndexAccess->getCount(); n < nCnt; ++n)
1177                     {
1178                         const Reference< XShape > axShape(xXIndexAccess->getByIndex(n), UNO_QUERY);
1179 
1180                         if(axShape.is())
1181                         {
1182                             // we are calculating the bound for a group, correct rotation for sub-objects
1183                             // to get the unrotated bounds for the group
1184                             const basegfx::B2DRange aExtend(getUnrotatedGroupBoundRange(axShape));
1185 
1186                             aRetval.expand(aExtend);
1187                         }
1188                     }
1189                 }
1190             }
1191             else
1192             {
1193                 // iT#s a xShape, get it's transformation
1194                 const Reference< XPropertySet > mXPropSet(rxShape, UNO_QUERY);
1195 
1196                 if(mXPropSet.is())
1197                 {
1198                     const Any aAny = mXPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("Transformation")));
1199 
1200                     if(aAny.hasValue())
1201                     {
1202                         HomogenMatrix3 aMatrix;
1203 
1204                         if(aAny >>= aMatrix)
1205                         {
1206                             basegfx::B2DHomMatrix aHomogenMatrix;
1207 
1208                             aHomogenMatrix.set(0, 0, aMatrix.Line1.Column1);
1209                             aHomogenMatrix.set(0, 1, aMatrix.Line1.Column2);
1210                             aHomogenMatrix.set(0, 2, aMatrix.Line1.Column3);
1211                             aHomogenMatrix.set(1, 0, aMatrix.Line2.Column1);
1212                             aHomogenMatrix.set(1, 1, aMatrix.Line2.Column2);
1213                             aHomogenMatrix.set(1, 2, aMatrix.Line2.Column3);
1214                             aHomogenMatrix.set(2, 0, aMatrix.Line3.Column1);
1215                             aHomogenMatrix.set(2, 1, aMatrix.Line3.Column2);
1216                             aHomogenMatrix.set(2, 2, aMatrix.Line3.Column3);
1217 
1218                             basegfx::B2DVector aScale, aTranslate;
1219                             double fRotate, fShearX;
1220 
1221                             // decopose transformation
1222                             aHomogenMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
1223 
1224                             // check if rotation needs to be corrected
1225                             if(!basegfx::fTools::equalZero(fRotate))
1226                             {
1227                                 // to correct, keep in mind that ppt graphics are rotated around their center
1228                                 const basegfx::B2DPoint aCenter(aHomogenMatrix * basegfx::B2DPoint(0.5, 0.5));
1229 
1230                                 aHomogenMatrix.translate(-aCenter.getX(), -aCenter.getY());
1231                                 aHomogenMatrix.rotate(-fRotate);
1232                                 aHomogenMatrix.translate(aCenter.getX(), aCenter.getY());
1233                             }
1234 
1235 
1236                             // check if shear needs to be corrected (always correct shear,
1237                             // ppt does not know about it)
1238                             if(!basegfx::fTools::equalZero(fShearX))
1239                             {
1240                                 const basegfx::B2DPoint aMinimum(aHomogenMatrix * basegfx::B2DPoint(0.0, 0.0));
1241 
1242                                 aHomogenMatrix.translate(-aMinimum.getX(), -aMinimum.getY());
1243                                 aHomogenMatrix.shearX(-fShearX);
1244                                 aHomogenMatrix.translate(aMinimum.getX(), aMinimum.getY());
1245                             }
1246 
1247                             // create range. It's no longer rotated (or sheared), so use
1248                             // minimum and maximum values
1249                             aRetval.expand(aHomogenMatrix * basegfx::B2DPoint(0.0, 0.0));
1250                             aRetval.expand(aHomogenMatrix * basegfx::B2DPoint(1.0, 1.0));
1251                         }
1252                     }
1253                 }
1254             }
1255         }
1256     }
1257     catch(::com::sun::star::uno::Exception&)
1258     {
1259     }
1260 
1261     return aRetval;
1262 }
1263 
Init(ImplEESdrWriter & rEx)1264 void ImplEESdrObject::Init( ImplEESdrWriter& rEx )
1265 {
1266 	mXPropSet = Reference< XPropertySet >::query( mXShape );
1267 	if( mXPropSet.is() )
1268 	{
1269 		static const sal_Char aPrefix[] = "com.sun.star.";
1270 		static const xub_StrLen nPrefix = sizeof(aPrefix)-1;
1271 
1272         // detect name first to make below test (is group) work
1273         mType = String( mXShape->getShapeType() );
1274         mType.Erase( 0, nPrefix );	// strip "com.sun.star."
1275         xub_StrLen nPos = mType.SearchAscii( "Shape" );
1276         mType.Erase( nPos, 5 );
1277 
1278         if(GetType().EqualsAscii("drawing.Group"))
1279         {
1280             // if it's a group, the unrotated range is needed for that group
1281             const basegfx::B2DRange aUnroatedRange(getUnrotatedGroupBoundRange(mXShape));
1282             const Point aNewP(basegfx::fround(aUnroatedRange.getMinX()), basegfx::fround(aUnroatedRange.getMinY()));
1283             const Size aNewS(basegfx::fround(aUnroatedRange.getWidth()), basegfx::fround(aUnroatedRange.getHeight()));
1284 
1285             SetRect(rEx.ImplMapPoint(aNewP), rEx.ImplMapSize(aNewS));
1286         }
1287         else
1288         {
1289             // if it's no group, use position and size directly, roated/sheared or not
1290             const Point aOldP(mXShape->getPosition().X, mXShape->getPosition().Y);
1291             const Size aOldS(mXShape->getSize().Width, mXShape->getSize().Height);
1292 
1293             SetRect(rEx.ImplMapPoint(aOldP), rEx.ImplMapSize(aOldS));
1294         }
1295 
1296 
1297 		static const OUString sPresStr(rtl::OUString::createFromAscii("IsPresentationObject"));
1298 		static const OUString sEmptyPresStr(rtl::OUString::createFromAscii("IsEmptyPresentationObject"));
1299 
1300 		if( ImplGetPropertyValue( sPresStr ) )
1301 			mbPresObj = ::cppu::any2bool( mAny );
1302 
1303 		if( mbPresObj && ImplGetPropertyValue( sEmptyPresStr ) )
1304 			mbEmptyPresObj = ::cppu::any2bool( mAny );
1305 
1306 		mbValid = sal_True;
1307 	}
1308 }
1309 
1310 //sal_Bool ImplEESdrObject::ImplGetPropertyValue( const OUString& rString )
ImplGetPropertyValue(const sal_Unicode * rString)1311 sal_Bool ImplEESdrObject::ImplGetPropertyValue( const sal_Unicode* rString )
1312 {
1313 	sal_Bool bRetValue = sal_False;
1314 	if( mbValid )
1315 	{
1316 		try
1317 		{
1318 			mAny = mXPropSet->getPropertyValue( rString );
1319 			if( mAny.hasValue() )
1320 				bRetValue = sal_True;
1321 		}
1322 		catch( ::com::sun::star::uno::Exception& )
1323 		{
1324 			bRetValue = sal_False;
1325 		}
1326 	}
1327 	return bRetValue;
1328 }
1329 
1330 #ifdef USED
ImplGetPropertyValue(const Reference<XPropertySet> & rXPropSet,const OUString & rString)1331 sal_Bool ImplEESdrObject::ImplGetPropertyValue( const Reference< XPropertySet >& rXPropSet,
1332 											const OUString& rString )
1333 {
1334 	sal_Bool bRetValue = sal_False;
1335 	if( mbValid )
1336 	{
1337 		try
1338 		{
1339 			mAny = rXPropSet->getPropertyValue( rString );
1340 			if( 0 != mAny.get() )
1341 				bRetValue = sal_True;
1342 		}
1343 		catch( ::com::sun::star::uno::Exception& )
1344 		{
1345 			bRetValue = sal_False;
1346 		}
1347 	}
1348 	return bRetValue;
1349 }
1350 #endif
1351 
SetRect(const Point & rPos,const Size & rSz)1352 void ImplEESdrObject::SetRect( const Point& rPos, const Size& rSz )
1353 {
1354 	maRect = Rectangle( rPos, rSz );
1355 }
1356 
GetSdrObject() const1357 const SdrObject* ImplEESdrObject::GetSdrObject() const
1358 {
1359 	return EscherEx::GetSdrObject( mXShape );
1360 }
1361 
1362 //  laedt und konvertiert text aus shape, ergebnis ist mnTextSize gespeichert
ImplGetText()1363 sal_uInt32 ImplEESdrObject::ImplGetText()
1364 {
1365 	Reference< XText > xXText( mXShape, UNO_QUERY );
1366 	mnTextSize = 0;
1367 	if( xXText.is() )
1368 		mnTextSize = xXText->getString().getLength();
1369 	return mnTextSize;
1370 }
1371 
ImplHasText() const1372 sal_Bool ImplEESdrObject::ImplHasText() const
1373 {
1374 	Reference< XText > xXText( mXShape, UNO_QUERY );
1375 	return xXText.is() && xXText->getString().getLength();
1376 }
1377 
1378