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