xref: /trunk/main/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx (revision a3cdc23e488c57f3433f22cd4458e65c27aa499c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_drawinglayer.hxx"
24 
25 #include <drawinglayer/processor2d/vclpixelprocessor2d.hxx>
26 #include <vcl/outdev.hxx>
27 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
28 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
29 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
30 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
31 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
32 #include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx>
33 #include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
34 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
35 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
36 #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
37 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
38 #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
39 #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
40 #include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
41 #include <drawinglayer/primitive2d/controlprimitive2d.hxx>
42 #include <com/sun/star/awt/XWindow2.hpp>
43 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
44 #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
45 #include <helperwrongspellrenderer.hxx>
46 #include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx>
47 #include <basegfx/polygon/b2dpolygontools.hxx>
48 #include <vcl/hatch.hxx>
49 #include <tools/diagnose_ex.h>
50 #include <com/sun/star/awt/PosSize.hpp>
51 #include <drawinglayer/primitive2d/invertprimitive2d.hxx>
52 #include <cstdio>
53 #include <drawinglayer/primitive2d/backgroundcolorprimitive2d.hxx>
54 #include <basegfx/matrix/b2dhommatrixtools.hxx>
55 #include <drawinglayer/primitive2d/epsprimitive2d.hxx>
56 #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
57 #include <toolkit/helper/vclunohelper.hxx>
58 #include <vcl/window.hxx>
59 
60 //////////////////////////////////////////////////////////////////////////////
61 
62 using namespace com::sun::star;
63 
64 //////////////////////////////////////////////////////////////////////////////
65 
66 namespace drawinglayer
67 {
68     namespace processor2d
69     {
70         VclPixelProcessor2D::VclPixelProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev)
71         :   VclProcessor2D(rViewInformation, rOutDev)
72         {
73             // prepare maCurrentTransformation matrix with viewTransformation to target directly to pixels
74             maCurrentTransformation = rViewInformation.getObjectToViewTransformation();
75 
76             // prepare output directly to pixels
77             mpOutputDevice->Push(PUSH_MAPMODE);
78             mpOutputDevice->SetMapMode();
79 
80             // react on AntiAliasing settings
81             if(getOptionsDrawinglayer().IsAntiAliasing())
82             {
83                 mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() | ANTIALIASING_ENABLE_B2DDRAW);
84             }
85             else
86             {
87                 mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW);
88             }
89         }
90 
91         VclPixelProcessor2D::~VclPixelProcessor2D()
92         {
93             // restore MapMode
94             mpOutputDevice->Pop();
95 
96             // restore AntiAliasing
97             mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW);
98         }
99 
100         bool VclPixelProcessor2D::tryDrawPolyPolygonColorPrimitive2DDirect(const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D& rSource, double fTransparency)
101         {
102             basegfx::B2DPolyPolygon aLocalPolyPolygon(rSource.getB2DPolyPolygon());
103 
104             if(!aLocalPolyPolygon.count())
105             {
106                 // no geometry, done
107                 return true;
108             }
109 
110             const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rSource.getBColor()));
111 
112             mpOutputDevice->SetFillColor(Color(aPolygonColor));
113             mpOutputDevice->SetLineColor();
114             aLocalPolyPolygon.transform(maCurrentTransformation);
115             mpOutputDevice->DrawTransparent(
116                 aLocalPolyPolygon,
117                 fTransparency);
118 
119             return true;
120         }
121 
122         bool VclPixelProcessor2D::tryDrawPolygonHairlinePrimitive2DDirect(const drawinglayer::primitive2d::PolygonHairlinePrimitive2D& rSource, double fTransparency)
123         {
124             basegfx::B2DPolygon aLocalPolygon(rSource.getB2DPolygon());
125 
126             if(!aLocalPolygon.count())
127             {
128                 // no geometry, done
129                 return true;
130             }
131 
132             const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rSource.getBColor()));
133 
134             mpOutputDevice->SetFillColor();
135             mpOutputDevice->SetLineColor(Color(aLineColor));
136             aLocalPolygon.transform(maCurrentTransformation);
137 
138             // try drawing; if it did not work, use standard fallback
139             if(mpOutputDevice->TryDrawPolyLineDirect(
140                 aLocalPolygon,
141                 0.0,
142                 fTransparency))
143             {
144                 return true;
145             }
146 
147             return false;
148         }
149 
150         bool VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect(const drawinglayer::primitive2d::PolygonStrokePrimitive2D& rSource, double fTransparency)
151         {
152             basegfx::B2DPolygon aLocalPolygon(rSource.getB2DPolygon());
153 
154             if(!aLocalPolygon.count())
155             {
156                 // no geometry, done
157                 return true;
158             }
159 
160             aLocalPolygon = basegfx::tools::simplifyCurveSegments(aLocalPolygon);
161             basegfx::B2DPolyPolygon aHairLinePolyPolygon;
162 
163             if(rSource.getStrokeAttribute().isDefault() || 0.0 == rSource.getStrokeAttribute().getFullDotDashLen())
164             {
165                 // no line dashing, just copy
166                 aHairLinePolyPolygon.append(aLocalPolygon);
167             }
168             else
169             {
170                 // apply LineStyle
171                 basegfx::tools::applyLineDashing(
172                     aLocalPolygon,
173                     rSource.getStrokeAttribute().getDotDashArray(),
174                     &aHairLinePolyPolygon,
175                     0,
176                     rSource.getStrokeAttribute().getFullDotDashLen());
177             }
178 
179             if(!aHairLinePolyPolygon.count())
180             {
181                 // no geometry, done
182                 return true;
183             }
184 
185             const basegfx::BColor aLineColor(
186                 maBColorModifierStack.getModifiedColor(
187                     rSource.getLineAttribute().getColor()));
188 
189             mpOutputDevice->SetFillColor();
190             mpOutputDevice->SetLineColor(Color(aLineColor));
191             aHairLinePolyPolygon.transform(maCurrentTransformation);
192 
193             double fLineWidth(rSource.getLineAttribute().getWidth());
194 
195             if(basegfx::fTools::more(fLineWidth, 0.0))
196             {
197                 basegfx::B2DVector aLineWidth(fLineWidth, 0.0);
198 
199                 aLineWidth = maCurrentTransformation * aLineWidth;
200                 fLineWidth = aLineWidth.getLength();
201             }
202 
203             bool bHasPoints(false);
204             bool bTryWorked(false);
205 
206             for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++)
207             {
208                 const basegfx::B2DPolygon aSingle(aHairLinePolyPolygon.getB2DPolygon(a));
209 
210                 if(aSingle.count())
211                 {
212                     bHasPoints = true;
213 
214                     if(mpOutputDevice->TryDrawPolyLineDirect(
215                         aSingle,
216                         fLineWidth,
217                         fTransparency,
218                         rSource.getLineAttribute().getLineJoin(),
219                         rSource.getLineAttribute().getLineCap()))
220                     {
221                         bTryWorked = true;
222                     }
223                 }
224             }
225 
226             if(!bTryWorked && !bHasPoints)
227             {
228                 // no geometry despite try
229                 bTryWorked = true;
230             }
231 
232             return bTryWorked;
233         }
234 
235         void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
236         {
237             switch(rCandidate.getPrimitive2DID())
238             {
239                 case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
240                 {
241                     // directdraw of wrong spell primitive; added test possibility to check wrong spell decompose
242                     static bool bHandleWrongSpellDirectly(true);
243 
244                     if(bHandleWrongSpellDirectly)
245                     {
246                         const primitive2d::WrongSpellPrimitive2D& rWrongSpellPrimitive = static_cast< const primitive2d::WrongSpellPrimitive2D& >(rCandidate);
247 
248                         if(!renderWrongSpellPrimitive2D(
249                             rWrongSpellPrimitive,
250                             *mpOutputDevice,
251                             maCurrentTransformation,
252                             maBColorModifierStack))
253                         {
254                             // fallback to decomposition (MetaFile)
255                             process(rWrongSpellPrimitive.get2DDecomposition(getViewInformation2D()));
256                         }
257                     }
258                     else
259                     {
260                         process(rCandidate.get2DDecomposition(getViewInformation2D()));
261                     }
262                     break;
263                 }
264                 case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
265                 {
266                     // directdraw of text simple portion; added test possibility to check text decompose
267                     static bool bForceSimpleTextDecomposition(false);
268 
269                     // Adapt evtl. used special DrawMode
270                     const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
271                     adaptTextToFillDrawMode();
272 
273                     if(!bForceSimpleTextDecomposition && getOptionsDrawinglayer().IsRenderSimpleTextDirect())
274                     {
275                         RenderTextSimpleOrDecoratedPortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate));
276                     }
277                     else
278                     {
279                         process(rCandidate.get2DDecomposition(getViewInformation2D()));
280                     }
281 
282                     // restore DrawMode
283                     mpOutputDevice->SetDrawMode(nOriginalDrawMode);
284 
285                     break;
286                 }
287                 case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
288                 {
289                     // directdraw of text simple portion; added test possibility to check text decompose
290                     static bool bForceComplexTextDecomposition(false);
291 
292                     // Adapt evtl. used special DrawMode
293                     const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
294                     adaptTextToFillDrawMode();
295 
296                     if(!bForceComplexTextDecomposition && getOptionsDrawinglayer().IsRenderDecoratedTextDirect())
297                     {
298                         RenderTextSimpleOrDecoratedPortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate));
299                     }
300                     else
301                     {
302                         process(rCandidate.get2DDecomposition(getViewInformation2D()));
303                     }
304 
305                     // restore DrawMode
306                     mpOutputDevice->SetDrawMode(nOriginalDrawMode);
307 
308                     break;
309                 }
310                 case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
311                 {
312                     // try to use directly
313                     const primitive2d::PolygonHairlinePrimitive2D& rPolygonHairlinePrimitive2D = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate);
314                     static bool bAllowed(true);
315 
316                     if(bAllowed && tryDrawPolygonHairlinePrimitive2DDirect(rPolygonHairlinePrimitive2D, 0.0))
317                     {
318                         break;
319                     }
320 
321                     // direct draw of hairline
322                     RenderPolygonHairlinePrimitive2D(rPolygonHairlinePrimitive2D, true);
323                     break;
324                 }
325                 case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
326                 {
327                     // direct draw of transformed BitmapEx primitive
328                     const primitive2d::BitmapPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate);
329 
330                     // check if graphic content is inside discrete local ViewPort
331                     const basegfx::B2DRange& rDiscreteViewPort(getViewInformation2D().getDiscreteViewport());
332                     const basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rBitmapCandidate.getTransform());
333 
334                     if(!rDiscreteViewPort.isEmpty())
335                     {
336                         basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
337 
338                         aUnitRange.transform(aLocalTransform);
339 
340                         if(!aUnitRange.overlaps(rDiscreteViewPort))
341                         {
342                             // content is outside discrete local ViewPort
343                             break;
344                         }
345                     }
346 
347                     RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
348                     break;
349                 }
350                 case PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D :
351                 {
352                     // direct draw of fillBitmapPrimitive
353                     RenderFillGraphicPrimitive2D(static_cast< const primitive2d::FillGraphicPrimitive2D& >(rCandidate));
354                     break;
355                 }
356                 case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D :
357                 {
358                     // direct draw of gradient
359                     const primitive2d::PolyPolygonGradientPrimitive2D& rPolygonCandidate = static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate);
360                     const attribute::FillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient());
361                     basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor()));
362                     basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor()));
363                     basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
364 
365                     if(aLocalPolyPolygon.count())
366                     {
367                         aLocalPolyPolygon.transform(maCurrentTransformation);
368 
369                         if(aStartColor == aEndColor)
370                         {
371                             // no gradient at all, draw as polygon in AA and non-AA case
372                             mpOutputDevice->SetLineColor();
373                             mpOutputDevice->SetFillColor(Color(aStartColor));
374                             mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
375                         }
376                         else
377                         {
378                             // use the primitive decomposition of the metafile
379                             process(rPolygonCandidate.get2DDecomposition(getViewInformation2D()));
380                         }
381                     }
382                     break;
383                 }
384                 case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D :
385                 {
386                     // direct draw of bitmap
387                     RenderPolyPolygonGraphicPrimitive2D(static_cast< const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate));
388                     break;
389                 }
390                 case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
391                 {
392                     // try to use directly
393                     const primitive2d::PolyPolygonColorPrimitive2D& rPolyPolygonColorPrimitive2D = static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate);
394                     basegfx::B2DPolyPolygon aLocalPolyPolygon;
395                     static bool bAllowed(true);
396 
397                     if(bAllowed && tryDrawPolyPolygonColorPrimitive2DDirect(rPolyPolygonColorPrimitive2D, 0.0))
398                     {
399                         // okay, done. In this case no gaps should have to be repaired, too
400                     }
401                     else
402                     {
403                         // direct draw of PolyPolygon with color
404                         const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolyPolygonColorPrimitive2D.getBColor()));
405 
406                         mpOutputDevice->SetFillColor(Color(aPolygonColor));
407                         mpOutputDevice->SetLineColor();
408                         aLocalPolyPolygon = rPolyPolygonColorPrimitive2D.getB2DPolyPolygon();
409                         aLocalPolyPolygon.transform(maCurrentTransformation);
410                         mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
411                     }
412 
413                     // when AA is on and this filled polygons are the result of stroked line geometry,
414                     // draw the geometry once extra as lines to avoid AA 'gaps' between partial polygons
415                     // Caution: This is needed in both cases (!)
416                     if(mnPolygonStrokePrimitive2D
417                         && getOptionsDrawinglayer().IsAntiAliasing()
418                         && (mpOutputDevice->GetAntialiasing() & ANTIALIASING_ENABLE_B2DDRAW))
419                     {
420                         const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolyPolygonColorPrimitive2D.getBColor()));
421                         sal_uInt32 nCount(aLocalPolyPolygon.count());
422 
423                         if(!nCount)
424                         {
425                             aLocalPolyPolygon = rPolyPolygonColorPrimitive2D.getB2DPolyPolygon();
426                             aLocalPolyPolygon.transform(maCurrentTransformation);
427                             nCount = aLocalPolyPolygon.count();
428                         }
429 
430                         mpOutputDevice->SetFillColor();
431                         mpOutputDevice->SetLineColor(Color(aPolygonColor));
432 
433                         for(sal_uInt32 a(0); a < nCount; a++)
434                         {
435                             mpOutputDevice->DrawPolyLine(aLocalPolyPolygon.getB2DPolygon(a), 0.0);
436                         }
437                     }
438 
439                     break;
440                 }
441                 case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
442                 {
443                     // #i98289#
444                     const bool bForceLineSnap(getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete());
445                     const sal_uInt16 nOldAntiAliase(mpOutputDevice->GetAntialiasing());
446 
447                     if(bForceLineSnap)
448                     {
449                         mpOutputDevice->SetAntialiasing(nOldAntiAliase | ANTIALIASING_PIXELSNAPHAIRLINE);
450                     }
451 
452                     // use new Metafile decomposition
453                     process(rCandidate.get2DDecomposition(getViewInformation2D()));
454 
455                     if(bForceLineSnap)
456                     {
457                         mpOutputDevice->SetAntialiasing(nOldAntiAliase);
458                     }
459 
460                     break;
461                 }
462                 case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
463                 {
464                     // mask group.
465                     RenderMaskPrimitive2DPixel(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate));
466                     break;
467                 }
468                 case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
469                 {
470                     // modified color group. Force output to unified color.
471                     RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate));
472                     break;
473                 }
474                 case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D :
475                 {
476                     // Detect if a single PolyPolygonColorPrimitive2D is contained; in that case,
477                     // use the faster OutputDevice::DrawTransparent method
478                     const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate = static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate);
479                     const primitive2d::Primitive2DSequence rContent = rUniTransparenceCandidate.getChildren();
480 
481                     if(rContent.hasElements())
482                     {
483                         if(0.0 == rUniTransparenceCandidate.getTransparence())
484                         {
485                             // not transparent at all, use content
486                             process(rUniTransparenceCandidate.getChildren());
487                         }
488                         else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0)
489                         {
490                             bool bDrawTransparentUsed(false);
491 
492                             // since DEV300 m33 DrawTransparent is supported in VCL (for some targets
493                             // natively), so I am now enabling this shortcut
494                             static bool bAllowUsingDrawTransparent(true);
495 
496                             if(bAllowUsingDrawTransparent && 1 == rContent.getLength())
497                             {
498                                 const primitive2d::Primitive2DReference xReference(rContent[0]);
499                                 const primitive2d::BasePrimitive2D* pBasePrimitive = dynamic_cast< const primitive2d::BasePrimitive2D* >(xReference.get());
500 
501                                 if(pBasePrimitive)
502                                 {
503                                     switch(pBasePrimitive->getPrimitive2DID())
504                                     {
505                                         case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D:
506                                         {
507                                             // single transparent PolyPolygon identified, use directly
508                                             const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = static_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(pBasePrimitive);
509                                             OSL_ENSURE(pPoPoColor, "OOps, PrimitiveID and PrimitiveType do not match (!)");
510                                             bDrawTransparentUsed = tryDrawPolyPolygonColorPrimitive2DDirect(*pPoPoColor, rUniTransparenceCandidate.getTransparence());
511                                             break;
512                                         }
513                                         case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D:
514                                         {
515                                             // single transparent PolygonHairlinePrimitive2D identified, use directly
516                                             const primitive2d::PolygonHairlinePrimitive2D* pPoHair = static_cast< const primitive2d::PolygonHairlinePrimitive2D* >(pBasePrimitive);
517                                             OSL_ENSURE(pPoHair, "OOps, PrimitiveID and PrimitiveType do not match (!)");
518 
519                                             // do no tallow by default - problem is that self-overlapping parts of this geometry will
520                                             // not be in a all-same transparency but will already alpha-cover themselves with blending.
521                                             // This is not what the UnifiedTransparencePrimitive2D defines: It requires all it's
522                                             // content to be uniformly transparent.
523                                             // For hairline the effect is pretty minimal, but still not correct.
524                                             static bool bAllowed(false);
525 
526                                             bDrawTransparentUsed = bAllowed && tryDrawPolygonHairlinePrimitive2DDirect(*pPoHair, rUniTransparenceCandidate.getTransparence());
527                                             break;
528                                         }
529                                         case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
530                                         {
531                                             // single transparent PolygonStrokePrimitive2D identified, use directly
532                                             const primitive2d::PolygonStrokePrimitive2D* pPoStroke = static_cast< const primitive2d::PolygonStrokePrimitive2D* >(pBasePrimitive);
533                                             OSL_ENSURE(pPoStroke, "OOps, PrimitiveID and PrimitiveType do not match (!)");
534 
535                                             // do no tallow by default - problem is that self-overlapping parts of this geometry will
536                                             // not be in a all-same transparency but will already alpha-cover themselves with blending.
537                                             // This is not what the UnifiedTransparencePrimitive2D defines: It requires all it's
538                                             // content to be uniformly transparent.
539                                             // To check, activate and draw a wide transparent self-crossing line/curve
540                                             static bool bAllowed(false);
541 
542                                             bDrawTransparentUsed = bAllowed && tryDrawPolygonStrokePrimitive2DDirect(*pPoStroke, rUniTransparenceCandidate.getTransparence());
543                                             break;
544                                         }
545                                     }
546                                 }
547                             }
548 
549                             if(!bDrawTransparentUsed)
550                             {
551                                 // unified sub-transparence. Draw to VDev first.
552                                 RenderUnifiedTransparencePrimitive2D(rUniTransparenceCandidate);
553                             }
554                         }
555                     }
556 
557                     break;
558                 }
559                 case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
560                 {
561                     // sub-transparence group. Draw to VDev first.
562                     RenderTransparencePrimitive2D(static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate));
563                     break;
564                 }
565                 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
566                 {
567                     // transform group.
568                     RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
569                     break;
570                 }
571                 case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
572                 {
573                     // new XDrawPage for ViewInformation2D
574                     RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate));
575                     break;
576                 }
577                 case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
578                 {
579                     // marker array
580                     RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate));
581                     break;
582                 }
583                 case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
584                 {
585                     // point array
586                     RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate));
587                     break;
588                 }
589                 case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
590                 {
591                     // control primitive
592                     const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate);
593                     const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl());
594 
595                     try
596                     {
597                         // remember old graphics and create new
598                         uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW);
599                         const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics());
600                         const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics());
601 
602                         if(xNewGraphics.is())
603                         {
604                             // link graphics and view
605                             xControlView->setGraphics(xNewGraphics);
606 
607                             // get position
608                             const basegfx::B2DHomMatrix aObjectToPixel(maCurrentTransformation * rControlPrimitive.getTransform());
609                             const basegfx::B2DPoint aTopLeftPixel(aObjectToPixel * basegfx::B2DPoint(0.0, 0.0));
610 
611                             // find out if the control is already visualized as a VCL-ChildWindow. If yes,
612                             // it does not need to be painted at all.
613                             uno::Reference< awt::XWindow2 > xControlWindow(rXControl, uno::UNO_QUERY_THROW);
614                             const bool bControlIsVisibleAsChildWindow(rXControl->getPeer().is() && xControlWindow->isVisible());
615 
616                             if(!bControlIsVisibleAsChildWindow)
617                             {
618                                 // draw it. Do not forget to use the evtl. offsetted origin of the target device,
619                                 // e.g. when used with mask/transparence buffer device
620                                 const Point aOrigin(mpOutputDevice->GetMapMode().GetOrigin());
621                                 xControlView->draw(
622                                     aOrigin.X() + basegfx::fround(aTopLeftPixel.getX()),
623                                     aOrigin.Y() + basegfx::fround(aTopLeftPixel.getY()));
624                             }
625 
626                             // restore original graphics
627                             xControlView->setGraphics(xOriginalGraphics);
628                         }
629                     }
630                     catch(const uno::Exception&)
631                     {
632                         // #i116763# removing since there is a good alternative when the xControlView
633                         // is not found and it is allowed to happen
634                         // DBG_UNHANDLED_EXCEPTION();
635 
636                         // process recursively and use the decomposition as Bitmap
637                         process(rCandidate.get2DDecomposition(getViewInformation2D()));
638                     }
639 
640                     break;
641                 }
642                 case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
643                 {
644                     // try to use directly
645                     const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive2D = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate);
646 
647                     if(tryDrawPolygonStrokePrimitive2DDirect(rPolygonStrokePrimitive2D, 0.0))
648                     {
649                         break;
650                     }
651 
652                     // the stroke primitive may be decomposed to filled polygons. To keep
653                     // evtl. set DrawModes aka DRAWMODE_BLACKLINE, DRAWMODE_GRAYLINE,
654                     // DRAWMODE_GHOSTEDLINE, DRAWMODE_WHITELINE or DRAWMODE_SETTINGSLINE
655                     // working, these need to be copied to the corresponding fill modes
656                     const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
657                     adaptLineToFillDrawMode();
658 
659                     // polygon stroke primitive
660                     static bool bSuppressFatToHairlineCorrection(false);
661 
662                     if(bSuppressFatToHairlineCorrection)
663                     {
664                         // remember that we enter a PolygonStrokePrimitive2D decomposition,
665                         // used for AA thick line drawing
666                         mnPolygonStrokePrimitive2D++;
667 
668                         // with AA there is no need to handle thin lines special
669                         process(rCandidate.get2DDecomposition(getViewInformation2D()));
670 
671                         // leave PolygonStrokePrimitive2D
672                         mnPolygonStrokePrimitive2D--;
673                     }
674                     else
675                     {
676                         // Lines with 1 and 2 pixel width without AA need special treatment since their visualization
677                         // as filled polygons is geometrically correct but looks wrong since polygon filling avoids
678                         // the right and bottom pixels. The used method evaluates that and takes the correct action,
679                         // including calling recursively with decomposition if line is wide enough
680                         RenderPolygonStrokePrimitive2D(rPolygonStrokePrimitive2D);
681                     }
682 
683                     // restore DrawMode
684                     mpOutputDevice->SetDrawMode(nOriginalDrawMode);
685 
686                     break;
687                 }
688                 case PRIMITIVE2D_ID_FILLHATCHPRIMITIVE2D :
689                 {
690                     static bool bForceIgnoreHatchSmoothing(false);
691 
692                     if(bForceIgnoreHatchSmoothing || getOptionsDrawinglayer().IsAntiAliasing())
693                     {
694                         // if AA is used (or ignore smoothing is on), there is no need to smooth
695                         // hatch painting, use decomposition
696                         process(rCandidate.get2DDecomposition(getViewInformation2D()));
697                     }
698                     else
699                     {
700                         // without AA, use VCL to draw the hatch. It snaps hatch distances to the next pixel
701                         // and forces hatch distance to be >= 3 pixels to make the hatch display look smoother.
702                         // This is wrong in principle, but looks nicer. This could also be done here directly
703                         // without VCL usage if needed
704                         const primitive2d::FillHatchPrimitive2D& rFillHatchPrimitive = static_cast< const primitive2d::FillHatchPrimitive2D& >(rCandidate);
705                         const attribute::FillHatchAttribute& rFillHatchAttributes = rFillHatchPrimitive.getFillHatch();
706 
707                         // create hatch polygon in range size and discrete coordinates
708                         basegfx::B2DRange aHatchRange(rFillHatchPrimitive.getOutputRange());
709                         aHatchRange.transform(maCurrentTransformation);
710                         const basegfx::B2DPolygon aHatchPolygon(basegfx::tools::createPolygonFromRect(aHatchRange));
711 
712                         if(rFillHatchAttributes.isFillBackground())
713                         {
714                             // #i111846# background fill is active; draw fill polygon
715                             const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rFillHatchPrimitive.getBColor()));
716 
717                             mpOutputDevice->SetFillColor(Color(aPolygonColor));
718                             mpOutputDevice->SetLineColor();
719                             mpOutputDevice->DrawPolygon(aHatchPolygon);
720                         }
721 
722                         // set hatch line color
723                         const basegfx::BColor aHatchColor(maBColorModifierStack.getModifiedColor(rFillHatchPrimitive.getBColor()));
724                         mpOutputDevice->SetFillColor();
725                         mpOutputDevice->SetLineColor(Color(aHatchColor));
726 
727                         // get hatch style
728                         HatchStyle eHatchStyle(HATCH_SINGLE);
729 
730                         switch(rFillHatchAttributes.getStyle())
731                         {
732                             default : // HATCHSTYLE_SINGLE
733                             {
734                                 break;
735                             }
736                             case attribute::HATCHSTYLE_DOUBLE :
737                             {
738                                 eHatchStyle = HATCH_DOUBLE;
739                                 break;
740                             }
741                             case attribute::HATCHSTYLE_TRIPLE :
742                             {
743                                 eHatchStyle = HATCH_TRIPLE;
744                                 break;
745                             }
746                         }
747 
748                         // create hatch
749                         const basegfx::B2DVector aDiscreteDistance(maCurrentTransformation * basegfx::B2DVector(rFillHatchAttributes.getDistance(), 0.0));
750                         const sal_uInt32 nDistance(basegfx::fround(aDiscreteDistance.getLength()));
751                         const sal_uInt16 nAngle10((sal_uInt16)basegfx::fround(rFillHatchAttributes.getAngle() / F_PI1800));
752                         ::Hatch aVCLHatch(eHatchStyle, Color(rFillHatchAttributes.getColor()), nDistance, nAngle10);
753 
754                         // draw hatch using VCL
755                         mpOutputDevice->DrawHatch(PolyPolygon(Polygon(aHatchPolygon)), aVCLHatch);
756                     }
757                     break;
758                 }
759                 case PRIMITIVE2D_ID_BACKGROUNDCOLORPRIMITIVE2D :
760                 {
761                     // #i98404# Handle directly, especially when AA is active
762                     const primitive2d::BackgroundColorPrimitive2D& rPrimitive = static_cast< const primitive2d::BackgroundColorPrimitive2D& >(rCandidate);
763                     const sal_uInt16 nOriginalAA(mpOutputDevice->GetAntialiasing());
764 
765                     // switch AA off in all cases
766                     mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW);
767 
768                     // create color for fill
769                     const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPrimitive.getBColor()));
770                     mpOutputDevice->SetFillColor(Color(aPolygonColor));
771                     mpOutputDevice->SetLineColor();
772 
773                     // create rectangle for fill
774                     const basegfx::B2DRange& aViewport(getViewInformation2D().getDiscreteViewport());
775                     const Rectangle aRectangle(
776                         (sal_Int32)floor(aViewport.getMinX()), (sal_Int32)floor(aViewport.getMinY()),
777                         (sal_Int32)ceil(aViewport.getMaxX()), (sal_Int32)ceil(aViewport.getMaxY()));
778                     mpOutputDevice->DrawRect(aRectangle);
779 
780                     // restore AA setting
781                     mpOutputDevice->SetAntialiasing(nOriginalAA);
782                     break;
783                 }
784                 case PRIMITIVE2D_ID_TEXTHIERARCHYEDITPRIMITIVE2D :
785                 {
786                     // #i97628#
787                     // This primitive means that the content is derived from an active text edit,
788                     // not from model data itself. Some renderers need to suppress this content, e.g.
789                     // the pixel renderer used for displaying the edit view (like this one). It's
790                     // not to be suppressed by the MetaFile renderers, so that the edited text is
791                     // part of the MetaFile, e.g. needed for presentation previews.
792                     // Action: Ignore here, do nothing.
793                     break;
794                 }
795                 case PRIMITIVE2D_ID_INVERTPRIMITIVE2D :
796                 {
797                     // invert primitive (currently only used for HighContrast fallback for selection in SW and SC).
798                     // Set OutDev to XOR and switch AA off (XOR does not work with AA)
799                     mpOutputDevice->Push();
800                     mpOutputDevice->SetRasterOp( ROP_XOR );
801                     const sal_uInt16 nAntiAliasing(mpOutputDevice->GetAntialiasing());
802                     mpOutputDevice->SetAntialiasing(nAntiAliasing & ~ANTIALIASING_ENABLE_B2DDRAW);
803 
804                     // process content recursively
805                     process(rCandidate.get2DDecomposition(getViewInformation2D()));
806 
807                     // restore OutDev
808                     mpOutputDevice->Pop();
809                     mpOutputDevice->SetAntialiasing(nAntiAliasing);
810                     break;
811                 }
812                 case PRIMITIVE2D_ID_EPSPRIMITIVE2D :
813                 {
814                     RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate));
815                     break;
816                 }
817                 case PRIMITIVE2D_ID_SVGLINEARATOMPRIMITIVE2D:
818                 {
819                     RenderSvgLinearAtomPrimitive2D(static_cast< const primitive2d::SvgLinearAtomPrimitive2D& >(rCandidate));
820                     break;
821                 }
822                 case PRIMITIVE2D_ID_SVGRADIALATOMPRIMITIVE2D:
823                 {
824                     RenderSvgRadialAtomPrimitive2D(static_cast< const primitive2d::SvgRadialAtomPrimitive2D& >(rCandidate));
825                     break;
826                 }
827                 default :
828                 {
829                     // process recursively
830                     process(rCandidate.get2DDecomposition(getViewInformation2D()));
831                     break;
832                 }
833             }
834         }
835     } // end of namespace processor2d
836 } // end of namespace drawinglayer
837 
838 /* vim: set noet sw=4 ts=4: */
839