1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
5 * $RCSfile: vclpixelprocessor2d.cxx,v $
9 * last change: $Author: aw $ $Date: 2008-06-26 16:21:48 $
11 * The Contents of this file are made available subject to
12 * the terms of GNU Lesser General Public License Version 2.1.
15 * GNU Lesser General Public License Version 2.1
16 * =============================================
17 * Copyright 2005 by Sun Microsystems, Inc.
18 * 901 San Antonio Road, Palo Alto, CA 94303, USA
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License version 2.1, as published by the Free Software Foundation.
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
34 ************************************************************************/
36 // MARKER(update_precomp.py): autogen include statement, do not remove
37 #include "precompiled_drawinglayer.hxx"
39 #include <drawinglayer/processor2d/vclpixelprocessor2d.hxx>
40 #include <vcl/outdev.hxx>
41 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
42 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
43 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
44 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
45 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
46 #include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
47 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
48 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
49 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
50 #include <drawinglayer/primitive2d/alphaprimitive2d.hxx>
51 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
52 #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
53 #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
54 #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
55 #include <drawinglayer/primitive2d/controlprimitive2d.hxx>
56 #include <com/sun/star/awt/XWindow2.hpp>
57 #include <drawinglayer/primitive2d/unifiedalphaprimitive2d.hxx>
58 #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
59 #include <drawinglayer/primitive2d/chartprimitive2d.hxx>
60 #include <helperchartrenderer.hxx>
61 #include <helperwrongspellrenderer.hxx>
62 #include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx>
63 #include <basegfx/polygon/b2dpolygontools.hxx>
64 #include <vcl/hatch.hxx>
65 #include <tools/diagnose_ex.h>
66 #include <com/sun/star/awt/PosSize.hpp>
67 #include <drawinglayer/primitive2d/invertprimitive2d.hxx>
69 #include <drawinglayer/primitive2d/backgroundcolorprimitive2d.hxx>
71 //////////////////////////////////////////////////////////////////////////////
73 using namespace com::sun::star
;
75 //////////////////////////////////////////////////////////////////////////////
77 namespace drawinglayer
81 VclPixelProcessor2D::VclPixelProcessor2D(const geometry::ViewInformation2D
& rViewInformation
, OutputDevice
& rOutDev
)
82 : VclProcessor2D(rViewInformation
, rOutDev
),
83 maOriginalMapMode(rOutDev
.GetMapMode())
85 // prepare maCurrentTransformation matrix with viewTransformation to target directly to pixels
86 maCurrentTransformation
= rViewInformation
.getObjectToViewTransformation();
88 // prepare output directly to pixels
89 mpOutputDevice
->Push(PUSH_MAPMODE
);
90 mpOutputDevice
->SetMapMode();
92 // react on AntiAliasing settings
93 if(getOptionsDrawinglayer().IsAntiAliasing())
95 mpOutputDevice
->SetAntialiasing(mpOutputDevice
->GetAntialiasing() | ANTIALIASING_ENABLE_B2DDRAW
);
99 mpOutputDevice
->SetAntialiasing(mpOutputDevice
->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW
);
103 VclPixelProcessor2D::~VclPixelProcessor2D()
106 mpOutputDevice
->Pop();
108 // restore AntiAliasing
109 mpOutputDevice
->SetAntialiasing(mpOutputDevice
->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW
);
112 void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D
& rCandidate
)
114 switch(rCandidate
.getPrimitiveID())
116 case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D
:
118 // directdraw of wrong spell primitive; added test possibility to check wrong spell decompose
119 static bool bHandleWrongSpellDirectly(true);
121 if(bHandleWrongSpellDirectly
)
123 const primitive2d::WrongSpellPrimitive2D
& rWrongSpellPrimitive
= static_cast< const primitive2d::WrongSpellPrimitive2D
& >(rCandidate
);
125 if(!renderWrongSpellPrimitive2D(
126 rWrongSpellPrimitive
,
128 maCurrentTransformation
,
129 maBColorModifierStack
))
131 // fallback to decomposition (MetaFile)
132 process(rWrongSpellPrimitive
.get2DDecomposition(getViewInformation2D()));
137 process(rCandidate
.get2DDecomposition(getViewInformation2D()));
141 case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D
:
143 // directdraw of text simple portion; added test possibility to check text decompose
144 static bool bForceSimpleTextDecomposition(false);
146 // Adapt evtl. used special DrawMode
147 const sal_uInt32
nOriginalDrawMode(mpOutputDevice
->GetDrawMode());
148 adaptTextToFillDrawMode();
150 if(!bForceSimpleTextDecomposition
&& getOptionsDrawinglayer().IsRenderSimpleTextDirect())
152 RenderTextSimpleOrDecoratedPortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D
& >(rCandidate
));
156 process(rCandidate
.get2DDecomposition(getViewInformation2D()));
160 mpOutputDevice
->SetDrawMode(nOriginalDrawMode
);
164 case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D
:
166 // directdraw of text simple portion; added test possibility to check text decompose
167 static bool bForceComplexTextDecomposition(false);
169 // Adapt evtl. used special DrawMode
170 const sal_uInt32
nOriginalDrawMode(mpOutputDevice
->GetDrawMode());
171 adaptTextToFillDrawMode();
173 if(!bForceComplexTextDecomposition
&& getOptionsDrawinglayer().IsRenderDecoratedTextDirect())
175 RenderTextSimpleOrDecoratedPortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D
& >(rCandidate
));
179 process(rCandidate
.get2DDecomposition(getViewInformation2D()));
183 mpOutputDevice
->SetDrawMode(nOriginalDrawMode
);
187 case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D
:
189 // direct draw of hairline
190 RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D
& >(rCandidate
), true);
193 case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D
:
195 // direct draw of transformed BitmapEx primitive
196 RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D
& >(rCandidate
));
199 case PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D
:
201 // direct draw of fillBitmapPrimitive
202 RenderFillBitmapPrimitive2D(static_cast< const primitive2d::FillBitmapPrimitive2D
& >(rCandidate
));
205 case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D
:
207 if(getOptionsDrawinglayer().IsAntiAliasing())
209 // For AA, direct render has to be avoided since it uses XOR maskings which will not
210 // work with AA. Instead, the decompose which uses MaskPrimitive2D with fillings is
212 process(rCandidate
.get2DDecomposition(getViewInformation2D()));
216 // direct draw of gradient
217 RenderPolyPolygonGradientPrimitive2D(static_cast< const primitive2d::PolyPolygonGradientPrimitive2D
& >(rCandidate
));
221 case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D
:
223 // direct draw of PolyPolygon with color
224 RenderPolyPolygonColorPrimitive2D(static_cast< const primitive2d::PolyPolygonColorPrimitive2D
& >(rCandidate
));
227 case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D
:
230 const bool bForceLineSnap(getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete());
231 const sal_uInt16
nOldAntiAliase(mpOutputDevice
->GetAntialiasing());
235 mpOutputDevice
->SetAntialiasing(nOldAntiAliase
| ANTIALIASING_PIXELSNAPHAIRLINE
);
238 // direct draw of MetaFile
239 RenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D
& >(rCandidate
));
243 mpOutputDevice
->SetAntialiasing(nOldAntiAliase
);
248 case PRIMITIVE2D_ID_MASKPRIMITIVE2D
:
251 RenderMaskPrimitive2DPixel(static_cast< const primitive2d::MaskPrimitive2D
& >(rCandidate
));
254 case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D
:
256 // modified color group. Force output to unified color.
257 RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D
& >(rCandidate
));
260 case PRIMITIVE2D_ID_UNIFIEDALPHAPRIMITIVE2D
:
262 // Detect if a single PolyPolygonColorPrimitive2D is contained; in that case,
263 // use the faster OutputDevice::DrawTransparent method
264 const primitive2d::UnifiedAlphaPrimitive2D
& rUniAlphaCandidate
= static_cast< const primitive2d::UnifiedAlphaPrimitive2D
& >(rCandidate
);
265 const primitive2d::Primitive2DSequence rContent
= rUniAlphaCandidate
.getChildren();
266 bool bDrawTransparentUsed(false);
268 // since DEV300 m33 DrawTransparent is supported in VCL (for some targets
269 // natively), so i am now enabling this shortcut
270 static bool bAllowUsingDrawTransparent(true);
272 if(bAllowUsingDrawTransparent
&& rContent
.hasElements() && 1 == rContent
.getLength())
274 const primitive2d::Primitive2DReference
xReference(rContent
[0]);
275 const primitive2d::PolyPolygonColorPrimitive2D
* pPoPoColor
= dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D
* >(xReference
.get());
277 if(pPoPoColor
&& PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D
== pPoPoColor
->getPrimitiveID())
279 // single transparent PolyPolygon identified, use directly
280 const basegfx::BColor
aPolygonColor(maBColorModifierStack
.getModifiedColor(pPoPoColor
->getBColor()));
281 mpOutputDevice
->SetFillColor(Color(aPolygonColor
));
282 mpOutputDevice
->SetLineColor();
284 basegfx::B2DPolyPolygon
aLocalPolyPolygon(pPoPoColor
->getB2DPolyPolygon());
285 aLocalPolyPolygon
.transform(maCurrentTransformation
);
287 mpOutputDevice
->DrawTransparent(aLocalPolyPolygon
, rUniAlphaCandidate
.getAlpha());
288 bDrawTransparentUsed
= true;
292 if(!bDrawTransparentUsed
)
294 // unified sub-transparence. Draw to VDev first.
295 RenderUnifiedAlphaPrimitive2D(rUniAlphaCandidate
);
300 case PRIMITIVE2D_ID_ALPHAPRIMITIVE2D
:
302 // sub-transparence group. Draw to VDev first.
303 RenderAlphaPrimitive2D(static_cast< const primitive2d::AlphaPrimitive2D
& >(rCandidate
));
306 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D
:
309 RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D
& >(rCandidate
));
312 case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D
:
314 // new XDrawPage for ViewInformation2D
315 RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D
& >(rCandidate
));
318 case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D
:
321 RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D
& >(rCandidate
));
324 case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D
:
327 RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D
& >(rCandidate
));
330 case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D
:
333 const primitive2d::ControlPrimitive2D
& rControlPrimitive
= static_cast< const primitive2d::ControlPrimitive2D
& >(rCandidate
);
334 const uno::Reference
< awt::XControl
>& rXControl(rControlPrimitive
.getXControl());
338 // remember old graphics and create new
339 uno::Reference
< awt::XView
> xControlView(rXControl
, uno::UNO_QUERY_THROW
);
340 const uno::Reference
< awt::XGraphics
> xOriginalGraphics(xControlView
->getGraphics());
341 const uno::Reference
< awt::XGraphics
> xNewGraphics(mpOutputDevice
->CreateUnoGraphics());
343 if(xNewGraphics
.is())
345 // link graphics and view
346 xControlView
->setGraphics(xNewGraphics
);
349 const basegfx::B2DHomMatrix
aObjectToPixel(maCurrentTransformation
* rControlPrimitive
.getTransform());
350 const basegfx::B2DPoint
aTopLeftPixel(aObjectToPixel
* basegfx::B2DPoint(0.0, 0.0));
352 // find out if the control is already visualized as a VCL-ChildWindow. If yes,
353 // it does not need to be painted at all.
354 uno::Reference
< awt::XWindow2
> xControlWindow(rXControl
, uno::UNO_QUERY_THROW
);
355 const bool bControlIsVisibleAsChildWindow(rXControl
->getPeer().is() && xControlWindow
->isVisible());
357 if(!bControlIsVisibleAsChildWindow
)
359 // draw it. Do not forget to use the evtl. offsetted origin of the target device,
360 // e.g. when used with mask/transparence buffer device
361 const Point
aOrigin(mpOutputDevice
->GetMapMode().GetOrigin());
363 aOrigin
.X() + basegfx::fround(aTopLeftPixel
.getX()),
364 aOrigin
.Y() + basegfx::fround(aTopLeftPixel
.getY()));
367 // restore original graphics
368 xControlView
->setGraphics(xOriginalGraphics
);
371 catch(const uno::Exception
&)
373 DBG_UNHANDLED_EXCEPTION();
375 // process recursively and use the decomposition as Bitmap
376 process(rCandidate
.get2DDecomposition(getViewInformation2D()));
381 case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D
:
383 // the stroke primitive may be decomposed to filled polygons. To keep
384 // evtl. set DrawModes aka DRAWMODE_BLACKLINE, DRAWMODE_GRAYLINE,
385 // DRAWMODE_GHOSTEDLINE, DRAWMODE_WHITELINE or DRAWMODE_SETTINGSLINE
386 // working, these need to be copied to the corresponding fill modes
387 const sal_uInt32
nOriginalDrawMode(mpOutputDevice
->GetDrawMode());
388 adaptLineToFillDrawMode();
390 // polygon stroke primitive
391 static bool bSuppressFatToHairlineCorrection(false);
393 if(bSuppressFatToHairlineCorrection
)
395 // remeber that we enter a PolygonStrokePrimitive2D decomposition,
396 // used for AA thick line drawing
397 mnPolygonStrokePrimitive2D
++;
399 // with AA there is no need to handle thin lines special
400 process(rCandidate
.get2DDecomposition(getViewInformation2D()));
402 // leave PolygonStrokePrimitive2D
403 mnPolygonStrokePrimitive2D
--;
407 // Lines with 1 and 2 pixel width without AA need special treatment since their vsiualisation
408 // as filled polygons is geometrically corret but looks wrong since polygon filling avoids
409 // the right and bottom pixels. The used method evaluates that and takes the correct action,
410 // including calling recursively with decomposition if line is wide enough
411 const primitive2d::PolygonStrokePrimitive2D
& rPolygonStrokePrimitive
= static_cast< const primitive2d::PolygonStrokePrimitive2D
& >(rCandidate
);
413 RenderPolygonStrokePrimitive2D(rPolygonStrokePrimitive
);
417 mpOutputDevice
->SetDrawMode(nOriginalDrawMode
);
421 case PRIMITIVE2D_ID_CHARTPRIMITIVE2D
:
423 // chart primitive in pixel renderer; restore original DrawMode during call
424 // since the evtl. used ChartPrettyPainter will use the MapMode
425 const primitive2d::ChartPrimitive2D
& rChartPrimitive
= static_cast< const primitive2d::ChartPrimitive2D
& >(rCandidate
);
426 mpOutputDevice
->Push(PUSH_MAPMODE
);
427 mpOutputDevice
->SetMapMode(maOriginalMapMode
);
429 if(!renderChartPrimitive2D(
432 getViewInformation2D()))
434 // fallback to decomposition (MetaFile)
435 process(rChartPrimitive
.get2DDecomposition(getViewInformation2D()));
438 mpOutputDevice
->Pop();
441 case PRIMITIVE2D_ID_FILLHATCHPRIMITIVE2D
:
443 static bool bForceIgnoreHatchSmoothing(false);
445 if(bForceIgnoreHatchSmoothing
|| getOptionsDrawinglayer().IsAntiAliasing())
447 // if AA is used (or ignore smoothing is on), there is no need to smooth
448 // hatch painting, use decomposition
449 process(rCandidate
.get2DDecomposition(getViewInformation2D()));
453 // without AA, use VCL to draw the hatch. It snaps hatch distances to the next pixel
454 // and forces hatch distance to be >= 3 pixels to make the hatch display look smoother.
455 // This is wrong in principle, but looks nicer. This could also be done here directly
456 // without VCL usage if needed
457 const primitive2d::FillHatchPrimitive2D
& rFillHatchPrimitive
= static_cast< const primitive2d::FillHatchPrimitive2D
& >(rCandidate
);
459 // create hatch polygon in range size and discrete coordinates
460 basegfx::B2DRange
aHatchRange(rFillHatchPrimitive
.getObjectRange());
461 aHatchRange
.transform(maCurrentTransformation
);
462 const basegfx::B2DPolygon
aHatchPolygon(basegfx::tools::createPolygonFromRect(aHatchRange
));
464 // set hatch line color
465 const basegfx::BColor
aHatchColor(maBColorModifierStack
.getModifiedColor(rFillHatchPrimitive
.getBColor()));
466 mpOutputDevice
->SetFillColor();
467 mpOutputDevice
->SetLineColor(Color(aHatchColor
));
470 const attribute::FillHatchAttribute
& rFillHatchAttributes
= rFillHatchPrimitive
.getFillHatch();
471 HatchStyle
eHatchStyle(HATCH_SINGLE
);
473 switch(rFillHatchAttributes
.getStyle())
475 default : // HATCHSTYLE_SINGLE
479 case attribute::HATCHSTYLE_DOUBLE
:
481 eHatchStyle
= HATCH_DOUBLE
;
484 case attribute::HATCHSTYLE_TRIPLE
:
486 eHatchStyle
= HATCH_TRIPLE
;
492 const basegfx::B2DVector
aDiscreteDistance(maCurrentTransformation
* basegfx::B2DVector(rFillHatchAttributes
.getDistance(), 0.0));
493 const sal_uInt32
nDistance(basegfx::fround(aDiscreteDistance
.getLength()));
494 const sal_uInt16
nAngle10((sal_uInt16
)basegfx::fround(rFillHatchAttributes
.getAngle() / F_PI1800
));
495 ::Hatch
aVCLHatch(eHatchStyle
, Color(rFillHatchAttributes
.getColor()), nDistance
, nAngle10
);
497 // draw hatch using VCL
498 mpOutputDevice
->DrawHatch(PolyPolygon(Polygon(aHatchPolygon
)), aVCLHatch
);
502 case PRIMITIVE2D_ID_BACKGROUNDCOLORPRIMITIVE2D
:
504 // #i98404# Handle directly, especially when AA is active
505 const primitive2d::BackgroundColorPrimitive2D
& rPrimitive
= static_cast< const primitive2d::BackgroundColorPrimitive2D
& >(rCandidate
);
506 const sal_uInt16
nOriginalAA(mpOutputDevice
->GetAntialiasing());
508 // switch AA off in all cases
509 mpOutputDevice
->SetAntialiasing(mpOutputDevice
->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW
);
511 // create color for fill
512 const basegfx::BColor
aPolygonColor(maBColorModifierStack
.getModifiedColor(rPrimitive
.getBColor()));
513 mpOutputDevice
->SetFillColor(Color(aPolygonColor
));
514 mpOutputDevice
->SetLineColor();
516 // create rectangle for fill
517 const basegfx::B2DRange
& aViewport(getViewInformation2D().getDiscreteViewport());
518 const Rectangle
aRectangle(
519 (sal_Int32
)floor(aViewport
.getMinX()), (sal_Int32
)floor(aViewport
.getMinY()),
520 (sal_Int32
)ceil(aViewport
.getMaxX()), (sal_Int32
)ceil(aViewport
.getMaxY()));
521 mpOutputDevice
->DrawRect(aRectangle
);
523 // restore AA setting
524 mpOutputDevice
->SetAntialiasing(nOriginalAA
);
528 case PRIMITIVE2D_ID_TEXTHIERARCHYEDITPRIMITIVE2D
:
531 // This primitive means that the content is derived from an active text edit,
532 // not from model data itself. Some renderers need to suppress this content, e.g.
533 // the pixel renderer used for displaying the edit view (like this one). It's
534 // not to be suppressed by the MetaFile renderers, so that the edited text is
535 // part of the MetaFile, e.g. needed for presentation previews.
536 // Action: Ignore here, do nothing.
539 case PRIMITIVE2D_ID_INVERTPRIMITIVE2D
:
541 // invert primitive (currently only used for HighContrast fallback for selection in SW and SC).
543 mpOutputDevice
->Push();
544 mpOutputDevice
->SetRasterOp( ROP_XOR
);
546 // force paint color to white by using ColorModifierStack
547 const basegfx::BColor
aColWhite(1.0, 1.0, 1.0);
548 const basegfx::BColorModifier
aColorModifier(aColWhite
, 0.0, basegfx::BCOLORMODIFYMODE_REPLACE
);
549 maBColorModifierStack
.push(aColorModifier
);
551 // process content recursively
552 process(rCandidate
.get2DDecomposition(getViewInformation2D()));
554 // restore ColorModifierStack
555 maBColorModifierStack
.pop();
558 mpOutputDevice
->Pop();
563 // process recursively
564 process(rCandidate
.get2DDecomposition(getViewInformation2D()));
569 } // end of namespace processor2d
570 } // end of namespace drawinglayer
572 //////////////////////////////////////////////////////////////////////////////