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