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 : #include <sal/types.h>
20 :
21 : #include <basegfx/matrix/b2dhommatrix.hxx>
22 : #include <basegfx/polygon/b2dpolygontools.hxx>
23 : #include <basegfx/polygon/b2dpolypolygontools.hxx>
24 : #include <boost/scoped_array.hpp>
25 : #include <tools/poly.hxx>
26 : #include <vcl/outdev.hxx>
27 : #include <vcl/virdev.hxx>
28 : #include <vcl/window.hxx>
29 :
30 : #include "salgdi.hxx"
31 :
32 : #define OUTDEV_POLYPOLY_STACKBUF 32
33 :
34 326484 : void OutputDevice::DrawPolyPolygon( const tools::PolyPolygon& rPolyPoly )
35 : {
36 326484 : assert_if_double_buffered_window();
37 :
38 326484 : if( mpMetaFile )
39 5 : mpMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPoly ) );
40 :
41 326484 : sal_uInt16 nPoly = rPolyPoly.Count();
42 :
43 326484 : if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || !nPoly || ImplIsRecordLayout() )
44 5 : return;
45 :
46 : // we need a graphics
47 326479 : if ( !mpGraphics && !AcquireGraphics() )
48 0 : return;
49 :
50 326479 : if ( mbInitClipRegion )
51 632 : InitClipRegion();
52 :
53 326479 : if ( mbOutputClipped )
54 0 : return;
55 :
56 326479 : if ( mbInitLineColor )
57 5840 : InitLineColor();
58 :
59 326479 : if ( mbInitFillColor )
60 9180 : InitFillColor();
61 :
62 : // use b2dpolygon drawing if possible
63 652976 : if((mnAntialiasing & AntialiasingFlags::EnableB2dDraw) &&
64 326497 : mpGraphics->supportsOperation(OutDevSupport_B2DDraw) &&
65 979437 : ROP_OVERPAINT == GetRasterOp() &&
66 0 : (IsLineColor() || IsFillColor()))
67 : {
68 0 : const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
69 0 : basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPoly.getB2DPolyPolygon());
70 0 : bool bSuccess(true);
71 :
72 : // transform the polygon and ensure closed
73 0 : aB2DPolyPolygon.transform(aTransform);
74 0 : aB2DPolyPolygon.setClosed(true);
75 :
76 0 : if(IsFillColor())
77 : {
78 0 : bSuccess = mpGraphics->DrawPolyPolygon(aB2DPolyPolygon, 0.0, this);
79 : }
80 :
81 0 : if(bSuccess && IsLineColor())
82 : {
83 0 : const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
84 :
85 0 : if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline)
86 : {
87 0 : aB2DPolyPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon);
88 : }
89 :
90 0 : for(sal_uInt32 a(0); bSuccess && a < aB2DPolyPolygon.count(); a++)
91 : {
92 : bSuccess = mpGraphics->DrawPolyLine( aB2DPolyPolygon.getB2DPolygon(a),
93 : 0.0,
94 : aB2DLineWidth,
95 : basegfx::B2DLineJoin::NONE,
96 : css::drawing::LineCap_BUTT,
97 0 : this);
98 0 : }
99 : }
100 :
101 0 : if(bSuccess)
102 : {
103 0 : return;
104 0 : }
105 : }
106 :
107 326479 : if ( nPoly == 1 )
108 : {
109 : // #100127# Map to DrawPolygon
110 323382 : Polygon aPoly = rPolyPoly.GetObject( 0 );
111 323382 : if( aPoly.GetSize() >= 2 )
112 : {
113 323382 : GDIMetaFile* pOldMF = mpMetaFile;
114 323382 : mpMetaFile = NULL;
115 :
116 323382 : DrawPolygon( aPoly );
117 :
118 323382 : mpMetaFile = pOldMF;
119 323382 : }
120 : }
121 : else
122 : {
123 : // #100127# moved real tools::PolyPolygon draw to separate method,
124 : // have to call recursively, avoiding duplicate
125 : // ImplLogicToDevicePixel calls
126 3097 : ImplDrawPolyPolygon( nPoly, ImplLogicToDevicePixel( rPolyPoly ) );
127 : }
128 326479 : if( mpAlphaVDev )
129 5656 : mpAlphaVDev->DrawPolyPolygon( rPolyPoly );
130 : }
131 :
132 1011 : void OutputDevice::DrawPolygon( const basegfx::B2DPolygon& rB2DPolygon)
133 : {
134 1011 : assert_if_double_buffered_window();
135 :
136 : // AW: Do NOT paint empty polygons
137 1011 : if(rB2DPolygon.count())
138 : {
139 1011 : basegfx::B2DPolyPolygon aPP( rB2DPolygon );
140 1011 : DrawPolyPolygon( aPP );
141 : }
142 1011 : }
143 :
144 337036 : void OutputDevice::DrawPolygon( const Polygon& rPoly )
145 : {
146 337036 : assert_if_double_buffered_window();
147 :
148 337036 : if( mpMetaFile )
149 6 : mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) );
150 :
151 337036 : sal_uInt16 nPoints = rPoly.GetSize();
152 :
153 337036 : if ( !IsDeviceOutputNecessary() || (!mbLineColor && !mbFillColor) || (nPoints < 2) || ImplIsRecordLayout() )
154 0 : return;
155 :
156 : // we need a graphics
157 337036 : if ( !mpGraphics && !AcquireGraphics() )
158 0 : return;
159 :
160 337036 : if ( mbInitClipRegion )
161 436 : InitClipRegion();
162 :
163 337036 : if ( mbOutputClipped )
164 0 : return;
165 :
166 337036 : if ( mbInitLineColor )
167 7821 : InitLineColor();
168 :
169 337036 : if ( mbInitFillColor )
170 7636 : InitFillColor();
171 :
172 : // use b2dpolygon drawing if possible
173 680566 : if((mnAntialiasing & AntialiasingFlags::EnableB2dDraw) &&
174 343530 : mpGraphics->supportsOperation(OutDevSupport_B2DDraw) &&
175 1011108 : ROP_OVERPAINT == GetRasterOp() &&
176 0 : (IsLineColor() || IsFillColor()))
177 : {
178 0 : const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
179 0 : basegfx::B2DPolygon aB2DPolygon(rPoly.getB2DPolygon());
180 0 : bool bSuccess(true);
181 :
182 : // transform the polygon and ensure closed
183 0 : aB2DPolygon.transform(aTransform);
184 0 : aB2DPolygon.setClosed(true);
185 :
186 0 : if(IsFillColor())
187 : {
188 0 : bSuccess = mpGraphics->DrawPolyPolygon(basegfx::B2DPolyPolygon(aB2DPolygon), 0.0, this);
189 : }
190 :
191 0 : if(bSuccess && IsLineColor())
192 : {
193 0 : const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
194 :
195 0 : if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline)
196 : {
197 0 : aB2DPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolygon);
198 : }
199 :
200 : bSuccess = mpGraphics->DrawPolyLine( aB2DPolygon,
201 : 0.0,
202 : aB2DLineWidth,
203 : basegfx::B2DLineJoin::NONE,
204 : css::drawing::LineCap_BUTT,
205 0 : this);
206 : }
207 :
208 0 : if(bSuccess)
209 : {
210 0 : return;
211 0 : }
212 : }
213 :
214 337036 : Polygon aPoly = ImplLogicToDevicePixel( rPoly );
215 337036 : const SalPoint* pPtAry = reinterpret_cast<const SalPoint*>(aPoly.GetConstPointAry());
216 :
217 : // #100127# Forward beziers to sal, if any
218 337036 : if( aPoly.HasFlags() )
219 : {
220 4409 : const sal_uInt8* pFlgAry = aPoly.GetConstFlagAry();
221 4409 : if( !mpGraphics->DrawPolygonBezier( nPoints, pPtAry, pFlgAry, this ) )
222 : {
223 4409 : aPoly = Polygon::SubdivideBezier(aPoly);
224 4409 : pPtAry = reinterpret_cast<const SalPoint*>(aPoly.GetConstPointAry());
225 4409 : mpGraphics->DrawPolygon( aPoly.GetSize(), pPtAry, this );
226 : }
227 : }
228 : else
229 : {
230 332627 : mpGraphics->DrawPolygon( nPoints, pPtAry, this );
231 : }
232 337036 : if( mpAlphaVDev )
233 5656 : mpAlphaVDev->DrawPolygon( rPoly );
234 : }
235 :
236 : // Caution: This method is nearly the same as
237 : // OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency),
238 : // so when changes are made here do not forget to make changes there, too
239 :
240 51158 : void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly )
241 : {
242 51158 : assert_if_double_buffered_window();
243 :
244 51158 : if( mpMetaFile )
245 1849 : mpMetaFile->AddAction( new MetaPolyPolygonAction( tools::PolyPolygon( rB2DPolyPoly ) ) );
246 :
247 : // call helper
248 51158 : ImplDrawPolyPolygonWithB2DPolyPolygon(rB2DPolyPoly);
249 51158 : }
250 :
251 51158 : void OutputDevice::ImplDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyPolygon& rB2DPolyPoly)
252 : {
253 : // Do not paint empty PolyPolygons
254 51158 : if(!rB2DPolyPoly.count() || !IsDeviceOutputNecessary())
255 3698 : return;
256 :
257 : // we need a graphics
258 49309 : if( !mpGraphics && !AcquireGraphics() )
259 0 : return;
260 :
261 49309 : if( mbInitClipRegion )
262 9 : InitClipRegion();
263 :
264 49309 : if( mbOutputClipped )
265 0 : return;
266 :
267 49309 : if( mbInitLineColor )
268 318 : InitLineColor();
269 :
270 49309 : if( mbInitFillColor )
271 45446 : InitFillColor();
272 :
273 98618 : if((mnAntialiasing & AntialiasingFlags::EnableB2dDraw) &&
274 49309 : mpGraphics->supportsOperation(OutDevSupport_B2DDraw) &&
275 147927 : ROP_OVERPAINT == GetRasterOp() &&
276 0 : (IsLineColor() || IsFillColor()))
277 : {
278 0 : const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation());
279 0 : basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly);
280 0 : bool bSuccess(true);
281 :
282 : // transform the polygon and ensure closed
283 0 : aB2DPolyPolygon.transform(aTransform);
284 0 : aB2DPolyPolygon.setClosed(true);
285 :
286 0 : if(IsFillColor())
287 : {
288 0 : bSuccess = mpGraphics->DrawPolyPolygon(aB2DPolyPolygon, 0.0, this);
289 : }
290 :
291 0 : if(bSuccess && IsLineColor())
292 : {
293 0 : const ::basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
294 :
295 0 : if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline)
296 : {
297 0 : aB2DPolyPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon);
298 : }
299 :
300 0 : for(sal_uInt32 a(0);bSuccess && a < aB2DPolyPolygon.count(); a++)
301 : {
302 : bSuccess = mpGraphics->DrawPolyLine( aB2DPolyPolygon.getB2DPolygon(a),
303 : 0.0,
304 : aB2DLineWidth,
305 : basegfx::B2DLineJoin::NONE,
306 : css::drawing::LineCap_BUTT,
307 0 : this);
308 0 : }
309 : }
310 :
311 0 : if(bSuccess)
312 : {
313 0 : return;
314 0 : }
315 : }
316 :
317 : // fallback to old polygon drawing if needed
318 49309 : const tools::PolyPolygon aToolsPolyPolygon( rB2DPolyPoly );
319 98618 : const tools::PolyPolygon aPixelPolyPolygon = ImplLogicToDevicePixel( aToolsPolyPolygon );
320 98618 : ImplDrawPolyPolygon( aPixelPolyPolygon.Count(), aPixelPolyPolygon );
321 : }
322 :
323 : // #100127# Extracted from OutputDevice::DrawPolyPolygon()
324 55258 : void OutputDevice::ImplDrawPolyPolygon( sal_uInt16 nPoly, const tools::PolyPolygon& rPolyPoly )
325 : {
326 : // AW: This crashes on empty PolyPolygons, avoid that
327 55258 : if(!nPoly)
328 55258 : return;
329 :
330 : sal_uInt32 aStackAry1[OUTDEV_POLYPOLY_STACKBUF];
331 : PCONSTSALPOINT aStackAry2[OUTDEV_POLYPOLY_STACKBUF];
332 : sal_uInt8* aStackAry3[OUTDEV_POLYPOLY_STACKBUF];
333 : sal_uInt32* pPointAry;
334 : PCONSTSALPOINT* pPointAryAry;
335 : const sal_uInt8** pFlagAryAry;
336 55258 : sal_uInt16 i = 0;
337 55258 : sal_uInt16 j = 0;
338 55258 : sal_uInt16 last = 0;
339 55258 : bool bHaveBezier = false;
340 55258 : if ( nPoly > OUTDEV_POLYPOLY_STACKBUF )
341 : {
342 110 : pPointAry = new sal_uInt32[nPoly];
343 110 : pPointAryAry = new PCONSTSALPOINT[nPoly];
344 110 : pFlagAryAry = new const sal_uInt8*[nPoly];
345 : }
346 : else
347 : {
348 55148 : pPointAry = aStackAry1;
349 55148 : pPointAryAry = aStackAry2;
350 55148 : pFlagAryAry = const_cast<const sal_uInt8**>(aStackAry3);
351 : }
352 :
353 73457 : do
354 : {
355 73457 : const Polygon& rPoly = rPolyPoly.GetObject( i );
356 73457 : sal_uInt16 nSize = rPoly.GetSize();
357 73457 : if ( nSize )
358 : {
359 73457 : pPointAry[j] = nSize;
360 73457 : pPointAryAry[j] = reinterpret_cast<PCONSTSALPOINT>(rPoly.GetConstPointAry());
361 73457 : pFlagAryAry[j] = rPoly.GetConstFlagAry();
362 73457 : last = i;
363 :
364 73457 : if( pFlagAryAry[j] )
365 11922 : bHaveBezier = true;
366 :
367 73457 : ++j;
368 : }
369 73457 : ++i;
370 : }
371 : while ( i < nPoly );
372 :
373 55258 : if ( j == 1 )
374 : {
375 : // #100127# Forward beziers to sal, if any
376 49016 : if( bHaveBezier )
377 : {
378 5131 : if( !mpGraphics->DrawPolygonBezier( *pPointAry, *pPointAryAry, *pFlagAryAry, this ) )
379 : {
380 5131 : Polygon aPoly = Polygon::SubdivideBezier( rPolyPoly.GetObject( last ) );
381 5131 : mpGraphics->DrawPolygon( aPoly.GetSize(), reinterpret_cast<const SalPoint*>(aPoly.GetConstPointAry()), this );
382 : }
383 : }
384 : else
385 : {
386 43885 : mpGraphics->DrawPolygon( *pPointAry, *pPointAryAry, this );
387 : }
388 : }
389 : else
390 : {
391 : // #100127# Forward beziers to sal, if any
392 6242 : if( bHaveBezier )
393 : {
394 2852 : if( !mpGraphics->DrawPolyPolygonBezier( j, pPointAry, pPointAryAry, pFlagAryAry, this ) )
395 : {
396 2852 : tools::PolyPolygon aPolyPoly = tools::PolyPolygon::SubdivideBezier( rPolyPoly );
397 2852 : ImplDrawPolyPolygon( aPolyPoly.Count(), aPolyPoly );
398 : }
399 : }
400 : else
401 : {
402 3390 : mpGraphics->DrawPolyPolygon( j, pPointAry, pPointAryAry, this );
403 : }
404 : }
405 :
406 55258 : if ( pPointAry != aStackAry1 )
407 : {
408 110 : delete[] pPointAry;
409 110 : delete[] pPointAryAry;
410 110 : delete[] pFlagAryAry;
411 : }
412 : }
413 :
414 1374408 : void OutputDevice::ImplDrawPolygon( const Polygon& rPoly, const tools::PolyPolygon* pClipPolyPoly )
415 : {
416 1374408 : if( pClipPolyPoly )
417 : {
418 0 : ImplDrawPolyPolygon( rPoly, pClipPolyPoly );
419 : }
420 : else
421 : {
422 1374408 : sal_uInt16 nPoints = rPoly.GetSize();
423 :
424 1374408 : if ( nPoints < 2 )
425 1374408 : return;
426 :
427 1374408 : const SalPoint* pPtAry = reinterpret_cast<const SalPoint*>(rPoly.GetConstPointAry());
428 1374408 : mpGraphics->DrawPolygon( nPoints, pPtAry, this );
429 : }
430 : }
431 :
432 0 : void OutputDevice::ImplDrawPolyPolygon( const tools::PolyPolygon& rPolyPoly, const tools::PolyPolygon* pClipPolyPoly )
433 : {
434 : tools::PolyPolygon* pPolyPoly;
435 :
436 0 : if( pClipPolyPoly )
437 : {
438 0 : pPolyPoly = new tools::PolyPolygon;
439 0 : rPolyPoly.GetIntersection( *pClipPolyPoly, *pPolyPoly );
440 : }
441 : else
442 : {
443 0 : pPolyPoly = const_cast<tools::PolyPolygon*>(&rPolyPoly);
444 : }
445 0 : if( pPolyPoly->Count() == 1 )
446 : {
447 0 : const Polygon rPoly = pPolyPoly->GetObject( 0 );
448 0 : sal_uInt16 nSize = rPoly.GetSize();
449 :
450 0 : if( nSize >= 2 )
451 : {
452 0 : const SalPoint* pPtAry = reinterpret_cast<const SalPoint*>(rPoly.GetConstPointAry());
453 0 : mpGraphics->DrawPolygon( nSize, pPtAry, this );
454 0 : }
455 : }
456 0 : else if( pPolyPoly->Count() )
457 : {
458 0 : sal_uInt16 nCount = pPolyPoly->Count();
459 0 : boost::scoped_array<sal_uInt32> pPointAry(new sal_uInt32[nCount]);
460 0 : boost::scoped_array<PCONSTSALPOINT> pPointAryAry(new PCONSTSALPOINT[nCount]);
461 0 : sal_uInt16 i = 0;
462 0 : do
463 : {
464 0 : const Polygon& rPoly = pPolyPoly->GetObject( i );
465 0 : sal_uInt16 nSize = rPoly.GetSize();
466 0 : if ( nSize )
467 : {
468 0 : pPointAry[i] = nSize;
469 0 : pPointAryAry[i] = reinterpret_cast<PCONSTSALPOINT>(rPoly.GetConstPointAry());
470 0 : i++;
471 : }
472 : else
473 0 : nCount--;
474 : }
475 : while( i < nCount );
476 :
477 0 : if( nCount == 1 )
478 0 : mpGraphics->DrawPolygon( pPointAry[0], pPointAryAry[0], this );
479 : else
480 0 : mpGraphics->DrawPolyPolygon( nCount, pPointAry.get(), pPointAryAry.get(), this );
481 : }
482 :
483 0 : if( pClipPolyPoly )
484 0 : delete pPolyPoly;
485 801 : }
486 :
487 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|