xref: /AOO41X/main/drawinglayer/source/primitive2d/graphicprimitive2d.cxx (revision 54befb6bcc47df7a34762ec9cc562856b04262b6)
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/animatedprimitive2d.hxx>
31 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
32 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
33 #include <basegfx/polygon/b2dpolygon.hxx>
34 #include <basegfx/polygon/b2dpolygontools.hxx>
35 #include <drawinglayer/primitive2d/cropprimitive2d.hxx>
36 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
37 #include <drawinglayer/primitive2d/maskprimitive2d.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 if(aTransformedGraphic.getSvgData().get())
297                         {
298                             // embedded Svg fill, create embed transform
299                             const basegfx::B2DRange& rSvgRange(aTransformedGraphic.getSvgData()->getRange());
300 
301                             if(basegfx::fTools::more(rSvgRange.getWidth(), 0.0) && basegfx::fTools::more(rSvgRange.getHeight(), 0.0))
302                             {
303                                 // translate back to origin, scale to unit coordinates
304                                 basegfx::B2DHomMatrix aEmbedSvg(
305                                     basegfx::tools::createTranslateB2DHomMatrix(
306                                         -rSvgRange.getMinX(),
307                                         -rSvgRange.getMinY()));
308 
309                                 aEmbedSvg.scale(
310                                     1.0 / rSvgRange.getWidth(),
311                                     1.0 / rSvgRange.getHeight());
312 
313                                 // apply created object transformation
314                                 aEmbedSvg = aTransform * aEmbedSvg;
315 
316                                 // add Svg primitives embedded
317                                 xPrimitive = new TransformPrimitive2D(
318                                     aEmbedSvg,
319                                     aTransformedGraphic.getSvgData()->getPrimitive2DSequence());
320                             }
321                         }
322 						else
323 						{
324 							xPrimitive = Primitive2DReference(new BitmapPrimitive2D(aTransformedGraphic.GetBitmapEx(), aTransform));
325 						}
326 
327 						break;
328 					}
329 
330 					case GRAPHIC_GDIMETAFILE :
331 					{
332 #ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
333                         static bool bDoTest(false);
334 
335                         if(bDoTest)
336                         {
337 							// All this is/was test code for testing MetafilePrimitive2D::create2DDecomposition
338 							// extensively. It may be needed again when diverse actions need debugging, so i leave
339 							// it in here, but take it out using USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE.
340 							// Use it by compiling with the code, insert any DrawObject, convert to Metafile. The
341 							// debugger will then stop here (when breakpoint set, of course). You may enter single
342 							// parts of actions and/or change to true what You want to check.
343                             GDIMetaFile aMtf;
344 			                VirtualDevice aOut;
345         		            const basegfx::B2DRange aRange(getB2DRange(rViewInformation));
346                             const Rectangle aRectangle(
347                                 basegfx::fround(aRange.getMinX()), basegfx::fround(aRange.getMinY()),
348                                 basegfx::fround(aRange.getMaxX()), basegfx::fround(aRange.getMaxY()));
349                             const Point aOrigin(aRectangle.TopLeft());
350                             const Fraction aScaleX(aRectangle.getWidth());
351                             const Fraction aScaleY(aRectangle.getHeight());
352                             MapMode aMapMode(MAP_100TH_MM, aOrigin, aScaleX, aScaleY);
353 
354                             Size aDummySize(2, 2);
355                             aOut.SetOutputSizePixel(aDummySize);
356 			                aOut.EnableOutput(FALSE);
357 			                aOut.SetMapMode(aMapMode);
358 
359                             aMtf.Clear();
360 			                aMtf.Record(&aOut);
361 
362 			                const Fraction aNeutralFraction(1, 1);
363 			                const MapMode aRelativeMapMode(
364                                 MAP_RELATIVE,
365                                 Point(-aRectangle.Left(), -aRectangle.Top()),
366                                 aNeutralFraction, aNeutralFraction);
367 			                aOut.SetMapMode(aRelativeMapMode);
368 
369                             if(false)
370                             {
371                                 const sal_Int32 nHor(aRectangle.getWidth() / 4);
372                                 const sal_Int32 nVer(aRectangle.getHeight() / 4);
373                                 const Rectangle aCenteredRectangle(
374                                     aRectangle.Left() + nHor, aRectangle.Top() + nVer,
375                                     aRectangle.Right() - nHor, aRectangle.Bottom() - nVer);
376                                 aOut.SetClipRegion(aCenteredRectangle);
377                             }
378 
379                             if(false)
380                             {
381                                 const Rectangle aRightRectangle(aRectangle.TopCenter(), aRectangle.BottomRight());
382                                 aOut.IntersectClipRegion(aRightRectangle);
383                             }
384 
385                             if(false)
386                             {
387                                 const Rectangle aRightRectangle(aRectangle.TopCenter(), aRectangle.BottomRight());
388                                 const Rectangle aBottomRectangle(aRectangle.LeftCenter(), aRectangle.BottomRight());
389                                 Region aRegion(aRightRectangle);
390                                 aRegion.Intersect(aBottomRectangle);
391                                 aOut.IntersectClipRegion(aRegion);
392                             }
393 
394                             if(false)
395                             {
396                                 const sal_Int32 nHor(aRectangle.getWidth() / 10);
397                                 const sal_Int32 nVer(aRectangle.getHeight() / 10);
398                                 aOut.MoveClipRegion(nHor, nVer);
399                             }
400 
401                             if(false)
402                             {
403                                 Wallpaper aWallpaper(Color(COL_BLACK));
404                                 aOut.DrawWallpaper(aRectangle, aWallpaper);
405                             }
406 
407                             if(false)
408                             {
409                                 Wallpaper aWallpaper(Gradient(GRADIENT_LINEAR, Color(COL_RED), Color(COL_GREEN)));
410                                 aOut.DrawWallpaper(aRectangle, aWallpaper);
411                             }
412 
413                             if(false)
414                             {
415             					SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ);
416                                 vcl::PNGReader aPNGReader(aRead);
417 		                        BitmapEx aBitmapEx(aPNGReader.Read());
418                                 Wallpaper aWallpaper(aBitmapEx);
419                                 aOut.DrawWallpaper(aRectangle, aWallpaper);
420                             }
421 
422                             if(false)
423                             {
424                                 const double fHor(aRectangle.getWidth());
425                                 const double fVer(aRectangle.getHeight());
426 								Color aColor(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0));
427 
428 								for(sal_uInt32 a(0); a < 5000; a++)
429 								{
430 									const Point aPoint(
431 										aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
432 										aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
433 
434 									if(!(a % 3))
435 									{
436 										aColor = Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0));
437 									}
438 
439 									aOut.DrawPixel(aPoint, aColor);
440 								}
441 							}
442 
443                             if(false)
444                             {
445                                 const double fHor(aRectangle.getWidth());
446                                 const double fVer(aRectangle.getHeight());
447 
448 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
449 								aOut.SetFillColor();
450 
451 								for(sal_uInt32 a(0); a < 5000; a++)
452 								{
453 									const Point aPoint(
454 										aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
455 										aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
456 									aOut.DrawPixel(aPoint);
457 								}
458 							}
459 
460                             if(false)
461                             {
462                                 const double fHor(aRectangle.getWidth());
463                                 const double fVer(aRectangle.getHeight());
464 
465 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
466 								aOut.SetFillColor();
467 
468 								Point aStart(
469 									aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
470 									aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
471 								Point aStop(
472 									aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
473 									aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
474 
475 								LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fHor / 50.0));
476 								bool bUseLineInfo(false);
477 
478 								for(sal_uInt32 a(0); a < 20; a++)
479 								{
480 									if(!(a%6))
481 									{
482 										bUseLineInfo = !bUseLineInfo;
483 									}
484 
485 									if(!(a%4))
486 									{
487 										aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
488 									}
489 
490 									if(a%3)
491 									{
492 										aStart = aStop;
493 										aStop = Point(
494 											aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
495 											aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
496 									}
497 									else
498 									{
499 										aStart = Point(
500 											aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
501 											aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
502 										aStop = Point(
503 											aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
504 											aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
505 									}
506 
507 									if(bUseLineInfo)
508 									{
509 										aOut.DrawLine(aStart, aStop, aLineInfo);
510 									}
511 									else
512 									{
513 										aOut.DrawLine(aStart, aStop);
514 									}
515 								}
516 							}
517 
518                             if(false)
519                             {
520 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
521 								aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
522 								aOut.DrawRect(aRectangle);
523 							}
524 
525                             if(false)
526                             {
527 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
528 								aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
529                                 const sal_uInt32 nHor(aRectangle.getWidth() / 10);
530                                 const sal_uInt32 nVer(aRectangle.getHeight() / 10);
531 								aOut.DrawRect(aRectangle, nHor, nVer);
532 							}
533 
534                             if(false)
535                             {
536 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
537 								aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
538 								aOut.DrawEllipse(aRectangle);
539 							}
540 
541                             if(false)
542                             {
543 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
544 								aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
545 								aOut.DrawArc(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter());
546 							}
547 
548                             if(false)
549                             {
550 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
551 								aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
552 								aOut.DrawPie(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter());
553 							}
554 
555                             if(false)
556                             {
557 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
558 								aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
559 								aOut.DrawChord(aRectangle, aRectangle.TopLeft(), aRectangle.BottomCenter());
560 							}
561 
562                             if(false)
563                             {
564                                 const double fHor(aRectangle.getWidth());
565                                 const double fVer(aRectangle.getHeight());
566 
567 								for(sal_uInt32 b(0); b < 5; b++)
568 								{
569 									const sal_uInt32 nCount(basegfx::fround(rand() * (20 / 32767.0)));
570 									const bool bClose(basegfx::fround(rand() / 32767.0));
571 									Polygon aPolygon(nCount + (bClose ? 1 : 0));
572 
573 									for(sal_uInt32 a(0); a < nCount; a++)
574 									{
575 										const Point aPoint(
576 											aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
577 											aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
578 										aPolygon[a] = aPoint;
579 									}
580 
581 									if(bClose)
582 									{
583 										aPolygon[aPolygon.GetSize() - 1] = aPolygon[0];
584 									}
585 
586 									aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
587 									aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
588 
589 									if(!(b%2))
590 									{
591 										const LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fHor / 50.0));
592 										aOut.DrawPolyLine(aPolygon, aLineInfo);
593 									}
594 									else
595 									{
596 										aOut.DrawPolyLine(aPolygon);
597 									}
598 								}
599 							}
600 
601                             if(false)
602                             {
603                                 const double fHor(aRectangle.getWidth());
604                                 const double fVer(aRectangle.getHeight());
605 
606 								for(sal_uInt32 b(0); b < 5; b++)
607 								{
608 									const sal_uInt32 nCount(basegfx::fround(rand() * (20 / 32767.0)));
609 									const bool bClose(basegfx::fround(rand() / 32767.0));
610 									Polygon aPolygon(nCount + (bClose ? 1 : 0));
611 
612 									for(sal_uInt32 a(0); a < nCount; a++)
613 									{
614 										const Point aPoint(
615 											aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
616 											aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
617 										aPolygon[a] = aPoint;
618 									}
619 
620 									if(bClose)
621 									{
622 										aPolygon[aPolygon.GetSize() - 1] = aPolygon[0];
623 									}
624 
625 									aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
626 									aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
627 									aOut.DrawPolygon(aPolygon);
628 								}
629 							}
630 
631                             if(false)
632                             {
633                                 const double fHor(aRectangle.getWidth());
634                                 const double fVer(aRectangle.getHeight());
635 								PolyPolygon aPolyPolygon;
636 
637 								for(sal_uInt32 b(0); b < 3; b++)
638 								{
639 									const sal_uInt32 nCount(basegfx::fround(rand() * (6 / 32767.0)));
640 									const bool bClose(basegfx::fround(rand() / 32767.0));
641 									Polygon aPolygon(nCount + (bClose ? 1 : 0));
642 
643 									for(sal_uInt32 a(0); a < nCount; a++)
644 									{
645 										const Point aPoint(
646 											aRectangle.Left() + basegfx::fround(rand() * (fHor / 32767.0)),
647 											aRectangle.Top() + basegfx::fround(rand() * (fVer / 32767.0)));
648 										aPolygon[a] = aPoint;
649 									}
650 
651 									if(bClose)
652 									{
653 										aPolygon[aPolygon.GetSize() - 1] = aPolygon[0];
654 									}
655 
656 									aPolyPolygon.Insert(aPolygon);
657 								}
658 
659 								aOut.SetLineColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
660 								aOut.SetFillColor(Color(basegfx::BColor(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0)));
661 								aOut.DrawPolyPolygon(aPolyPolygon);
662 							}
663 
664                             if(false)
665                             {
666             					SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ);
667                                 vcl::PNGReader aPNGReader(aRead);
668 		                        BitmapEx aBitmapEx(aPNGReader.Read());
669 								aOut.DrawBitmapEx(aRectangle.TopLeft(), aBitmapEx);
670 							}
671 
672                             if(false)
673                             {
674             					SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ);
675                                 vcl::PNGReader aPNGReader(aRead);
676 		                        BitmapEx aBitmapEx(aPNGReader.Read());
677 								aOut.DrawBitmapEx(aRectangle.TopLeft(), aRectangle.GetSize(), aBitmapEx);
678 							}
679 
680                             if(false)
681                             {
682             					SvFileStream aRead((const String&)String(ByteString( "c:\\test.png" ), RTL_TEXTENCODING_UTF8), STREAM_READ);
683                                 vcl::PNGReader aPNGReader(aRead);
684 		                        BitmapEx aBitmapEx(aPNGReader.Read());
685 								const Size aSizePixel(aBitmapEx.GetSizePixel());
686 								aOut.DrawBitmapEx(
687 									aRectangle.TopLeft(),
688 									aRectangle.GetSize(),
689 									Point(0, 0),
690 									Size(aSizePixel.Width() /2, aSizePixel.Height() / 2),
691 									aBitmapEx);
692 							}
693 
694                             if(false)
695                             {
696                                 const double fHor(aRectangle.getWidth());
697                                 const double fVer(aRectangle.getHeight());
698 								const Point aPointA(
699 									aRectangle.Left() + basegfx::fround(fHor * 0.2),
700 									aRectangle.Top() + basegfx::fround(fVer * 0.3));
701 								const Point aPointB(
702 									aRectangle.Left() + basegfx::fround(fHor * 0.2),
703 									aRectangle.Top() + basegfx::fround(fVer * 0.5));
704 								const Point aPointC(
705 									aRectangle.Left() + basegfx::fround(fHor * 0.2),
706 									aRectangle.Top() + basegfx::fround(fVer * 0.7));
707                                 const String aText(ByteString("Hello, World!"), RTL_TEXTENCODING_UTF8);
708 
709                                 const String aFontName(ByteString("Comic Sans MS"), RTL_TEXTENCODING_UTF8);
710                                 Font aFont(aFontName, Size(0, 1000));
711                                 aFont.SetAlign(ALIGN_BASELINE);
712                                 aFont.SetColor(COL_RED);
713                                 //sal_Int32* pDXArray = new sal_Int32[aText.Len()];
714 
715                                 aFont.SetOutline(true);
716                                 aOut.SetFont(aFont);
717                                 aOut.DrawText(aPointA, aText, 0, aText.Len());
718 
719                                 aFont.SetShadow(true);
720                                 aOut.SetFont(aFont);
721                                 aOut.DrawText(aPointB, aText, 0, aText.Len());
722 
723                                 aFont.SetRelief(RELIEF_EMBOSSED);
724                                 aOut.SetFont(aFont);
725                                 aOut.DrawText(aPointC, aText, 0, aText.Len());
726 
727                                 //delete pDXArray;
728                             }
729 
730                             if(false)
731                             {
732                                 const double fHor(aRectangle.getWidth());
733                                 const double fVer(aRectangle.getHeight());
734 								const Point aPointA(
735 									aRectangle.Left() + basegfx::fround(fHor * 0.2),
736 									aRectangle.Top() + basegfx::fround(fVer * 0.3));
737 								const Point aPointB(
738 									aRectangle.Left() + basegfx::fround(fHor * 0.2),
739 									aRectangle.Top() + basegfx::fround(fVer * 0.5));
740 								const Point aPointC(
741 									aRectangle.Left() + basegfx::fround(fHor * 0.2),
742 									aRectangle.Top() + basegfx::fround(fVer * 0.7));
743                                 const String aText(ByteString("Hello, World!"), RTL_TEXTENCODING_UTF8);
744 
745                                 const String aFontName(ByteString("Comic Sans MS"), RTL_TEXTENCODING_UTF8);
746                                 Font aFont(aFontName, Size(0, 1000));
747                                 aFont.SetAlign(ALIGN_BASELINE);
748                                 aFont.SetColor(COL_RED);
749 
750                                 aOut.SetFont(aFont);
751 								const sal_Int32 nWidth(aOut.GetTextWidth(aText, 0, aText.Len()));
752                                 aOut.DrawText(aPointA, aText, 0, aText.Len());
753                                 aOut.DrawTextLine(aPointA, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE);
754                                 aOut.DrawTextLine(aPointB, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE);
755                                 aOut.DrawTextLine(aPointC, nWidth, STRIKEOUT_SINGLE, UNDERLINE_SINGLE, UNDERLINE_SMALLWAVE);
756                             }
757 
758                             aMtf.Stop();
759 			                aMtf.WindStart();
760 		                    aMtf.SetPrefMapMode(MapMode(MAP_100TH_MM));
761 			                aMtf.SetPrefSize(Size(aRectangle.getWidth(), aRectangle.getHeight()));
762 
763                             xPrimitive = Primitive2DReference(
764                                 new MetafilePrimitive2D(
765                                     aTransform,
766                                     aMtf));
767                         }
768                         else
769                         {
770 #endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
771                             // create MetafilePrimitive2D
772                             const GDIMetaFile& rMetafile = aTransformedGraphic.GetGDIMetaFile();
773 
774                             xPrimitive = Primitive2DReference(
775                                 new MetafilePrimitive2D(
776                                     aTransform,
777                                     rMetafile));
778 
779                             // #i100357# find out if clipping is needed for this primitive. Unfortunately,
780                             // there exist Metafiles who's content is bigger than the proposed PrefSize set
781                             // at them. This is an error, but we need to work around this
782                             const Size aMetaFilePrefSize(rMetafile.GetPrefSize());
783                             const Size aMetaFileRealSize(
784                                 const_cast< GDIMetaFile& >(rMetafile).GetBoundRect(
785                                     *Application::GetDefaultDevice()).GetSize());
786 
787                             if(aMetaFileRealSize.getWidth() > aMetaFilePrefSize.getWidth()
788                                 || aMetaFileRealSize.getHeight() > aMetaFilePrefSize.getHeight())
789                             {
790                                 // clipping needed. Embed to MaskPrimitive2D. Create childs and mask polygon
791                                 const primitive2d::Primitive2DSequence aChildContent(&xPrimitive, 1);
792                                 basegfx::B2DPolygon aMaskPolygon(basegfx::tools::createUnitPolygon());
793                                 aMaskPolygon.transform(aTransform);
794 
795                                 xPrimitive = Primitive2DReference(
796                                     new MaskPrimitive2D(
797                                         basegfx::B2DPolyPolygon(aMaskPolygon),
798                                         aChildContent));
799                             }
800 #ifdef USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
801                         }
802 #endif // USE_DEBUG_CODE_TO_TEST_METAFILE_DECOMPOSE
803 
804 						break;
805 					}
806 
807 					default:
808 					{
809 						// nothing to create
810 						break;
811 					}
812 				}
813 
814                 if(xPrimitive.is())
815                 {
816                     // check for cropping
817                     if(getGraphicAttr().IsCropped())
818                     {
819                         // calculate scalings between real image size and logic object size. This
820                         // is necessary since the crop values are relative to original bitmap size
821                         double fFactorX(1.0);
822                         double fFactorY(1.0);
823 
824                         {
825                             const MapMode aMapMode100thmm(MAP_100TH_MM);
826                             Size aBitmapSize(rGraphicObject.GetPrefSize());
827 
828                             // #i95968# better support PrefMapMode; special for MAP_PIXEL was missing
829                             if(MAP_PIXEL == rGraphicObject.GetPrefMapMode().GetMapUnit())
830                             {
831                                 aBitmapSize = Application::GetDefaultDevice()->PixelToLogic(aBitmapSize, aMapMode100thmm);
832                             }
833                             else
834                             {
835                                 aBitmapSize = Application::GetDefaultDevice()->LogicToLogic(aBitmapSize, rGraphicObject.GetPrefMapMode(), aMapMode100thmm);
836                             }
837 
838                             const double fDivX(aBitmapSize.Width() - getGraphicAttr().GetLeftCrop() - getGraphicAttr().GetRightCrop());
839                             const double fDivY(aBitmapSize.Height() - getGraphicAttr().GetTopCrop() - getGraphicAttr().GetBottomCrop());
840                             const basegfx::B2DVector aScale(aTransform * basegfx::B2DVector(1.0, 1.0));
841 
842                             if(!basegfx::fTools::equalZero(fDivX))
843                             {
844                                 fFactorX = fabs(aScale.getX()) / fDivX;
845                             }
846 
847                             if(!basegfx::fTools::equalZero(fDivY))
848                             {
849                                 fFactorY = fabs(aScale.getY()) / fDivY;
850                             }
851                         }
852 
853                         // embed content in cropPrimitive
854                         xPrimitive = new CropPrimitive2D(
855                             Primitive2DSequence(&xPrimitive, 1),
856                             aTransform,
857                             getGraphicAttr().GetLeftCrop() * fFactorX,
858                             getGraphicAttr().GetTopCrop() * fFactorY,
859                             getGraphicAttr().GetRightCrop() * fFactorX,
860                             getGraphicAttr().GetBottomCrop() * fFactorY);
861                     }
862 
863                     // add to decomposition
864                     appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xPrimitive);
865                 }
866 			}
867 
868 			return aRetval;
869 		}
870 
871 		GraphicPrimitive2D::GraphicPrimitive2D(
872 			const basegfx::B2DHomMatrix& rTransform,
873 			const GraphicObject& rGraphicObject,
874 			const GraphicAttr& rGraphicAttr)
875 		:	BufferedDecompositionPrimitive2D(),
876 			maTransform(rTransform),
877 			maGraphicObject(rGraphicObject),
878 			maGraphicAttr(rGraphicAttr)
879 		{
880 		}
881 
882 		GraphicPrimitive2D::GraphicPrimitive2D(
883 			const basegfx::B2DHomMatrix& rTransform,
884 			const GraphicObject& rGraphicObject)
885 		:	BufferedDecompositionPrimitive2D(),
886 			maTransform(rTransform),
887 			maGraphicObject(rGraphicObject),
888 			maGraphicAttr()
889 		{
890 		}
891 
892 		bool GraphicPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
893 		{
894 			if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
895 			{
896 				const GraphicPrimitive2D& rCompare = (GraphicPrimitive2D&)rPrimitive;
897 
898 				return (getTransform() == rCompare.getTransform()
899 					&& getGraphicObject() == rCompare.getGraphicObject()
900 					&& getGraphicAttr() == rCompare.getGraphicAttr());
901 			}
902 
903 			return false;
904 		}
905 
906 		basegfx::B2DRange GraphicPrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
907 		{
908 			basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
909 			aRetval.transform(getTransform());
910 			return aRetval;
911 		}
912 
913 		// provide unique ID
914 		ImplPrimitrive2DIDBlock(GraphicPrimitive2D, PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D)
915 
916 	} // end of namespace primitive2d
917 } // end of namespace drawinglayer
918 
919 //////////////////////////////////////////////////////////////////////////////
920 // eof
921