1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "vclpixelprocessor2d.hxx"
21 #include <vcl/outdev.hxx>
22 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
23 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
24 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
25 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
26 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
27 #include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx>
28 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
29 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
30 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
31 #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
32 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
33 #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
34 #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
35 #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
36 #include <drawinglayer/primitive2d/controlprimitive2d.hxx>
37 #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
38 #include <com/sun/star/awt/XWindow2.hpp>
39 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
40 #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
41 #include "helperwrongspellrenderer.hxx"
42 #include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx>
43 #include <basegfx/polygon/b2dpolygontools.hxx>
44 #include <vcl/hatch.hxx>
45 #include <tools/diagnose_ex.h>
46 #include <sal/log.hxx>
47 #include <com/sun/star/awt/XControl.hpp>
48 #include <com/sun/star/awt/PosSize.hpp>
49 #include <drawinglayer/primitive2d/invertprimitive2d.hxx>
51 #include <drawinglayer/primitive2d/backgroundcolorprimitive2d.hxx>
52 #include <basegfx/matrix/b2dhommatrixtools.hxx>
53 #include <drawinglayer/primitive2d/epsprimitive2d.hxx>
54 #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
55 #include <vcl/window.hxx>
56 #include <svtools/borderhelper.hxx>
57 #include <editeng/borderline.hxx>
59 #include <com/sun/star/table/BorderLineStyle.hpp>
61 using namespace com::sun::star
;
63 namespace drawinglayer
67 struct VclPixelProcessor2D::Impl
69 AntialiasingFlags m_nOrigAntiAliasing
;
71 explicit Impl(OutputDevice
const& rOutDev
)
72 : m_nOrigAntiAliasing(rOutDev
.GetAntialiasing())
76 VclPixelProcessor2D::VclPixelProcessor2D(const geometry::ViewInformation2D
& rViewInformation
, OutputDevice
& rOutDev
)
77 : VclProcessor2D(rViewInformation
, rOutDev
)
78 , m_pImpl(new Impl(rOutDev
))
80 // prepare maCurrentTransformation matrix with viewTransformation to target directly to pixels
81 maCurrentTransformation
= rViewInformation
.getObjectToViewTransformation();
83 // prepare output directly to pixels
84 mpOutputDevice
->Push(PushFlags::MAPMODE
);
85 mpOutputDevice
->SetMapMode();
87 // react on AntiAliasing settings
88 if(getOptionsDrawinglayer().IsAntiAliasing())
90 mpOutputDevice
->SetAntialiasing(
91 m_pImpl
->m_nOrigAntiAliasing
| AntialiasingFlags::EnableB2dDraw
);
95 mpOutputDevice
->SetAntialiasing(
96 m_pImpl
->m_nOrigAntiAliasing
& ~AntialiasingFlags::EnableB2dDraw
);
100 VclPixelProcessor2D::~VclPixelProcessor2D()
103 mpOutputDevice
->Pop();
105 // restore AntiAliasing
106 mpOutputDevice
->SetAntialiasing(m_pImpl
->m_nOrigAntiAliasing
);
109 void VclPixelProcessor2D::tryDrawPolyPolygonColorPrimitive2DDirect(const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D
& rSource
, double fTransparency
)
111 if(!rSource
.getB2DPolyPolygon().count())
117 const basegfx::BColor
aPolygonColor(maBColorModifierStack
.getModifiedColor(rSource
.getBColor()));
119 mpOutputDevice
->SetFillColor(Color(aPolygonColor
));
120 mpOutputDevice
->SetLineColor();
121 mpOutputDevice
->DrawTransparent(
122 maCurrentTransformation
,
123 rSource
.getB2DPolyPolygon(),
127 bool VclPixelProcessor2D::tryDrawPolygonHairlinePrimitive2DDirect(const drawinglayer::primitive2d::PolygonHairlinePrimitive2D
& rSource
, double fTransparency
)
129 const basegfx::B2DPolygon
& rLocalPolygon(rSource
.getB2DPolygon());
131 if(!rLocalPolygon
.count())
137 const basegfx::BColor
aLineColor(maBColorModifierStack
.getModifiedColor(rSource
.getBColor()));
139 mpOutputDevice
->SetFillColor();
140 mpOutputDevice
->SetLineColor(Color(aLineColor
));
141 //aLocalPolygon.transform(maCurrentTransformation);
143 // try drawing; if it did not work, use standard fallback
144 return mpOutputDevice
->DrawPolyLineDirect(
145 maCurrentTransformation
,
151 bool VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect(const drawinglayer::primitive2d::PolygonStrokePrimitive2D
& rSource
, double fTransparency
)
153 if(!rSource
.getB2DPolygon().count())
159 // get geometry data, prepare hairline data
160 const basegfx::B2DPolygon
& aLocalPolygon(rSource
.getB2DPolygon());
161 basegfx::B2DPolyPolygon aHairLinePolyPolygon
;
163 // simplify curve segments
164 // moved to PolygonStrokePrimitive2D::PolygonStrokePrimitive2D
165 // aLocalPolygon = basegfx::utils::simplifyCurveSegments(aLocalPolygon);
167 if(rSource
.getStrokeAttribute().isDefault() || 0.0 == rSource
.getStrokeAttribute().getFullDotDashLen())
169 // no line dashing, just copy
170 aHairLinePolyPolygon
.append(aLocalPolygon
);
175 basegfx::utils::applyLineDashing(
177 rSource
.getStrokeAttribute().getDotDashArray(),
178 &aHairLinePolyPolygon
,
180 rSource
.getStrokeAttribute().getFullDotDashLen());
183 if(!aHairLinePolyPolygon
.count())
189 // check if LineWidth can be simplified in world coordinates
190 double fLineWidth(rSource
.getLineAttribute().getWidth());
192 if(basegfx::fTools::more(fLineWidth
, 0.0))
194 basegfx::B2DVector
aLineWidth(fLineWidth
, 0.0);
195 aLineWidth
= maCurrentTransformation
* aLineWidth
;
196 const double fWorldLineWidth(aLineWidth
.getLength());
198 // draw simple hairline for small line widths
199 // see also RenderPolygonStrokePrimitive2D which is used if this try fails
200 bool bIsAntiAliasing
= getOptionsDrawinglayer().IsAntiAliasing();
201 if ( (basegfx::fTools::lessOrEqual(fWorldLineWidth
, 1.0) && bIsAntiAliasing
)
202 || (basegfx::fTools::lessOrEqual(fWorldLineWidth
, 1.5) && !bIsAntiAliasing
))
204 // draw simple hairline
209 const basegfx::BColor
aLineColor(
210 maBColorModifierStack
.getModifiedColor(
211 rSource
.getLineAttribute().getColor()));
213 mpOutputDevice
->SetFillColor();
214 mpOutputDevice
->SetLineColor(Color(aLineColor
));
216 // do not transform self
217 // aHairLinePolyPolygon.transform(maCurrentTransformation);
219 bool bHasPoints(false);
220 bool bTryWorked(false);
222 for(sal_uInt32
a(0); a
< aHairLinePolyPolygon
.count(); a
++)
224 const basegfx::B2DPolygon
& aSingle(aHairLinePolyPolygon
.getB2DPolygon(a
));
230 if(mpOutputDevice
->DrawPolyLineDirect(
231 maCurrentTransformation
,
235 rSource
.getLineAttribute().getLineJoin(),
236 rSource
.getLineAttribute().getLineCap(),
237 rSource
.getLineAttribute().getMiterMinimumAngle()
238 /* false bBypassAACheck, default*/))
245 if(!bTryWorked
&& !bHasPoints
)
247 // no geometry despite try
254 void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D
& rCandidate
)
256 switch(rCandidate
.getPrimitive2DID())
258 case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D
:
260 processWrongSpellPrimitive2D(static_cast<const primitive2d::WrongSpellPrimitive2D
&>(rCandidate
));
263 case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D
:
265 processTextSimplePortionPrimitive2D(static_cast<const primitive2d::TextSimplePortionPrimitive2D
&>(rCandidate
));
268 case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D
:
270 processTextDecoratedPortionPrimitive2D(static_cast<const primitive2d::TextSimplePortionPrimitive2D
&>(rCandidate
));
273 case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D
:
275 processPolygonHairlinePrimitive2D(static_cast<const primitive2d::PolygonHairlinePrimitive2D
&>(rCandidate
));
278 case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D
:
280 // direct draw of transformed BitmapEx primitive
281 processBitmapPrimitive2D(static_cast<const primitive2d::BitmapPrimitive2D
&>(rCandidate
));
284 case PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D
:
286 // direct draw of fillBitmapPrimitive
287 RenderFillGraphicPrimitive2D(static_cast< const primitive2d::FillGraphicPrimitive2D
& >(rCandidate
));
290 case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D
:
292 processPolyPolygonGradientPrimitive2D(static_cast<const primitive2d::PolyPolygonGradientPrimitive2D
&>(rCandidate
));
295 case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D
:
297 // direct draw of bitmap
298 RenderPolyPolygonGraphicPrimitive2D(static_cast< const primitive2d::PolyPolygonGraphicPrimitive2D
& >(rCandidate
));
301 case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D
:
303 processPolyPolygonColorPrimitive2D(static_cast<const primitive2d::PolyPolygonColorPrimitive2D
&>(rCandidate
));
306 case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D
:
308 processMetaFilePrimitive2D(rCandidate
);
311 case PRIMITIVE2D_ID_MASKPRIMITIVE2D
:
314 RenderMaskPrimitive2DPixel(static_cast< const primitive2d::MaskPrimitive2D
& >(rCandidate
));
317 case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D
:
319 // modified color group. Force output to unified color.
320 RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D
& >(rCandidate
));
323 case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D
:
325 processUnifiedTransparencePrimitive2D(static_cast<const primitive2d::UnifiedTransparencePrimitive2D
&>(rCandidate
));
328 case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D
:
330 // sub-transparence group. Draw to VDev first.
331 RenderTransparencePrimitive2D(static_cast< const primitive2d::TransparencePrimitive2D
& >(rCandidate
));
334 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D
:
337 RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D
& >(rCandidate
));
340 case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D
:
342 // new XDrawPage for ViewInformation2D
343 RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D
& >(rCandidate
));
346 case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D
:
349 RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D
& >(rCandidate
));
352 case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D
:
355 RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D
& >(rCandidate
));
358 case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D
:
360 processControlPrimitive2D(static_cast<const primitive2d::ControlPrimitive2D
&>(rCandidate
));
363 case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D
:
365 processPolygonStrokePrimitive2D(static_cast<const primitive2d::PolygonStrokePrimitive2D
&>(rCandidate
));
368 case PRIMITIVE2D_ID_FILLHATCHPRIMITIVE2D
:
370 processFillHatchPrimitive2D(static_cast<const primitive2d::FillHatchPrimitive2D
&>(rCandidate
));
373 case PRIMITIVE2D_ID_BACKGROUNDCOLORPRIMITIVE2D
:
375 processBackgroundColorPrimitive2D(static_cast<const primitive2d::BackgroundColorPrimitive2D
&>(rCandidate
));
378 case PRIMITIVE2D_ID_TEXTHIERARCHYEDITPRIMITIVE2D
:
381 // This primitive means that the content is derived from an active text edit,
382 // not from model data itself. Some renderers need to suppress this content, e.g.
383 // the pixel renderer used for displaying the edit view (like this one). It's
384 // not to be suppressed by the MetaFile renderers, so that the edited text is
385 // part of the MetaFile, e.g. needed for presentation previews.
386 // Action: Ignore here, do nothing.
389 case PRIMITIVE2D_ID_INVERTPRIMITIVE2D
:
391 processInvertPrimitive2D(rCandidate
);
394 case PRIMITIVE2D_ID_EPSPRIMITIVE2D
:
396 RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D
& >(rCandidate
));
399 case PRIMITIVE2D_ID_SVGLINEARATOMPRIMITIVE2D
:
401 RenderSvgLinearAtomPrimitive2D(static_cast< const primitive2d::SvgLinearAtomPrimitive2D
& >(rCandidate
));
404 case PRIMITIVE2D_ID_SVGRADIALATOMPRIMITIVE2D
:
406 RenderSvgRadialAtomPrimitive2D(static_cast< const primitive2d::SvgRadialAtomPrimitive2D
& >(rCandidate
));
409 case PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D
:
411 processBorderLinePrimitive2D(static_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D
&>(rCandidate
));
416 SAL_INFO("drawinglayer", "default case for " << drawinglayer::primitive2d::idToString(rCandidate
.getPrimitive2DID()));
417 // process recursively
424 void VclPixelProcessor2D::processWrongSpellPrimitive2D(const primitive2d::WrongSpellPrimitive2D
& rWrongSpellPrimitive
)
426 if(!renderWrongSpellPrimitive2D(
427 rWrongSpellPrimitive
,
429 maCurrentTransformation
,
430 maBColorModifierStack
))
432 // fallback to decomposition (MetaFile)
433 process(rWrongSpellPrimitive
);
437 void VclPixelProcessor2D::processTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D
& rCandidate
)
439 // Adapt evtl. used special DrawMode
440 const DrawModeFlags
nOriginalDrawMode(mpOutputDevice
->GetDrawMode());
441 adaptTextToFillDrawMode();
443 if(getOptionsDrawinglayer().IsRenderSimpleTextDirect())
445 RenderTextSimpleOrDecoratedPortionPrimitive2D(rCandidate
);
453 mpOutputDevice
->SetDrawMode(nOriginalDrawMode
);
456 void VclPixelProcessor2D::processTextDecoratedPortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D
& rCandidate
)
458 // Adapt evtl. used special DrawMode
459 const DrawModeFlags
nOriginalDrawMode(mpOutputDevice
->GetDrawMode());
460 adaptTextToFillDrawMode();
462 if(getOptionsDrawinglayer().IsRenderDecoratedTextDirect())
464 RenderTextSimpleOrDecoratedPortionPrimitive2D(rCandidate
);
472 mpOutputDevice
->SetDrawMode(nOriginalDrawMode
);
475 void VclPixelProcessor2D::processPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D
& rPolygonHairlinePrimitive2D
)
477 if(tryDrawPolygonHairlinePrimitive2DDirect(rPolygonHairlinePrimitive2D
, 0.0))
482 // direct draw of hairline
483 RenderPolygonHairlinePrimitive2D(rPolygonHairlinePrimitive2D
, true);
486 void VclPixelProcessor2D::processBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D
& rBitmapCandidate
)
488 // check if graphic content is inside discrete local ViewPort
489 const basegfx::B2DRange
& rDiscreteViewPort(getViewInformation2D().getDiscreteViewport());
490 const basegfx::B2DHomMatrix
aLocalTransform(maCurrentTransformation
* rBitmapCandidate
.getTransform());
492 if(!rDiscreteViewPort
.isEmpty())
494 basegfx::B2DRange
aUnitRange(0.0, 0.0, 1.0, 1.0);
496 aUnitRange
.transform(aLocalTransform
);
498 if(!aUnitRange
.overlaps(rDiscreteViewPort
))
500 // content is outside discrete local ViewPort
505 RenderBitmapPrimitive2D(rBitmapCandidate
);
508 void VclPixelProcessor2D::processPolyPolygonGradientPrimitive2D(const primitive2d::PolyPolygonGradientPrimitive2D
& rPolygonCandidate
)
510 // direct draw of gradient
511 const attribute::FillGradientAttribute
& rGradient(rPolygonCandidate
.getFillGradient());
512 basegfx::BColor
aStartColor(maBColorModifierStack
.getModifiedColor(rGradient
.getStartColor()));
513 basegfx::BColor
aEndColor(maBColorModifierStack
.getModifiedColor(rGradient
.getEndColor()));
514 basegfx::B2DPolyPolygon
aLocalPolyPolygon(rPolygonCandidate
.getB2DPolyPolygon());
516 if(aLocalPolyPolygon
.count())
518 aLocalPolyPolygon
.transform(maCurrentTransformation
);
520 if(aStartColor
== aEndColor
)
522 // no gradient at all, draw as polygon in AA and non-AA case
523 mpOutputDevice
->SetLineColor();
524 mpOutputDevice
->SetFillColor(Color(aStartColor
));
525 mpOutputDevice
->DrawPolyPolygon(aLocalPolyPolygon
);
529 // use the primitive decomposition of the metafile
530 process(rPolygonCandidate
);
535 void VclPixelProcessor2D::processPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D
& rPolyPolygonColorPrimitive2D
)
537 // try to use directly
538 basegfx::B2DPolyPolygon aLocalPolyPolygon
;
540 tryDrawPolyPolygonColorPrimitive2DDirect(rPolyPolygonColorPrimitive2D
, 0.0);
541 // okay, done. In this case no gaps should have to be repaired, too
543 // when AA is on and this filled polygons are the result of stroked line geometry,
544 // draw the geometry once extra as lines to avoid AA 'gaps' between partial polygons
545 // Caution: This is needed in both cases (!)
546 if(mnPolygonStrokePrimitive2D
547 && getOptionsDrawinglayer().IsAntiAliasing()
548 && (mpOutputDevice
->GetAntialiasing() & AntialiasingFlags::EnableB2dDraw
))
550 const basegfx::BColor
aPolygonColor(maBColorModifierStack
.getModifiedColor(rPolyPolygonColorPrimitive2D
.getBColor()));
551 sal_uInt32
nCount(aLocalPolyPolygon
.count());
555 aLocalPolyPolygon
= rPolyPolygonColorPrimitive2D
.getB2DPolyPolygon();
556 aLocalPolyPolygon
.transform(maCurrentTransformation
);
557 nCount
= aLocalPolyPolygon
.count();
560 mpOutputDevice
->SetFillColor();
561 mpOutputDevice
->SetLineColor(Color(aPolygonColor
));
563 for(sal_uInt32
a(0); a
< nCount
; a
++)
565 mpOutputDevice
->DrawPolyLine(aLocalPolyPolygon
.getB2DPolygon(a
), 0.0);
570 void VclPixelProcessor2D::processUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D
& rUniTransparenceCandidate
)
572 // Detect if a single PolyPolygonColorPrimitive2D is contained; in that case,
573 // use the faster OutputDevice::DrawTransparent method
574 const primitive2d::Primitive2DContainer
& rContent
= rUniTransparenceCandidate
.getChildren();
576 if(!rContent
.empty())
578 if(0.0 == rUniTransparenceCandidate
.getTransparence())
580 // not transparent at all, use content
581 process(rUniTransparenceCandidate
.getChildren());
583 else if(rUniTransparenceCandidate
.getTransparence() > 0.0 && rUniTransparenceCandidate
.getTransparence() < 1.0)
585 bool bDrawTransparentUsed(false);
587 if(1 == rContent
.size())
589 const primitive2d::Primitive2DReference
xReference(rContent
[0]);
590 const primitive2d::BasePrimitive2D
* pBasePrimitive
= dynamic_cast< const primitive2d::BasePrimitive2D
* >(xReference
.get());
594 switch(pBasePrimitive
->getPrimitive2DID())
596 case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D
:
598 // single transparent tools::PolyPolygon identified, use directly
599 const primitive2d::PolyPolygonColorPrimitive2D
* pPoPoColor
= static_cast< const primitive2d::PolyPolygonColorPrimitive2D
* >(pBasePrimitive
);
600 OSL_ENSURE(pPoPoColor
, "OOps, PrimitiveID and PrimitiveType do not match (!)");
601 bDrawTransparentUsed
= true;
602 tryDrawPolyPolygonColorPrimitive2DDirect(*pPoPoColor
, rUniTransparenceCandidate
.getTransparence());
605 case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D
:
607 // single transparent PolygonHairlinePrimitive2D identified, use directly
608 const primitive2d::PolygonHairlinePrimitive2D
* pPoHair
= static_cast< const primitive2d::PolygonHairlinePrimitive2D
* >(pBasePrimitive
);
609 OSL_ENSURE(pPoHair
, "OOps, PrimitiveID and PrimitiveType do not match (!)");
611 // do no tallow by default - problem is that self-overlapping parts of this geometry will
612 // not be in an all-same transparency but will already alpha-cover themselves with blending.
613 // This is not what the UnifiedTransparencePrimitive2D defines: It requires all its
614 // content to be uniformly transparent.
615 // For hairline the effect is pretty minimal, but still not correct.
616 bDrawTransparentUsed
= false;
619 case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D
:
621 // single transparent PolygonStrokePrimitive2D identified, use directly
622 const primitive2d::PolygonStrokePrimitive2D
* pPoStroke
= static_cast< const primitive2d::PolygonStrokePrimitive2D
* >(pBasePrimitive
);
623 OSL_ENSURE(pPoStroke
, "OOps, PrimitiveID and PrimitiveType do not match (!)");
625 // do no tallow by default - problem is that self-overlapping parts of this geometry will
626 // not be in an all-same transparency but will already alpha-cover themselves with blending.
627 // This is not what the UnifiedTransparencePrimitive2D defines: It requires all its
628 // content to be uniformly transparent.
629 // To check, activate and draw a wide transparent self-crossing line/curve
630 bDrawTransparentUsed
= false;
634 SAL_INFO("drawinglayer", "default case for " << drawinglayer::primitive2d::idToString(rUniTransparenceCandidate
.getPrimitive2DID()));
640 if(!bDrawTransparentUsed
)
642 // unified sub-transparence. Draw to VDev first.
643 RenderUnifiedTransparencePrimitive2D(rUniTransparenceCandidate
);
649 void VclPixelProcessor2D::processControlPrimitive2D(const primitive2d::ControlPrimitive2D
& rControlPrimitive
)
652 const uno::Reference
< awt::XControl
>& rXControl(rControlPrimitive
.getXControl());
656 // remember old graphics and create new
657 uno::Reference
< awt::XView
> xControlView(rXControl
, uno::UNO_QUERY_THROW
);
658 const uno::Reference
< awt::XGraphics
> xOriginalGraphics(xControlView
->getGraphics());
659 const uno::Reference
< awt::XGraphics
> xNewGraphics(mpOutputDevice
->CreateUnoGraphics());
661 if(xNewGraphics
.is())
663 // link graphics and view
664 xControlView
->setGraphics(xNewGraphics
);
667 const basegfx::B2DHomMatrix
aObjectToPixel(maCurrentTransformation
* rControlPrimitive
.getTransform());
668 const basegfx::B2DPoint
aTopLeftPixel(aObjectToPixel
* basegfx::B2DPoint(0.0, 0.0));
670 // find out if the control is already visualized as a VCL-ChildWindow. If yes,
671 // it does not need to be painted at all.
672 uno::Reference
< awt::XWindow2
> xControlWindow(rXControl
, uno::UNO_QUERY_THROW
);
673 const bool bControlIsVisibleAsChildWindow(rXControl
->getPeer().is() && xControlWindow
->isVisible());
675 if(!bControlIsVisibleAsChildWindow
)
677 // draw it. Do not forget to use the evtl. offsetted origin of the target device,
678 // e.g. when used with mask/transparence buffer device
679 const Point
aOrigin(mpOutputDevice
->GetMapMode().GetOrigin());
681 aOrigin
.X() + basegfx::fround(aTopLeftPixel
.getX()),
682 aOrigin
.Y() + basegfx::fround(aTopLeftPixel
.getY()));
685 // restore original graphics
686 xControlView
->setGraphics(xOriginalGraphics
);
689 catch(const uno::Exception
&)
691 // #i116763# removing since there is a good alternative when the xControlView
692 // is not found and it is allowed to happen
693 // DBG_UNHANDLED_EXCEPTION();
695 // process recursively and use the decomposition as Bitmap
696 process(rControlPrimitive
);
700 void VclPixelProcessor2D::processPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D
& rPolygonStrokePrimitive2D
)
702 // try to use directly
703 if(tryDrawPolygonStrokePrimitive2DDirect(rPolygonStrokePrimitive2D
, 0.0))
708 // the stroke primitive may be decomposed to filled polygons. To keep
709 // evtl. set DrawModes aka DrawModeFlags::BlackLine, DrawModeFlags::GrayLine,
710 // DrawModeFlags::GhostedLine, DrawModeFlags::WhiteLine or DrawModeFlags::SettingsLine
711 // working, these need to be copied to the corresponding fill modes
712 const DrawModeFlags
nOriginalDrawMode(mpOutputDevice
->GetDrawMode());
713 adaptLineToFillDrawMode();
715 // polygon stroke primitive
717 // Lines with 1 and 2 pixel width without AA need special treatment since their visualization
718 // as filled polygons is geometrically correct but looks wrong since polygon filling avoids
719 // the right and bottom pixels. The used method evaluates that and takes the correct action,
720 // including calling recursively with decomposition if line is wide enough
721 RenderPolygonStrokePrimitive2D(rPolygonStrokePrimitive2D
);
724 mpOutputDevice
->SetDrawMode(nOriginalDrawMode
);
727 void VclPixelProcessor2D::processFillHatchPrimitive2D(const primitive2d::FillHatchPrimitive2D
& rFillHatchPrimitive
)
729 if(getOptionsDrawinglayer().IsAntiAliasing())
731 // if AA is used (or ignore smoothing is on), there is no need to smooth
732 // hatch painting, use decomposition
733 process(rFillHatchPrimitive
);
737 // without AA, use VCL to draw the hatch. It snaps hatch distances to the next pixel
738 // and forces hatch distance to be >= 3 pixels to make the hatch display look smoother.
739 // This is wrong in principle, but looks nicer. This could also be done here directly
740 // without VCL usage if needed
741 const attribute::FillHatchAttribute
& rFillHatchAttributes
= rFillHatchPrimitive
.getFillHatch();
743 // create hatch polygon in range size and discrete coordinates
744 basegfx::B2DRange
aHatchRange(rFillHatchPrimitive
.getOutputRange());
745 aHatchRange
.transform(maCurrentTransformation
);
746 const basegfx::B2DPolygon
aHatchPolygon(basegfx::utils::createPolygonFromRect(aHatchRange
));
748 if(rFillHatchAttributes
.isFillBackground())
750 // #i111846# background fill is active; draw fill polygon
751 const basegfx::BColor
aPolygonColor(maBColorModifierStack
.getModifiedColor(rFillHatchPrimitive
.getBColor()));
753 mpOutputDevice
->SetFillColor(Color(aPolygonColor
));
754 mpOutputDevice
->SetLineColor();
755 mpOutputDevice
->DrawPolygon(aHatchPolygon
);
758 // set hatch line color
759 const basegfx::BColor
aHatchColor(maBColorModifierStack
.getModifiedColor(rFillHatchPrimitive
.getBColor()));
760 mpOutputDevice
->SetFillColor();
761 mpOutputDevice
->SetLineColor(Color(aHatchColor
));
764 HatchStyle
eHatchStyle(HatchStyle::Single
);
766 switch(rFillHatchAttributes
.getStyle())
768 default : // HatchStyle::Single
772 case attribute::HatchStyle::Double
:
774 eHatchStyle
= HatchStyle::Double
;
777 case attribute::HatchStyle::Triple
:
779 eHatchStyle
= HatchStyle::Triple
;
785 const basegfx::B2DVector
aDiscreteDistance(maCurrentTransformation
* basegfx::B2DVector(rFillHatchAttributes
.getDistance(), 0.0));
786 const sal_uInt32
nDistance(basegfx::fround(aDiscreteDistance
.getLength()));
787 const sal_uInt16
nAngle10(static_cast<sal_uInt16
>(basegfx::fround(rFillHatchAttributes
.getAngle() / F_PI1800
)));
788 ::Hatch
aVCLHatch(eHatchStyle
, Color(rFillHatchAttributes
.getColor()), nDistance
, nAngle10
);
790 // draw hatch using VCL
791 mpOutputDevice
->DrawHatch(::tools::PolyPolygon(::tools::Polygon(aHatchPolygon
)), aVCLHatch
);
795 void VclPixelProcessor2D::processBackgroundColorPrimitive2D(const primitive2d::BackgroundColorPrimitive2D
& rPrimitive
)
797 // #i98404# Handle directly, especially when AA is active
798 const AntialiasingFlags
nOriginalAA(mpOutputDevice
->GetAntialiasing());
800 // switch AA off in all cases
801 mpOutputDevice
->SetAntialiasing(mpOutputDevice
->GetAntialiasing() & ~AntialiasingFlags::EnableB2dDraw
);
803 // create color for fill
804 const basegfx::BColor
aPolygonColor(maBColorModifierStack
.getModifiedColor(rPrimitive
.getBColor()));
805 Color
aFillColor(aPolygonColor
);
806 aFillColor
.SetTransparency(sal_uInt8((rPrimitive
.getTransparency() * 255.0) + 0.5));
807 mpOutputDevice
->SetFillColor(aFillColor
);
808 mpOutputDevice
->SetLineColor();
810 // create rectangle for fill
811 const basegfx::B2DRange
& aViewport(getViewInformation2D().getDiscreteViewport());
812 const ::tools::Rectangle
aRectangle(
813 static_cast<sal_Int32
>(floor(aViewport
.getMinX())), static_cast<sal_Int32
>(floor(aViewport
.getMinY())),
814 static_cast<sal_Int32
>(ceil(aViewport
.getMaxX())), static_cast<sal_Int32
>(ceil(aViewport
.getMaxY())));
815 mpOutputDevice
->DrawRect(aRectangle
);
817 // restore AA setting
818 mpOutputDevice
->SetAntialiasing(nOriginalAA
);
821 void VclPixelProcessor2D::processBorderLinePrimitive2D(const drawinglayer::primitive2d::BorderLinePrimitive2D
& rBorder
)
823 // Process recursively, but switch off AntiAliasing for
824 // horizontal/vertical lines (*not* diagonal lines).
825 // Checked using AntialiasingFlags::PixelSnapHairline instead,
826 // but with AntiAliasing on the display really is too 'ghosty' when
827 // using fine stroking. Correct, but 'ghosty'.
829 // It has shown that there are quite some problems here:
830 // - vcl OutDev renderer methods still use fallbacks to paint
831 // multiple single lines between discrete sizes of < 3.5 what
832 // looks bad and does not match
833 // - mix of filled Polygons and Lines is bad when AA switched off
834 // - Alignment of AA with non-AA may be bad in diverse different
837 // Due to these reasons I change the strategy: Always draw AAed, but
838 // allow fallback to test/check and if needed. The normal case
839 // where BorderLines will be system-dependently snapped to have at
840 // least a single discrete width per partial line (there may be up to
841 // three) works well nowadays due to most renderers moving the AA stuff
842 // by 0.5 pixels (discrete units) to match well with the non-AAed parts.
844 // Env-Switch for steering this, default is off.
845 // Enable by setting at all (and to something)
846 static const char* pSwitchOffAntiAliasingForHorVerBorderlines(getenv("SAL_SWITCH_OFF_ANTIALIASING_FOR_HOR_VER_BORTDERLINES"));
847 static bool bSwitchOffAntiAliasingForHorVerBorderlines(nullptr != pSwitchOffAntiAliasingForHorVerBorderlines
);
849 if (bSwitchOffAntiAliasingForHorVerBorderlines
&& rBorder
.isHorizontalOrVertical(getViewInformation2D()))
851 AntialiasingFlags nAntiAliasing
= mpOutputDevice
->GetAntialiasing();
852 mpOutputDevice
->SetAntialiasing(nAntiAliasing
& ~AntialiasingFlags::EnableB2dDraw
);
854 mpOutputDevice
->SetAntialiasing(nAntiAliasing
);
862 void VclPixelProcessor2D::processInvertPrimitive2D(const primitive2d::BasePrimitive2D
& rCandidate
)
864 // invert primitive (currently only used for HighContrast fallback for selection in SW and SC).
865 // (Not true, also used at least for the drawing of dragged column and row boundaries in SC.)
866 // Set OutDev to XOR and switch AA off (XOR does not work with AA)
867 mpOutputDevice
->Push();
868 mpOutputDevice
->SetRasterOp( RasterOp::Xor
);
869 const AntialiasingFlags
nAntiAliasing(mpOutputDevice
->GetAntialiasing());
870 mpOutputDevice
->SetAntialiasing(nAntiAliasing
& ~AntialiasingFlags::EnableB2dDraw
);
872 // process content recursively
876 mpOutputDevice
->Pop();
877 mpOutputDevice
->SetAntialiasing(nAntiAliasing
);
880 void VclPixelProcessor2D::processMetaFilePrimitive2D(const primitive2d::BasePrimitive2D
& rCandidate
)
883 const bool bForceLineSnap(getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete());
884 const AntialiasingFlags
nOldAntiAliase(mpOutputDevice
->GetAntialiasing());
888 mpOutputDevice
->SetAntialiasing(nOldAntiAliase
| AntialiasingFlags::PixelSnapHairline
);
895 mpOutputDevice
->SetAntialiasing(nOldAntiAliase
);
898 } // end of namespace processor2d
899 } // end of namespace drawinglayer
901 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */