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