xref: /AOO41X/main/drawinglayer/source/primitive2d/graphicprimitive2d.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_drawinglayer.hxx"
30 
31 #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
32 #include <drawinglayer/animation/animationtiming.hxx>
33 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
34 #include <drawinglayer/primitive2d/rendergraphicprimitive2d.hxx>
35 #include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
36 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
37 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
38 #include <basegfx/polygon/b2dpolygon.hxx>
39 #include <basegfx/polygon/b2dpolygontools.hxx>
40 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
41 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
42 
43 //////////////////////////////////////////////////////////////////////////////
44 // helper class for animated graphics
45 
46 #include <vcl/animate.hxx>
47 #include <vcl/graph.hxx>
48 #include <vcl/virdev.hxx>
49 #include <vcl/svapp.hxx>
50 #include <vcl/metaact.hxx>
51 
52 //////////////////////////////////////////////////////////////////////////////
53 // includes for testing MetafilePrimitive2D::create2DDecomposition
54 
55 // this switch defines if the test code is included or not
56 #undef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
57 
58 #ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
59 #include <vcl/gradient.hxx>
60 #include <vcl/pngread.hxx>
61 #include <vcl/lineinfo.hxx>
62 #endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
63 
64 //////////////////////////////////////////////////////////////////////////////
65 
66 namespace
67 {
68 	struct animationStep
69 	{
70 		BitmapEx								maBitmapEx;
71 		sal_uInt32								mnTime;
72 	};
73 
74 	class animatedBitmapExPreparator
75 	{
76 		::Animation								maAnimation;
77 		::std::vector< animationStep >			maSteps;
78 
79 		sal_uInt32 generateStepTime(sal_uInt32 nIndex) const;
80 
81 	public:
82 		animatedBitmapExPreparator(const Graphic& rGraphic);
83 
84 		sal_uInt32 count() const { return maSteps.size(); }
85 		sal_uInt32 loopCount() const { return (sal_uInt32)maAnimation.GetLoopCount(); }
86 		sal_uInt32 stepTime(sal_uInt32 a) const { return maSteps[a].mnTime; }
87 		const BitmapEx& stepBitmapEx(sal_uInt32 a) const { return maSteps[a].maBitmapEx; }
88 	};
89 
90 	sal_uInt32 animatedBitmapExPreparator::generateStepTime(sal_uInt32 nIndex) const
91 	{
92 		const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(nIndex));
93 		sal_uInt32 nWaitTime(rAnimBitmap.nWait * 10);
94 
95 		// #115934#
96 		// Take care of special value for MultiPage TIFFs. ATM these shall just
97 		// show their first page. Later we will offer some switching when object
98 		// is selected.
99 		if(ANIMATION_TIMEOUT_ON_CLICK == rAnimBitmap.nWait)
100 		{
101 			// ATM the huge value would block the timer, so
102 			// use a long time to show first page (whole day)
103 			nWaitTime = 100 * 60 * 60 * 24;
104 		}
105 
106 		// Bad trap: There are animated gifs with no set WaitTime (!).
107 		// In that case use a default value.
108 		if(0L == nWaitTime)
109 		{
110 			nWaitTime = 100L;
111 		}
112 
113 		return nWaitTime;
114 	}
115 
116 	animatedBitmapExPreparator::animatedBitmapExPreparator(const Graphic& rGraphic)
117 	:	maAnimation(rGraphic.GetAnimation())
118 	{
119 		OSL_ENSURE(GRAPHIC_BITMAP == rGraphic.GetType() && rGraphic.IsAnimated(), "animatedBitmapExPreparator: graphic is not animated (!)");
120 
121 		// #128539# secure access to Animation, looks like there exist animated GIFs out there
122 		// with a step count of zero
123 		if(maAnimation.Count())
124 		{
125 			VirtualDevice aVirtualDevice(*Application::GetDefaultDevice());
126 			VirtualDevice aVirtualDeviceMask(*Application::GetDefaultDevice(), 1L);
127 
128 			// Prepare VirtualDevices and their states
129 			aVirtualDevice.EnableMapMode(sal_False);
130 			aVirtualDeviceMask.EnableMapMode(sal_False);
131 			aVirtualDevice.SetOutputSizePixel(maAnimation.GetDisplaySizePixel());
132 			aVirtualDeviceMask.SetOutputSizePixel(maAnimation.GetDisplaySizePixel());
133 			aVirtualDevice.Erase();
134 			aVirtualDeviceMask.Erase();
135 
136 			for(sal_uInt16 a(0L); a < maAnimation.Count(); a++)
137 			{
138 				animationStep aNextStep;
139 				aNextStep.mnTime = generateStepTime(a);
140 
141 				// prepare step
142 				const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(a));
143 
144 				switch(rAnimBitmap.eDisposal)
145 				{
146 					case DISPOSE_NOT:
147 					{
148 						aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
149 						Bitmap aMask = rAnimBitmap.aBmpEx.GetMask();
150 
151 						if(aMask.IsEmpty())
152 						{
153 							const Point aEmpty;
154 							const Rectangle aRect(aEmpty, aVirtualDeviceMask.GetOutputSizePixel());
155 							const Wallpaper aWallpaper(COL_BLACK);
156 							aVirtualDeviceMask.DrawWallpaper(aRect, aWallpaper);
157 						}
158 						else
159 						{
160 							BitmapEx aExpandVisibilityMask = BitmapEx(aMask, aMask);
161 							aVirtualDeviceMask.DrawBitmapEx(rAnimBitmap.aPosPix, aExpandVisibilityMask);
162 						}
163 
164 						break;
165 					}
166 					case DISPOSE_BACK:
167 					{
168 						// #i70772# react on no mask, for primitives, too.
169 						const Bitmap aMask(rAnimBitmap.aBmpEx.GetMask());
170 						const Bitmap aContent(rAnimBitmap.aBmpEx.GetBitmap());
171 
172 						aVirtualDeviceMask.Erase();
173 						aVirtualDevice.DrawBitmap(rAnimBitmap.aPosPix, aContent);
174 
175 						if(aMask.IsEmpty())
176 						{
177 							const Rectangle aRect(rAnimBitmap.aPosPix, aContent.GetSizePixel());
178 							aVirtualDeviceMask.SetFillColor(COL_BLACK);
179 							aVirtualDeviceMask.SetLineColor();
180 							aVirtualDeviceMask.DrawRect(aRect);
181 						}
182 						else
183 						{
184 							aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, aMask);
185 						}
186 
187 						break;
188 					}
189 					case DISPOSE_FULL:
190 					{
191 						aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
192 						break;
193 					}
194 					case DISPOSE_PREVIOUS :
195 					{
196 						aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
197 						aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx.GetMask());
198 						break;
199 					}
200 				}
201 
202 				// create BitmapEx
203 				Bitmap aMainBitmap = aVirtualDevice.GetBitmap(Point(), aVirtualDevice.GetOutputSizePixel());
204 				Bitmap aMaskBitmap = aVirtualDeviceMask.GetBitmap(Point(), aVirtualDeviceMask.GetOutputSizePixel());
205 				aNextStep.maBitmapEx = BitmapEx(aMainBitmap, aMaskBitmap);
206 
207 				// add to vector
208 				maSteps.push_back(aNextStep);
209 			}
210 		}
211 	}
212 } // end of anonymous namespace
213 
214 //////////////////////////////////////////////////////////////////////////////
215 
216 namespace drawinglayer
217 {
218 	namespace primitive2d
219 	{
220 		Primitive2DSequence GraphicPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D&
221 #ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
222             rViewInformation
223 #else
224             /*rViewInformation*/
225 #endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
226             ) const
227 		{
228 			Primitive2DSequence aRetval;
229 
230 			if(255L != getGraphicAttr().GetTransparency())
231 			{
232 				Primitive2DReference xPrimitive;
233 
234                 // do not apply mirroring from GraphicAttr to the Metafile by calling
235                 // GetTransformedGraphic, this will try to mirror the Metafile using Scale()
236                 // at the Metafile. This again calls Scale at the single MetaFile actions,
237                 // but this implementation never worked. I reworked that implementations,
238                 // but for security reasons i will try not to use it.
239                 basegfx::B2DHomMatrix aTransform(getTransform());
240 
241                 if(getGraphicAttr().IsMirrored())
242                 {
243                     // content needs mirroring
244                     const bool bHMirr(getGraphicAttr().GetMirrorFlags() & BMP_MIRROR_HORZ);
245                     const bool bVMirr(getGraphicAttr().GetMirrorFlags() & BMP_MIRROR_VERT);
246 
247                     // mirror by applying negative scale to the unit primitive and
248                     // applying the object transformation on it.
249                     aTransform = basegfx::tools::createScaleB2DHomMatrix(
250                         bHMirr ? -1.0 : 1.0,
251                         bVMirr ? -1.0 : 1.0);
252                     aTransform.translate(
253                         bHMirr ? 1.0 : 0.0,
254                         bVMirr ? 1.0 : 0.0);
255                     aTransform = getTransform() * aTransform;
256                 }
257 
258 		        // Get transformed graphic. Suppress rotation and cropping, only filtering is needed
259 		        // here (and may be replaced later on). Cropping is handled below as mask primitive (if set).
260                 // Also need to suppress mirroring, it is part of the transformation now (see above).
261 		        GraphicAttr aSuppressGraphicAttr(getGraphicAttr());
262 		        aSuppressGraphicAttr.SetCrop(0, 0, 0, 0);
263 		        aSuppressGraphicAttr.SetRotation(0);
264 		        aSuppressGraphicAttr.SetMirrorFlags(0);
265 
266                 const GraphicObject&    rGraphicObject = getGraphicObject();
267                 const Graphic           aTransformedGraphic(rGraphicObject.GetTransformedGraphic(&aSuppressGraphicAttr));
268 
269                 switch(aTransformedGraphic.GetType())
270 				{
271 					case GRAPHIC_BITMAP :
272 					{
273                         if(aTransformedGraphic.IsAnimated())
274 						{
275 							// prepare animation data
276 							animatedBitmapExPreparator aData(aTransformedGraphic);
277 
278 							if(aData.count())
279 							{
280 								// create sub-primitives for animated bitmap and the needed animation loop
281 								animation::AnimationEntryLoop aAnimationLoop(aData.loopCount() ? aData.loopCount() : 0xffff);
282 								Primitive2DSequence aBitmapPrimitives(aData.count());
283 
284 								for(sal_uInt32 a(0L); a < aData.count(); a++)
285 								{
286                                     animation::AnimationEntryFixed aTime((double)aData.stepTime(a), (double)a / (double)aData.count());
287 									aAnimationLoop.append(aTime);
288 									const Primitive2DReference xRef(new BitmapPrimitive2D(aData.stepBitmapEx(a), aTransform));
289 									aBitmapPrimitives[a] = xRef;
290 								}
291 
292 								// prepare animation list
293 								animation::AnimationEntryList aAnimationList;
294 								aAnimationList.append(aAnimationLoop);
295 
296 								// create and add animated switch primitive
297 								xPrimitive = Primitive2DReference(new AnimatedSwitchPrimitive2D(aAnimationList, aBitmapPrimitives, false));
298 							}
299 						}
300 						else
301 						{
302 							xPrimitive = Primitive2DReference(new BitmapPrimitive2D(aTransformedGraphic.GetBitmapEx(), aTransform));
303 						}
304 
305 						break;
306 					}
307 
308 					case GRAPHIC_GDIMETAFILE :
309 					{
310 #ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
311                         static bool bDoTest(false);
312 
313                         if(bDoTest)
314                         {
315 							// All this is/was test code for testing MetafilePrimitive2D::create2DDecomposition
316 							// extensively. It may be needed again when diverse actions need debugging, so i leave
317 							// it in here, but take it out using USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE.
318 							// Use it by compiling with the code, insert any DrawObject, convert to Metafile. The
319 							// debugger will then stop here (when breakpoint set, of course). You may enter single
320 							// parts of actions and/or change to true what You want to check.
321                             GDIMetaFile aMtf;
322 			                VirtualDevice aOut;
323         		            const basegfx::B2DRange aRange(getB2DRange(rViewInformation));
324                             const Rectangle aRectangle(
325                                 basegfx::fround(aRange.getMinX()), basegfx::fround(aRange.getMinY()),
326                                 basegfx::fround(aRange.getMaxX()), basegfx::fround(aRange.getMaxY()));
327                             const Point aOrigin(aRectangle.TopLeft());
328                             const Fraction aScaleX(aRectangle.getWidth());
329                             const Fraction aScaleY(aRectangle.getHeight());
330                             MapMode aMapMode(MAP_100TH_MM, aOrigin, aScaleX, aScaleY);
331 
332                             Size aDummySize(2, 2);
333                             aOut.SetOutputSizePixel(aDummySize);
334 			                aOut.EnableOutput(FALSE);
335 			                aOut.SetMapMode(aMapMode);
336 
337                             aMtf.Clear();
338 			                aMtf.Record(&aOut);
339 
340 			                const Fraction aNeutralFraction(1, 1);
341 			                const MapMode aRelativeMapMode(
342                                 MAP_RELATIVE,
343                                 Point(-aRectangle.Left(), -aRectangle.Top()),
344                                 aNeutralFraction, aNeutralFraction);
345 			                aOut.SetMapMode(aRelativeMapMode);
346 
347                             if(false)
348                             {
349                                 const sal_Int32 nHor(aRectangle.getWidth() / 4);
350                                 const sal_Int32 nVer(aRectangle.getHeight() / 4);
351                                 const Rectangle aCenteredRectangle(
352                                     aRectangle.Left() + nHor, aRectangle.Top() + nVer,
353                                     aRectangle.Right() - nHor, aRectangle.Bottom() - nVer);
354                                 aOut.SetClipRegion(aCenteredRectangle);
355                             }
356 
357                             if(false)
358                             {
359                                 const Rectangle aRightRectangle(aRectangle.TopCenter(), aRectangle.BottomRight());
360                                 aOut.IntersectClipRegion(aRightRectangle);
361                             }
362 
363                             if(false)
364                             {
365                                 const Rectangle aRightRectangle(aRectangle.TopCenter(), aRectangle.BottomRight());
366                                 const Rectangle aBottomRectangle(aRectangle.LeftCenter(), aRectangle.BottomRight());
367                                 Region aRegion(aRightRectangle);
368                                 aRegion.Intersect(aBottomRectangle);
369                                 aOut.IntersectClipRegion(aRegion);
370                             }
371 
372                             if(false)
373                             {
374                                 const sal_Int32 nHor(aRectangle.getWidth() / 10);
375                                 const sal_Int32 nVer(aRectangle.getHeight() / 10);
376                                 aOut.MoveClipRegion(nHor, nVer);
377                             }
378 
379                             if(false)
380                             {
381                                 Wallpaper aWallpaper(Color(COL_BLACK));
382                                 aOut.DrawWallpaper(aRectangle, aWallpaper);
383                             }
384 
385                             if(false)
386                             {
387                                 Wallpaper aWallpaper(Gradient(GRADIENT_LINEAR, Color(COL_RED), Color(COL_GREEN)));
388                                 aOut.DrawWallpaper(aRectangle, aWallpaper);
389                             }
390 
391                             if(false)
392                             {
393             					SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ);
394                                 vcl::PNGReader aPNGReader(aRead);
395 		                        BitmapEx aBitmapEx(aPNGReader.Read());
396                                 Wallpaper aWallpaper(aBitmapEx);
397                                 aOut.DrawWallpaper(aRectangle, aWallpaper);
398                             }
399 
400                             if(false)
401                             {
402                                 const double fHor(aRectangle.getWidth());
403                                 const double fVer(aRectangle.getHeight());
404 								Color aColor(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0));
405 
406 								for(sal_uInt32 a(0); a < 5000; a++)
407 								{
408 									const Point aPoint(
409 										aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
410 										aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
411 
412 									if(!(a % 3))
413 									{
414 										aColor = Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0));
415 									}
416 
417 									aOut.DrawPixel(aPoint, aColor);
418 								}
419 							}
420 
421                             if(false)
422                             {
423                                 const double fHor(aRectangle.getWidth());
424                                 const double fVer(aRectangle.getHeight());
425 
426 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
427 								aOut.SetFillColor();
428 
429 								for(sal_uInt32 a(0); a < 5000; a++)
430 								{
431 									const Point aPoint(
432 										aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
433 										aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
434 									aOut.DrawPixel(aPoint);
435 								}
436 							}
437 
438                             if(false)
439                             {
440                                 const double fHor(aRectangle.getWidth());
441                                 const double fVer(aRectangle.getHeight());
442 
443 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
444 								aOut.SetFillColor();
445 
446 								Point aStart(
447 									aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
448 									aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
449 								Point aStop(
450 									aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
451 									aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
452 
453 								LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fHor / 50.0));
454 								bool bUseLineInfo(false);
455 
456 								for(sal_uInt32 a(0); a < 20; a++)
457 								{
458 									if(!(a%6))
459 									{
460 										bUseLineInfo = !bUseLineInfo;
461 									}
462 
463 									if(!(a%4))
464 									{
465 										aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
466 									}
467 
468 									if(a%3)
469 									{
470 										aStart = aStop;
471 										aStop = Point(
472 											aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
473 											aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
474 									}
475 									else
476 									{
477 										aStart = Point(
478 											aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
479 											aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
480 										aStop = Point(
481 											aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
482 											aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
483 									}
484 
485 									if(bUseLineInfo)
486 									{
487 										aOut.DrawLine(aStart, aStop, aLineInfo);
488 									}
489 									else
490 									{
491 										aOut.DrawLine(aStart, aStop);
492 									}
493 								}
494 							}
495 
496                             if(false)
497                             {
498 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
499 								aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
500 								aOut.DrawRect(aRectangle);
501 							}
502 
503                             if(false)
504                             {
505 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
506 								aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
507                                 const sal_uInt32 nHor(aRectangle.getWidth() / 10);
508                                 const sal_uInt32 nVer(aRectangle.getHeight() / 10);
509 								aOut.DrawRect(aRectangle, nHor, nVer);
510 							}
511 
512                             if(false)
513                             {
514 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
515 								aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
516 								aOut.DrawEllipse(aRectangle);
517 							}
518 
519                             if(false)
520                             {
521 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
522 								aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
523 								aOut.DrawArc(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter());
524 							}
525 
526                             if(false)
527                             {
528 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
529 								aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
530 								aOut.DrawPie(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter());
531 							}
532 
533                             if(false)
534                             {
535 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
536 								aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
537 								aOut.DrawChord(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter());
538 							}
539 
540                             if(false)
541                             {
542                                 const double fHor(aRectangle.getWidth());
543                                 const double fVer(aRectangle.getHeight());
544 
545 								for(sal_uInt32 b(0); b < 5; b++)
546 								{
547 									const sal_uInt32 nCount(basegfx::fround(rand() * (20 / 32767.0)));
548 									const bool bClose(basegfx::fround(rand() / 32767.0));
549 									Polygon aPolygon(nCount + (bClose ? 1 : 0));
550 
551 									for(sal_uInt32 a(0); a < nCount; a++)
552 									{
553 										const Point aPoint(
554 											aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
555 											aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
556 										aPolygon[a] = aPoint;
557 									}
558 
559 									if(bClose)
560 									{
561 										aPolygon[aPolygon.GetSize() - 1] = aPolygon[0];
562 									}
563 
564 									aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
565 									aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
566 
567 									if(!(b%2))
568 									{
569 										const LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fHor / 50.0));
570 										aOut.DrawPolyLine(aPolygon, aLineInfo);
571 									}
572 									else
573 									{
574 										aOut.DrawPolyLine(aPolygon);
575 									}
576 								}
577 							}
578 
579                             if(false)
580                             {
581                                 const double fHor(aRectangle.getWidth());
582                                 const double fVer(aRectangle.getHeight());
583 
584 								for(sal_uInt32 b(0); b < 5; b++)
585 								{
586 									const sal_uInt32 nCount(basegfx::fround(rand() * (20 / 32767.0)));
587 									const bool bClose(basegfx::fround(rand() / 32767.0));
588 									Polygon aPolygon(nCount + (bClose ? 1 : 0));
589 
590 									for(sal_uInt32 a(0); a < nCount; a++)
591 									{
592 										const Point aPoint(
593 											aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
594 											aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
595 										aPolygon[a] = aPoint;
596 									}
597 
598 									if(bClose)
599 									{
600 										aPolygon[aPolygon.GetSize() - 1] = aPolygon[0];
601 									}
602 
603 									aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
604 									aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
605 									aOut.DrawPolygon(aPolygon);
606 								}
607 							}
608 
609                             if(false)
610                             {
611                                 const double fHor(aRectangle.getWidth());
612                                 const double fVer(aRectangle.getHeight());
613 								PolyPolygon aPolyPolygon;
614 
615 								for(sal_uInt32 b(0); b < 3; b++)
616 								{
617 									const sal_uInt32 nCount(basegfx::fround(rand() * (6 / 32767.0)));
618 									const bool bClose(basegfx::fround(rand() / 32767.0));
619 									Polygon aPolygon(nCount + (bClose ? 1 : 0));
620 
621 									for(sal_uInt32 a(0); a < nCount; a++)
622 									{
623 										const Point aPoint(
624 											aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
625 											aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
626 										aPolygon[a] = aPoint;
627 									}
628 
629 									if(bClose)
630 									{
631 										aPolygon[aPolygon.GetSize() - 1] = aPolygon[0];
632 									}
633 
634 									aPolyPolygon.Insert(aPolygon);
635 								}
636 
637 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
638 								aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
639 								aOut.DrawPolyPolygon(aPolyPolygon);
640 							}
641 
642                             if(false)
643                             {
644             					SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ);
645                                 vcl::PNGReader aPNGReader(aRead);
646 		                        BitmapEx aBitmapEx(aPNGReader.Read());
647 								aOut.DrawBitmapEx(aRectangle.TopLeft(), aBitmapEx);
648 							}
649 
650                             if(false)
651                             {
652             					SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ);
653                                 vcl::PNGReader aPNGReader(aRead);
654 		                        BitmapEx aBitmapEx(aPNGReader.Read());
655 								aOut.DrawBitmapEx(aRectangle.TopLeft(), aRectangle.GetSize(), aBitmapEx);
656 							}
657 
658                             if(false)
659                             {
660             					SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ);
661                                 vcl::PNGReader aPNGReader(aRead);
662 		                        BitmapEx aBitmapEx(aPNGReader.Read());
663 								const Size aSizePixel(aBitmapEx.GetSizePixel());
664 								aOut.DrawBitmapEx(
665 									aRectangle.TopLeft(),
666 									aRectangle.GetSize(),
667 									Point(0, 0),
668 									Size(aSizePixel.Width() /2, aSizePixel.Height() / 2),
669 									aBitmapEx);
670 							}
671 
672                             if(false)
673                             {
674                                 const double fHor(aRectangle.getWidth());
675                                 const double fVer(aRectangle.getHeight());
676 								const Point aPointA(
677 									aRectangle.Left() + basegfx::fround(fHor * 0.2),
678 									aRectangle.Top() + basegfx::fround(fVer * 0.3));
679 								const Point aPointB(
680 									aRectangle.Left() + basegfx::fround(fHor * 0.2),
681 									aRectangle.Top() + basegfx::fround(fVer * 0.5));
682 								const Point aPointC(
683 									aRectangle.Left() + basegfx::fround(fHor * 0.2),
684 									aRectangle.Top() + basegfx::fround(fVer * 0.7));
685                                 const String aText(ByteString("Hello, World!"), RTL_TEXTENCODING_UTF8);
686 
687                                 const String aFontName(ByteString("Comic Sans MS"), RTL_TEXTENCODING_UTF8);
688                                 Font aFont(aFontName, Size(0, 1000));
689                                 aFont.SetAlign(ALIGN_BASELINE);
690                                 aFont.SetColor(COL_RED);
691                                 //sal_Int32* pDXArray = new sal_Int32[aText.Len()];
692 
693                                 aFont.SetOutline(true);
694                                 aOut.SetFont(aFont);
695                                 aOut.DrawText(aPointA, aText, 0, aText.Len());
696 
697                                 aFont.SetShadow(true);
698                                 aOut.SetFont(aFont);
699                                 aOut.DrawText(aPointB, aText, 0, aText.Len());
700 
701                                 aFont.SetRelief(RELIEF_EMBOSSED);
702                                 aOut.SetFont(aFont);
703                                 aOut.DrawText(aPointC, aText, 0, aText.Len());
704 
705                                 //delete pDXArray;
706                             }
707 
708                             if(false)
709                             {
710                                 const double fHor(aRectangle.getWidth());
711                                 const double fVer(aRectangle.getHeight());
712 								const Point aPointA(
713 									aRectangle.Left() + basegfx::fround(fHor * 0.2),
714 									aRectangle.Top() + basegfx::fround(fVer * 0.3));
715 								const Point aPointB(
716 									aRectangle.Left() + basegfx::fround(fHor * 0.2),
717 									aRectangle.Top() + basegfx::fround(fVer * 0.5));
718 								const Point aPointC(
719 									aRectangle.Left() + basegfx::fround(fHor * 0.2),
720 									aRectangle.Top() + basegfx::fround(fVer * 0.7));
721                                 const String aText(ByteString("Hello, World!"), RTL_TEXTENCODING_UTF8);
722 
723                                 const String aFontName(ByteString("Comic Sans MS"), RTL_TEXTENCODING_UTF8);
724                                 Font aFont(aFontName, Size(0, 1000));
725                                 aFont.SetAlign(ALIGN_BASELINE);
726                                 aFont.SetColor(COL_RED);
727 
728                                 aOut.SetFont(aFont);
729 								const sal_Int32 nWidth(aOut.GetTextWidth(aText, 0, aText.Len()));
730                                 aOut.DrawText(aPointA, aText, 0, aText.Len());
731                                 aOut.DrawTextLine(aPointA, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE);
732                                 aOut.DrawTextLine(aPointB, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE);
733                                 aOut.DrawTextLine(aPointC, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE);
734                             }
735 
736                             aMtf.Stop();
737 			                aMtf.WindStart();
738 		                    aMtf.SetPrefMapMode(MapMode(MAP_100TH_MM));
739 			                aMtf.SetPrefSize(Size(aRectangle.getWidth(), aRectangle.getHeight()));
740 
741                             xPrimitive = Primitive2DReference(
742                                 new MetafilePrimitive2D(
743                                     aTransform,
744                                     aMtf));
745                         }
746                         else
747                         {
748 #endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
749 	                        // create MetafilePrimitive2D
750                             const GDIMetaFile& rMetafile = aTransformedGraphic.GetGDIMetaFile();
751 
752                             if( aTransformedGraphic.IsRenderGraphic() )
753                             {
754                                 xPrimitive = Primitive2DReference(
755                                     new RenderGraphicPrimitive2D(
756                                         static_cast< MetaRenderGraphicAction* >(rMetafile.GetAction(0))->GetRenderGraphic(),
757                                         aTransform));
758                             }
759                             else
760                             {
761                                 xPrimitive = Primitive2DReference(
762                                     new MetafilePrimitive2D(
763                                         aTransform,
764                                         rMetafile));
765 
766                                 // #i100357# find out if clipping is needed for this primitive. Unfortunately,
767                                 // there exist Metafiles who's content is bigger than the proposed PrefSize set
768                                 // at them. This is an error, but we need to work around this
769                                 const Size aMetaFilePrefSize(rMetafile.GetPrefSize());
770                                 const Size aMetaFileRealSize(
771                                     const_cast< GDIMetaFile& >(rMetafile).GetBoundRect(
772                                         *Application::GetDefaultDevice()).GetSize());
773 
774                                 if(aMetaFileRealSize.getWidth() > aMetaFilePrefSize.getWidth()
775                                     || aMetaFileRealSize.getHeight() > aMetaFilePrefSize.getHeight())
776                                 {
777                                     // clipping needed. Embed to MaskPrimitive2D. Create childs and mask polygon
778                                     const primitive2d::Primitive2DSequence aChildContent(&xPrimitive, 1);
779                                     basegfx::B2DPolygon aMaskPolygon(basegfx::tools::createUnitPolygon());
780                                     aMaskPolygon.transform(aTransform);
781 
782                                     xPrimitive = Primitive2DReference(
783                                         new MaskPrimitive2D(
784                                             basegfx::B2DPolyPolygon(aMaskPolygon),
785                                             aChildContent));
786                                 }
787                             }
788 #ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
789                         }
790 #endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
791 
792 						break;
793 					}
794 
795 					default:
796 					{
797 						// nothing to create
798 						break;
799 					}
800 				}
801 
802 				if(xPrimitive.is())
803 				{
804 					// check for cropping
805 					if(getGraphicAttr().IsCropped())
806 					{
807 						// decompose to get current pos and size
808 						basegfx::B2DVector aScale, aTranslate;
809 						double fRotate, fShearX;
810 						getTransform().decompose(aScale, aTranslate, fRotate, fShearX);
811 
812 						// create ranges. The current object range is just scale and translate
813 						const basegfx::B2DRange aCurrent(
814 							aTranslate.getX(), aTranslate.getY(),
815 							aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
816 
817 						// calculate scalings between real image size and logic object size. This
818 						// is necessary since the crop values are relative to original bitmap size
819 						double fFactorX(1.0);
820 						double fFactorY(1.0);
821 
822 						{
823 							const MapMode aMapMode100thmm(MAP_100TH_MM);
824 							Size aBitmapSize(rGraphicObject.GetPrefSize());
825 
826 							// #i95968# better support PrefMapMode; special for MAP_PIXEL was missing
827 							if(MAP_PIXEL == rGraphicObject.GetPrefMapMode().GetMapUnit())
828 							{
829 								aBitmapSize = Application::GetDefaultDevice()->PixelToLogic(aBitmapSize, aMapMode100thmm);
830 							}
831 							else
832 							{
833 								aBitmapSize = Application::GetDefaultDevice()->LogicToLogic(aBitmapSize, rGraphicObject.GetPrefMapMode(), aMapMode100thmm);
834 							}
835 
836 							const double fDivX(aBitmapSize.Width() - getGraphicAttr().GetLeftCrop() - getGraphicAttr().GetRightCrop());
837 							const double fDivY(aBitmapSize.Height() - getGraphicAttr().GetTopCrop() - getGraphicAttr().GetBottomCrop());
838 
839 							if(!basegfx::fTools::equalZero(fDivX))
840 							{
841 								fFactorX = aScale.getX() / fDivX;
842 							}
843 
844 							if(!basegfx::fTools::equalZero(fDivY))
845 							{
846 								fFactorY = aScale.getY() / fDivY;
847 							}
848 						}
849 
850 						// Create cropped range, describes the bounds of the original graphic
851 						basegfx::B2DRange aCropped;
852 						aCropped.expand(aCurrent.getMinimum() - basegfx::B2DPoint(getGraphicAttr().GetLeftCrop() * fFactorX, getGraphicAttr().GetTopCrop() * fFactorY));
853 						aCropped.expand(aCurrent.getMaximum() + basegfx::B2DPoint(getGraphicAttr().GetRightCrop() * fFactorX, getGraphicAttr().GetBottomCrop() * fFactorY));
854 
855 						if(aCropped.isEmpty())
856 						{
857 							// nothing to add since cropped bitmap is completely empty
858 							// xPrimitive will not be used
859 						}
860 						else
861 						{
862 							// build new object transformation for transform primitive which contains xPrimitive
863 							basegfx::B2DHomMatrix aNewObjectTransform(getTransform());
864 							aNewObjectTransform.invert();
865 							aNewObjectTransform = basegfx::tools::createScaleTranslateB2DHomMatrix(
866 								aCropped.getWidth(), aCropped.getHeight(),
867 								aCropped.getMinX() - aCurrent.getMinX(), aCropped.getMinY() - aCurrent.getMinY())
868 								* aNewObjectTransform;
869 
870 							// add shear, rotate and translate using combined matrix to speedup
871 							const basegfx::B2DHomMatrix aCombinedMatrix(basegfx::tools::createShearXRotateTranslateB2DHomMatrix(
872 								fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
873 							aNewObjectTransform = aCombinedMatrix * aNewObjectTransform;
874 
875 							// prepare TransformPrimitive2D with xPrimitive
876 							const Primitive2DReference xTransformPrimitive(new TransformPrimitive2D(aNewObjectTransform, Primitive2DSequence(&xPrimitive, 1L)));
877 
878 							if(aCurrent.isInside(aCropped))
879 							{
880 								// cropped just got smaller, no need to really use a mask. Add to destination directly
881 								appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xTransformPrimitive);
882 							}
883 							else
884 							{
885 								// cropped got bigger, mask it with original object's bounds
886 								basegfx::B2DPolyPolygon aMaskPolyPolygon(basegfx::tools::createUnitPolygon());
887 								aMaskPolyPolygon.transform(getTransform());
888 
889 								// create maskPrimitive with aMaskPolyPolygon and aMaskContentVector
890 								const Primitive2DReference xRefB(new MaskPrimitive2D(aMaskPolyPolygon, Primitive2DSequence(&xTransformPrimitive, 1L)));
891 								appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xRefB);
892 							}
893 						}
894 					}
895 					else
896 					{
897 						// add to decomposition
898 						appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xPrimitive);
899 					}
900 				}
901 			}
902 
903 			return aRetval;
904 		}
905 
906 		GraphicPrimitive2D::GraphicPrimitive2D(
907 			const basegfx::B2DHomMatrix& rTransform,
908 			const GraphicObject& rGraphicObject,
909 			const GraphicAttr& rGraphicAttr)
910 		:	BufferedDecompositionPrimitive2D(),
911 			maTransform(rTransform),
912 			maGraphicObject(rGraphicObject),
913 			maGraphicAttr(rGraphicAttr)
914 		{
915 		}
916 
917 		GraphicPrimitive2D::GraphicPrimitive2D(
918 			const basegfx::B2DHomMatrix& rTransform,
919 			const GraphicObject& rGraphicObject)
920 		:	BufferedDecompositionPrimitive2D(),
921 			maTransform(rTransform),
922 			maGraphicObject(rGraphicObject),
923 			maGraphicAttr()
924 		{
925 		}
926 
927 		bool GraphicPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
928 		{
929 			if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
930 			{
931 				const GraphicPrimitive2D& rCompare = (GraphicPrimitive2D&)rPrimitive;
932 
933 				return (getTransform() == rCompare.getTransform()
934 					&& getGraphicObject() == rCompare.getGraphicObject()
935 					&& getGraphicAttr() == rCompare.getGraphicAttr());
936 			}
937 
938 			return false;
939 		}
940 
941 		basegfx::B2DRange GraphicPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
942 		{
943 			basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
944 			aRetval.transform(getTransform());
945 			return aRetval;
946 		}
947 
948 		// provide unique ID
949 		ImplPrimitrive2DIDBlock(GraphicPrimitive2D, PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D)
950 
951 	} // end of namespace primitive2d
952 } // end of namespace drawinglayer
953 
954 //////////////////////////////////////////////////////////////////////////////
955 // eof
956