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