1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
5 * $RCSfile: vclprocessor2d.cxx,v $
7 * The Contents of this file are made available subject to
8 * the terms of GNU Lesser General Public License Version 2.1.
11 * GNU Lesser General Public License Version 2.1
12 * =============================================
13 * Copyright 2005 by Sun Microsystems, Inc.
14 * 901 San Antonio Road, Palo Alto, CA 94303, USA
16 * This library is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Lesser General Public
18 * License version 2.1, as published by the Free Software Foundation.
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
30 ************************************************************************/
32 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "precompiled_drawinglayer.hxx"
35 #include <drawinglayer/processor2d/vclprocessor2d.hxx>
36 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
37 #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
38 #include <tools/debug.hxx>
39 #include <vcl/outdev.hxx>
40 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
41 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
42 #include <vclhelperbitmaptransform.hxx>
43 #include <basegfx/polygon/b2dpolygontools.hxx>
44 #include <vclhelperbitmaprender.hxx>
45 #include <drawinglayer/attribute/sdrfillbitmapattribute.hxx>
46 #include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
47 #include <drawinglayer/attribute/fillattribute.hxx>
48 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
49 #include <vclhelpergradient.hxx>
50 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
51 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
52 #include <basegfx/polygon/b2dpolypolygontools.hxx>
53 #include <vclhelperbufferdevice.hxx>
54 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
55 #include <drawinglayer/primitive2d/unifiedalphaprimitive2d.hxx>
56 #include <drawinglayer/primitive2d/alphaprimitive2d.hxx>
57 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
58 #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
59 #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
60 #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
61 #include <svtools/ctloptions.hxx>
62 #include <vcl/svapp.hxx>
63 #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
64 #include <tools/diagnose_ex.h>
65 #include <vcl/metric.hxx>
67 //////////////////////////////////////////////////////////////////////////////
70 #include <com/sun/star/awt/XWindow2.hpp>
71 #include <com/sun/star/awt/PosSize.hpp>
72 #include <com/sun/star/awt/XView.hpp>
73 #include <drawinglayer/primitive2d/controlprimitive2d.hxx>
74 #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
76 //////////////////////////////////////////////////////////////////////////////
77 // for test, can be removed again
79 #include <basegfx/polygon/b2dpolygonclipper.hxx>
81 //////////////////////////////////////////////////////////////////////////////
83 using namespace com::sun::star
;
85 //////////////////////////////////////////////////////////////////////////////
87 namespace drawinglayer
91 //////////////////////////////////////////////////////////////////////////////
93 using ::com::sun::star::uno::Reference
;
94 using ::com::sun::star::uno::UNO_QUERY
;
95 using ::com::sun::star::uno::UNO_QUERY_THROW
;
96 using ::com::sun::star::uno::Exception
;
97 using ::com::sun::star::awt::XView
;
98 using ::com::sun::star::awt::XGraphics
;
99 using ::com::sun::star::awt::XWindow
;
100 using ::com::sun::star::awt::PosSize::POSSIZE
;
102 static FontUnderline
mapTextLineStyle(primitive2d::FontUnderline eLineStyle
)
107 DBG_WARNING1( "DrawingLayer: Unknown text line style attribute (%d)!", eLineStyle
);
109 case primitive2d::FONT_UNDERLINE_NONE
: return UNDERLINE_NONE
;
110 case primitive2d::FONT_UNDERLINE_SINGLE
: return UNDERLINE_SINGLE
;
111 case primitive2d::FONT_UNDERLINE_DOUBLE
: return UNDERLINE_DOUBLE
;
112 case primitive2d::FONT_UNDERLINE_DOTTED
: return UNDERLINE_DOTTED
;
113 case primitive2d::FONT_UNDERLINE_DASH
: return UNDERLINE_DASH
;
114 case primitive2d::FONT_UNDERLINE_LONGDASH
: return UNDERLINE_LONGDASH
;
115 case primitive2d::FONT_UNDERLINE_DASHDOT
: return UNDERLINE_DASHDOT
;
116 case primitive2d::FONT_UNDERLINE_DASHDOTDOT
: return UNDERLINE_DASHDOTDOT
;
117 case primitive2d::FONT_UNDERLINE_SMALLWAVE
: return UNDERLINE_SMALLWAVE
;
118 case primitive2d::FONT_UNDERLINE_WAVE
: return UNDERLINE_WAVE
;
119 case primitive2d::FONT_UNDERLINE_DOUBLEWAVE
: return UNDERLINE_DOUBLEWAVE
;
120 case primitive2d::FONT_UNDERLINE_BOLD
: return UNDERLINE_BOLD
;
121 case primitive2d::FONT_UNDERLINE_BOLDDOTTED
: return UNDERLINE_BOLDDOTTED
;
122 case primitive2d::FONT_UNDERLINE_BOLDDASH
: return UNDERLINE_BOLDDASH
;
123 case primitive2d::FONT_UNDERLINE_BOLDLONGDASH
: return UNDERLINE_LONGDASH
;
124 case primitive2d::FONT_UNDERLINE_BOLDDASHDOT
: return UNDERLINE_BOLDDASHDOT
;
125 case primitive2d::FONT_UNDERLINE_BOLDDASHDOTDOT
:return UNDERLINE_BOLDDASHDOT
;
126 case primitive2d::FONT_UNDERLINE_BOLDWAVE
: return UNDERLINE_BOLDWAVE
;
130 //////////////////////////////////////////////////////////////////////////////
133 // directdraw of text simple portion or decorated portion primitive. When decorated, all the extra
134 // information is translated to VCL parameters and set at the font.
135 // Acceptance is restricted to no shearing and positive scaling in X and Y (no font mirroring
137 void VclProcessor2D::RenderTextSimpleOrDecoratedPortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D
& rTextCandidate
)
139 // decompose matrix to have position and size of text
140 basegfx::B2DHomMatrix
aLocalTransform(maCurrentTransformation
* rTextCandidate
.getTextTransform());
141 basegfx::B2DVector aScale
, aTranslate
;
142 double fRotate
, fShearX
;
143 aLocalTransform
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
144 bool bPrimitiveAccepted(false);
146 if(basegfx::fTools::equalZero(fShearX
))
148 if(basegfx::fTools::less(aScale
.getX(), 0.0) && basegfx::fTools::less(aScale
.getY(), 0.0))
150 // handle special case: If scale is negative in (x,y) (3rd quadrant), it can
151 // be expressed as rotation by PI
152 aScale
= basegfx::absolute(aScale
);
156 if(basegfx::fTools::more(aScale
.getX(), 0.0) && basegfx::fTools::more(aScale
.getY(), 0.0))
158 // #i96581# Get the font forced without FontStretching (use FontHeight as FontWidth)
159 Font
aFont(primitive2d::getVclFontFromFontAttributes(
160 rTextCandidate
.getFontAttributes(),
162 // #i100373# FontScaling
164 // There are two different definitions for unscaled fonts, (1) 0==width and
165 // (2) height==width where (2) is the more modern one supported on all non-WIN32
166 // systems and (1) is the old one coming from WIN16-VCL definitions where
167 // that ominous FontWidth (available over FontMetric) is involved. While
168 // WIN32 only supports (1), all other systems support (2). When on WIN32, the
169 // support for (1) is ensured inside getVclFontFromFontAttributes.
171 // The former usage of (2) leads to problems when it is used on non-WIN32 systems
172 // and exported to MetaFile FontActions where the scale is taken over unseen. When
173 // such a MetaFile is imported on a WIN32-System supporting (1), all fonts are
174 // seen as scaled an look wrong.
176 // The simplest and fastest solution is to fallback to (1) independent from the
177 // system we are running on.
179 // The best solution would be a system-independent Y-value just expressing the
180 // font scaling, e.g. when (2) is used and width == height, use 1.0 as Y-Value,
181 // which would also solve the involved ominous FontWidth value for WIN32-systems.
182 // This is a region which needs redesign urgently.
188 rTextCandidate
.getLocale(),
191 if(!basegfx::fTools::equal(aScale
.getX(), aScale
.getY()))
193 // #100424# We have a hint on FontScaling here. To decide a look
194 // at the pure font's scale is needed, since e.g. SC uses unequally scaled
195 // MapModes (was: #i96581#, but use available full precision from primitive
196 // now). aTranslate and fShearX can be reused since no longer needed.
197 basegfx::B2DVector aFontScale
;
199 rTextCandidate
.getTextTransform().decompose(aFontScale
, aTranslate
, fFontRotate
, fShearX
);
201 if(!basegfx::fTools::equal(aFontScale
.getX(), aFontScale
.getY()))
203 // indeed a FontScaling. Set at Font. Use the combined scale
205 aFont
= primitive2d::getVclFontFromFontAttributes(
206 rTextCandidate
.getFontAttributes(),
210 rTextCandidate
.getLocale(),
215 // handle additional font attributes
216 const primitive2d::TextDecoratedPortionPrimitive2D
* pTCPP
=
217 dynamic_cast<const primitive2d::TextDecoratedPortionPrimitive2D
*>( &rTextCandidate
);
222 // set the color of text decorations
223 const basegfx::BColor aTextlineColor
= maBColorModifierStack
.getModifiedColor(pTCPP
->getTextlineColor());
224 mpOutputDevice
->SetTextLineColor( Color(aTextlineColor
) );
226 // set Overline attribute
227 FontUnderline eFontOverline
= mapTextLineStyle( pTCPP
->getFontOverline() );
228 if( eFontOverline
!= UNDERLINE_NONE
)
230 aFont
.SetOverline( eFontOverline
);
231 const basegfx::BColor aOverlineColor
= maBColorModifierStack
.getModifiedColor(pTCPP
->getOverlineColor());
232 mpOutputDevice
->SetOverlineColor( Color(aOverlineColor
) );
233 if( pTCPP
->getWordLineMode() )
234 aFont
.SetWordLineMode( true );
237 // set Underline attribute
238 FontUnderline eFontUnderline
= mapTextLineStyle( pTCPP
->getFontUnderline() );
239 if( eFontUnderline
!= UNDERLINE_NONE
)
241 aFont
.SetUnderline( eFontUnderline
);
242 if( pTCPP
->getWordLineMode() )
243 aFont
.SetWordLineMode( true );
244 //TODO: ??? if( pTCPP->getUnderlineAbove() )
245 // aFont.SetUnderlineAbove( true );
248 // set Strikeout attribute
249 FontStrikeout eFontStrikeout
= STRIKEOUT_NONE
;
250 switch( pTCPP
->getFontStrikeout() )
253 DBG_WARNING1( "DrawingLayer: Unknown strikeout attribute (%d)!", pTCPP
->getFontStrikeout() );
255 case primitive2d::FONT_STRIKEOUT_NONE
: eFontStrikeout
= STRIKEOUT_NONE
; break;
256 case primitive2d::FONT_STRIKEOUT_SINGLE
: eFontStrikeout
= STRIKEOUT_SINGLE
; break;
257 case primitive2d::FONT_STRIKEOUT_DOUBLE
: eFontStrikeout
= STRIKEOUT_DOUBLE
; break;
258 case primitive2d::FONT_STRIKEOUT_BOLD
: eFontStrikeout
= STRIKEOUT_BOLD
; break;
259 case primitive2d::FONT_STRIKEOUT_SLASH
: eFontStrikeout
= STRIKEOUT_SLASH
; break;
260 case primitive2d::FONT_STRIKEOUT_X
: eFontStrikeout
= STRIKEOUT_X
; break;
263 if( eFontStrikeout
!= STRIKEOUT_NONE
)
264 aFont
.SetStrikeout( eFontStrikeout
);
266 // set EmphasisMark attribute
267 FontEmphasisMark eFontEmphasisMark
= EMPHASISMARK_NONE
;
268 switch( pTCPP
->getFontEmphasisMark() )
271 DBG_WARNING1( "DrawingLayer: Unknown EmphasisMark style (%d)!", pTCPP
->getFontEmphasisMark() );
273 case primitive2d::FONT_EMPHASISMARK_NONE
: eFontEmphasisMark
= EMPHASISMARK_NONE
; break;
274 case primitive2d::FONT_EMPHASISMARK_DOT
: eFontEmphasisMark
= EMPHASISMARK_DOT
; break;
275 case primitive2d::FONT_EMPHASISMARK_CIRCLE
: eFontEmphasisMark
= EMPHASISMARK_CIRCLE
; break;
276 case primitive2d::FONT_EMPHASISMARK_DISC
: eFontEmphasisMark
= EMPHASISMARK_DISC
; break;
277 case primitive2d::FONT_EMPHASISMARK_ACCENT
: eFontEmphasisMark
= EMPHASISMARK_ACCENT
; break;
280 if( eFontEmphasisMark
!= EMPHASISMARK_NONE
)
282 DBG_ASSERT( (pTCPP
->getEmphasisMarkAbove() != pTCPP
->getEmphasisMarkBelow()),
283 "DrawingLayer: Bad EmphasisMark position!" );
284 if( pTCPP
->getEmphasisMarkAbove() )
285 eFontEmphasisMark
|= EMPHASISMARK_POS_ABOVE
;
287 eFontEmphasisMark
|= EMPHASISMARK_POS_BELOW
;
288 aFont
.SetEmphasisMark( eFontEmphasisMark
);
291 // set Relief attribute
292 FontRelief eFontRelief
= RELIEF_NONE
;
293 switch( pTCPP
->getFontRelief() )
296 DBG_WARNING1( "DrawingLayer: Unknown Relief style (%d)!", pTCPP
->getFontRelief() );
298 case primitive2d::FONT_RELIEF_NONE
: eFontRelief
= RELIEF_NONE
; break;
299 case primitive2d::FONT_RELIEF_EMBOSSED
: eFontRelief
= RELIEF_EMBOSSED
; break;
300 case primitive2d::FONT_RELIEF_ENGRAVED
: eFontRelief
= RELIEF_ENGRAVED
; break;
303 if( eFontRelief
!= RELIEF_NONE
)
304 aFont
.SetRelief( eFontRelief
);
306 // set Shadow attribute
307 if( pTCPP
->getShadow() )
308 aFont
.SetShadow( true );
311 // create transformed integer DXArray in view coordinate system
312 ::std::vector
< sal_Int32
> aTransformedDXArray
;
314 if(rTextCandidate
.getDXArray().size())
316 aTransformedDXArray
.reserve(rTextCandidate
.getDXArray().size());
317 const basegfx::B2DVector
aPixelVector(aLocalTransform
* basegfx::B2DVector(1.0, 0.0));
318 const double fPixelVectorFactor(aPixelVector
.getLength());
320 for(::std::vector
< double >::const_iterator
aStart(rTextCandidate
.getDXArray().begin()); aStart
!= rTextCandidate
.getDXArray().end(); aStart
++)
322 aTransformedDXArray
.push_back(basegfx::fround((*aStart
) * fPixelVectorFactor
));
326 // set parameters and paint text snippet
327 const basegfx::BColor
aRGBFontColor(maBColorModifierStack
.getModifiedColor(rTextCandidate
.getFontColor()));
328 const basegfx::B2DPoint
aPoint(aLocalTransform
* basegfx::B2DPoint(0.0, 0.0));
329 const Point
aStartPoint(basegfx::fround(aPoint
.getX()), basegfx::fround(aPoint
.getY()));
330 const sal_uInt32
nOldLayoutMode(mpOutputDevice
->GetLayoutMode());
332 if(rTextCandidate
.getFontAttributes().getRTL())
334 sal_uInt32
nRTLLayoutMode(nOldLayoutMode
& ~(TEXT_LAYOUT_COMPLEX_DISABLED
|TEXT_LAYOUT_BIDI_STRONG
));
335 nRTLLayoutMode
|= TEXT_LAYOUT_BIDI_RTL
|TEXT_LAYOUT_TEXTORIGIN_LEFT
;
336 mpOutputDevice
->SetLayoutMode(nRTLLayoutMode
);
339 mpOutputDevice
->SetFont(aFont
);
340 mpOutputDevice
->SetTextColor(Color(aRGBFontColor
));
342 if(aTransformedDXArray
.size())
344 mpOutputDevice
->DrawTextArray(
346 rTextCandidate
.getText(),
347 &(aTransformedDXArray
[0]),
348 rTextCandidate
.getTextPosition(),
349 rTextCandidate
.getTextLength());
353 mpOutputDevice
->DrawText(
355 rTextCandidate
.getText(),
356 rTextCandidate
.getTextPosition(),
357 rTextCandidate
.getTextLength());
360 if(rTextCandidate
.getFontAttributes().getRTL())
362 mpOutputDevice
->SetLayoutMode(nOldLayoutMode
);
365 bPrimitiveAccepted
= true;
369 if(!bPrimitiveAccepted
)
372 process(rTextCandidate
.get2DDecomposition(getViewInformation2D()));
376 // direct draw of hairline
377 void VclProcessor2D::RenderPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D
& rPolygonCandidate
, bool bPixelBased
)
379 const basegfx::BColor
aHairlineColor(maBColorModifierStack
.getModifiedColor(rPolygonCandidate
.getBColor()));
380 mpOutputDevice
->SetLineColor(Color(aHairlineColor
));
381 mpOutputDevice
->SetFillColor();
383 basegfx::B2DPolygon
aLocalPolygon(rPolygonCandidate
.getB2DPolygon());
384 aLocalPolygon
.transform(maCurrentTransformation
);
386 if(bPixelBased
&& getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete())
389 // when a Hairline is painted and AntiAliasing is on the option SnapHorVerLinesToDiscrete
390 // allows to suppress AntiAliasing for pure horizontal or vertical lines. This is done since
391 // not-AntiAliased such lines look more pleasing to the eye (e.g. 2D chart content). This
392 // NEEDS to be done in discrete coordinates, so only useful for pixel based rendering.
393 aLocalPolygon
= basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aLocalPolygon
);
396 mpOutputDevice
->DrawPolyLine(aLocalPolygon
, 0.0);
399 // direct draw of transformed BitmapEx primitive
400 void VclProcessor2D::RenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D
& rBitmapCandidate
)
402 // create local transform
403 basegfx::B2DHomMatrix
aLocalTransform(maCurrentTransformation
* rBitmapCandidate
.getTransform());
404 BitmapEx
aBitmapEx(rBitmapCandidate
.getBitmapEx());
405 bool bPainted(false);
407 if(maBColorModifierStack
.count())
409 aBitmapEx
= impModifyBitmapEx(maBColorModifierStack
, aBitmapEx
);
411 if(aBitmapEx
.IsEmpty())
413 // color gets completely replaced, get it
414 const basegfx::BColor
aModifiedColor(maBColorModifierStack
.getModifiedColor(basegfx::BColor()));
415 basegfx::B2DPolygon
aPolygon(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0)));
416 aPolygon
.transform(aLocalTransform
);
418 mpOutputDevice
->SetFillColor(Color(aModifiedColor
));
419 mpOutputDevice
->SetLineColor();
420 mpOutputDevice
->DrawPolygon(aPolygon
);
428 static bool bForceUseOfOwnTransformer(false);
429 static bool bUseGraphicManager(true);
431 // decompose matrix to check for shear, rotate and mirroring
432 basegfx::B2DVector aScale
, aTranslate
;
433 double fRotate
, fShearX
;
434 aLocalTransform
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
436 if(!bForceUseOfOwnTransformer
&& basegfx::fTools::equalZero(fShearX
))
438 if(!bUseGraphicManager
&& basegfx::fTools::equalZero(fRotate
))
440 RenderBitmapPrimitive2D_BitmapEx(*mpOutputDevice
, aBitmapEx
, aLocalTransform
);
444 RenderBitmapPrimitive2D_GraphicManager(*mpOutputDevice
, aBitmapEx
, aLocalTransform
);
449 if(!aBitmapEx
.IsTransparent() && (!basegfx::fTools::equalZero(fShearX
) || !basegfx::fTools::equalZero(fRotate
)))
451 // parts will be uncovered, extend aBitmapEx with a mask bitmap
452 const Bitmap
aContent(aBitmapEx
.GetBitmap());
453 aBitmapEx
= BitmapEx(aContent
, Bitmap(aContent
.GetSizePixel(), 1));
456 RenderBitmapPrimitive2D_self(*mpOutputDevice
, aBitmapEx
, aLocalTransform
);
461 void VclProcessor2D::RenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D
& rFillBitmapCandidate
)
463 const attribute::FillBitmapAttribute
& rFillBitmapAttribute(rFillBitmapCandidate
.getFillBitmap());
464 bool bPrimitiveAccepted(false);
466 if(rFillBitmapAttribute
.getTiling())
468 // decompose matrix to check for shear, rotate and mirroring
469 basegfx::B2DHomMatrix
aLocalTransform(maCurrentTransformation
* rFillBitmapCandidate
.getTransformation());
470 basegfx::B2DVector aScale
, aTranslate
;
471 double fRotate
, fShearX
;
472 aLocalTransform
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
474 if(basegfx::fTools::equalZero(fRotate
) && basegfx::fTools::equalZero(fShearX
))
476 // no shear or rotate, draw direct in pixel coordinates
477 bPrimitiveAccepted
= true;
478 BitmapEx
aBitmapEx(rFillBitmapAttribute
.getBitmap());
479 bool bPainted(false);
481 if(maBColorModifierStack
.count())
483 aBitmapEx
= impModifyBitmapEx(maBColorModifierStack
, aBitmapEx
);
485 if(aBitmapEx
.IsEmpty())
487 // color gets completely replaced, get it
488 const basegfx::BColor
aModifiedColor(maBColorModifierStack
.getModifiedColor(basegfx::BColor()));
489 basegfx::B2DPolygon
aPolygon(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0)));
490 aPolygon
.transform(aLocalTransform
);
492 mpOutputDevice
->SetFillColor(Color(aModifiedColor
));
493 mpOutputDevice
->SetLineColor();
494 mpOutputDevice
->DrawPolygon(aPolygon
);
502 const basegfx::B2DPoint
aObjTopLeft(aTranslate
.getX(), aTranslate
.getY());
503 const basegfx::B2DPoint
aObjBottomRight(aTranslate
.getX() + aScale
.getX(), aTranslate
.getY() + aScale
.getY());
504 const Point
aObjTL(mpOutputDevice
->LogicToPixel(Point((sal_Int32
)aObjTopLeft
.getX(), (sal_Int32
)aObjTopLeft
.getY())));
505 const Point
aObjBR(mpOutputDevice
->LogicToPixel(Point((sal_Int32
)aObjBottomRight
.getX(), (sal_Int32
)aObjBottomRight
.getY())));
507 const basegfx::B2DPoint
aBmpTopLeft(aLocalTransform
* rFillBitmapAttribute
.getTopLeft());
508 const basegfx::B2DPoint
aBmpBottomRight(aLocalTransform
* basegfx::B2DPoint(rFillBitmapAttribute
.getTopLeft() + rFillBitmapAttribute
.getSize()));
509 const Point
aBmpTL(mpOutputDevice
->LogicToPixel(Point((sal_Int32
)aBmpTopLeft
.getX(), (sal_Int32
)aBmpTopLeft
.getY())));
510 const Point
aBmpBR(mpOutputDevice
->LogicToPixel(Point((sal_Int32
)aBmpBottomRight
.getX(), (sal_Int32
)aBmpBottomRight
.getY())));
512 sal_Int32
nOWidth(aObjBR
.X() - aObjTL
.X());
513 sal_Int32
nOHeight(aObjBR
.Y() - aObjTL
.Y());
515 // only do something when object has a size in discrete units
516 if(nOWidth
> 0 && nOHeight
> 0)
518 sal_Int32
nBWidth(aBmpBR
.X() - aBmpTL
.X());
519 sal_Int32
nBHeight(aBmpBR
.Y() - aBmpTL
.Y());
521 // only do something when bitmap fill has a size in discrete units
522 if(nBWidth
> 0 && nBHeight
> 0)
524 sal_Int32
nBLeft(aBmpTL
.X());
525 sal_Int32
nBTop(aBmpTL
.Y());
527 if(nBLeft
> aObjTL
.X())
529 nBLeft
-= ((nBLeft
/ nBWidth
) + 1L) * nBWidth
;
532 if(nBLeft
+ nBWidth
<= aObjTL
.X())
534 nBLeft
-= (nBLeft
/ nBWidth
) * nBWidth
;
537 if(nBTop
> aObjTL
.Y())
539 nBTop
-= ((nBTop
/ nBHeight
) + 1L) * nBHeight
;
542 if(nBTop
+ nBHeight
<= aObjTL
.Y())
544 nBTop
-= (nBTop
/ nBHeight
) * nBHeight
;
547 // nBWidth, nBHeight is the pixel size of the neede bitmap. To not need to scale it
548 // in vcl many times, create a size-optimized version
549 const Size
aNeededBitmapSizePixel(nBWidth
, nBHeight
);
551 if(aNeededBitmapSizePixel
!= aBitmapEx
.GetSizePixel())
553 aBitmapEx
.Scale(aNeededBitmapSizePixel
);
557 const Point
aEmptyPoint(0, 0);
558 const Rectangle
aVisiblePixel(aEmptyPoint
, mpOutputDevice
->GetOutputSizePixel());
559 const bool bWasEnabled(mpOutputDevice
->IsMapModeEnabled());
560 mpOutputDevice
->EnableMapMode(false);
562 for(sal_Int32
nXPos(nBLeft
); nXPos
< aObjTL
.X() + nOWidth
; nXPos
+= nBWidth
)
564 for(sal_Int32
nYPos(nBTop
); nYPos
< aObjTL
.Y() + nOHeight
; nYPos
+= nBHeight
)
566 const Rectangle
aOutRectPixel(Point(nXPos
, nYPos
), aNeededBitmapSizePixel
);
568 if(aOutRectPixel
.IsOver(aVisiblePixel
))
570 mpOutputDevice
->DrawBitmapEx(aOutRectPixel
.TopLeft(), aBitmapEx
);
576 mpOutputDevice
->EnableMapMode(bWasEnabled
);
583 if(!bPrimitiveAccepted
)
585 // do not accept, use decomposition
586 process(rFillBitmapCandidate
.get2DDecomposition(getViewInformation2D()));
590 // direct draw of gradient
591 void VclProcessor2D::RenderPolyPolygonGradientPrimitive2D(const primitive2d::PolyPolygonGradientPrimitive2D
& rPolygonCandidate
)
593 const attribute::FillGradientAttribute
& rGradient(rPolygonCandidate
.getFillGradient());
594 basegfx::BColor
aStartColor(maBColorModifierStack
.getModifiedColor(rGradient
.getStartColor()));
595 basegfx::BColor
aEndColor(maBColorModifierStack
.getModifiedColor(rGradient
.getEndColor()));
596 basegfx::B2DPolyPolygon
aLocalPolyPolygon(rPolygonCandidate
.getB2DPolyPolygon());
597 aLocalPolyPolygon
.transform(maCurrentTransformation
);
599 if(aStartColor
== aEndColor
)
601 // no gradient at all, draw as polygon
602 mpOutputDevice
->SetLineColor();
603 mpOutputDevice
->SetFillColor(Color(aStartColor
));
604 mpOutputDevice
->DrawPolyPolygon(aLocalPolyPolygon
);
608 impDrawGradientToOutDev(
609 *mpOutputDevice
, aLocalPolyPolygon
, rGradient
.getStyle(), rGradient
.getSteps(),
610 aStartColor
, aEndColor
, rGradient
.getBorder(),
611 -rGradient
.getAngle(), rGradient
.getOffsetX(), rGradient
.getOffsetY(), false);
615 // direct draw of PolyPolygon with color
616 void VclProcessor2D::RenderPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D
& rPolygonCandidate
)
618 const basegfx::BColor
aPolygonColor(maBColorModifierStack
.getModifiedColor(rPolygonCandidate
.getBColor()));
619 mpOutputDevice
->SetFillColor(Color(aPolygonColor
));
620 mpOutputDevice
->SetLineColor();
622 basegfx::B2DPolyPolygon
aLocalPolyPolygon(rPolygonCandidate
.getB2DPolyPolygon());
623 aLocalPolyPolygon
.transform(maCurrentTransformation
);
624 mpOutputDevice
->DrawPolyPolygon(aLocalPolyPolygon
);
626 if(mnPolygonStrokePrimitive2D
&& getOptionsDrawinglayer().IsAntiAliasing())
628 // when AA is on and this filled polygons are the result of stroked line geometry,
629 // draw the geometry once extra as lines to avoid AA 'gaps' between partial polygons
630 mpOutputDevice
->SetFillColor();
631 mpOutputDevice
->SetLineColor(Color(aPolygonColor
));
632 const sal_uInt32
nCount(aLocalPolyPolygon
.count());
634 for(sal_uInt32
a(0); a
< nCount
; a
++)
636 mpOutputDevice
->DrawPolyLine(aLocalPolyPolygon
.getB2DPolygon(a
), 0.0);
640 static bool bTestPolygonClipping(false);
641 if(bTestPolygonClipping
)
643 static bool bInside(true);
644 static bool bFilled(false);
645 static bool bLine(false);
647 basegfx::B2DRange
aRange(aLocalPolyPolygon
.getB2DRange());
648 aRange
.grow(aRange
.getWidth() * -0.1);
652 basegfx::B2DPolyPolygon
aFilledClipped(basegfx::tools::clipPolyPolygonOnRange(aLocalPolyPolygon
, aRange
, bInside
, false));
653 basegfx::BColor
aRand(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0);
654 mpOutputDevice
->SetFillColor(Color(aRand
));
655 mpOutputDevice
->SetLineColor();
656 mpOutputDevice
->DrawPolyPolygon(aFilledClipped
);
661 basegfx::B2DPolyPolygon
aLineClipped(basegfx::tools::clipPolyPolygonOnRange(aLocalPolyPolygon
, aRange
, bInside
, true));
662 basegfx::BColor
aRand(rand() / 32767.0, rand() / 32767.0, rand() / 32767.0);
663 mpOutputDevice
->SetFillColor();
664 mpOutputDevice
->SetLineColor(Color(aRand
));
666 for(sal_uInt32
a(0); a
< aLineClipped
.count(); a
++)
668 mpOutputDevice
->DrawPolyLine(aLineClipped
.getB2DPolygon(a
), 0.0);
674 // direct draw of MetaFile
675 void VclProcessor2D::RenderMetafilePrimitive2D(const primitive2d::MetafilePrimitive2D
& rMetaCandidate
)
677 // decompose matrix to check for shear, rotate and mirroring
678 basegfx::B2DHomMatrix
aLocalTransform(maCurrentTransformation
* rMetaCandidate
.getTransform());
679 basegfx::B2DVector aScale
, aTranslate
;
680 double fRotate
, fShearX
;
681 aLocalTransform
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
683 if(basegfx::fTools::less(aScale
.getX(), 0.0) && basegfx::fTools::less(aScale
.getY(), 0.0))
685 // #i102175# handle special case: If scale is negative in (x,y) (3rd quadrant), it can
686 // be expressed as rotation by PI. This needs to be done for Metafiles since
687 // these can be rotated, but not really mirrored
688 aScale
= basegfx::absolute(aScale
);
693 basegfx::B2DRange
aOutlineRange(rMetaCandidate
.getB2DRange(getViewInformation2D()));
694 aOutlineRange
.transform(maCurrentTransformation
);
696 // Due to the integer MapModes used from VCL aind inside MetaFiles errors of up to three
697 // pixels in size may happen. As long as there is no better way (e.g. convert the MetaFile
698 // to primitives) it is necessary to reduce maximum pixel size by 1 in X and Y and to use
699 // the inner pixel bounds accordingly (ceil resp. floor). This will also be done for logic
700 // units e.g. when creating a new MetaFile, but since much huger value ranges are used
701 // there typically will be okay for this compromize.
702 Rectangle
aDestRectView(
703 // !!CAUTION!! Here, ceil and floor are exchanged BY PURPOSE, do NOT copy when
704 // looking for a standard conversion to rectangle (!)
705 (sal_Int32
)ceil(aOutlineRange
.getMinX()), (sal_Int32
)ceil(aOutlineRange
.getMinY()),
706 (sal_Int32
)floor(aOutlineRange
.getMaxX()), (sal_Int32
)floor(aOutlineRange
.getMaxY()));
708 // get metafile (copy it)
709 GDIMetaFile aMetaFile
;
711 if(maBColorModifierStack
.count())
713 const basegfx::BColor
aRGBBaseColor(0, 0, 0);
714 const basegfx::BColor
aRGBColor(maBColorModifierStack
.getModifiedColor(aRGBBaseColor
));
715 aMetaFile
= rMetaCandidate
.getMetaFile().GetMonochromeMtf(Color(aRGBColor
));
719 aMetaFile
= rMetaCandidate
.getMetaFile();
723 if(!basegfx::fTools::equalZero(fRotate
))
726 // MetaFile::Rotate has no input parameter check, so the parameter needs to be
727 // well-aligned to the old range [0..3600] 10th degrees with inverse orientation
728 sal_Int16
nRotation((sal_Int16
)((fRotate
/ F_PI180
) * -10.0));
733 while(nRotation
>= 3600)
736 aMetaFile
.Rotate(nRotation
);
739 // Prepare target output size
740 Size
aDestSize(aDestRectView
.GetSize());
742 if(aDestSize
.getWidth() && aDestSize
.getHeight())
744 // Get preferred Metafile output size. When it's very equal to the output size, it's probably
745 // a rounding error somewhere, so correct it to get a 1:1 output without single pixel scalings
746 // of the Metafile (esp. for contaned Bitmaps, e.g 3D charts)
747 const Size
aPrefSize(mpOutputDevice
->LogicToPixel(aMetaFile
.GetPrefSize(), aMetaFile
.GetPrefMapMode()));
749 if(aPrefSize
.getWidth() && (aPrefSize
.getWidth() - 1 == aDestSize
.getWidth() || aPrefSize
.getWidth() + 1 == aDestSize
.getWidth()))
751 aDestSize
.setWidth(aPrefSize
.getWidth());
754 if(aPrefSize
.getHeight() && (aPrefSize
.getHeight() - 1 == aDestSize
.getHeight() || aPrefSize
.getHeight() + 1 == aDestSize
.getHeight()))
756 aDestSize
.setHeight(aPrefSize
.getHeight());
760 aMetaFile
.WindStart();
761 aMetaFile
.Play(mpOutputDevice
, aDestRectView
.TopLeft(), aDestSize
);
765 // mask group. Force output to VDev and create mask from given mask
766 void VclProcessor2D::RenderMaskPrimitive2DPixel(const primitive2d::MaskPrimitive2D
& rMaskCandidate
)
768 if(rMaskCandidate
.getChildren().hasElements())
770 basegfx::B2DPolyPolygon
aMask(rMaskCandidate
.getMask());
774 aMask
.transform(maCurrentTransformation
);
775 const basegfx::B2DRange
aRange(basegfx::tools::getRange(aMask
));
776 impBufferDevice
aBufferDevice(*mpOutputDevice
, aRange
, true);
778 if(aBufferDevice
.isVisible())
780 // remember last OutDev and set to content
781 OutputDevice
* pLastOutputDevice
= mpOutputDevice
;
782 mpOutputDevice
= &aBufferDevice
.getContent();
785 process(rMaskCandidate
.getChildren());
787 // back to old OutDev
788 mpOutputDevice
= pLastOutputDevice
;
791 if(getOptionsDrawinglayer().IsAntiAliasing())
793 // with AA, use 8bit AlphaMask to get nice borders
794 VirtualDevice
& rAlpha
= aBufferDevice
.getAlpha();
795 rAlpha
.SetLineColor();
796 rAlpha
.SetFillColor(COL_BLACK
);
797 rAlpha
.DrawPolyPolygon(aMask
);
799 // dump buffer to outdev
800 aBufferDevice
.paint();
804 // No AA, use 1bit mask
805 VirtualDevice
& rMask
= aBufferDevice
.getMask();
806 rMask
.SetLineColor();
807 rMask
.SetFillColor(COL_BLACK
);
808 rMask
.DrawPolyPolygon(aMask
);
810 // dump buffer to outdev
811 aBufferDevice
.paint();
818 // modified color group. Force output to unified color.
819 void VclProcessor2D::RenderModifiedColorPrimitive2D(const primitive2d::ModifiedColorPrimitive2D
& rModifiedCandidate
)
821 if(rModifiedCandidate
.getChildren().hasElements())
823 maBColorModifierStack
.push(rModifiedCandidate
.getColorModifier());
824 process(rModifiedCandidate
.getChildren());
825 maBColorModifierStack
.pop();
829 // unified sub-transparence. Draw to VDev first.
830 void VclProcessor2D::RenderUnifiedAlphaPrimitive2D(const primitive2d::UnifiedAlphaPrimitive2D
& rTransCandidate
)
832 static bool bForceToDecomposition(false);
834 if(rTransCandidate
.getChildren().hasElements())
836 if(bForceToDecomposition
)
839 process(rTransCandidate
.get2DDecomposition(getViewInformation2D()));
843 if(0.0 == rTransCandidate
.getAlpha())
845 // no transparence used, so just use the content
846 process(rTransCandidate
.getChildren());
848 else if(rTransCandidate
.getAlpha() > 0.0 && rTransCandidate
.getAlpha() < 1.0)
850 // alpha is in visible range
851 basegfx::B2DRange
aRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rTransCandidate
.getChildren(), getViewInformation2D()));
852 aRange
.transform(maCurrentTransformation
);
853 impBufferDevice
aBufferDevice(*mpOutputDevice
, aRange
, true);
855 if(aBufferDevice
.isVisible())
857 // remember last OutDev and set to content
858 OutputDevice
* pLastOutputDevice
= mpOutputDevice
;
859 mpOutputDevice
= &aBufferDevice
.getContent();
861 // paint content to it
862 process(rTransCandidate
.getChildren());
864 // back to old OutDev
865 mpOutputDevice
= pLastOutputDevice
;
867 // dump buffer to outdev using given alpha
868 aBufferDevice
.paint(rTransCandidate
.getAlpha());
875 // sub-transparence group. Draw to VDev first.
876 void VclProcessor2D::RenderAlphaPrimitive2D(const primitive2d::AlphaPrimitive2D
& rTransCandidate
)
878 if(rTransCandidate
.getChildren().hasElements())
880 basegfx::B2DRange
aRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rTransCandidate
.getChildren(), getViewInformation2D()));
881 aRange
.transform(maCurrentTransformation
);
882 impBufferDevice
aBufferDevice(*mpOutputDevice
, aRange
, true);
884 if(aBufferDevice
.isVisible())
886 // remember last OutDev and set to content
887 OutputDevice
* pLastOutputDevice
= mpOutputDevice
;
888 mpOutputDevice
= &aBufferDevice
.getContent();
890 // paint content to it
891 process(rTransCandidate
.getChildren());
894 mpOutputDevice
= &aBufferDevice
.getAlpha();
896 // when painting alpha masks, reset the color stack
897 basegfx::BColorModifierStack
aLastBColorModifierStack(maBColorModifierStack
);
898 maBColorModifierStack
= basegfx::BColorModifierStack();
900 // paint mask to it (always with alpha intensities, evtl. with AA)
901 process(rTransCandidate
.getAlpha());
903 // back to old color stack
904 maBColorModifierStack
= aLastBColorModifierStack
;
906 // back to old OutDev
907 mpOutputDevice
= pLastOutputDevice
;
909 // dump buffer to outdev
910 aBufferDevice
.paint();
916 void VclProcessor2D::RenderTransformPrimitive2D(const primitive2d::TransformPrimitive2D
& rTransformCandidate
)
918 // remember current transformation and ViewInformation
919 const basegfx::B2DHomMatrix
aLastCurrentTransformation(maCurrentTransformation
);
920 const geometry::ViewInformation2D
aLastViewInformation2D(getViewInformation2D());
922 // create new transformations for CurrentTransformation
923 // and for local ViewInformation2D
924 maCurrentTransformation
= maCurrentTransformation
* rTransformCandidate
.getTransformation();
925 const geometry::ViewInformation2D
aViewInformation2D(
926 getViewInformation2D().getObjectTransformation() * rTransformCandidate
.getTransformation(),
927 getViewInformation2D().getViewTransformation(),
928 getViewInformation2D().getViewport(),
929 getViewInformation2D().getVisualizedPage(),
930 getViewInformation2D().getViewTime(),
931 getViewInformation2D().getExtendedInformationSequence());
932 updateViewInformation(aViewInformation2D
);
935 process(rTransformCandidate
.getChildren());
937 // restore transformations
938 maCurrentTransformation
= aLastCurrentTransformation
;
939 updateViewInformation(aLastViewInformation2D
);
942 // new XDrawPage for ViewInformation2D
943 void VclProcessor2D::RenderPagePreviewPrimitive2D(const primitive2d::PagePreviewPrimitive2D
& rPagePreviewCandidate
)
945 // remember current transformation and ViewInformation
946 const geometry::ViewInformation2D
aLastViewInformation2D(getViewInformation2D());
948 // create new local ViewInformation2D
949 const geometry::ViewInformation2D
aViewInformation2D(
950 getViewInformation2D().getObjectTransformation(),
951 getViewInformation2D().getViewTransformation(),
952 getViewInformation2D().getViewport(),
953 rPagePreviewCandidate
.getXDrawPage(),
954 getViewInformation2D().getViewTime(),
955 getViewInformation2D().getExtendedInformationSequence());
956 updateViewInformation(aViewInformation2D
);
958 // proccess decomposed content
959 process(rPagePreviewCandidate
.get2DDecomposition(getViewInformation2D()));
961 // restore transformations
962 updateViewInformation(aLastViewInformation2D
);
966 void VclProcessor2D::RenderMarkerArrayPrimitive2D(const primitive2d::MarkerArrayPrimitive2D
& rMarkArrayCandidate
)
968 static bool bCheckCompleteMarkerDecompose(false);
969 if(bCheckCompleteMarkerDecompose
)
971 process(rMarkArrayCandidate
.get2DDecomposition(getViewInformation2D()));
976 const std::vector
< basegfx::B2DPoint
>& rPositions
= rMarkArrayCandidate
.getPositions();
977 const sal_uInt32
nCount(rPositions
.size());
979 if(nCount
&& !rMarkArrayCandidate
.getMarker().IsEmpty())
982 const BitmapEx
& rMarker(rMarkArrayCandidate
.getMarker());
983 const Size
aBitmapSize(rMarker
.GetSizePixel());
985 if(aBitmapSize
.Width() && aBitmapSize
.Height())
987 // get discrete half size
988 const basegfx::B2DVector
aDiscreteHalfSize(
989 (aBitmapSize
.getWidth() - 1.0) * 0.5,
990 (aBitmapSize
.getHeight() - 1.0) * 0.5);
991 const bool bWasEnabled(mpOutputDevice
->IsMapModeEnabled());
993 // do not forget evtl. moved origin in target device MapMode when
994 // switching it off; it would be missing and lead to wrong positions.
995 // All his could be done using logic sizes and coordinates, too, but
996 // we want a 1:1 bitmap rendering here, so it's more safe and faster
997 // to work with switching off MapMode usage completely.
998 const Point
aOrigin(mpOutputDevice
->GetMapMode().GetOrigin());
1000 mpOutputDevice
->EnableMapMode(false);
1002 for(std::vector
< basegfx::B2DPoint
>::const_iterator
aIter(rPositions
.begin()); aIter
!= rPositions
.end(); aIter
++)
1004 const basegfx::B2DPoint
aDiscreteTopLeft((maCurrentTransformation
* (*aIter
)) - aDiscreteHalfSize
);
1005 const Point
aDiscretePoint(basegfx::fround(aDiscreteTopLeft
.getX()), basegfx::fround(aDiscreteTopLeft
.getY()));
1007 mpOutputDevice
->DrawBitmapEx(aDiscretePoint
+ aOrigin
, rMarker
);
1010 mpOutputDevice
->EnableMapMode(bWasEnabled
);
1016 void VclProcessor2D::RenderPointArrayPrimitive2D(const primitive2d::PointArrayPrimitive2D
& rPointArrayCandidate
)
1018 const std::vector
< basegfx::B2DPoint
>& rPositions
= rPointArrayCandidate
.getPositions();
1019 const basegfx::BColor
aRGBColor(maBColorModifierStack
.getModifiedColor(rPointArrayCandidate
.getRGBColor()));
1020 const Color
aVCLColor(aRGBColor
);
1022 for(std::vector
< basegfx::B2DPoint
>::const_iterator
aIter(rPositions
.begin()); aIter
!= rPositions
.end(); aIter
++)
1024 const basegfx::B2DPoint
aViewPosition(maCurrentTransformation
* (*aIter
));
1025 const Point
aPos(basegfx::fround(aViewPosition
.getX()), basegfx::fround(aViewPosition
.getY()));
1027 mpOutputDevice
->DrawPixel(aPos
, aVCLColor
);
1031 void VclProcessor2D::RenderPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D
& rPolygonStrokeCandidate
)
1033 // #i101491# method restructured to clearly use the DrawPolyLine
1034 // calls starting from a deined line width
1035 const attribute::LineAttribute
& rLineAttribute
= rPolygonStrokeCandidate
.getLineAttribute();
1036 const double fLineWidth(rLineAttribute
.getWidth());
1039 if(basegfx::fTools::more(fLineWidth
, 0.0))
1041 const basegfx::B2DVector
aDiscreteUnit(maCurrentTransformation
* basegfx::B2DVector(fLineWidth
, 0.0));
1042 const double fDiscreteLineWidth(aDiscreteUnit
.getLength());
1043 const attribute::StrokeAttribute
& rStrokeAttribute
= rPolygonStrokeCandidate
.getStrokeAttribute();
1044 const basegfx::BColor
aHairlineColor(maBColorModifierStack
.getModifiedColor(rLineAttribute
.getColor()));
1045 basegfx::B2DPolyPolygon aHairlinePolyPolygon
;
1047 mpOutputDevice
->SetLineColor(Color(aHairlineColor
));
1048 mpOutputDevice
->SetFillColor();
1050 if(0.0 == rStrokeAttribute
.getFullDotDashLen())
1052 // no line dashing, just copy
1053 aHairlinePolyPolygon
.append(rPolygonStrokeCandidate
.getB2DPolygon());
1057 // else apply LineStyle
1058 basegfx::tools::applyLineDashing(rPolygonStrokeCandidate
.getB2DPolygon(),
1059 rStrokeAttribute
.getDotDashArray(),
1060 &aHairlinePolyPolygon
, 0, rStrokeAttribute
.getFullDotDashLen());
1063 const sal_uInt32
nCount(aHairlinePolyPolygon
.count());
1067 const bool bAntiAliased(getOptionsDrawinglayer().IsAntiAliasing());
1068 aHairlinePolyPolygon
.transform(maCurrentTransformation
);
1070 for(sal_uInt32
a(0); a
< nCount
; a
++)
1072 basegfx::B2DPolygon
aCandidate(aHairlinePolyPolygon
.getB2DPolygon(a
));
1076 if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth
, 1.0))
1078 // line in range ]0.0 .. 1.0[
1079 // paint as simple hairline
1080 mpOutputDevice
->DrawPolyLine(aCandidate
, 0.0);
1083 else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth
, 2.0))
1085 // line in range [1.0 .. 2.0[
1086 // paint as 2x2 with dynamic line distance
1087 basegfx::B2DHomMatrix aMat
;
1088 const double fDistance(fDiscreteLineWidth
- 1.0);
1089 const double fHalfDistance(fDistance
* 0.5);
1091 aMat
.set(0, 2, -fHalfDistance
);
1092 aMat
.set(1, 2, -fHalfDistance
);
1093 aCandidate
.transform(aMat
);
1094 mpOutputDevice
->DrawPolyLine(aCandidate
, 0.0);
1096 aMat
.set(0, 2, fDistance
);
1097 aMat
.set(1, 2, 0.0);
1098 aCandidate
.transform(aMat
);
1099 mpOutputDevice
->DrawPolyLine(aCandidate
, 0.0);
1101 aMat
.set(0, 2, 0.0);
1102 aMat
.set(1, 2, fDistance
);
1103 aCandidate
.transform(aMat
);
1104 mpOutputDevice
->DrawPolyLine(aCandidate
, 0.0);
1106 aMat
.set(0, 2, -fDistance
);
1107 aMat
.set(1, 2, 0.0);
1108 aCandidate
.transform(aMat
);
1109 mpOutputDevice
->DrawPolyLine(aCandidate
, 0.0);
1112 else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth
, 3.0))
1114 // line in range [2.0 .. 3.0]
1115 // paint as cross in a 3x3 with dynamic line distance
1116 basegfx::B2DHomMatrix aMat
;
1117 const double fDistance((fDiscreteLineWidth
- 1.0) * 0.5);
1119 mpOutputDevice
->DrawPolyLine(aCandidate
, 0.0);
1121 aMat
.set(0, 2, -fDistance
);
1122 aMat
.set(1, 2, 0.0);
1123 aCandidate
.transform(aMat
);
1124 mpOutputDevice
->DrawPolyLine(aCandidate
, 0.0);
1126 aMat
.set(0, 2, fDistance
);
1127 aMat
.set(1, 2, -fDistance
);
1128 aCandidate
.transform(aMat
);
1129 mpOutputDevice
->DrawPolyLine(aCandidate
, 0.0);
1131 aMat
.set(0, 2, fDistance
);
1132 aMat
.set(1, 2, fDistance
);
1133 aCandidate
.transform(aMat
);
1134 mpOutputDevice
->DrawPolyLine(aCandidate
, 0.0);
1136 aMat
.set(0, 2, -fDistance
);
1137 aMat
.set(1, 2, fDistance
);
1138 aCandidate
.transform(aMat
);
1139 mpOutputDevice
->DrawPolyLine(aCandidate
, 0.0);
1144 // #i101491# line width above 3.0
1149 if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth
, 1.5))
1151 // line width below 1.5, draw the basic hairline polygon
1152 mpOutputDevice
->DrawPolyLine(aCandidate
, 0.0);
1155 else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth
, 2.5))
1157 // line width is in range ]1.5 .. 2.5], use four hairlines
1158 // drawn in a square
1159 basegfx::B2DHomMatrix aMat
;
1160 mpOutputDevice
->DrawPolyLine(aCandidate
, 0.0);
1162 aMat
.set(0, 2, 1.0);
1163 aMat
.set(1, 2, 0.0);
1164 aCandidate
.transform(aMat
);
1166 mpOutputDevice
->DrawPolyLine(aCandidate
, 0.0);
1168 aMat
.set(0, 2, 0.0);
1169 aMat
.set(1, 2, 1.0);
1170 aCandidate
.transform(aMat
);
1172 mpOutputDevice
->DrawPolyLine(aCandidate
, 0.0);
1174 aMat
.set(0, 2, -1.0);
1175 aMat
.set(1, 2, 0.0);
1176 aCandidate
.transform(aMat
);
1178 mpOutputDevice
->DrawPolyLine(aCandidate
, 0.0);
1183 // #i101491# line width is above 2.5
1187 if(!bDone
&& rPolygonStrokeCandidate
.getB2DPolygon().count() > 1000)
1189 // #i101491# If the polygon complexity uses more than a given amount, do
1190 // use OuputDevice::DrawPolyLine directly; this will avoid buffering all
1191 // decompositions in primtives (memory) and fallback to old line painting
1192 // for very complex polygons, too
1193 mpOutputDevice
->DrawPolyLine(aCandidate
, fDiscreteLineWidth
, rLineAttribute
.getLineJoin());
1202 // remeber that we enter a PolygonStrokePrimitive2D decomposition,
1203 // used for AA thick line drawing
1204 mnPolygonStrokePrimitive2D
++;
1206 // line width is big enough for standard filled polygon visualisation or zero
1207 process(rPolygonStrokeCandidate
.get2DDecomposition(getViewInformation2D()));
1209 // leave PolygonStrokePrimitive2D
1210 mnPolygonStrokePrimitive2D
--;
1214 void VclProcessor2D::adaptLineToFillDrawMode() const
1216 const sal_uInt32
nOriginalDrawMode(mpOutputDevice
->GetDrawMode());
1218 if(nOriginalDrawMode
& (DRAWMODE_BLACKLINE
|DRAWMODE_GRAYLINE
|DRAWMODE_GHOSTEDLINE
|DRAWMODE_WHITELINE
|DRAWMODE_SETTINGSLINE
))
1220 sal_uInt32
nAdaptedDrawMode(nOriginalDrawMode
);
1222 if(nOriginalDrawMode
& DRAWMODE_BLACKLINE
)
1224 nAdaptedDrawMode
|= DRAWMODE_BLACKFILL
;
1228 nAdaptedDrawMode
&= ~DRAWMODE_BLACKFILL
;
1231 if(nOriginalDrawMode
& DRAWMODE_GRAYLINE
)
1233 nAdaptedDrawMode
|= DRAWMODE_GRAYFILL
;
1237 nAdaptedDrawMode
&= ~DRAWMODE_GRAYFILL
;
1240 if(nOriginalDrawMode
& DRAWMODE_GHOSTEDLINE
)
1242 nAdaptedDrawMode
|= DRAWMODE_GHOSTEDFILL
;
1246 nAdaptedDrawMode
&= ~DRAWMODE_GHOSTEDFILL
;
1249 if(nOriginalDrawMode
& DRAWMODE_WHITELINE
)
1251 nAdaptedDrawMode
|= DRAWMODE_WHITEFILL
;
1255 nAdaptedDrawMode
&= ~DRAWMODE_WHITEFILL
;
1258 if(nOriginalDrawMode
& DRAWMODE_SETTINGSLINE
)
1260 nAdaptedDrawMode
|= DRAWMODE_SETTINGSFILL
;
1264 nAdaptedDrawMode
&= ~DRAWMODE_SETTINGSFILL
;
1267 mpOutputDevice
->SetDrawMode(nAdaptedDrawMode
);
1271 void VclProcessor2D::adaptTextToFillDrawMode() const
1273 const sal_uInt32
nOriginalDrawMode(mpOutputDevice
->GetDrawMode());
1274 if(nOriginalDrawMode
& (DRAWMODE_BLACKTEXT
|DRAWMODE_GRAYTEXT
|DRAWMODE_GHOSTEDTEXT
|DRAWMODE_WHITETEXT
|DRAWMODE_SETTINGSTEXT
))
1276 sal_uInt32
nAdaptedDrawMode(nOriginalDrawMode
);
1278 if(nOriginalDrawMode
& DRAWMODE_BLACKTEXT
)
1280 nAdaptedDrawMode
|= DRAWMODE_BLACKFILL
;
1284 nAdaptedDrawMode
&= ~DRAWMODE_BLACKFILL
;
1287 if(nOriginalDrawMode
& DRAWMODE_GRAYTEXT
)
1289 nAdaptedDrawMode
|= DRAWMODE_GRAYFILL
;
1293 nAdaptedDrawMode
&= ~DRAWMODE_GRAYFILL
;
1296 if(nOriginalDrawMode
& DRAWMODE_GHOSTEDTEXT
)
1298 nAdaptedDrawMode
|= DRAWMODE_GHOSTEDFILL
;
1302 nAdaptedDrawMode
&= ~DRAWMODE_GHOSTEDFILL
;
1305 if(nOriginalDrawMode
& DRAWMODE_WHITETEXT
)
1307 nAdaptedDrawMode
|= DRAWMODE_WHITEFILL
;
1311 nAdaptedDrawMode
&= ~DRAWMODE_WHITEFILL
;
1314 if(nOriginalDrawMode
& DRAWMODE_SETTINGSTEXT
)
1316 nAdaptedDrawMode
|= DRAWMODE_SETTINGSFILL
;
1320 nAdaptedDrawMode
&= ~DRAWMODE_SETTINGSFILL
;
1323 mpOutputDevice
->SetDrawMode(nAdaptedDrawMode
);
1327 //////////////////////////////////////////////////////////////////////////////
1330 VclProcessor2D::VclProcessor2D(
1331 const geometry::ViewInformation2D
& rViewInformation
,
1332 OutputDevice
& rOutDev
)
1333 : BaseProcessor2D(rViewInformation
),
1334 mpOutputDevice(&rOutDev
),
1335 maBColorModifierStack(),
1336 maCurrentTransformation(),
1337 maDrawinglayerOpt(),
1338 mnPolygonStrokePrimitive2D(0)
1340 // set digit language, derived from SvtCTLOptions to have the correct
1341 // number display for arabic/hindi numerals
1342 const SvtCTLOptions aSvtCTLOptions
;
1343 LanguageType
eLang(LANGUAGE_SYSTEM
);
1345 if(SvtCTLOptions::NUMERALS_HINDI
== aSvtCTLOptions
.GetCTLTextNumerals())
1347 eLang
= LANGUAGE_ARABIC_SAUDI_ARABIA
;
1349 else if(SvtCTLOptions::NUMERALS_ARABIC
== aSvtCTLOptions
.GetCTLTextNumerals())
1351 eLang
= LANGUAGE_ENGLISH
;
1355 eLang
= (LanguageType
)Application::GetSettings().GetLanguage();
1358 rOutDev
.SetDigitLanguage(eLang
);
1361 VclProcessor2D::~VclProcessor2D()
1364 } // end of namespace processor2d
1365 } // end of namespace drawinglayer
1367 //////////////////////////////////////////////////////////////////////////////