1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/types.h>
21 #include <basegfx/matrix/b2dhommatrix.hxx>
22 #include <tools/poly.hxx>
24 #include <vcl/metaact.hxx>
25 #include <vcl/virdev.hxx>
32 #define OUTDEV_POLYPOLY_STACKBUF 32
34 void OutputDevice::DrawPolyPolygon( const tools::PolyPolygon
& rPolyPoly
)
36 assert(!is_double_buffered_window());
39 mpMetaFile
->AddAction( new MetaPolyPolygonAction( rPolyPoly
) );
41 sal_uInt16 nPoly
= rPolyPoly
.Count();
43 if ( !IsDeviceOutputNecessary() || (!mbLineColor
&& !mbFillColor
) || !nPoly
|| ImplIsRecordLayout() )
47 if ( !mpGraphics
&& !AcquireGraphics() )
51 if ( mbInitClipRegion
)
54 if ( mbOutputClipped
)
57 if ( mbInitLineColor
)
60 if ( mbInitFillColor
)
63 // use b2dpolygon drawing if possible
64 if (RasterOp::OverPaint
== GetRasterOp() && (IsLineColor() || IsFillColor()))
66 const basegfx::B2DHomMatrix
aTransform(ImplGetDeviceTransformation());
67 basegfx::B2DPolyPolygon
aB2DPolyPolygon(rPolyPoly
.getB2DPolyPolygon());
69 // ensure closed - may be asserted, will prevent buffering
70 if(!aB2DPolyPolygon
.isClosed())
72 aB2DPolyPolygon
.setClosed(true);
77 mpGraphics
->DrawPolyPolygon(
87 const bool bPixelSnapHairline(mnAntialiasing
& AntialiasingFlags::PixelSnapHairline
);
89 for(auto const& rPolygon
: std::as_const(aB2DPolyPolygon
))
91 bSuccess
= mpGraphics
->DrawPolyLine(
95 0.0, // tdf#124848 hairline
97 basegfx::B2DLineJoin::NONE
,
98 css::drawing::LineCap_BUTT
,
99 basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
110 mpAlphaVDev
->DrawPolyPolygon( rPolyPoly
);
117 // #100127# Map to DrawPolygon
118 const tools::Polygon
& aPoly
= rPolyPoly
.GetObject( 0 );
119 if( aPoly
.GetSize() >= 2 )
121 GDIMetaFile
* pOldMF
= mpMetaFile
;
122 mpMetaFile
= nullptr;
124 DrawPolygon( aPoly
);
131 // #100127# moved real tools::PolyPolygon draw to separate method,
132 // have to call recursively, avoiding duplicate
133 // ImplLogicToDevicePixel calls
134 ImplDrawPolyPolygon( nPoly
, ImplLogicToDevicePixel( rPolyPoly
) );
137 mpAlphaVDev
->DrawPolyPolygon( rPolyPoly
);
140 void OutputDevice::DrawPolygon( const basegfx::B2DPolygon
& rB2DPolygon
)
142 assert(!is_double_buffered_window());
144 // AW: Do NOT paint empty polygons
145 if(rB2DPolygon
.count())
147 basegfx::B2DPolyPolygon
aPP( rB2DPolygon
);
148 DrawPolyPolygon( aPP
);
152 void OutputDevice::DrawPolygon( const tools::Polygon
& rPoly
)
154 assert(!is_double_buffered_window());
157 mpMetaFile
->AddAction( new MetaPolygonAction( rPoly
) );
159 sal_uInt16 nPoints
= rPoly
.GetSize();
161 if ( !IsDeviceOutputNecessary() || (!mbLineColor
&& !mbFillColor
) || (nPoints
< 2) || ImplIsRecordLayout() )
164 // we need a graphics
165 if ( !mpGraphics
&& !AcquireGraphics() )
169 if ( mbInitClipRegion
)
172 if ( mbOutputClipped
)
175 if ( mbInitLineColor
)
178 if ( mbInitFillColor
)
181 // use b2dpolygon drawing if possible
182 if (RasterOp::OverPaint
== GetRasterOp() && (IsLineColor() || IsFillColor()))
184 const basegfx::B2DHomMatrix
aTransform(ImplGetDeviceTransformation());
185 basegfx::B2DPolygon
aB2DPolygon(rPoly
.getB2DPolygon());
187 // ensure closed - maybe assert, hinders buffering
188 if(!aB2DPolygon
.isClosed())
190 aB2DPolygon
.setClosed(true);
195 mpGraphics
->DrawPolyPolygon(
197 basegfx::B2DPolyPolygon(aB2DPolygon
),
205 const bool bPixelSnapHairline(mnAntialiasing
& AntialiasingFlags::PixelSnapHairline
);
207 bSuccess
= mpGraphics
->DrawPolyLine(
211 0.0, // tdf#124848 hairline
213 basegfx::B2DLineJoin::NONE
,
214 css::drawing::LineCap_BUTT
,
215 basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
223 mpAlphaVDev
->DrawPolygon( rPoly
);
228 tools::Polygon aPoly
= ImplLogicToDevicePixel( rPoly
);
229 const Point
* pPtAry
= aPoly
.GetConstPointAry();
231 // #100127# Forward beziers to sal, if any
232 if( aPoly
.HasFlags() )
234 const PolyFlags
* pFlgAry
= aPoly
.GetConstFlagAry();
235 if( !mpGraphics
->DrawPolygonBezier( nPoints
, pPtAry
, pFlgAry
, *this ) )
237 aPoly
= tools::Polygon::SubdivideBezier(aPoly
);
238 pPtAry
= aPoly
.GetConstPointAry();
239 mpGraphics
->DrawPolygon( aPoly
.GetSize(), pPtAry
, *this );
244 mpGraphics
->DrawPolygon( nPoints
, pPtAry
, *this );
247 mpAlphaVDev
->DrawPolygon( rPoly
);
250 // Caution: This method is nearly the same as
251 // OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency),
252 // so when changes are made here do not forget to make changes there, too
254 void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon
& rB2DPolyPoly
)
256 assert(!is_double_buffered_window());
259 mpMetaFile
->AddAction( new MetaPolyPolygonAction( tools::PolyPolygon( rB2DPolyPoly
) ) );
262 ImplDrawPolyPolygonWithB2DPolyPolygon(rB2DPolyPoly
);
265 void OutputDevice::ImplDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyPolygon
& rB2DPolyPoly
)
267 // Do not paint empty PolyPolygons
268 if(!rB2DPolyPoly
.count() || !IsDeviceOutputNecessary())
271 // we need a graphics
272 if( !mpGraphics
&& !AcquireGraphics() )
276 if( mbInitClipRegion
)
279 if( mbOutputClipped
)
282 if( mbInitLineColor
)
285 if( mbInitFillColor
)
288 bool bSuccess(false);
290 if (RasterOp::OverPaint
== GetRasterOp() && (IsLineColor() || IsFillColor()))
292 const basegfx::B2DHomMatrix
aTransform(ImplGetDeviceTransformation());
293 basegfx::B2DPolyPolygon
aB2DPolyPolygon(rB2DPolyPoly
);
296 // ensure closed - maybe assert, hinders buffering
297 if(!aB2DPolyPolygon
.isClosed())
299 aB2DPolyPolygon
.setClosed(true);
304 mpGraphics
->DrawPolyPolygon(
313 const bool bPixelSnapHairline(mnAntialiasing
& AntialiasingFlags::PixelSnapHairline
);
315 for(auto const& rPolygon
: std::as_const(aB2DPolyPolygon
))
317 bSuccess
= mpGraphics
->DrawPolyLine(
321 0.0, // tdf#124848 hairline
323 basegfx::B2DLineJoin::NONE
,
324 css::drawing::LineCap_BUTT
,
325 basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
336 // fallback to old polygon drawing if needed
337 const tools::PolyPolygon
aToolsPolyPolygon(rB2DPolyPoly
);
338 const tools::PolyPolygon aPixelPolyPolygon
= ImplLogicToDevicePixel(aToolsPolyPolygon
);
339 ImplDrawPolyPolygon(aPixelPolyPolygon
.Count(), aPixelPolyPolygon
);
343 mpAlphaVDev
->ImplDrawPolyPolygonWithB2DPolyPolygon(rB2DPolyPoly
);
346 // #100127# Extracted from OutputDevice::DrawPolyPolygon()
347 void OutputDevice::ImplDrawPolyPolygon( sal_uInt16 nPoly
, const tools::PolyPolygon
& rPolyPoly
)
349 // AW: This crashes on empty PolyPolygons, avoid that
353 sal_uInt32 aStackAry1
[OUTDEV_POLYPOLY_STACKBUF
];
354 const Point
* aStackAry2
[OUTDEV_POLYPOLY_STACKBUF
];
355 PolyFlags
* aStackAry3
[OUTDEV_POLYPOLY_STACKBUF
];
356 sal_uInt32
* pPointAry
;
357 const Point
** pPointAryAry
;
358 const PolyFlags
** pFlagAryAry
;
362 bool bHaveBezier
= false;
363 if ( nPoly
> OUTDEV_POLYPOLY_STACKBUF
)
365 pPointAry
= new sal_uInt32
[nPoly
];
366 pPointAryAry
= new const Point
*[nPoly
];
367 pFlagAryAry
= new const PolyFlags
*[nPoly
];
371 pPointAry
= aStackAry1
;
372 pPointAryAry
= aStackAry2
;
373 pFlagAryAry
= const_cast<const PolyFlags
**>(aStackAry3
);
378 const tools::Polygon
& rPoly
= rPolyPoly
.GetObject( i
);
379 sal_uInt16 nSize
= rPoly
.GetSize();
382 pPointAry
[j
] = nSize
;
383 pPointAryAry
[j
] = rPoly
.GetConstPointAry();
384 pFlagAryAry
[j
] = rPoly
.GetConstFlagAry();
398 // #100127# Forward beziers to sal, if any
401 if( !mpGraphics
->DrawPolygonBezier( *pPointAry
, *pPointAryAry
, *pFlagAryAry
, *this ) )
403 tools::Polygon aPoly
= tools::Polygon::SubdivideBezier( rPolyPoly
.GetObject( last
) );
404 mpGraphics
->DrawPolygon( aPoly
.GetSize(), aPoly
.GetConstPointAry(), *this );
409 mpGraphics
->DrawPolygon( *pPointAry
, *pPointAryAry
, *this );
414 // #100127# Forward beziers to sal, if any
417 if (!mpGraphics
->DrawPolyPolygonBezier(j
, pPointAry
, pPointAryAry
, pFlagAryAry
, *this))
419 tools::PolyPolygon aPolyPoly
= tools::PolyPolygon::SubdivideBezier( rPolyPoly
);
420 ImplDrawPolyPolygon( aPolyPoly
.Count(), aPolyPoly
);
425 mpGraphics
->DrawPolyPolygon( j
, pPointAry
, pPointAryAry
, *this );
429 if ( pPointAry
!= aStackAry1
)
432 delete[] pPointAryAry
;
433 delete[] pFlagAryAry
;
437 void OutputDevice::ImplDrawPolygon( const tools::Polygon
& rPoly
, const tools::PolyPolygon
* pClipPolyPoly
)
441 ImplDrawPolyPolygon( tools::PolyPolygon(rPoly
), pClipPolyPoly
);
445 sal_uInt16 nPoints
= rPoly
.GetSize();
450 const Point
* pPtAry
= rPoly
.GetConstPointAry();
451 mpGraphics
->DrawPolygon( nPoints
, pPtAry
, *this );
455 void OutputDevice::ImplDrawPolyPolygon( const tools::PolyPolygon
& rPolyPoly
, const tools::PolyPolygon
* pClipPolyPoly
)
457 tools::PolyPolygon
* pPolyPoly
;
461 pPolyPoly
= new tools::PolyPolygon
;
462 rPolyPoly
.GetIntersection( *pClipPolyPoly
, *pPolyPoly
);
466 pPolyPoly
= const_cast<tools::PolyPolygon
*>(&rPolyPoly
);
468 if( pPolyPoly
->Count() == 1 )
470 const tools::Polygon
& rPoly
= pPolyPoly
->GetObject( 0 );
471 sal_uInt16 nSize
= rPoly
.GetSize();
475 const Point
* pPtAry
= rPoly
.GetConstPointAry();
476 mpGraphics
->DrawPolygon( nSize
, pPtAry
, *this );
479 else if( pPolyPoly
->Count() )
481 sal_uInt16 nCount
= pPolyPoly
->Count();
482 std::unique_ptr
<sal_uInt32
[]> pPointAry(new sal_uInt32
[nCount
]);
483 std::unique_ptr
<const Point
*[]> pPointAryAry(new const Point
*[nCount
]);
487 const tools::Polygon
& rPoly
= pPolyPoly
->GetObject( i
);
488 sal_uInt16 nSize
= rPoly
.GetSize();
491 pPointAry
[i
] = nSize
;
492 pPointAryAry
[i
] = rPoly
.GetConstPointAry();
501 mpGraphics
->DrawPolygon( pPointAry
[0], pPointAryAry
[0], *this );
503 mpGraphics
->DrawPolyPolygon( nCount
, pPointAry
.get(), pPointAryAry
.get(), *this );
510 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */