Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / drawinglayer / source / processor2d / vclpixelprocessor2d.cxx
blobf5ad3de9f4175ee7bd9f5950146035135cae7315
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
50 #include <cstdio>
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
65 namespace processor2d
67 struct VclPixelProcessor2D::Impl
69 AntialiasingFlags m_nOrigAntiAliasing;
71 explicit Impl(OutputDevice const& rOutDev)
72 : m_nOrigAntiAliasing(rOutDev.GetAntialiasing())
73 { }
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);
93 else
95 mpOutputDevice->SetAntialiasing(
96 m_pImpl->m_nOrigAntiAliasing & ~AntialiasingFlags::EnableB2dDraw);
100 VclPixelProcessor2D::~VclPixelProcessor2D()
102 // restore MapMode
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())
113 // no geometry, done
114 return;
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(),
124 fTransparency);
127 bool VclPixelProcessor2D::tryDrawPolygonHairlinePrimitive2DDirect(const drawinglayer::primitive2d::PolygonHairlinePrimitive2D& rSource, double fTransparency)
129 const basegfx::B2DPolygon& rLocalPolygon(rSource.getB2DPolygon());
131 if(!rLocalPolygon.count())
133 // no geometry, done
134 return true;
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,
146 rLocalPolygon,
147 0.0,
148 fTransparency);
151 bool VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect(const drawinglayer::primitive2d::PolygonStrokePrimitive2D& rSource, double fTransparency)
153 if(!rSource.getB2DPolygon().count())
155 // no geometry, done
156 return true;
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);
172 else
174 // apply LineStyle
175 basegfx::utils::applyLineDashing(
176 aLocalPolygon,
177 rSource.getStrokeAttribute().getDotDashArray(),
178 &aHairLinePolyPolygon,
179 nullptr,
180 rSource.getStrokeAttribute().getFullDotDashLen());
183 if(!aHairLinePolyPolygon.count())
185 // no geometry, done
186 return true;
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
205 fLineWidth = 0.0;
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));
226 if(aSingle.count())
228 bHasPoints = true;
230 if(mpOutputDevice->DrawPolyLineDirect(
231 maCurrentTransformation,
232 aSingle,
233 fLineWidth,
234 fTransparency,
235 rSource.getLineAttribute().getLineJoin(),
236 rSource.getLineAttribute().getLineCap(),
237 rSource.getLineAttribute().getMiterMinimumAngle()
238 /* false bBypassAACheck, default*/))
240 bTryWorked = true;
245 if(!bTryWorked && !bHasPoints)
247 // no geometry despite try
248 bTryWorked = true;
251 return bTryWorked;
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));
261 break;
263 case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
265 processTextSimplePortionPrimitive2D(static_cast<const primitive2d::TextSimplePortionPrimitive2D&>(rCandidate));
266 break;
268 case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
270 processTextDecoratedPortionPrimitive2D(static_cast<const primitive2d::TextSimplePortionPrimitive2D&>(rCandidate));
271 break;
273 case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
275 processPolygonHairlinePrimitive2D(static_cast<const primitive2d::PolygonHairlinePrimitive2D&>(rCandidate));
276 break;
278 case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
280 // direct draw of transformed BitmapEx primitive
281 processBitmapPrimitive2D(static_cast<const primitive2d::BitmapPrimitive2D&>(rCandidate));
282 break;
284 case PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D :
286 // direct draw of fillBitmapPrimitive
287 RenderFillGraphicPrimitive2D(static_cast< const primitive2d::FillGraphicPrimitive2D& >(rCandidate));
288 break;
290 case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D :
292 processPolyPolygonGradientPrimitive2D(static_cast<const primitive2d::PolyPolygonGradientPrimitive2D&>(rCandidate));
293 break;
295 case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D :
297 // direct draw of bitmap
298 RenderPolyPolygonGraphicPrimitive2D(static_cast< const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate));
299 break;
301 case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
303 processPolyPolygonColorPrimitive2D(static_cast<const primitive2d::PolyPolygonColorPrimitive2D&>(rCandidate));
304 break;
306 case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
308 processMetaFilePrimitive2D(rCandidate);
309 break;
311 case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
313 // mask group.
314 RenderMaskPrimitive2DPixel(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate));
315 break;
317 case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
319 // modified color group. Force output to unified color.
320 RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate));
321 break;
323 case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D :
325 processUnifiedTransparencePrimitive2D(static_cast<const primitive2d::UnifiedTransparencePrimitive2D&>(rCandidate));
326 break;
328 case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
330 // sub-transparence group. Draw to VDev first.
331 RenderTransparencePrimitive2D(static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate));
332 break;
334 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
336 // transform group.
337 RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
338 break;
340 case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
342 // new XDrawPage for ViewInformation2D
343 RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate));
344 break;
346 case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
348 // marker array
349 RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate));
350 break;
352 case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
354 // point array
355 RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate));
356 break;
358 case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
360 processControlPrimitive2D(static_cast<const primitive2d::ControlPrimitive2D&>(rCandidate));
361 break;
363 case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
365 processPolygonStrokePrimitive2D(static_cast<const primitive2d::PolygonStrokePrimitive2D&>(rCandidate));
366 break;
368 case PRIMITIVE2D_ID_FILLHATCHPRIMITIVE2D :
370 processFillHatchPrimitive2D(static_cast<const primitive2d::FillHatchPrimitive2D&>(rCandidate));
371 break;
373 case PRIMITIVE2D_ID_BACKGROUNDCOLORPRIMITIVE2D :
375 processBackgroundColorPrimitive2D(static_cast<const primitive2d::BackgroundColorPrimitive2D&>(rCandidate));
376 break;
378 case PRIMITIVE2D_ID_TEXTHIERARCHYEDITPRIMITIVE2D :
380 // #i97628#
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.
387 break;
389 case PRIMITIVE2D_ID_INVERTPRIMITIVE2D :
391 processInvertPrimitive2D(rCandidate);
392 break;
394 case PRIMITIVE2D_ID_EPSPRIMITIVE2D :
396 RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate));
397 break;
399 case PRIMITIVE2D_ID_SVGLINEARATOMPRIMITIVE2D:
401 RenderSvgLinearAtomPrimitive2D(static_cast< const primitive2d::SvgLinearAtomPrimitive2D& >(rCandidate));
402 break;
404 case PRIMITIVE2D_ID_SVGRADIALATOMPRIMITIVE2D:
406 RenderSvgRadialAtomPrimitive2D(static_cast< const primitive2d::SvgRadialAtomPrimitive2D& >(rCandidate));
407 break;
409 case PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D:
411 processBorderLinePrimitive2D(static_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D&>(rCandidate));
412 break;
414 default :
416 SAL_INFO("drawinglayer", "default case for " << drawinglayer::primitive2d::idToString(rCandidate.getPrimitive2DID()));
417 // process recursively
418 process(rCandidate);
419 break;
424 void VclPixelProcessor2D::processWrongSpellPrimitive2D(const primitive2d::WrongSpellPrimitive2D& rWrongSpellPrimitive)
426 if(!renderWrongSpellPrimitive2D(
427 rWrongSpellPrimitive,
428 *mpOutputDevice,
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);
447 else
449 process(rCandidate);
452 // restore DrawMode
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);
466 else
468 process(rCandidate);
471 // restore DrawMode
472 mpOutputDevice->SetDrawMode(nOriginalDrawMode);
475 void VclPixelProcessor2D::processPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D& rPolygonHairlinePrimitive2D)
477 if(tryDrawPolygonHairlinePrimitive2DDirect(rPolygonHairlinePrimitive2D, 0.0))
479 return;
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
501 return;
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);
527 else
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());
553 if(!nCount)
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());
592 if(pBasePrimitive)
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());
603 break;
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;
617 break;
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;
631 break;
633 default:
634 SAL_INFO("drawinglayer", "default case for " << drawinglayer::primitive2d::idToString(rUniTransparenceCandidate.getPrimitive2DID()));
635 break;
640 if(!bDrawTransparentUsed)
642 // unified sub-transparence. Draw to VDev first.
643 RenderUnifiedTransparencePrimitive2D(rUniTransparenceCandidate);
649 void VclPixelProcessor2D::processControlPrimitive2D(const primitive2d::ControlPrimitive2D& rControlPrimitive)
651 // control primitive
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);
666 // get position
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());
680 xControlView->draw(
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))
705 return;
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);
723 // restore DrawMode
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);
735 else
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));
763 // get hatch style
764 HatchStyle eHatchStyle(HatchStyle::Single);
766 switch(rFillHatchAttributes.getStyle())
768 default : // HatchStyle::Single
770 break;
772 case attribute::HatchStyle::Double :
774 eHatchStyle = HatchStyle::Double;
775 break;
777 case attribute::HatchStyle::Triple :
779 eHatchStyle = HatchStyle::Triple;
780 break;
784 // create hatch
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
835 // renderers
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);
853 process(rBorder);
854 mpOutputDevice->SetAntialiasing(nAntiAliasing);
856 else
858 process(rBorder);
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
873 process(rCandidate);
875 // restore OutDev
876 mpOutputDevice->Pop();
877 mpOutputDevice->SetAntialiasing(nAntiAliasing);
880 void VclPixelProcessor2D::processMetaFilePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
882 // #i98289#
883 const bool bForceLineSnap(getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete());
884 const AntialiasingFlags nOldAntiAliase(mpOutputDevice->GetAntialiasing());
886 if(bForceLineSnap)
888 mpOutputDevice->SetAntialiasing(nOldAntiAliase | AntialiasingFlags::PixelSnapHairline);
891 process(rCandidate);
893 if(bForceLineSnap)
895 mpOutputDevice->SetAntialiasing(nOldAntiAliase);
898 } // end of namespace processor2d
899 } // end of namespace drawinglayer
901 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */