LibreOffice Module drawinglayer (master) 1
vclpixelprocessor2d.cxx
Go to the documentation of this file.
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
23#include <comphelper/lok.hxx>
24
25#include <sal/log.hxx>
26#include <vcl/outdev.hxx>
27#include <vcl/hatch.hxx>
28#include <vcl/canvastools.hxx>
32
62
63#include <com/sun/star/awt/XWindow2.hpp>
64#include <com/sun/star/awt/XControl.hpp>
65
67#include <vcl/gradient.hxx>
68
69using namespace com::sun::star;
70
72{
74 OutputDevice& rOutDev,
75 const basegfx::BColorModifierStack& rInitStack)
76 : VclProcessor2D(rViewInformation, rOutDev, rInitStack)
77 , m_nOrigAntiAliasing(rOutDev.GetAntialiasing())
78{
79 // prepare maCurrentTransformation matrix with viewTransformation to target directly to pixels
81
82 // prepare output directly to pixels
84 mpOutputDevice->SetMapMode();
85
86 // react on AntiAliasing settings
87 if (rViewInformation.getUseAntiAliasing())
88 {
89 mpOutputDevice->SetAntialiasing(m_nOrigAntiAliasing | AntialiasingFlags::Enable);
90 }
91 else
92 {
93 mpOutputDevice->SetAntialiasing(m_nOrigAntiAliasing & ~AntialiasingFlags::Enable);
94 }
95}
96
98{
99 // restore MapMode
100 mpOutputDevice->Pop();
101
102 // restore AntiAliasing
103 mpOutputDevice->SetAntialiasing(m_nOrigAntiAliasing);
104}
105
107 const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D& rSource, double fTransparency)
108{
109 if (!rSource.getB2DPolyPolygon().count() || fTransparency < 0.0 || fTransparency >= 1.0)
110 {
111 // no geometry, done
112 return;
113 }
114
115 const basegfx::BColor aPolygonColor(
117
118 mpOutputDevice->SetFillColor(Color(aPolygonColor));
119 mpOutputDevice->SetLineColor();
120 mpOutputDevice->DrawTransparent(maCurrentTransformation, rSource.getB2DPolyPolygon(),
121 fTransparency);
122}
123
125 const drawinglayer::primitive2d::PolygonHairlinePrimitive2D& rSource, double fTransparency)
126{
127 const basegfx::B2DPolygon& rLocalPolygon(rSource.getB2DPolygon());
128
129 if (!rLocalPolygon.count() || fTransparency < 0.0 || fTransparency >= 1.0)
130 {
131 // no geometry, done
132 return true;
133 }
134
136
137 mpOutputDevice->SetFillColor();
138 mpOutputDevice->SetLineColor(Color(aLineColor));
139 //aLocalPolygon.transform(maCurrentTransformation);
140
141 // try drawing; if it did not work, use standard fallback
142 return mpOutputDevice->DrawPolyLineDirect(maCurrentTransformation, rLocalPolygon, 0.0,
143 fTransparency);
144}
145
147 const drawinglayer::primitive2d::PolygonStrokePrimitive2D& rSource, double fTransparency)
148{
149 const basegfx::B2DPolygon& rLocalPolygon(rSource.getB2DPolygon());
150
151 if (!rLocalPolygon.count() || fTransparency < 0.0 || fTransparency >= 1.0)
152 {
153 // no geometry, done
154 return true;
155 }
156
158 && css::drawing::LineCap_BUTT != rSource.getLineAttribute().getLineCap())
159 {
160 // better use decompose to get that combination done for now, see discussion
161 // at https://bugs.documentfoundation.org/show_bug.cgi?id=130478#c17 and ff
162 return false;
163 }
164
165 // MM01: Radically change here - no dismantle/applyLineDashing,
166 // let that happen low-level at DrawPolyLineDirect implementations
167 // to open up for buffering and evtl. direct draw with sys-dep
168 // graphic systems. Check for stroke is in use
169 const bool bStrokeAttributeNotUsed(rSource.getStrokeAttribute().isDefault()
170 || 0.0 == rSource.getStrokeAttribute().getFullDotDashLen());
171
172 const basegfx::BColor aLineColor(
174
175 mpOutputDevice->SetFillColor();
176 mpOutputDevice->SetLineColor(Color(aLineColor));
177
178 // MM01 draw direct, hand over dash data if available
179 return mpOutputDevice->DrawPolyLineDirect(
180 maCurrentTransformation, rLocalPolygon,
181 // tdf#124848 use LineWidth direct, do not try to solve for zero-case (aka hairline)
182 rSource.getLineAttribute().getWidth(), fTransparency,
183 bStrokeAttributeNotUsed ? nullptr : &rSource.getStrokeAttribute().getDotDashArray(),
186}
187
189{
190 switch (rCandidate.getPrimitive2DID())
191 {
193 {
195 static_cast<const primitive2d::WrongSpellPrimitive2D&>(rCandidate));
196 break;
197 }
199 {
201 static_cast<const primitive2d::TextSimplePortionPrimitive2D&>(rCandidate));
202 break;
203 }
205 {
207 static_cast<const primitive2d::TextSimplePortionPrimitive2D&>(rCandidate));
208 break;
209 }
211 {
213 static_cast<const primitive2d::PolygonHairlinePrimitive2D&>(rCandidate));
214 break;
215 }
217 {
218 // direct draw of transformed BitmapEx primitive
220 static_cast<const primitive2d::BitmapPrimitive2D&>(rCandidate));
221 break;
222 }
224 {
225 // direct draw of fillBitmapPrimitive
227 static_cast<const primitive2d::FillGraphicPrimitive2D&>(rCandidate));
228 break;
229 }
231 {
233 static_cast<const primitive2d::PolyPolygonGradientPrimitive2D&>(rCandidate));
234 break;
235 }
237 {
238 // direct draw of bitmap
240 static_cast<const primitive2d::PolyPolygonGraphicPrimitive2D&>(rCandidate));
241 break;
242 }
244 {
246 static_cast<const primitive2d::PolyPolygonColorPrimitive2D&>(rCandidate));
247 break;
248 }
250 {
251 processMetaFilePrimitive2D(rCandidate);
252 break;
253 }
255 {
256 // mask group.
258 static_cast<const primitive2d::MaskPrimitive2D&>(rCandidate));
259 break;
260 }
262 {
263 // modified color group. Force output to unified color.
265 static_cast<const primitive2d::ModifiedColorPrimitive2D&>(rCandidate));
266 break;
267 }
269 {
271 static_cast<const primitive2d::UnifiedTransparencePrimitive2D&>(rCandidate));
272 break;
273 }
275 {
276 // sub-transparence group. Draw to VDev first.
278 static_cast<const primitive2d::TransparencePrimitive2D&>(rCandidate));
279 break;
280 }
282 {
283 // transform group.
285 static_cast<const primitive2d::TransformPrimitive2D&>(rCandidate));
286 break;
287 }
289 {
290 // new XDrawPage for ViewInformation2D
292 static_cast<const primitive2d::PagePreviewPrimitive2D&>(rCandidate));
293 break;
294 }
296 {
297 // marker array
299 static_cast<const primitive2d::MarkerArrayPrimitive2D&>(rCandidate));
300 break;
301 }
303 {
304 // point array
306 static_cast<const primitive2d::PointArrayPrimitive2D&>(rCandidate));
307 break;
308 }
310 {
312 static_cast<const primitive2d::ControlPrimitive2D&>(rCandidate));
313 break;
314 }
316 {
318 static_cast<const primitive2d::PolygonStrokePrimitive2D&>(rCandidate));
319 break;
320 }
322 {
324 static_cast<const primitive2d::FillHatchPrimitive2D&>(rCandidate));
325 break;
326 }
328 {
330 static_cast<const primitive2d::BackgroundColorPrimitive2D&>(rCandidate));
331 break;
332 }
334 {
335 processInvertPrimitive2D(rCandidate);
336 break;
337 }
339 {
340 RenderEpsPrimitive2D(static_cast<const primitive2d::EpsPrimitive2D&>(rCandidate));
341 break;
342 }
344 {
346 static_cast<const primitive2d::SvgLinearAtomPrimitive2D&>(rCandidate));
347 break;
348 }
350 {
352 static_cast<const primitive2d::SvgRadialAtomPrimitive2D&>(rCandidate));
353 break;
354 }
356 {
358 static_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D&>(rCandidate));
359 break;
360 }
362 {
364 static_cast<const drawinglayer::primitive2d::FillGradientPrimitive2D&>(rCandidate));
365 break;
366 }
368 {
370 static_cast<const drawinglayer::primitive2d::PatternFillPrimitive2D&>(rCandidate));
371 break;
372 }
373 default:
374 {
375 SAL_INFO("drawinglayer", "default case for " << drawinglayer::primitive2d::idToString(
376 rCandidate.getPrimitive2DID()));
377 // process recursively
378 process(rCandidate);
379 break;
380 }
381 }
382}
383
385 const primitive2d::WrongSpellPrimitive2D& rWrongSpellPrimitive)
386{
389 {
390 // fallback to decomposition (MetaFile)
391 process(rWrongSpellPrimitive);
392 }
393}
394
397{
398 // Adapt evtl. used special DrawMode
399 const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode());
401
403 {
405 }
406 else
407 {
408 process(rCandidate);
409 }
410
411 // restore DrawMode
412 mpOutputDevice->SetDrawMode(nOriginalDrawMode);
413}
414
417{
418 // Adapt evtl. used special DrawMode
419 const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode());
421
423 {
425 }
426 else
427 {
428 process(rCandidate);
429 }
430
431 // restore DrawMode
432 mpOutputDevice->SetDrawMode(nOriginalDrawMode);
433}
434
436 const primitive2d::PolygonHairlinePrimitive2D& rPolygonHairlinePrimitive2D)
437{
438 if (tryDrawPolygonHairlinePrimitive2DDirect(rPolygonHairlinePrimitive2D, 0.0))
439 {
440 return;
441 }
442
443 // direct draw of hairline
444 RenderPolygonHairlinePrimitive2D(rPolygonHairlinePrimitive2D, true);
445}
446
448 const primitive2d::BitmapPrimitive2D& rBitmapCandidate)
449{
450 // check if graphic content is inside discrete local ViewPort
451 const basegfx::B2DRange& rDiscreteViewPort(getViewInformation2D().getDiscreteViewport());
453 * rBitmapCandidate.getTransform());
454
455 if (!rDiscreteViewPort.isEmpty())
456 {
457 basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
458
459 aUnitRange.transform(aLocalTransform);
460
461 if (!aUnitRange.overlaps(rDiscreteViewPort))
462 {
463 // content is outside discrete local ViewPort
464 return;
465 }
466 }
467
468 RenderBitmapPrimitive2D(rBitmapCandidate);
469}
470
472 const primitive2d::PolyPolygonGradientPrimitive2D& rPolygonCandidate)
473{
474 basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
475
476 // no geometry, no need to render, done
477 if (!aLocalPolyPolygon.count())
478 return;
479
480 // *try* direct draw (AKA using old VCL stuff) to render gradient
481 const attribute::FillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient());
482
483 // MCGR: *many* - and not only GradientStops - cases cannot be handled by VCL
484 // so use decomposition
485 // NOTE: There may be even more reasons to detect, e.g. a ViewTransformation
486 // that uses shear/rotate/mirror (what VCL cannot handle at all), see
487 // other checks already in processFillGradientPrimitive2D
488 if (rGradient.cannotBeHandledByVCL())
489 {
490 process(rPolygonCandidate);
491 return;
492 }
493
494 basegfx::BColor aStartColor(
495 maBColorModifierStack.getModifiedColor(rGradient.getColorStops().front().getStopColor()));
496 basegfx::BColor aEndColor(
497 maBColorModifierStack.getModifiedColor(rGradient.getColorStops().back().getStopColor()));
498
499 if (aStartColor == aEndColor)
500 {
501 // no gradient at all, draw as polygon in AA and non-AA case
502 aLocalPolyPolygon.transform(maCurrentTransformation);
503 mpOutputDevice->SetLineColor();
504 mpOutputDevice->SetFillColor(Color(aStartColor));
505 mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
506 return;
507 }
508
509 // use the primitive decomposition
510 process(rPolygonCandidate);
511}
512
514 const primitive2d::PolyPolygonColorPrimitive2D& rPolyPolygonColorPrimitive2D)
515{
516 // try to use directly
517 basegfx::B2DPolyPolygon aLocalPolyPolygon;
518
519 tryDrawPolyPolygonColorPrimitive2DDirect(rPolyPolygonColorPrimitive2D, 0.0);
520 // okay, done. In this case no gaps should have to be repaired, too
521
522 // when AA is on and this filled polygons are the result of stroked line geometry,
523 // draw the geometry once extra as lines to avoid AA 'gaps' between partial polygons
524 // Caution: This is needed in both cases (!)
525 if (!(mnPolygonStrokePrimitive2D && getViewInformation2D().getUseAntiAliasing()
526 && (mpOutputDevice->GetAntialiasing() & AntialiasingFlags::Enable)))
527 return;
528
529 const basegfx::BColor aPolygonColor(
530 maBColorModifierStack.getModifiedColor(rPolyPolygonColorPrimitive2D.getBColor()));
531 sal_uInt32 nCount(aLocalPolyPolygon.count());
532
533 if (!nCount)
534 {
535 aLocalPolyPolygon = rPolyPolygonColorPrimitive2D.getB2DPolyPolygon();
536 aLocalPolyPolygon.transform(maCurrentTransformation);
537 nCount = aLocalPolyPolygon.count();
538 }
539
540 mpOutputDevice->SetFillColor();
541 mpOutputDevice->SetLineColor(Color(aPolygonColor));
542
543 for (sal_uInt32 a(0); a < nCount; a++)
544 {
545 mpOutputDevice->DrawPolyLine(aLocalPolyPolygon.getB2DPolygon(a), 0.0);
546 }
547}
548
550 const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate)
551{
552 // Detect if a single PolyPolygonColorPrimitive2D is contained; in that case,
553 // use the faster OutputDevice::DrawTransparent method
554 const primitive2d::Primitive2DContainer& rContent = rUniTransparenceCandidate.getChildren();
555
556 if (rContent.empty())
557 return;
558
559 if (0.0 == rUniTransparenceCandidate.getTransparence())
560 {
561 // not transparent at all, use content
562 process(rUniTransparenceCandidate.getChildren());
563 }
564 else if (rUniTransparenceCandidate.getTransparence() > 0.0
565 && rUniTransparenceCandidate.getTransparence() < 1.0)
566 {
567 bool bDrawTransparentUsed(false);
568
569 if (1 == rContent.size())
570 {
571 const primitive2d::BasePrimitive2D* pBasePrimitive = rContent[0].get();
572
573 switch (pBasePrimitive->getPrimitive2DID())
574 {
576 {
577 // single transparent tools::PolyPolygon identified, use directly
579 = static_cast<const primitive2d::PolyPolygonColorPrimitive2D*>(
580 pBasePrimitive);
581 SAL_WARN_IF(!pPoPoColor, "drawinglayer",
582 "OOps, PrimitiveID and PrimitiveType do not match (!)");
583 bDrawTransparentUsed = true;
585 *pPoPoColor, rUniTransparenceCandidate.getTransparence());
586 break;
587 }
589 {
590 // single transparent PolygonHairlinePrimitive2D identified, use directly
592 = static_cast<const primitive2d::PolygonHairlinePrimitive2D*>(
593 pBasePrimitive);
594 SAL_WARN_IF(!pPoHair, "drawinglayer",
595 "OOps, PrimitiveID and PrimitiveType do not match (!)");
596
597 // do no tallow by default - problem is that self-overlapping parts of this geometry will
598 // not be in an all-same transparency but will already alpha-cover themselves with blending.
599 // This is not what the UnifiedTransparencePrimitive2D defines: It requires all its
600 // content to be uniformly transparent.
601 // For hairline the effect is pretty minimal, but still not correct.
602 bDrawTransparentUsed = false;
603 break;
604 }
606 {
607 // single transparent PolygonStrokePrimitive2D identified, use directly
609 = static_cast<const primitive2d::PolygonStrokePrimitive2D*>(pBasePrimitive);
610 SAL_WARN_IF(!pPoStroke, "drawinglayer",
611 "OOps, PrimitiveID and PrimitiveType do not match (!)");
612
613 // do no tallow by default - problem is that self-overlapping parts of this geometry will
614 // not be in an all-same transparency but will already alpha-cover themselves with blending.
615 // This is not what the UnifiedTransparencePrimitive2D defines: It requires all its
616 // content to be uniformly transparent.
617 // To check, activate and draw a wide transparent self-crossing line/curve
618 bDrawTransparentUsed = false;
619 break;
620 }
621 default:
622 SAL_INFO("drawinglayer",
623 "default case for " << drawinglayer::primitive2d::idToString(
624 rUniTransparenceCandidate.getPrimitive2DID()));
625 break;
626 }
627 }
628
629 if (!bDrawTransparentUsed)
630 {
631 // unified sub-transparence. Draw to VDev first.
632 RenderUnifiedTransparencePrimitive2D(rUniTransparenceCandidate);
633 }
634 }
635}
636
638 const primitive2d::ControlPrimitive2D& rControlPrimitive)
639{
640 // control primitive
641 const uno::Reference<awt::XControl>& rXControl(rControlPrimitive.getXControl());
642
643 try
644 {
645 // remember old graphics and create new
646 uno::Reference<awt::XView> xControlView(rXControl, uno::UNO_QUERY_THROW);
647 const uno::Reference<awt::XGraphics> xOriginalGraphics(xControlView->getGraphics());
648 const uno::Reference<awt::XGraphics> xNewGraphics(mpOutputDevice->CreateUnoGraphics());
649
650 if (xNewGraphics.is())
651 {
652 // find out if the control is already visualized as a VCL-ChildWindow. If yes,
653 // it does not need to be painted at all.
654 uno::Reference<awt::XWindow2> xControlWindow(rXControl, uno::UNO_QUERY_THROW);
655 bool bControlIsVisibleAsChildWindow(rXControl->getPeer().is()
656 && xControlWindow->isVisible());
657
658 // tdf#131281 The FormControls are not painted when using the Tiled Rendering for a simple
659 // reason: when e.g. bControlIsVisibleAsChildWindow is true. This is the case because the
660 // office is in non-layout mode (default for controls at startup). For the common office
661 // this means that there exists a real VCL-System-Window for the control, so it is *not*
662 // painted here due to being exactly obscured by that real Window (and creates danger of
663 // flickering, too).
664 // Tiled Rendering clients usually do *not* have real VCL-Windows for the controls, but
665 // exactly that would be needed on each client displaying the tiles (what would be hard
666 // to do but also would have advantages - the clients would have real controls in the
667 // shape of their target system which could be interacted with...). It is also what the
668 // office does.
669 // For now, fallback to just render these controls when Tiled Rendering is active to just
670 // have them displayed on all clients.
671 if (bControlIsVisibleAsChildWindow && comphelper::LibreOfficeKit::isActive())
672 {
673 // Do force paint when we are in Tiled Renderer and FormControl is 'visible'
674 bControlIsVisibleAsChildWindow = false;
675 }
676
677 if (!bControlIsVisibleAsChildWindow)
678 {
679 // Needs to be drawn. Link new graphics and view
680 xControlView->setGraphics(xNewGraphics);
681
682 // get position
684 * rControlPrimitive.getTransform());
685 const basegfx::B2DPoint aTopLeftPixel(aObjectToPixel * basegfx::B2DPoint(0.0, 0.0));
686
687 // Do not forget to use the evtl. offsetted origin of the target device,
688 // e.g. when used with mask/transparence buffer device
689 const Point aOrigin(mpOutputDevice->GetMapMode().GetOrigin());
690 xControlView->draw(aOrigin.X() + basegfx::fround(aTopLeftPixel.getX()),
691 aOrigin.Y() + basegfx::fround(aTopLeftPixel.getY()));
692
693 // restore original graphics
694 xControlView->setGraphics(xOriginalGraphics);
695 }
696 }
697 }
698 catch (const uno::Exception&)
699 {
700 // #i116763# removing since there is a good alternative when the xControlView
701 // is not found and it is allowed to happen
702 // DBG_UNHANDLED_EXCEPTION();
703
704 // process recursively and use the decomposition as Bitmap
705 process(rControlPrimitive);
706 }
707}
708
710 const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive2D)
711{
712 // try to use directly
713 if (tryDrawPolygonStrokePrimitive2DDirect(rPolygonStrokePrimitive2D, 0.0))
714 {
715 return;
716 }
717
718 // the stroke primitive may be decomposed to filled polygons. To keep
719 // evtl. set DrawModes aka DrawModeFlags::BlackLine, DrawModeFlags::GrayLine,
720 // DrawModeFlags::GhostedLine, DrawModeFlags::WhiteLine or DrawModeFlags::SettingsLine
721 // working, these need to be copied to the corresponding fill modes
722 const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode());
724
725 // polygon stroke primitive
726
727 // Lines with 1 and 2 pixel width without AA need special treatment since their visualization
728 // as filled polygons is geometrically correct but looks wrong since polygon filling avoids
729 // the right and bottom pixels. The used method evaluates that and takes the correct action,
730 // including calling recursively with decomposition if line is wide enough
731 RenderPolygonStrokePrimitive2D(rPolygonStrokePrimitive2D);
732
733 // restore DrawMode
734 mpOutputDevice->SetDrawMode(nOriginalDrawMode);
735}
736
738 const primitive2d::FillHatchPrimitive2D& rFillHatchPrimitive)
739{
740 if (getViewInformation2D().getUseAntiAliasing())
741 {
742 // if AA is used (or ignore smoothing is on), there is no need to smooth
743 // hatch painting, use decomposition
744 process(rFillHatchPrimitive);
745 }
746 else
747 {
748 // without AA, use VCL to draw the hatch. It snaps hatch distances to the next pixel
749 // and forces hatch distance to be >= 3 pixels to make the hatch display look smoother.
750 // This is wrong in principle, but looks nicer. This could also be done here directly
751 // without VCL usage if needed
752 const attribute::FillHatchAttribute& rFillHatchAttributes
753 = rFillHatchPrimitive.getFillHatch();
754
755 // create hatch polygon in range size and discrete coordinates
756 basegfx::B2DRange aHatchRange(rFillHatchPrimitive.getOutputRange());
758 const basegfx::B2DPolygon aHatchPolygon(basegfx::utils::createPolygonFromRect(aHatchRange));
759
760 if (rFillHatchAttributes.isFillBackground())
761 {
762 // #i111846# background fill is active; draw fill polygon
763 const basegfx::BColor aPolygonColor(
764 maBColorModifierStack.getModifiedColor(rFillHatchPrimitive.getBColor()));
765
766 mpOutputDevice->SetFillColor(Color(aPolygonColor));
767 mpOutputDevice->SetLineColor();
768 mpOutputDevice->DrawPolygon(aHatchPolygon);
769 }
770
771 // set hatch line color
772 const basegfx::BColor aHatchColor(
773 maBColorModifierStack.getModifiedColor(rFillHatchPrimitive.getBColor()));
774 mpOutputDevice->SetFillColor();
775 mpOutputDevice->SetLineColor(Color(aHatchColor));
776
777 // get hatch style
778 HatchStyle eHatchStyle(HatchStyle::Single);
779
780 switch (rFillHatchAttributes.getStyle())
781 {
782 default: // HatchStyle::Single
783 {
784 break;
785 }
787 {
788 eHatchStyle = HatchStyle::Double;
789 break;
790 }
792 {
793 eHatchStyle = HatchStyle::Triple;
794 break;
795 }
796 }
797
798 // create hatch
799 const basegfx::B2DVector aDiscreteDistance(
800 maCurrentTransformation * basegfx::B2DVector(rFillHatchAttributes.getDistance(), 0.0));
801 const sal_uInt32 nDistance(basegfx::fround(aDiscreteDistance.getLength()));
802 const sal_uInt32 nAngle10(
803 basegfx::rad2deg<10>(basegfx::fround(rFillHatchAttributes.getAngle())));
804 ::Hatch aVCLHatch(eHatchStyle, Color(rFillHatchAttributes.getColor()), nDistance,
805 Degree10(nAngle10));
806
807 // draw hatch using VCL
808 mpOutputDevice->DrawHatch(::tools::PolyPolygon(::tools::Polygon(aHatchPolygon)), aVCLHatch);
809 }
810}
811
814{
815 // #i98404# Handle directly, especially when AA is active
816 const AntialiasingFlags nOriginalAA(mpOutputDevice->GetAntialiasing());
817
818 // switch AA off in all cases
819 mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~AntialiasingFlags::Enable);
820
821 // create color for fill
822 const basegfx::BColor aPolygonColor(
824 Color aFillColor(aPolygonColor);
825 aFillColor.SetAlpha(255 - sal_uInt8((rPrimitive.getTransparency() * 255.0) + 0.5));
826 mpOutputDevice->SetFillColor(aFillColor);
827 mpOutputDevice->SetLineColor();
828
829 // create rectangle for fill
830 const basegfx::B2DRange& aViewport(getViewInformation2D().getDiscreteViewport());
831 const ::tools::Rectangle aRectangle(static_cast<sal_Int32>(floor(aViewport.getMinX())),
832 static_cast<sal_Int32>(floor(aViewport.getMinY())),
833 static_cast<sal_Int32>(ceil(aViewport.getMaxX())),
834 static_cast<sal_Int32>(ceil(aViewport.getMaxY())));
835 mpOutputDevice->DrawRect(aRectangle);
836
837 // restore AA setting
838 mpOutputDevice->SetAntialiasing(nOriginalAA);
839}
840
843{
844 // Process recursively, but switch off AntiAliasing for
845 // horizontal/vertical lines (*not* diagonal lines).
846 // Checked using AntialiasingFlags::PixelSnapHairline instead,
847 // but with AntiAliasing on the display really is too 'ghosty' when
848 // using fine stroking. Correct, but 'ghosty'.
849
850 // It has shown that there are quite some problems here:
851 // - vcl OutDev renderer methods still use fallbacks to paint
852 // multiple single lines between discrete sizes of < 3.5 what
853 // looks bad and does not match
854 // - mix of filled Polygons and Lines is bad when AA switched off
855 // - Alignment of AA with non-AA may be bad in diverse different
856 // renderers
857 //
858 // Due to these reasons I change the strategy: Always draw AAed, but
859 // allow fallback to test/check and if needed. The normal case
860 // where BorderLines will be system-dependently snapped to have at
861 // least a single discrete width per partial line (there may be up to
862 // three) works well nowadays due to most renderers moving the AA stuff
863 // by 0.5 pixels (discrete units) to match well with the non-AAed parts.
864 //
865 // Env-Switch for steering this, default is off.
866 // Enable by setting at all (and to something)
867 static const char* pSwitchOffAntiAliasingForHorVerBorderlines(
868 getenv("SAL_SWITCH_OFF_ANTIALIASING_FOR_HOR_VER_BORTDERLINES"));
869 static bool bSwitchOffAntiAliasingForHorVerBorderlines(
870 nullptr != pSwitchOffAntiAliasingForHorVerBorderlines);
871
872 if (bSwitchOffAntiAliasingForHorVerBorderlines
874 {
875 AntialiasingFlags nAntiAliasing = mpOutputDevice->GetAntialiasing();
876 mpOutputDevice->SetAntialiasing(nAntiAliasing & ~AntialiasingFlags::Enable);
877 process(rBorder);
878 mpOutputDevice->SetAntialiasing(nAntiAliasing);
879 }
880 else
881 {
882 process(rBorder);
883 }
884}
885
887{
888 // invert primitive (currently only used for HighContrast fallback for selection in SW and SC).
889 // (Not true, also used at least for the drawing of dragged column and row boundaries in SC.)
890 // Set OutDev to XOR and switch AA off (XOR does not work with AA)
891 mpOutputDevice->Push();
892 mpOutputDevice->SetRasterOp(RasterOp::Xor);
893 const AntialiasingFlags nAntiAliasing(mpOutputDevice->GetAntialiasing());
894 mpOutputDevice->SetAntialiasing(nAntiAliasing & ~AntialiasingFlags::Enable);
895
896 // process content recursively
897 process(rCandidate);
898
899 // restore OutDev
900 mpOutputDevice->Pop();
901 mpOutputDevice->SetAntialiasing(nAntiAliasing);
902}
903
905{
906 // #i98289#
907 const bool bForceLineSnap(getViewInformation2D().getPixelSnapHairline());
908 const AntialiasingFlags nOldAntiAliase(mpOutputDevice->GetAntialiasing());
909
910 if (bForceLineSnap)
911 {
912 mpOutputDevice->SetAntialiasing(nOldAntiAliase | AntialiasingFlags::PixelSnapHairline);
913 }
914
915 process(rCandidate);
916
917 if (bForceLineSnap)
918 {
919 mpOutputDevice->SetAntialiasing(nOldAntiAliase);
920 }
921}
922
924 const primitive2d::FillGradientPrimitive2D& rPrimitive)
925{
926 const attribute::FillGradientAttribute& rFillGradient = rPrimitive.getFillGradient();
927 bool useDecompose(false);
928
929 // MCGR: *many* - and not only GradientStops - cases cannot be handled by VCL
930 // so use decomposition
931 if (rFillGradient.cannotBeHandledByVCL())
932 {
933 useDecompose = true;
934 }
935
936 // tdf#149754 VCL gradient draw is not capable to handle all primitive gradient definitions,
937 // what should be clear due to being developed to extend/replace them in
938 // capabilities & precision.
939 // It is e.g. not capable to correctly paint if the OutputRange is not completely
940 // inside the DefinitionRange, thus forcing to paint gradient parts *outside* the
941 // DefinitionRange.
942 // This happens for Writer with Frames anchored in Frames (and was broken due to
943 // falling back to VCL Gradient paint here), and for the new SlideBackgroundFill
944 // Fill mode for objects using it that reach outside the page (which is the
945 // DefinitionRange in that case).
946 // I see no real reason to fallback here to OutputDevice::DrawGradient and VCL
947 // gradient paint at all (system-dependent renderers wouldn't in the future), but
948 // will for convenience only add that needed additional correcting case
949 if (!useDecompose && !rPrimitive.getDefinitionRange().isInside(rPrimitive.getOutputRange()))
950 {
951 useDecompose = true;
952 }
953
954 // tdf#151081 need to use regular primitive decomposition when the gradient
955 // is transformed in any other way then just translate & scale
956 if (!useDecompose)
957 {
958 basegfx::B2DVector aScale, aTranslate;
959 double fRotate, fShearX;
960
961 maCurrentTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
962
963 // detect if transformation is rotated, sheared or mirrored in X and/or Y
965 || aScale.getX() < 0.0 || aScale.getY() < 0.0)
966 {
967 useDecompose = true;
968 }
969 }
970
971 if (useDecompose)
972 {
973 // default is to use the direct render below. For security,
974 // keep the (simple) fallback to decompose in place here
975 static bool bTryDirectRender(true);
976
977 if (bTryDirectRender)
978 {
979 // MCGR: Avoid one level of primitive creation, use FillGradientPrimitive2D
980 // tooling to directly create needed geometry & color for getting better
981 // performance (partially compensate for potentially more expensive multi
982 // color gradients).
983 // To handle a primitive that needs paint, either use decompose, or - when you
984 // do not want that for any reason, e.g. extra primitives created - implement
985 // a direct handling in your primitive renderer. This is always possible
986 // since primitives by definition are self-contained what means they have all
987 // needed data locally available to do so.
988 // The question is the complexity to invest - the implemented decompose
989 // is always a good hint of what is needed to do this. In this case I decided
990 // to add some tooling methods to the primitive itself to support this. These
991 // are used in decompose and can be used - as here now - for direct handling,
992 // too. This is always a possibility in primitive handling - you can, but do not
993 // have to.
994 mpOutputDevice->SetFillColor(
996 mpOutputDevice->SetLineColor();
997 mpOutputDevice->DrawTransparent(
1001 0.0);
1002
1003 // paint solid fill steps by providing callback as lambda
1004 auto aCallback([&rPrimitive, this](const basegfx::B2DHomMatrix& rMatrix,
1005 const basegfx::BColor& rColor) {
1006 // create part polygon
1007 basegfx::B2DPolygon aNewPoly(rPrimitive.getUnitPolygon());
1008 aNewPoly.transform(rMatrix);
1009
1010 // create solid fill
1012 mpOutputDevice->DrawTransparent(maCurrentTransformation,
1013 basegfx::B2DPolyPolygon(aNewPoly), 0.0);
1014 });
1015
1016 // call value generator to trigger callbacks
1017 rPrimitive.generateMatricesAndColors(aCallback);
1018 }
1019 else
1020 {
1021 // use the decompose
1022 process(rPrimitive);
1023 }
1024
1025 return;
1026 }
1027
1028 // try to use vcl - since vcl uses the old gradient paint mechanisms this may
1029 // create wrong geometries. If so, add another case above for useDecompose
1030 Gradient aGradient(rFillGradient.getStyle(),
1031 Color(rFillGradient.getColorStops().front().getStopColor()),
1032 Color(rFillGradient.getColorStops().back().getStopColor()));
1033
1034 aGradient.SetAngle(Degree10(static_cast<int>(basegfx::rad2deg<10>(rFillGradient.getAngle()))));
1035 aGradient.SetBorder(rFillGradient.getBorder() * 100);
1036 aGradient.SetOfsX(rFillGradient.getOffsetX() * 100.0);
1037 aGradient.SetOfsY(rFillGradient.getOffsetY() * 100.0);
1038 aGradient.SetSteps(rFillGradient.getSteps());
1039
1040 basegfx::B2DRange aOutputRange(rPrimitive.getOutputRange());
1041 aOutputRange.transform(maCurrentTransformation);
1042 basegfx::B2DRange aFullRange(rPrimitive.getDefinitionRange());
1044
1045 const tools::Rectangle aOutputRectangle(
1046 std::floor(aOutputRange.getMinX()), std::floor(aOutputRange.getMinY()),
1047 std::ceil(aOutputRange.getMaxX()), std::ceil(aOutputRange.getMaxY()));
1048 const tools::Rectangle aFullRectangle(
1049 std::floor(aFullRange.getMinX()), std::floor(aFullRange.getMinY()),
1050 std::ceil(aFullRange.getMaxX()), std::ceil(aFullRange.getMaxY()));
1051
1053 mpOutputDevice->IntersectClipRegion(aOutputRectangle);
1054 mpOutputDevice->DrawGradient(aFullRectangle, aGradient);
1055 mpOutputDevice->Pop();
1056}
1057
1059 const primitive2d::PatternFillPrimitive2D& rPrimitive)
1060{
1061 const basegfx::B2DRange& rReferenceRange = rPrimitive.getReferenceRange();
1062 if (rReferenceRange.isEmpty() || rReferenceRange.getWidth() <= 0.0
1063 || rReferenceRange.getHeight() <= 0.0)
1064 return;
1065
1066 basegfx::B2DPolyPolygon aMask = rPrimitive.getMask();
1068 const basegfx::B2DRange aMaskRange(aMask.getB2DRange());
1069
1070 if (aMaskRange.isEmpty() || aMaskRange.getWidth() <= 0.0 || aMaskRange.getHeight() <= 0.0)
1071 return;
1072
1073 sal_uInt32 nTileWidth, nTileHeight;
1074 rPrimitive.getTileSize(nTileWidth, nTileHeight, getViewInformation2D());
1075 if (nTileWidth == 0 || nTileHeight == 0)
1076 return;
1077 BitmapEx aTileImage = rPrimitive.createTileImage(nTileWidth, nTileHeight);
1079
1080 // Unless smooth edges are needed, simply use clipping.
1081 if (basegfx::utils::isRectangle(aMask) || !getViewInformation2D().getUseAntiAliasing())
1082 {
1084 mpOutputDevice->IntersectClipRegion(vcl::Region(aMask));
1085 Wallpaper aWallpaper(aTileImage);
1086 aWallpaper.SetColor(COL_TRANSPARENT);
1087 mpOutputDevice->DrawWallpaper(aMaskRect, aWallpaper);
1088 mpOutputDevice->Pop();
1089 return;
1090 }
1091
1092 impBufferDevice aBufferDevice(*mpOutputDevice, aMaskRange);
1093
1094 if (!aBufferDevice.isVisible())
1095 return;
1096
1097 // remember last OutDev and set to content
1098 OutputDevice* pLastOutputDevice = mpOutputDevice;
1099 mpOutputDevice = &aBufferDevice.getContent();
1100
1101 // if the tile is a single pixel big, just flood fill with that pixel color
1102 if (nTileWidth == 1 && nTileHeight == 1)
1103 {
1104 Color col = aTileImage.GetPixelColor(0, 0);
1105 mpOutputDevice->SetLineColor(col);
1106 mpOutputDevice->SetFillColor(col);
1107 mpOutputDevice->DrawRect(aMaskRect);
1108 }
1109 else
1110 {
1111 Wallpaper aWallpaper(aTileImage);
1112 aWallpaper.SetColor(COL_TRANSPARENT);
1113 mpOutputDevice->DrawWallpaper(aMaskRect, aWallpaper);
1114 }
1115
1116 // back to old OutDev
1117 mpOutputDevice = pLastOutputDevice;
1118
1119 // draw mask
1120 VirtualDevice& rMask = aBufferDevice.getTransparence();
1121 rMask.SetLineColor();
1122 rMask.SetFillColor(COL_BLACK);
1123 rMask.DrawPolyPolygon(aMask);
1124
1125 // dump buffer to outdev
1126 aBufferDevice.paint();
1127}
1128
1129} // end of namespace
1130
1131/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
AntialiasingFlags
DrawModeFlags
::Color GetPixelColor(sal_Int32 nX, sal_Int32 nY) const
void SetAlpha(sal_uInt8 nAlpha)
void SetOfsX(sal_uInt16 nOfsX)
void SetBorder(sal_uInt16 nBorder)
void SetSteps(sal_uInt16 nSteps)
void SetOfsY(sal_uInt16 nOfsY)
void SetAngle(Degree10 nAngle)
void SetLineColor()
void SetFillColor()
void DrawPolyPolygon(const tools::PolyPolygon &rPolyPoly)
constexpr tools::Long Y() const
constexpr tools::Long X() const
void SetColor(const Color &rColor)
bool decompose(B2DTuple &rScale, B2DTuple &rTranslate, double &rRotate, double &rShearX) const
B2DPolygon const & getB2DPolygon(sal_uInt32 nIndex) const
void transform(const basegfx::B2DHomMatrix &rMatrix)
B2DRange getB2DRange() const
sal_uInt32 count() const
void transform(const basegfx::B2DHomMatrix &rMatrix)
sal_uInt32 count() const
BASEGFX_DLLPUBLIC void transform(const B2DHomMatrix &rMatrix)
double getLength() const
::basegfx::BColor getModifiedColor(const ::basegfx::BColor &rSource) const
TYPE getMaxX() const
TYPE getWidth() const
TYPE getMinX() const
TYPE getMinY() const
TYPE getMaxY() const
bool isInside(const Tuple2D< TYPE > &rTuple) const
bool isEmpty() const
TYPE getHeight() const
bool overlaps(const Range2D &rRange) const
TYPE getX() const
TYPE getY() const
const basegfx::BColorStops & getColorStops() const
basegfx::B2DLineJoin getLineJoin() const
css::drawing::LineCap getLineCap() const
const basegfx::BColor & getColor() const
const ::std::vector< double > & getDotDashArray() const
bool getUseAntiAliasing() const
Determine if to use AntiAliasing on target pixel device, PropertyName is 'UseAntiAliasing'.
const basegfx::B2DHomMatrix & getObjectToViewTransformation() const
On-demand prepared Object to View transformation and its inverse for convenience.
const basegfx::BColor & getBColor() const
data read access
virtual sal_uInt32 getPrimitive2DID() const =0
provide unique ID for fast identifying of known primitive implementations in renderers.
const basegfx::B2DHomMatrix & getTransform() const
bool isHorizontalOrVertical(const geometry::ViewInformation2D &rViewInformation) const
helper to decide if AntiAliasing should be used
const css::uno::Reference< css::awt::XControl > & getXControl() const
mxControl access.
const basegfx::B2DHomMatrix & getTransform() const
data read access
basegfx::B2DPolygon getUnitPolygon() const
helpers that support e.g. direct paint/geometry creation
const basegfx::B2DRange & getOutputRange() const
data read access
const attribute::FillGradientAttribute & getFillGradient() const
void generateMatricesAndColors(std::function< void(const basegfx::B2DHomMatrix &rMatrix, const basegfx::BColor &rColor)> aCallback) const
const basegfx::B2DRange & getOutputRange() const
data read access
const attribute::FillHatchAttribute & getFillHatch() const
const Primitive2DContainer & getChildren() const
data read access
void getTileSize(sal_uInt32 &rWidth, sal_uInt32 &rHeight, const geometry::ViewInformation2D &rViewInformation) const
helper that is capable to calculate the needed discrete buffer size for eventually buffered content
const basegfx::B2DPolyPolygon & getMask() const
data read access
BitmapEx createTileImage(sal_uInt32 nWidth, sal_uInt32 nHeight) const
helper which creates the content - checks if clipping is needed and eventually creates buffered conte...
const basegfx::B2DPolyPolygon & getB2DPolyPolygon() const
data read access
const basegfx::B2DPolyPolygon & getB2DPolyPolygon() const
data read access
const attribute::FillGradientAttribute & getFillGradient() const
const basegfx::B2DPolygon & getB2DPolygon() const
data read access
const attribute::StrokeAttribute & getStrokeAttribute() const
const basegfx::B2DPolygon & getB2DPolygon() const
data read access
const attribute::LineAttribute & getLineAttribute() const
virtual sal_uInt32 getPrimitive2DID() const override
provide unique ID
void process(const primitive2d::BasePrimitive2D &rCandidate)
const geometry::ViewInformation2D & getViewInformation2D() const
data read access
void processWrongSpellPrimitive2D(const primitive2d::WrongSpellPrimitive2D &rWrongSpellPrimitive)
void processBorderLinePrimitive2D(const drawinglayer::primitive2d::BorderLinePrimitive2D &rBorder)
virtual void processBasePrimitive2D(const primitive2d::BasePrimitive2D &rCandidate) override
void processFillGradientPrimitive2D(const primitive2d::FillGradientPrimitive2D &rPrimitive)
void processBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D &rBitmapCandidate)
void processInvertPrimitive2D(const primitive2d::BasePrimitive2D &rCandidate)
void tryDrawPolyPolygonColorPrimitive2DDirect(const primitive2d::PolyPolygonColorPrimitive2D &rSource, double fTransparency)
void processPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D &rPolyPolygonColorPrimitive2D)
void processFillHatchPrimitive2D(const primitive2d::FillHatchPrimitive2D &rFillHatchPrimitive)
bool tryDrawPolygonHairlinePrimitive2DDirect(const primitive2d::PolygonHairlinePrimitive2D &rSource, double fTransparency)
void processPatternFillPrimitive2D(const primitive2d::PatternFillPrimitive2D &rPrimitive)
void processTextDecoratedPortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D &rCandidate)
void processTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D &rCandidate)
bool tryDrawPolygonStrokePrimitive2DDirect(const primitive2d::PolygonStrokePrimitive2D &rSource, double fTransparency)
void processUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D &rUniTransparenceCandidate)
void processMetaFilePrimitive2D(const primitive2d::BasePrimitive2D &rCandidate)
void processPolyPolygonGradientPrimitive2D(const primitive2d::PolyPolygonGradientPrimitive2D &rPolygonCandidate)
void processPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D &rPolygonStrokePrimitive2D)
void processBackgroundColorPrimitive2D(const primitive2d::BackgroundColorPrimitive2D &rPrimitive)
void processControlPrimitive2D(const primitive2d::ControlPrimitive2D &rControlPrimitive)
VclPixelProcessor2D(const geometry::ViewInformation2D &rViewInformation, OutputDevice &rOutDev, const basegfx::BColorModifierStack &rInitStack=basegfx::BColorModifierStack())
constructor/destructor
void processPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D &rPolygonHairlinePrimitive2D)
void RenderPointArrayPrimitive2D(const primitive2d::PointArrayPrimitive2D &rPointArrayCandidate)
void RenderPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D &rPolygonStrokeCandidate)
void RenderEpsPrimitive2D(const primitive2d::EpsPrimitive2D &rEpsPrimitive2D)
void RenderPolyPolygonGraphicPrimitive2D(const primitive2d::PolyPolygonGraphicPrimitive2D &rPolygonCandidate)
basegfx::BColorModifierStack maBColorModifierStack
void RenderPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D &rPolygonCandidate, bool bPixelBased)
void RenderSvgLinearAtomPrimitive2D(const primitive2d::SvgLinearAtomPrimitive2D &rCandidate)
void RenderFillGraphicPrimitive2D(const primitive2d::FillGraphicPrimitive2D &rFillBitmapCandidate)
void RenderUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D &rTransCandidate)
void RenderTransformPrimitive2D(const primitive2d::TransformPrimitive2D &rTransformCandidate)
void RenderPagePreviewPrimitive2D(const primitive2d::PagePreviewPrimitive2D &rPagePreviewCandidate)
void RenderMaskPrimitive2DPixel(const primitive2d::MaskPrimitive2D &rMaskCandidate)
void RenderModifiedColorPrimitive2D(const primitive2d::ModifiedColorPrimitive2D &rModifiedCandidate)
void RenderMarkerArrayPrimitive2D(const primitive2d::MarkerArrayPrimitive2D &rMarkerArrayCandidate)
void RenderSvgRadialAtomPrimitive2D(const primitive2d::SvgRadialAtomPrimitive2D &rCandidate)
void RenderTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D &rTransCandidate)
void RenderTextSimpleOrDecoratedPortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D &rTextCandidate)
void RenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D &rBitmapCandidate)
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
constexpr ::Color COL_TRANSPARENT(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
int nCount
#define PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D
#define PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D
#define PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D
#define PRIMITIVE2D_ID_SVGLINEARATOMPRIMITIVE2D
#define PRIMITIVE2D_ID_CONTROLPRIMITIVE2D
#define PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D
#define PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D
#define PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D
#define PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D
#define PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D
#define PRIMITIVE2D_ID_INVERTPRIMITIVE2D
#define PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D
#define PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D
#define PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D
#define PRIMITIVE2D_ID_FILLHATCHPRIMITIVE2D
#define PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D
#define PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D
#define PRIMITIVE2D_ID_EPSPRIMITIVE2D
#define PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D
#define PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D
#define PRIMITIVE2D_ID_MASKPRIMITIVE2D
#define PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D
#define PRIMITIVE2D_ID_METAFILEPRIMITIVE2D
#define PRIMITIVE2D_ID_PATTERNFILLPRIMITIVE2D
#define PRIMITIVE2D_ID_BITMAPPRIMITIVE2D
#define PRIMITIVE2D_ID_SVGRADIALATOMPRIMITIVE2D
#define PRIMITIVE2D_ID_BACKGROUNDCOLORPRIMITIVE2D
#define PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D
#define PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D
uno_Any a
#define SAL_WARN_IF(condition, area, stream)
#define SAL_INFO(area, stream)
RttiCompleteObjectLocator col
bool IsRenderDecoratedTextDirect()
bool equalZero(const T &rfVal)
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
bool isRectangle(const B2DPolygon &rPoly)
B2IRange fround(const B2DRange &rRange)
OUString idToString(sal_uInt32 nId)
bool renderWrongSpellPrimitive2D(const primitive2d::WrongSpellPrimitive2D &rWrongSpellCandidate, OutputDevice &rOutputDevice, const basegfx::B2DHomMatrix &rObjectToViewTransformation, const basegfx::BColorModifierStack &rBColorModifierStack)
::tools::Rectangle rectangleFromB2DRectangle(const basegfx::B2DRange &rRect)
unsigned char sal_uInt8
HatchStyle