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