xref: /AOO41X/main/drawinglayer/source/processor2d/vclprocessor2d.cxx (revision 66d002e8364738f4240879a2942fc03d856dcbe7)
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/processor2d/vclprocessor2d.hxx>
28 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
29 #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
30 #include <tools/debug.hxx>
31 #include <vcl/outdev.hxx>
32 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
33 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
34 #include <vclhelperbitmaptransform.hxx>
35 #include <basegfx/polygon/b2dpolygontools.hxx>
36 #include <vclhelperbitmaprender.hxx>
37 #include <drawinglayer/attribute/sdrfillbitmapattribute.hxx>
38 #include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
39 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
40 #include <vclhelpergradient.hxx>
41 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
42 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
43 #include <basegfx/polygon/b2dpolypolygontools.hxx>
44 #include <vclhelperbufferdevice.hxx>
45 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
46 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
47 #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
48 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
49 #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
50 #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
51 #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
52 #include <svl/ctloptions.hxx>
53 #include <vcl/svapp.hxx>
54 #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
55 #include <tools/diagnose_ex.h>
56 #include <vcl/metric.hxx>
57 #include <drawinglayer/primitive2d/textenumsprimitive2d.hxx>
58 #include <drawinglayer/primitive2d/epsprimitive2d.hxx>
59 
60 //////////////////////////////////////////////////////////////////////////////
61 // control support
62 
63 #include <com/sun/star/awt/XWindow2.hpp>
64 #include <com/sun/star/awt/PosSize.hpp>
65 #include <com/sun/star/awt/XView.hpp>
66 #include <drawinglayer/primitive2d/controlprimitive2d.hxx>
67 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
68 
69 //////////////////////////////////////////////////////////////////////////////
70 // for test, can be removed again
71 
72 #include <basegfx/polygon/b2dpolygonclipper.hxx>
73 #include <basegfx/polygon/b2dtrapezoid.hxx>
74 
75 //////////////////////////////////////////////////////////////////////////////
76 
77 using namespace com::sun::star;
78 
79 //////////////////////////////////////////////////////////////////////////////
80 
81 namespace drawinglayer
82 {
83 	namespace processor2d
84 	{
85 		//////////////////////////////////////////////////////////////////////////////
86 		// UNO class usages
87 		using ::com::sun::star::uno::Reference;
88 		using ::com::sun::star::uno::UNO_QUERY;
89 	    using ::com::sun::star::uno::UNO_QUERY_THROW;
90         using ::com::sun::star::uno::Exception;
91 		using ::com::sun::star::awt::XView;
92 		using ::com::sun::star::awt::XGraphics;
93 	    using ::com::sun::star::awt::XWindow;
94 	    using ::com::sun::star::awt::PosSize::POSSIZE;
95 
96 		//////////////////////////////////////////////////////////////////////////////
97 		// rendering support
98 
99 		// directdraw of text simple portion or decorated portion primitive. When decorated, all the extra
100 		// information is translated to VCL parameters and set at the font.
101 		// Acceptance is restricted to no shearing and positive scaling in X and Y (no font mirroring
102 		// for VCL)
103 		void VclProcessor2D::RenderTextSimpleOrDecoratedPortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate)
104 		{
105             // decompose matrix to have position and size of text
106 			basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rTextCandidate.getTextTransform());
107 			basegfx::B2DVector aFontScaling, aTranslate;
108 			double fRotate, fShearX;
109 			aLocalTransform.decompose(aFontScaling, aTranslate, fRotate, fShearX);
110 			bool bPrimitiveAccepted(false);
111 
112 			if(basegfx::fTools::equalZero(fShearX))
113 			{
114 				if(basegfx::fTools::less(aFontScaling.getX(), 0.0) && basegfx::fTools::less(aFontScaling.getY(), 0.0))
115 				{
116 					// handle special case: If scale is negative in (x,y) (3rd quadrant), it can
117 					// be expressed as rotation by PI. Use this since the Font rendering will not
118                     // apply the negative scales in any form
119 					aFontScaling = basegfx::absolute(aFontScaling);
120 					fRotate += F_PI;
121 				}
122 
123 				if(basegfx::fTools::more(aFontScaling.getX(), 0.0) && basegfx::fTools::more(aFontScaling.getY(), 0.0))
124 				{
125                     // Get the VCL font (use FontHeight as FontWidth)
126                     Font aFont(primitive2d::getVclFontFromFontAttribute(
127                         rTextCandidate.getFontAttribute(),
128                         aFontScaling.getX(),
129                         aFontScaling.getY(),
130                         fRotate,
131                         rTextCandidate.getLocale()));
132 
133 					// handle additional font attributes
134 					const primitive2d::TextDecoratedPortionPrimitive2D* pTCPP =
135 						dynamic_cast<const primitive2d::TextDecoratedPortionPrimitive2D*>( &rTextCandidate );
136 
137 					if( pTCPP != NULL )
138 					{
139 
140                         // set the color of text decorations
141                         const basegfx::BColor aTextlineColor = maBColorModifierStack.getModifiedColor(pTCPP->getTextlineColor());
142                         mpOutputDevice->SetTextLineColor( Color(aTextlineColor) );
143 
144                         // set Overline attribute
145                         const FontUnderline eFontOverline(primitive2d::mapTextLineToFontUnderline( pTCPP->getFontOverline() ));
146                         if( eFontOverline != UNDERLINE_NONE )
147                         {
148                             aFont.SetOverline( eFontOverline );
149                             const basegfx::BColor aOverlineColor = maBColorModifierStack.getModifiedColor(pTCPP->getOverlineColor());
150                             mpOutputDevice->SetOverlineColor( Color(aOverlineColor) );
151                             if( pTCPP->getWordLineMode() )
152                                 aFont.SetWordLineMode( true );
153                         }
154 
155                         // set Underline attribute
156                         const FontUnderline eFontUnderline(primitive2d::mapTextLineToFontUnderline( pTCPP->getFontUnderline() ));
157                         if( eFontUnderline != UNDERLINE_NONE )
158 						{
159 							aFont.SetUnderline( eFontUnderline );
160 							if( pTCPP->getWordLineMode() )
161 								aFont.SetWordLineMode( true );
162 //TODO: ???					if( pTCPP->getUnderlineAbove() )
163 //								aFont.SetUnderlineAbove( true );
164 						}
165 
166 						// set Strikeout attribute
167 						const FontStrikeout eFontStrikeout(primitive2d::mapTextStrikeoutToFontStrikeout(pTCPP->getTextStrikeout()));
168 
169 						if( eFontStrikeout != STRIKEOUT_NONE )
170 							aFont.SetStrikeout( eFontStrikeout );
171 
172 						// set EmphasisMark attribute
173 						FontEmphasisMark eFontEmphasisMark = EMPHASISMARK_NONE;
174 						switch( pTCPP->getTextEmphasisMark() )
175 						{
176 							default:
177 								DBG_WARNING1( "DrawingLayer: Unknown EmphasisMark style (%d)!", pTCPP->getTextEmphasisMark() );
178 								// fall through
179 							case primitive2d::TEXT_EMPHASISMARK_NONE:	eFontEmphasisMark = EMPHASISMARK_NONE; break;
180 							case primitive2d::TEXT_EMPHASISMARK_DOT:	eFontEmphasisMark = EMPHASISMARK_DOT; break;
181 							case primitive2d::TEXT_EMPHASISMARK_CIRCLE:	eFontEmphasisMark = EMPHASISMARK_CIRCLE; break;
182 							case primitive2d::TEXT_EMPHASISMARK_DISC:	eFontEmphasisMark = EMPHASISMARK_DISC; break;
183 							case primitive2d::TEXT_EMPHASISMARK_ACCENT:	eFontEmphasisMark = EMPHASISMARK_ACCENT; break;
184 						}
185 
186 						if( eFontEmphasisMark != EMPHASISMARK_NONE )
187 						{
188 							DBG_ASSERT( (pTCPP->getEmphasisMarkAbove() != pTCPP->getEmphasisMarkBelow()),
189 								"DrawingLayer: Bad EmphasisMark position!" );
190 							if( pTCPP->getEmphasisMarkAbove() )
191 								eFontEmphasisMark |= EMPHASISMARK_POS_ABOVE;
192 							else
193 								eFontEmphasisMark |= EMPHASISMARK_POS_BELOW;
194 							aFont.SetEmphasisMark( eFontEmphasisMark );
195 						}
196 
197 						// set Relief attribute
198 						FontRelief eFontRelief = RELIEF_NONE;
199 						switch( pTCPP->getTextRelief() )
200 						{
201 							default:
202 								DBG_WARNING1( "DrawingLayer: Unknown Relief style (%d)!", pTCPP->getTextRelief() );
203 								// fall through
204 							case primitive2d::TEXT_RELIEF_NONE:		eFontRelief = RELIEF_NONE; break;
205 							case primitive2d::TEXT_RELIEF_EMBOSSED:	eFontRelief = RELIEF_EMBOSSED; break;
206 							case primitive2d::TEXT_RELIEF_ENGRAVED:	eFontRelief = RELIEF_ENGRAVED; break;
207 						}
208 
209 						if( eFontRelief != RELIEF_NONE )
210 							aFont.SetRelief( eFontRelief );
211 
212 						// set Shadow attribute
213 						if( pTCPP->getShadow() )
214 							aFont.SetShadow( true );
215 					}
216 
217 					// create transformed integer DXArray in view coordinate system
218 					::std::vector< sal_Int32 > aTransformedDXArray;
219 
220 					if(rTextCandidate.getDXArray().size())
221 					{
222 						aTransformedDXArray.reserve(rTextCandidate.getDXArray().size());
223 						const basegfx::B2DVector aPixelVector(maCurrentTransformation * basegfx::B2DVector(1.0, 0.0));
224 						const double fPixelVectorFactor(aPixelVector.getLength());
225 
226 						for(::std::vector< double >::const_iterator aStart(rTextCandidate.getDXArray().begin());
227                             aStart != rTextCandidate.getDXArray().end(); aStart++)
228 						{
229 							aTransformedDXArray.push_back(basegfx::fround((*aStart) * fPixelVectorFactor));
230 						}
231 					}
232 
233 					// set parameters and paint text snippet
234 					const basegfx::BColor aRGBFontColor(maBColorModifierStack.getModifiedColor(rTextCandidate.getFontColor()));
235 					const basegfx::B2DPoint aPoint(aLocalTransform * basegfx::B2DPoint(0.0, 0.0));
236 					const Point aStartPoint(basegfx::fround(aPoint.getX()), basegfx::fround(aPoint.getY()));
237                     const sal_uInt32 nOldLayoutMode(mpOutputDevice->GetLayoutMode());
238 
239                     if(rTextCandidate.getFontAttribute().getRTL())
240                     {
241                         sal_uInt32 nRTLLayoutMode(nOldLayoutMode & ~(TEXT_LAYOUT_COMPLEX_DISABLED|TEXT_LAYOUT_BIDI_STRONG));
242                         nRTLLayoutMode |= TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_TEXTORIGIN_LEFT;
243                         mpOutputDevice->SetLayoutMode(nRTLLayoutMode);
244                     }
245 
246 					mpOutputDevice->SetFont(aFont);
247 					mpOutputDevice->SetTextColor(Color(aRGBFontColor));
248 
249 					if(aTransformedDXArray.size())
250 					{
251 						mpOutputDevice->DrawTextArray(
252 							aStartPoint,
253 							rTextCandidate.getText(),
254 							&(aTransformedDXArray[0]),
255 							rTextCandidate.getTextPosition(),
256 							rTextCandidate.getTextLength());
257 					}
258 					else
259 					{
260 						mpOutputDevice->DrawText(
261 							aStartPoint,
262 							rTextCandidate.getText(),
263 							rTextCandidate.getTextPosition(),
264 							rTextCandidate.getTextLength());
265 					}
266 
267                     if(rTextCandidate.getFontAttribute().getRTL())
268                     {
269                         mpOutputDevice->SetLayoutMode(nOldLayoutMode);
270                     }
271 
272 					bPrimitiveAccepted = true;
273 				}
274 			}
275 
276 			if(!bPrimitiveAccepted)
277 			{
278 				// let break down
279 				process(rTextCandidate.get2DDecomposition(getViewInformation2D()));
280 			}
281 		}
282 
283 		// direct draw of hairline
284 		void VclProcessor2D::RenderPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate, bool bPixelBased)
285 		{
286             const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
287 			mpOutputDevice->SetLineColor(Color(aHairlineColor));
288 			mpOutputDevice->SetFillColor();
289 
290 			basegfx::B2DPolygon aLocalPolygon(rPolygonCandidate.getB2DPolygon());
291 			aLocalPolygon.transform(maCurrentTransformation);
292 
293             static bool bCheckTrapezoidDecomposition(false);
294             static bool bShowOutlinesThere(false);
295             if(bCheckTrapezoidDecomposition)
296             {
297                 // clip against discrete ViewPort
298                 const basegfx::B2DRange& rDiscreteViewport = getViewInformation2D().getDiscreteViewport();
299                 basegfx::B2DPolyPolygon aLocalPolyPolygon(basegfx::tools::clipPolygonOnRange(
300                     aLocalPolygon, rDiscreteViewport, true, false));
301 
302                 if(aLocalPolyPolygon.count())
303                 {
304                     // subdivide
305                     aLocalPolyPolygon = basegfx::tools::adaptiveSubdivideByDistance(
306                         aLocalPolyPolygon, 0.5);
307 
308                     // trapezoidize
309                     static double fLineWidth(2.0);
310                     basegfx::B2DTrapezoidVector aB2DTrapezoidVector;
311                     basegfx::tools::createLineTrapezoidFromB2DPolyPolygon(aB2DTrapezoidVector, aLocalPolyPolygon, fLineWidth);
312 
313                     const sal_uInt32 nCount(aB2DTrapezoidVector.size());
314 
315                     if(nCount)
316                     {
317                         basegfx::BColor aInvPolygonColor(aHairlineColor);
318                         aInvPolygonColor.invert();
319 
320                         for(sal_uInt32 a(0); a < nCount; a++)
321                         {
322                             const basegfx::B2DPolygon aTempPolygon(aB2DTrapezoidVector[a].getB2DPolygon());
323 
324                             if(bShowOutlinesThere)
325                             {
326                                 mpOutputDevice->SetFillColor(Color(aHairlineColor));
327 			                    mpOutputDevice->SetLineColor();
328                             }
329 
330                             mpOutputDevice->DrawPolygon(aTempPolygon);
331 
332                             if(bShowOutlinesThere)
333                             {
334                                 mpOutputDevice->SetFillColor();
335         		                mpOutputDevice->SetLineColor(Color(aInvPolygonColor));
336     	    		            mpOutputDevice->DrawPolyLine(aTempPolygon, 0.0);
337                             }
338                         }
339                     }
340                 }
341             }
342             else
343             {
344 			    if(bPixelBased && getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete())
345 			    {
346 				    // #i98289#
347 				    // when a Hairline is painted and AntiAliasing is on the option SnapHorVerLinesToDiscrete
348 				    // allows to suppress AntiAliasing for pure horizontal or vertical lines. This is done since
349 				    // not-AntiAliased such lines look more pleasing to the eye (e.g. 2D chart content). This
350 				    // NEEDS to be done in discrete coordinates, so only useful for pixel based rendering.
351 				    aLocalPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aLocalPolygon);
352 			    }
353 
354 			    mpOutputDevice->DrawPolyLine(aLocalPolygon, 0.0);
355             }
356 		}
357 
358 		// direct draw of transformed BitmapEx primitive
359 		void VclProcessor2D::RenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate)
360 		{
361             // create local transform
362 			basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rBitmapCandidate.getTransform());
363 			BitmapEx aBitmapEx(rBitmapCandidate.getBitmapEx());
364 			bool bPainted(false);
365 
366 			if(maBColorModifierStack.count())
367 			{
368 				aBitmapEx = impModifyBitmapEx(maBColorModifierStack, aBitmapEx);
369 
370 				if(aBitmapEx.IsEmpty())
371 				{
372 					// color gets completely replaced, get it
373 					const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor()));
374 					basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon());
375 					aPolygon.transform(aLocalTransform);
376 
377 					mpOutputDevice->SetFillColor(Color(aModifiedColor));
378 					mpOutputDevice->SetLineColor();
379 					mpOutputDevice->DrawPolygon(aPolygon);
380 
381 					bPainted = true;
382 				}
383 			}
384 
385 			if(!bPainted)
386 			{
387 				static bool bForceUseOfOwnTransformer(false);
388 				static bool bUseGraphicManager(true);
389 
390 				// decompose matrix to check for shear, rotate and mirroring
391 				basegfx::B2DVector aScale, aTranslate;
392 				double fRotate, fShearX;
393 				aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
394 
395 				if(!bForceUseOfOwnTransformer && basegfx::fTools::equalZero(fShearX))
396 				{
397 					if(!bUseGraphicManager && basegfx::fTools::equalZero(fRotate))
398 					{
399 						RenderBitmapPrimitive2D_BitmapEx(*mpOutputDevice, aBitmapEx, aLocalTransform);
400 					}
401 					else
402 					{
403 						RenderBitmapPrimitive2D_GraphicManager(*mpOutputDevice, aBitmapEx, aLocalTransform);
404 					}
405 				}
406 				else
407 				{
408 					if(!aBitmapEx.IsTransparent() && (!basegfx::fTools::equalZero(fShearX) || !basegfx::fTools::equalZero(fRotate)))
409 					{
410 						// parts will be uncovered, extend aBitmapEx with a mask bitmap
411 						const Bitmap aContent(aBitmapEx.GetBitmap());
412 						aBitmapEx = BitmapEx(aContent, Bitmap(aContent.GetSizePixel(), 1));
413 					}
414 
415 					RenderBitmapPrimitive2D_self(*mpOutputDevice, aBitmapEx, aLocalTransform);
416 				}
417 			}
418 		}
419 
420 		void VclProcessor2D::RenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D& rFillBitmapCandidate)
421 		{
422 			const attribute::FillBitmapAttribute& rFillBitmapAttribute(rFillBitmapCandidate.getFillBitmap());
423 			bool bPrimitiveAccepted(false);
424 
425 			if(rFillBitmapAttribute.getTiling())
426 			{
427 				// decompose matrix to check for shear, rotate and mirroring
428 				basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rFillBitmapCandidate.getTransformation());
429 				basegfx::B2DVector aScale, aTranslate;
430 				double fRotate, fShearX;
431 				aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
432 
433 				if(basegfx::fTools::equalZero(fRotate) && basegfx::fTools::equalZero(fShearX))
434 				{
435 					// no shear or rotate, draw direct in pixel coordinates
436 					bPrimitiveAccepted = true;
437 					BitmapEx aBitmapEx(rFillBitmapAttribute.getBitmapEx());
438 					bool bPainted(false);
439 
440 					if(maBColorModifierStack.count())
441 					{
442 						aBitmapEx = impModifyBitmapEx(maBColorModifierStack, aBitmapEx);
443 
444 						if(aBitmapEx.IsEmpty())
445 						{
446 							// color gets completely replaced, get it
447 							const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor()));
448 							basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon());
449 							aPolygon.transform(aLocalTransform);
450 
451 							mpOutputDevice->SetFillColor(Color(aModifiedColor));
452 							mpOutputDevice->SetLineColor();
453 							mpOutputDevice->DrawPolygon(aPolygon);
454 
455 							bPainted = true;
456 						}
457 					}
458 
459 					if(!bPainted)
460 					{
461 						const basegfx::B2DPoint aObjTopLeft(aTranslate.getX(), aTranslate.getY());
462 						const basegfx::B2DPoint aObjBottomRight(aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
463 						const Point aObjTL(mpOutputDevice->LogicToPixel(Point((sal_Int32)aObjTopLeft.getX(), (sal_Int32)aObjTopLeft.getY())));
464 						const Point aObjBR(mpOutputDevice->LogicToPixel(Point((sal_Int32)aObjBottomRight.getX(), (sal_Int32)aObjBottomRight.getY())));
465 
466 						const basegfx::B2DPoint aBmpTopLeft(aLocalTransform * rFillBitmapAttribute.getTopLeft());
467 						const basegfx::B2DPoint aBmpBottomRight(aLocalTransform * basegfx::B2DPoint(rFillBitmapAttribute.getTopLeft() + rFillBitmapAttribute.getSize()));
468 						const Point aBmpTL(mpOutputDevice->LogicToPixel(Point((sal_Int32)aBmpTopLeft.getX(), (sal_Int32)aBmpTopLeft.getY())));
469 						const Point aBmpBR(mpOutputDevice->LogicToPixel(Point((sal_Int32)aBmpBottomRight.getX(), (sal_Int32)aBmpBottomRight.getY())));
470 
471 						sal_Int32 nOWidth(aObjBR.X() - aObjTL.X());
472 						sal_Int32 nOHeight(aObjBR.Y() - aObjTL.Y());
473 
474                         // only do something when object has a size in discrete units
475 						if(nOWidth > 0 && nOHeight > 0)
476 						{
477 						    sal_Int32 nBWidth(aBmpBR.X() - aBmpTL.X());
478 						    sal_Int32 nBHeight(aBmpBR.Y() - aBmpTL.Y());
479 
480                             // only do something when bitmap fill has a size in discrete units
481 						    if(nBWidth > 0 && nBHeight > 0)
482 						    {
483 						        sal_Int32 nBLeft(aBmpTL.X());
484 						        sal_Int32 nBTop(aBmpTL.Y());
485 
486 						        if(nBLeft > aObjTL.X())
487 						        {
488 							        nBLeft -= ((nBLeft / nBWidth) + 1L) * nBWidth;
489 						        }
490 
491 						        if(nBLeft + nBWidth <= aObjTL.X())
492 						        {
493 							        nBLeft -= (nBLeft / nBWidth) * nBWidth;
494 						        }
495 
496 						        if(nBTop > aObjTL.Y())
497 						        {
498 							        nBTop -= ((nBTop / nBHeight) + 1L) * nBHeight;
499 						        }
500 
501 						        if(nBTop + nBHeight <= aObjTL.Y())
502 						        {
503 							        nBTop -= (nBTop / nBHeight) * nBHeight;
504 						        }
505 
506 						        // nBWidth, nBHeight is the pixel size of the neede bitmap. To not need to scale it
507 						        // in vcl many times, create a size-optimized version
508 						        const Size aNeededBitmapSizePixel(nBWidth, nBHeight);
509 
510 						        if(aNeededBitmapSizePixel != aBitmapEx.GetSizePixel())
511 						        {
512 							        aBitmapEx.Scale(aNeededBitmapSizePixel);
513 						        }
514 
515 						        // prepare OutDev
516 						        const Point aEmptyPoint(0, 0);
517 						        const Rectangle aVisiblePixel(aEmptyPoint, mpOutputDevice->GetOutputSizePixel());
518 						        const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled());
519 						        mpOutputDevice->EnableMapMode(false);
520 
521 						        for(sal_Int32 nXPos(nBLeft); nXPos < aObjTL.X() + nOWidth; nXPos += nBWidth)
522 						        {
523 							        for(sal_Int32 nYPos(nBTop); nYPos < aObjTL.Y() + nOHeight; nYPos += nBHeight)
524 							        {
525 								        const Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel);
526 
527 								        if(aOutRectPixel.IsOver(aVisiblePixel))
528 								        {
529 									        mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx);
530 								        }
531 							        }
532 						        }
533 
534 						        // restore OutDev
535 						        mpOutputDevice->EnableMapMode(bWasEnabled);
536                             }
537                         }
538 					}
539 				}
540 			}
541 
542 			if(!bPrimitiveAccepted)
543 			{
544 				// do not accept, use decomposition
545 				process(rFillBitmapCandidate.get2DDecomposition(getViewInformation2D()));
546 			}
547 		}
548 
549 		// direct draw of gradient
550 		void VclProcessor2D::RenderPolyPolygonGradientPrimitive2D(const primitive2d::PolyPolygonGradientPrimitive2D& rPolygonCandidate)
551 		{
552 			const attribute::FillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient());
553 			basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor()));
554 			basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor()));
555 			basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
556 
557 			if(aLocalPolyPolygon.count())
558 			{
559 				aLocalPolyPolygon.transform(maCurrentTransformation);
560 
561 				if(aStartColor == aEndColor)
562 				{
563 					// no gradient at all, draw as polygon in AA and non-AA case
564 					mpOutputDevice->SetLineColor();
565 					mpOutputDevice->SetFillColor(Color(aStartColor));
566 					mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
567 				}
568 				else if(getOptionsDrawinglayer().IsAntiAliasing())
569 				{
570 					// For AA, direct render has to be avoided since it uses XOR maskings which will not
571 					// work with AA. Instead, the decompose which uses MaskPrimitive2D with fillings is
572 					// used
573 					process(rPolygonCandidate.get2DDecomposition(getViewInformation2D()));
574 				}
575 				else
576 				{
577 					impDrawGradientToOutDev(
578 						*mpOutputDevice, aLocalPolyPolygon, rGradient.getStyle(), rGradient.getSteps(),
579 						aStartColor, aEndColor, rGradient.getBorder(),
580 						rGradient.getAngle(), rGradient.getOffsetX(), rGradient.getOffsetY(), false);
581 				}
582 			}
583 		}
584 
585 		// direct draw of bitmap
586 		void VclProcessor2D::RenderPolyPolygonBitmapPrimitive2D(const primitive2d::PolyPolygonBitmapPrimitive2D& rPolygonCandidate)
587 		{
588 			bool bDone(false);
589 			const basegfx::B2DPolyPolygon& rPolyPolygon = rPolygonCandidate.getB2DPolyPolygon();
590 
591 			if(rPolyPolygon.count())
592 			{
593 				const attribute::FillBitmapAttribute& rFillBitmapAttribute = rPolygonCandidate.getFillBitmap();
594 				const BitmapEx& rBitmapEx = rFillBitmapAttribute.getBitmapEx();
595 
596 				if(rBitmapEx.IsEmpty())
597 				{
598 					// empty bitmap, done
599 					bDone = true;
600 				}
601 				else
602 				{
603 					// try to catch cases where the bitmap will be color-modified to a single
604 					// color (e.g. shadow). This would NOT be optimizable with an transparence channel
605 					// at the Bitmap which we do not have here. When this should change, this
606 					// optimization has to be reworked accordingly.
607 					const sal_uInt32 nBColorModifierStackCount(maBColorModifierStack.count());
608 
609 					if(nBColorModifierStackCount)
610 					{
611 						const basegfx::BColorModifier& rTopmostModifier = maBColorModifierStack.getBColorModifier(nBColorModifierStackCount - 1);
612 
613 						if(basegfx::BCOLORMODIFYMODE_REPLACE == rTopmostModifier.getMode())
614 						{
615 							// the bitmap fill is in unified color, so we can replace it with
616 							// a single polygon fill. The form of the fill depends on tiling
617 							if(rFillBitmapAttribute.getTiling())
618 							{
619 								// with tiling, fill the whole PolyPolygon with the modifier color
620 								basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolyPolygon);
621 
622 								aLocalPolyPolygon.transform(maCurrentTransformation);
623 								mpOutputDevice->SetLineColor();
624 								mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor()));
625 								mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
626 							}
627 							else
628 							{
629 								// without tiling, only the area common to the bitmap tile and the
630 								// PolyPolygon is filled. Create the bitmap tile area in object
631 								// coordinates. For this, the object transformation needs to be created
632 								// from the already scaled PolyPolygon. The tile area in object
633 								// coordinates wil always be non-rotated, so it's not necessary to
634 								// work with a polygon here
635 								basegfx::B2DRange aTileRange(rFillBitmapAttribute.getTopLeft(),
636 									rFillBitmapAttribute.getTopLeft() + rFillBitmapAttribute.getSize());
637 								const basegfx::B2DRange aPolyPolygonRange(rPolyPolygon.getB2DRange());
638 								basegfx::B2DHomMatrix aNewObjectTransform;
639 
640 								aNewObjectTransform.set(0, 0, aPolyPolygonRange.getWidth());
641 								aNewObjectTransform.set(1, 1, aPolyPolygonRange.getHeight());
642 								aNewObjectTransform.set(0, 2, aPolyPolygonRange.getMinX());
643 								aNewObjectTransform.set(1, 2, aPolyPolygonRange.getMinY());
644 								aTileRange.transform(aNewObjectTransform);
645 
646 								// now clip the object polyPolygon against the tile range
647 								// to get the common area (OR)
648 								basegfx::B2DPolyPolygon aTarget = basegfx::tools::clipPolyPolygonOnRange(rPolyPolygon, aTileRange, true, false);
649 
650 								if(aTarget.count())
651 								{
652 									aTarget.transform(maCurrentTransformation);
653 									mpOutputDevice->SetLineColor();
654 									mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor()));
655 									mpOutputDevice->DrawPolyPolygon(aTarget);
656 								}
657 							}
658 
659 							bDone = true;
660 						}
661 					}
662 				}
663 			}
664 			else
665 			{
666 				// empty polyPolygon, done
667 				bDone = true;
668 			}
669 
670 			if(!bDone)
671 			{
672 				// use default decomposition
673 				process(rPolygonCandidate.get2DDecomposition(getViewInformation2D()));
674 			}
675 		}
676 
677 		// direct draw of PolyPolygon with color
678 		void VclProcessor2D::RenderPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate)
679 		{
680 			const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
681 			mpOutputDevice->SetFillColor(Color(aPolygonColor));
682 			mpOutputDevice->SetLineColor();
683 
684 			basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
685 			aLocalPolyPolygon.transform(maCurrentTransformation);
686 
687             static bool bCheckTrapezoidDecomposition(false);
688             static bool bShowOutlinesThere(false);
689             if(bCheckTrapezoidDecomposition)
690             {
691                 // clip against discrete ViewPort
692                 const basegfx::B2DRange& rDiscreteViewport = getViewInformation2D().getDiscreteViewport();
693                 aLocalPolyPolygon = basegfx::tools::clipPolyPolygonOnRange(
694                     aLocalPolyPolygon, rDiscreteViewport, true, false);
695 
696                 if(aLocalPolyPolygon.count())
697                 {
698                     // subdivide
699                     aLocalPolyPolygon = basegfx::tools::adaptiveSubdivideByDistance(
700                         aLocalPolyPolygon, 0.5);
701 
702                     // trapezoidize
703                     basegfx::B2DTrapezoidVector aB2DTrapezoidVector;
704                     basegfx::tools::trapezoidSubdivide(aB2DTrapezoidVector, aLocalPolyPolygon);
705 
706                     const sal_uInt32 nCount(aB2DTrapezoidVector.size());
707 
708                     if(nCount)
709                     {
710                         basegfx::BColor aInvPolygonColor(aPolygonColor);
711                         aInvPolygonColor.invert();
712 
713                         for(sal_uInt32 a(0); a < nCount; a++)
714                         {
715                             const basegfx::B2DPolygon aTempPolygon(aB2DTrapezoidVector[a].getB2DPolygon());
716 
717                             if(bShowOutlinesThere)
718                             {
719                                 mpOutputDevice->SetFillColor(Color(aPolygonColor));
720 			                    mpOutputDevice->SetLineColor();
721                             }
722 
723                             mpOutputDevice->DrawPolygon(aTempPolygon);
724 
725                             if(bShowOutlinesThere)
726                             {
727                                 mpOutputDevice->SetFillColor();
728         		                mpOutputDevice->SetLineColor(Color(aInvPolygonColor));
729     	    		            mpOutputDevice->DrawPolyLine(aTempPolygon, 0.0);
730                             }
731                         }
732                     }
733                 }
734             }
735             else
736             {
737 			    mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
738 
739                 if(mnPolygonStrokePrimitive2D
740                     && getOptionsDrawinglayer().IsAntiAliasing()
741                     && (mpOutputDevice->GetAntialiasing() & ANTIALIASING_ENABLE_B2DDRAW))
742                 {
743                     // when AA is on and this filled polygons are the result of stroked line geometry,
744                     // draw the geometry once extra as lines to avoid AA 'gaps' between partial polygons
745 			        mpOutputDevice->SetFillColor();
746 			        mpOutputDevice->SetLineColor(Color(aPolygonColor));
747                     const sal_uInt32 nCount(aLocalPolyPolygon.count());
748 
749                     for(sal_uInt32 a(0); a < nCount; a++)
750                     {
751                         mpOutputDevice->DrawPolyLine(aLocalPolyPolygon.getB2DPolygon(a), 0.0);
752                     }
753                 }
754             }
755 		}
756 
757 		// direct draw of MetaFile
758 		void VclProcessor2D::RenderMetafilePrimitive2D(const primitive2d::MetafilePrimitive2D& rMetaCandidate)
759 		{
760 			// decompose matrix to check for shear, rotate and mirroring
761 			basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rMetaCandidate.getTransform());
762 			basegfx::B2DVector aScale, aTranslate;
763 			double fRotate, fShearX;
764 			aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
765 
766 			if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0))
767 			{
768 				// #i102175# handle special case: If scale is negative in (x,y) (3rd quadrant), it can
769 				// be expressed as rotation by PI. This needs to be done for Metafiles since
770                 // these can be rotated, but not really mirrored
771 				aScale = basegfx::absolute(aScale);
772 				fRotate += F_PI;
773 			}
774 
775             // get BoundRect
776 			basegfx::B2DRange aOutlineRange(rMetaCandidate.getB2DRange(getViewInformation2D()));
777 			aOutlineRange.transform(maCurrentTransformation);
778 
779 			// Due to the integer MapModes used from VCL aind inside MetaFiles errors of up to three
780 			// pixels in size may happen. As long as there is no better way (e.g. convert the MetaFile
781 			// to primitives) it is necessary to reduce maximum pixel size by 1 in X and Y and to use
782 			// the inner pixel bounds accordingly (ceil resp. floor). This will also be done for logic
783 			// units e.g. when creating a new MetaFile, but since much huger value ranges are used
784 			// there typically will be okay for this compromize.
785 			Rectangle aDestRectView(
786                 // !!CAUTION!! Here, ceil and floor are exchanged BY PURPOSE, do NOT copy when
787                 // looking for a standard conversion to rectangle (!)
788 				(sal_Int32)ceil(aOutlineRange.getMinX()), (sal_Int32)ceil(aOutlineRange.getMinY()),
789 				(sal_Int32)floor(aOutlineRange.getMaxX()), (sal_Int32)floor(aOutlineRange.getMaxY()));
790 
791 			// get metafile (copy it)
792 			GDIMetaFile aMetaFile;
793 
794 			if(maBColorModifierStack.count())
795 			{
796 				const basegfx::BColor aRGBBaseColor(0, 0, 0);
797 				const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor));
798 				aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor));
799 			}
800 			else
801 			{
802 				aMetaFile = rMetaCandidate.getMetaFile();
803 			}
804 
805 			// rotation
806 			if(!basegfx::fTools::equalZero(fRotate))
807 			{
808                 // #i103530#
809                 // MetaFile::Rotate has no input parameter check, so the parameter needs to be
810                 // well-aligned to the old range [0..3600] 10th degrees with inverse orientation
811 				sal_Int16 nRotation((sal_Int16)((fRotate / F_PI180) * -10.0));
812 
813                 while(nRotation < 0)
814                     nRotation += 3600;
815 
816                 while(nRotation >= 3600)
817                     nRotation -= 3600;
818 
819 				aMetaFile.Rotate(nRotation);
820 			}
821 
822 			// Prepare target output size
823 			Size aDestSize(aDestRectView.GetSize());
824 
825 			if(aDestSize.getWidth() && aDestSize.getHeight())
826 			{
827 				// Get preferred Metafile output size. When it's very equal to the output size, it's probably
828 				// a rounding error somewhere, so correct it to get a 1:1 output without single pixel scalings
829 				// of the Metafile (esp. for contaned Bitmaps, e.g 3D charts)
830 				const Size aPrefSize(mpOutputDevice->LogicToPixel(aMetaFile.GetPrefSize(), aMetaFile.GetPrefMapMode()));
831 
832 				if(aPrefSize.getWidth() && (aPrefSize.getWidth() - 1 == aDestSize.getWidth() || aPrefSize.getWidth() + 1 == aDestSize.getWidth()))
833 				{
834 					aDestSize.setWidth(aPrefSize.getWidth());
835 				}
836 
837 				if(aPrefSize.getHeight() && (aPrefSize.getHeight() - 1 == aDestSize.getHeight() || aPrefSize.getHeight() + 1 == aDestSize.getHeight()))
838 				{
839 					aDestSize.setHeight(aPrefSize.getHeight());
840 				}
841 
842 				// paint it
843 				aMetaFile.WindStart();
844 				aMetaFile.Play(mpOutputDevice, aDestRectView.TopLeft(), aDestSize);
845 			}
846 		}
847 
848 		// mask group. Force output to VDev and create mask from given mask
849 		void VclProcessor2D::RenderMaskPrimitive2DPixel(const primitive2d::MaskPrimitive2D& rMaskCandidate)
850 		{
851 			if(rMaskCandidate.getChildren().hasElements())
852 			{
853 				basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
854 
855 				if(aMask.count())
856 				{
857 					aMask.transform(maCurrentTransformation);
858 					const basegfx::B2DRange aRange(basegfx::tools::getRange(aMask));
859 					impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true);
860 
861 					if(aBufferDevice.isVisible())
862 					{
863 						// remember last OutDev and set to content
864 						OutputDevice* pLastOutputDevice = mpOutputDevice;
865 						mpOutputDevice = &aBufferDevice.getContent();
866 
867 						// paint to it
868 						process(rMaskCandidate.getChildren());
869 
870 						// back to old OutDev
871 						mpOutputDevice = pLastOutputDevice;
872 
873 					    // draw mask
874                         if(getOptionsDrawinglayer().IsAntiAliasing())
875                         {
876                             // with AA, use 8bit AlphaMask to get nice borders
877 						    VirtualDevice& rTransparence = aBufferDevice.getTransparence();
878 						    rTransparence.SetLineColor();
879 						    rTransparence.SetFillColor(COL_BLACK);
880 						    rTransparence.DrawPolyPolygon(aMask);
881 
882 						    // dump buffer to outdev
883 						    aBufferDevice.paint();
884                         }
885                         else
886                         {
887                             // No AA, use 1bit mask
888 						    VirtualDevice& rMask = aBufferDevice.getMask();
889 						    rMask.SetLineColor();
890 						    rMask.SetFillColor(COL_BLACK);
891 						    rMask.DrawPolyPolygon(aMask);
892 
893 						    // dump buffer to outdev
894 						    aBufferDevice.paint();
895                         }
896 					}
897 				}
898 			}
899 		}
900 
901 		// modified color group. Force output to unified color.
902 		void VclProcessor2D::RenderModifiedColorPrimitive2D(const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate)
903 		{
904 			if(rModifiedCandidate.getChildren().hasElements())
905 			{
906 				maBColorModifierStack.push(rModifiedCandidate.getColorModifier());
907 				process(rModifiedCandidate.getChildren());
908 				maBColorModifierStack.pop();
909 			}
910 		}
911 
912 		// unified sub-transparence. Draw to VDev first.
913 		void VclProcessor2D::RenderUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rTransCandidate)
914 		{
915             static bool bForceToDecomposition(false);
916 
917             if(rTransCandidate.getChildren().hasElements())
918             {
919                 if(bForceToDecomposition)
920                 {
921     			    // use decomposition
922 	    		    process(rTransCandidate.get2DDecomposition(getViewInformation2D()));
923                 }
924                 else
925                 {
926 			        if(0.0 == rTransCandidate.getTransparence())
927 			        {
928 				        // no transparence used, so just use the content
929     	    		    process(rTransCandidate.getChildren());
930 			        }
931 			        else if(rTransCandidate.getTransparence() > 0.0 && rTransCandidate.getTransparence() < 1.0)
932 			        {
933                         // transparence is in visible range
934 				        basegfx::B2DRange aRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rTransCandidate.getChildren(), getViewInformation2D()));
935 				        aRange.transform(maCurrentTransformation);
936 				        impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true);
937 
938 				        if(aBufferDevice.isVisible())
939 				        {
940 					        // remember last OutDev and set to content
941 					        OutputDevice* pLastOutputDevice = mpOutputDevice;
942 					        mpOutputDevice = &aBufferDevice.getContent();
943 
944 					        // paint content to it
945 					        process(rTransCandidate.getChildren());
946 
947 					        // back to old OutDev
948 					        mpOutputDevice = pLastOutputDevice;
949 
950 					        // dump buffer to outdev using given transparence
951 					        aBufferDevice.paint(rTransCandidate.getTransparence());
952 				        }
953 			        }
954                 }
955             }
956 		}
957 
958 		// sub-transparence group. Draw to VDev first.
959 		void VclProcessor2D::RenderTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D& rTransCandidate)
960 		{
961 			if(rTransCandidate.getChildren().hasElements())
962 			{
963 				basegfx::B2DRange aRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rTransCandidate.getChildren(), getViewInformation2D()));
964 				aRange.transform(maCurrentTransformation);
965 				impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true);
966 
967 				if(aBufferDevice.isVisible())
968 				{
969 					// remember last OutDev and set to content
970 					OutputDevice* pLastOutputDevice = mpOutputDevice;
971 					mpOutputDevice = &aBufferDevice.getContent();
972 
973 					// paint content to it
974 					process(rTransCandidate.getChildren());
975 
976 					// set to mask
977 					mpOutputDevice = &aBufferDevice.getTransparence();
978 
979 					// when painting transparence masks, reset the color stack
980 					basegfx::BColorModifierStack aLastBColorModifierStack(maBColorModifierStack);
981 					maBColorModifierStack = basegfx::BColorModifierStack();
982 
983 					// paint mask to it (always with transparence intensities, evtl. with AA)
984 					process(rTransCandidate.getTransparence());
985 
986 					// back to old color stack
987 					maBColorModifierStack = aLastBColorModifierStack;
988 
989 					// back to old OutDev
990 					mpOutputDevice = pLastOutputDevice;
991 
992 					// dump buffer to outdev
993 					aBufferDevice.paint();
994 				}
995 			}
996 		}
997 
998 		// transform group.
999 		void VclProcessor2D::RenderTransformPrimitive2D(const primitive2d::TransformPrimitive2D& rTransformCandidate)
1000 		{
1001 			// remember current transformation and ViewInformation
1002 			const basegfx::B2DHomMatrix aLastCurrentTransformation(maCurrentTransformation);
1003             const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
1004 
1005 			// create new transformations for CurrentTransformation
1006             // and for local ViewInformation2D
1007 			maCurrentTransformation = maCurrentTransformation * rTransformCandidate.getTransformation();
1008             const geometry::ViewInformation2D aViewInformation2D(
1009                 getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(),
1010                 getViewInformation2D().getViewTransformation(),
1011                 getViewInformation2D().getViewport(),
1012 				getViewInformation2D().getVisualizedPage(),
1013                 getViewInformation2D().getViewTime(),
1014 				getViewInformation2D().getExtendedInformationSequence());
1015 			updateViewInformation(aViewInformation2D);
1016 
1017 			// proccess content
1018 			process(rTransformCandidate.getChildren());
1019 
1020 			// restore transformations
1021 			maCurrentTransformation = aLastCurrentTransformation;
1022             updateViewInformation(aLastViewInformation2D);
1023 		}
1024 
1025 		// new XDrawPage for ViewInformation2D
1026 		void VclProcessor2D::RenderPagePreviewPrimitive2D(const primitive2d::PagePreviewPrimitive2D& rPagePreviewCandidate)
1027 		{
1028 			// remember current transformation and ViewInformation
1029             const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
1030 
1031 			// create new local ViewInformation2D
1032             const geometry::ViewInformation2D aViewInformation2D(
1033                 getViewInformation2D().getObjectTransformation(),
1034                 getViewInformation2D().getViewTransformation(),
1035                 getViewInformation2D().getViewport(),
1036 				rPagePreviewCandidate.getXDrawPage(),
1037                 getViewInformation2D().getViewTime(),
1038 				getViewInformation2D().getExtendedInformationSequence());
1039 			updateViewInformation(aViewInformation2D);
1040 
1041 			// proccess decomposed content
1042 			process(rPagePreviewCandidate.get2DDecomposition(getViewInformation2D()));
1043 
1044 			// restore transformations
1045             updateViewInformation(aLastViewInformation2D);
1046 		}
1047 
1048 		// marker
1049 		void VclProcessor2D::RenderMarkerArrayPrimitive2D(const primitive2d::MarkerArrayPrimitive2D& rMarkArrayCandidate)
1050 		{
1051             static bool bCheckCompleteMarkerDecompose(false);
1052             if(bCheckCompleteMarkerDecompose)
1053             {
1054 			    process(rMarkArrayCandidate.get2DDecomposition(getViewInformation2D()));
1055                 return;
1056             }
1057 
1058 			// get data
1059 	        const std::vector< basegfx::B2DPoint >& rPositions = rMarkArrayCandidate.getPositions();
1060 			const sal_uInt32 nCount(rPositions.size());
1061 
1062 			if(nCount && !rMarkArrayCandidate.getMarker().IsEmpty())
1063 			{
1064 				// get pixel size
1065 				const BitmapEx& rMarker(rMarkArrayCandidate.getMarker());
1066 				const Size aBitmapSize(rMarker.GetSizePixel());
1067 
1068 				if(aBitmapSize.Width() && aBitmapSize.Height())
1069 				{
1070 					// get discrete half size
1071 					const basegfx::B2DVector aDiscreteHalfSize(
1072                         (aBitmapSize.getWidth() - 1.0) * 0.5,
1073                         (aBitmapSize.getHeight() - 1.0) * 0.5);
1074 			        const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled());
1075 
1076                     // do not forget evtl. moved origin in target device MapMode when
1077                     // switching it off; it would be missing and lead to wrong positions.
1078                     // All his could be done using logic sizes and coordinates, too, but
1079                     // we want a 1:1 bitmap rendering here, so it's more safe and faster
1080                     // to work with switching off MapMode usage completely.
1081                     const Point aOrigin(mpOutputDevice->GetMapMode().GetOrigin());
1082 
1083                     mpOutputDevice->EnableMapMode(false);
1084 
1085 					for(std::vector< basegfx::B2DPoint >::const_iterator aIter(rPositions.begin()); aIter != rPositions.end(); aIter++)
1086 				    {
1087 					    const basegfx::B2DPoint aDiscreteTopLeft((maCurrentTransformation * (*aIter)) - aDiscreteHalfSize);
1088                         const Point aDiscretePoint(basegfx::fround(aDiscreteTopLeft.getX()), basegfx::fround(aDiscreteTopLeft.getY()));
1089 
1090 						mpOutputDevice->DrawBitmapEx(aDiscretePoint + aOrigin, rMarker);
1091 					}
1092 
1093 			        mpOutputDevice->EnableMapMode(bWasEnabled);
1094 				}
1095 			}
1096 		}
1097 
1098 		// point
1099 		void VclProcessor2D::RenderPointArrayPrimitive2D(const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate)
1100 		{
1101 			const std::vector< basegfx::B2DPoint >& rPositions = rPointArrayCandidate.getPositions();
1102 			const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rPointArrayCandidate.getRGBColor()));
1103 			const Color aVCLColor(aRGBColor);
1104 
1105 			for(std::vector< basegfx::B2DPoint >::const_iterator aIter(rPositions.begin()); aIter != rPositions.end(); aIter++)
1106 			{
1107 				const basegfx::B2DPoint aViewPosition(maCurrentTransformation * (*aIter));
1108 				const Point aPos(basegfx::fround(aViewPosition.getX()), basegfx::fround(aViewPosition.getY()));
1109 
1110 				mpOutputDevice->DrawPixel(aPos, aVCLColor);
1111 			}
1112 		}
1113 
1114 		void VclProcessor2D::RenderPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokeCandidate)
1115 		{
1116             // #i101491# method restructured to clearly use the DrawPolyLine
1117             // calls starting from a deined line width
1118 			const attribute::LineAttribute& rLineAttribute = rPolygonStrokeCandidate.getLineAttribute();
1119 			const double fLineWidth(rLineAttribute.getWidth());
1120 			bool bDone(false);
1121 
1122 			if(basegfx::fTools::more(fLineWidth, 0.0))
1123 			{
1124 				const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(fLineWidth, 0.0));
1125 				const double fDiscreteLineWidth(aDiscreteUnit.getLength());
1126 				const attribute::StrokeAttribute& rStrokeAttribute = rPolygonStrokeCandidate.getStrokeAttribute();
1127 				const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor()));
1128 				basegfx::B2DPolyPolygon aHairlinePolyPolygon;
1129 
1130 				mpOutputDevice->SetLineColor(Color(aHairlineColor));
1131 				mpOutputDevice->SetFillColor();
1132 
1133 				if(0.0 == rStrokeAttribute.getFullDotDashLen())
1134 				{
1135 					// no line dashing, just copy
1136 					aHairlinePolyPolygon.append(rPolygonStrokeCandidate.getB2DPolygon());
1137 				}
1138 				else
1139 				{
1140 					// else apply LineStyle
1141 					basegfx::tools::applyLineDashing(rPolygonStrokeCandidate.getB2DPolygon(),
1142 						rStrokeAttribute.getDotDashArray(),
1143 						&aHairlinePolyPolygon, 0, rStrokeAttribute.getFullDotDashLen());
1144 				}
1145 
1146 				const sal_uInt32 nCount(aHairlinePolyPolygon.count());
1147 
1148 				if(nCount)
1149 				{
1150                     const bool bAntiAliased(getOptionsDrawinglayer().IsAntiAliasing());
1151         			aHairlinePolyPolygon.transform(maCurrentTransformation);
1152 
1153                     for(sal_uInt32 a(0); a < nCount; a++)
1154 				    {
1155 					    basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a));
1156 
1157                         if(bAntiAliased)
1158                         {
1159 						    if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 1.0))
1160                             {
1161                                 // line in range ]0.0 .. 1.0[
1162                                 // paint as simple hairline
1163 							    mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
1164 								bDone = true;
1165                             }
1166 						    else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 2.0))
1167                             {
1168                                 // line in range [1.0 .. 2.0[
1169                                 // paint as 2x2 with dynamic line distance
1170 							    basegfx::B2DHomMatrix aMat;
1171                                 const double fDistance(fDiscreteLineWidth - 1.0);
1172                                 const double fHalfDistance(fDistance * 0.5);
1173 
1174 			                    aMat.set(0, 2, -fHalfDistance);
1175 			                    aMat.set(1, 2, -fHalfDistance);
1176                                 aCandidate.transform(aMat);
1177 			                    mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
1178 
1179 			                    aMat.set(0, 2, fDistance);
1180 			                    aMat.set(1, 2, 0.0);
1181                                 aCandidate.transform(aMat);
1182 			                    mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
1183 
1184 			                    aMat.set(0, 2, 0.0);
1185 			                    aMat.set(1, 2, fDistance);
1186                                 aCandidate.transform(aMat);
1187 			                    mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
1188 
1189 			                    aMat.set(0, 2, -fDistance);
1190 			                    aMat.set(1, 2, 0.0);
1191                                 aCandidate.transform(aMat);
1192 			                    mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
1193 								bDone = true;
1194                             }
1195                             else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 3.0))
1196                             {
1197                                 // line in range [2.0 .. 3.0]
1198                                 // paint as cross in a 3x3  with dynamic line distance
1199 							    basegfx::B2DHomMatrix aMat;
1200                                 const double fDistance((fDiscreteLineWidth - 1.0) * 0.5);
1201 
1202                                 mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
1203 
1204                                 aMat.set(0, 2, -fDistance);
1205 			                    aMat.set(1, 2, 0.0);
1206                                 aCandidate.transform(aMat);
1207 			                    mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
1208 
1209                                 aMat.set(0, 2, fDistance);
1210 			                    aMat.set(1, 2, -fDistance);
1211                                 aCandidate.transform(aMat);
1212 			                    mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
1213 
1214                                 aMat.set(0, 2, fDistance);
1215 			                    aMat.set(1, 2, fDistance);
1216                                 aCandidate.transform(aMat);
1217 			                    mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
1218 
1219                                 aMat.set(0, 2, -fDistance);
1220 			                    aMat.set(1, 2, fDistance);
1221                                 aCandidate.transform(aMat);
1222 			                    mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
1223 								bDone = true;
1224                             }
1225                             else
1226                             {
1227                                 // #i101491# line width above 3.0
1228                             }
1229                         }
1230                         else
1231                         {
1232 						    if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 1.5))
1233                             {
1234 							    // line width below 1.5, draw the basic hairline polygon
1235 							    mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
1236 								bDone = true;
1237                             }
1238                             else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 2.5))
1239                             {
1240 							    // line width is in range ]1.5 .. 2.5], use four hairlines
1241 							    // drawn in a square
1242 							    basegfx::B2DHomMatrix aMat;
1243 							    mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
1244 
1245 							    aMat.set(0, 2, 1.0);
1246 							    aMat.set(1, 2, 0.0);
1247 							    aCandidate.transform(aMat);
1248 
1249 							    mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
1250 
1251 							    aMat.set(0, 2, 0.0);
1252 							    aMat.set(1, 2, 1.0);
1253 							    aCandidate.transform(aMat);
1254 
1255 							    mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
1256 
1257 							    aMat.set(0, 2, -1.0);
1258 							    aMat.set(1, 2, 0.0);
1259 							    aCandidate.transform(aMat);
1260 
1261 							    mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
1262 								bDone = true;
1263                             }
1264                             else
1265                             {
1266                                 // #i101491# line width is above 2.5
1267                             }
1268                         }
1269 
1270 						if(!bDone && rPolygonStrokeCandidate.getB2DPolygon().count() > 1000)
1271 						{
1272                             // #i101491# If the polygon complexity uses more than a given amount, do
1273 							// use OuputDevice::DrawPolyLine directly; this will avoid buffering all
1274 							// decompositions in primtives (memory) and fallback to old line painting
1275 							// for very complex polygons, too
1276 		                    mpOutputDevice->DrawPolyLine(aCandidate, fDiscreteLineWidth, rLineAttribute.getLineJoin());
1277 							bDone = true;
1278 						}
1279                     }
1280                 }
1281             }
1282 
1283 			if(!bDone)
1284             {
1285                 // remeber that we enter a PolygonStrokePrimitive2D decomposition,
1286                 // used for AA thick line drawing
1287                 mnPolygonStrokePrimitive2D++;
1288 
1289                 // line width is big enough for standard filled polygon visualisation or zero
1290 				process(rPolygonStrokeCandidate.get2DDecomposition(getViewInformation2D()));
1291 
1292                 // leave PolygonStrokePrimitive2D
1293                 mnPolygonStrokePrimitive2D--;
1294             }
1295 		}
1296 
1297         void VclProcessor2D::RenderEpsPrimitive2D(const primitive2d::EpsPrimitive2D& rEpsPrimitive2D)
1298         {
1299             // The new decomposition of Metafiles made it necessary to add an Eps
1300             // primitive to handle embedded Eps data. On some devices, this can be
1301             // painted directly (mac, printer).
1302             // To be able to handle the replacement correctly, i need to handle it myself
1303             // since DrawEPS will not be able e.g. to rotate the replacement. To be able
1304             // to do that, i added a boolean return to OutputDevice::DrawEPS(..)
1305             // to know when EPS was handled directly already.
1306 			basegfx::B2DRange aRange(0.0, 0.0, 1.0, 1.0);
1307             aRange.transform(maCurrentTransformation * rEpsPrimitive2D.getEpsTransform());
1308 
1309             if(!aRange.isEmpty())
1310             {
1311                 const Rectangle aRectangle(
1312 				    (sal_Int32)floor(aRange.getMinX()), (sal_Int32)floor(aRange.getMinY()),
1313 				    (sal_Int32)ceil(aRange.getMaxX()), (sal_Int32)ceil(aRange.getMaxY()));
1314 
1315                 if(!aRectangle.IsEmpty())
1316                 {
1317                     // try to paint EPS directly without fallback visualisation
1318                     const bool bEPSPaintedDirectly(mpOutputDevice->DrawEPS(
1319                         aRectangle.TopLeft(),
1320                         aRectangle.GetSize(),
1321                         rEpsPrimitive2D.getGfxLink(),
1322                         0));
1323 
1324                     if(!bEPSPaintedDirectly)
1325                     {
1326                         // use the decomposition which will correctly handle the
1327                         // fallback visualisation using full transformation (e.g. rotation)
1328         				process(rEpsPrimitive2D.get2DDecomposition(getViewInformation2D()));
1329                     }
1330                 }
1331             }
1332         }
1333 
1334 		void VclProcessor2D::adaptLineToFillDrawMode() const
1335 		{
1336 			const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
1337 
1338 			if(nOriginalDrawMode & (DRAWMODE_BLACKLINE|DRAWMODE_GRAYLINE|DRAWMODE_GHOSTEDLINE|DRAWMODE_WHITELINE|DRAWMODE_SETTINGSLINE))
1339 			{
1340 				sal_uInt32 nAdaptedDrawMode(nOriginalDrawMode);
1341 
1342 				if(nOriginalDrawMode & DRAWMODE_BLACKLINE)
1343 				{
1344 					nAdaptedDrawMode |= DRAWMODE_BLACKFILL;
1345 				}
1346 				else
1347 				{
1348 					nAdaptedDrawMode &= ~DRAWMODE_BLACKFILL;
1349 				}
1350 
1351 				if(nOriginalDrawMode & DRAWMODE_GRAYLINE)
1352 				{
1353 					nAdaptedDrawMode |= DRAWMODE_GRAYFILL;
1354 				}
1355 				else
1356 				{
1357 					nAdaptedDrawMode &= ~DRAWMODE_GRAYFILL;
1358 				}
1359 
1360 				if(nOriginalDrawMode & DRAWMODE_GHOSTEDLINE)
1361 				{
1362 					nAdaptedDrawMode |= DRAWMODE_GHOSTEDFILL;
1363 				}
1364 				else
1365 				{
1366 					nAdaptedDrawMode &= ~DRAWMODE_GHOSTEDFILL;
1367 				}
1368 
1369 				if(nOriginalDrawMode & DRAWMODE_WHITELINE)
1370 				{
1371 					nAdaptedDrawMode |= DRAWMODE_WHITEFILL;
1372 				}
1373 				else
1374 				{
1375 					nAdaptedDrawMode &= ~DRAWMODE_WHITEFILL;
1376 				}
1377 
1378 				if(nOriginalDrawMode & DRAWMODE_SETTINGSLINE)
1379 				{
1380 					nAdaptedDrawMode |= DRAWMODE_SETTINGSFILL;
1381 				}
1382 				else
1383 				{
1384 					nAdaptedDrawMode &= ~DRAWMODE_SETTINGSFILL;
1385 				}
1386 
1387 				mpOutputDevice->SetDrawMode(nAdaptedDrawMode);
1388 			}
1389 		}
1390 
1391 		void VclProcessor2D::adaptTextToFillDrawMode() const
1392 		{
1393 			const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
1394 			if(nOriginalDrawMode & (DRAWMODE_BLACKTEXT|DRAWMODE_GRAYTEXT|DRAWMODE_GHOSTEDTEXT|DRAWMODE_WHITETEXT|DRAWMODE_SETTINGSTEXT))
1395 			{
1396 				sal_uInt32 nAdaptedDrawMode(nOriginalDrawMode);
1397 
1398 				if(nOriginalDrawMode & DRAWMODE_BLACKTEXT)
1399 				{
1400 					nAdaptedDrawMode |= DRAWMODE_BLACKFILL;
1401 				}
1402 				else
1403 				{
1404 					nAdaptedDrawMode &= ~DRAWMODE_BLACKFILL;
1405 				}
1406 
1407 				if(nOriginalDrawMode & DRAWMODE_GRAYTEXT)
1408 				{
1409 					nAdaptedDrawMode |= DRAWMODE_GRAYFILL;
1410 				}
1411 				else
1412 				{
1413 					nAdaptedDrawMode &= ~DRAWMODE_GRAYFILL;
1414 				}
1415 
1416 				if(nOriginalDrawMode & DRAWMODE_GHOSTEDTEXT)
1417 				{
1418 					nAdaptedDrawMode |= DRAWMODE_GHOSTEDFILL;
1419 				}
1420 				else
1421 				{
1422 					nAdaptedDrawMode &= ~DRAWMODE_GHOSTEDFILL;
1423 				}
1424 
1425 				if(nOriginalDrawMode & DRAWMODE_WHITETEXT)
1426 				{
1427 					nAdaptedDrawMode |= DRAWMODE_WHITEFILL;
1428 				}
1429 				else
1430 				{
1431 					nAdaptedDrawMode &= ~DRAWMODE_WHITEFILL;
1432 				}
1433 
1434 				if(nOriginalDrawMode & DRAWMODE_SETTINGSTEXT)
1435 				{
1436 					nAdaptedDrawMode |= DRAWMODE_SETTINGSFILL;
1437 				}
1438 				else
1439 				{
1440 					nAdaptedDrawMode &= ~DRAWMODE_SETTINGSFILL;
1441 				}
1442 
1443 				mpOutputDevice->SetDrawMode(nAdaptedDrawMode);
1444 			}
1445 		}
1446 
1447 		//////////////////////////////////////////////////////////////////////////////
1448 		// process support
1449 
1450 		VclProcessor2D::VclProcessor2D(
1451 			const geometry::ViewInformation2D& rViewInformation,
1452 			OutputDevice& rOutDev)
1453 		:	BaseProcessor2D(rViewInformation),
1454 			mpOutputDevice(&rOutDev),
1455 			maBColorModifierStack(),
1456 			maCurrentTransformation(),
1457 			maDrawinglayerOpt(),
1458             mnPolygonStrokePrimitive2D(0)
1459 		{
1460             // set digit language, derived from SvtCTLOptions to have the correct
1461             // number display for arabic/hindi numerals
1462             const SvtCTLOptions aSvtCTLOptions;
1463             LanguageType eLang(LANGUAGE_SYSTEM);
1464 
1465             if(SvtCTLOptions::NUMERALS_HINDI == aSvtCTLOptions.GetCTLTextNumerals())
1466             {
1467                 eLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
1468             }
1469             else if(SvtCTLOptions::NUMERALS_ARABIC == aSvtCTLOptions.GetCTLTextNumerals())
1470             {
1471                 eLang = LANGUAGE_ENGLISH;
1472             }
1473             else
1474             {
1475                 eLang = (LanguageType)Application::GetSettings().GetLanguage();
1476             }
1477 
1478             rOutDev.SetDigitLanguage(eLang);
1479 		}
1480 
1481 		VclProcessor2D::~VclProcessor2D()
1482 		{
1483 		}
1484 	} // end of namespace processor2d
1485 } // end of namespace drawinglayer
1486 
1487 //////////////////////////////////////////////////////////////////////////////
1488 // eof
1489