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