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