LibreOffice Module vcl (master) 1
transparent.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
20#include <sal/types.h>
21#include <osl/diagnose.h>
22#include <rtl/math.hxx>
24#include <tools/helpers.hxx>
25#include <officecfg/Office/Common.hxx>
26
27#include <vcl/BitmapTools.hxx>
28#include <vcl/metaact.hxx>
29#include <vcl/print.hxx>
30#include <vcl/settings.hxx>
31#include <vcl/svapp.hxx>
32#include <vcl/virdev.hxx>
33
36#include <salgdi.hxx>
37
38#include <list>
39#include <memory>
40
41#define MAX_TILE_WIDTH 1024
42#define MAX_TILE_HEIGHT 1024
43
44namespace
45{
51 tools::Polygon toPolygon( const basegfx::B2DPolygon& rPoly )
52 {
53 basegfx::B2DRange aRange = rPoly.getB2DRange();
54 double fW = aRange.getWidth(), fH = aRange.getHeight();
55 if (0.0 < fW && 0.0 < fH && (fW <= 1.0 || fH <= 1.0))
56 {
57 // This polygon not empty but is too small to display. Approximate it
58 // with a rectangle large enough to be displayed.
59 double nX = aRange.getMinX(), nY = aRange.getMinY();
60 double nW = std::max<double>(1.0, rtl::math::round(fW));
61 double nH = std::max<double>(1.0, rtl::math::round(fH));
62
63 tools::Polygon aTarget;
64 aTarget.Insert(0, Point(nX, nY));
65 aTarget.Insert(1, Point(nX+nW, nY));
66 aTarget.Insert(2, Point(nX+nW, nY+nH));
67 aTarget.Insert(3, Point(nX, nY+nH));
68 aTarget.Insert(4, Point(nX, nY));
69 return aTarget;
70 }
71 return tools::Polygon(rPoly);
72 }
73
74 tools::PolyPolygon toPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly )
75 {
76 tools::PolyPolygon aTarget;
77 for (auto const& rB2DPolygon : rPolyPoly)
78 aTarget.Insert(toPolygon(rB2DPolygon));
79
80 return aTarget;
81 }
82}
83
84// Caution: This method is nearly the same as
85// void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly )
86// so when changes are made here do not forget to make changes there, too
87
89 const basegfx::B2DHomMatrix& rObjectTransform,
90 const basegfx::B2DPolyPolygon& rB2DPolyPoly,
91 double fTransparency)
92{
94
95 // AW: Do NOT paint empty PolyPolygons
96 if(!rB2DPolyPoly.count())
97 return;
98
99 // we need a graphics
100 if( !mpGraphics && !AcquireGraphics() )
101 return;
102 assert(mpGraphics);
103
104 if( mbInitClipRegion )
106
107 if( mbOutputClipped )
108 return;
109
110 if( mbInitLineColor )
112
113 if( mbInitFillColor )
115
118 {
119 // b2dpolygon support not implemented yet on non-UNX platforms
120 basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly);
121
122 // ensure it is closed
123 if(!aB2DPolyPolygon.isClosed())
124 {
125 // maybe assert, prevents buffering due to making a copy
126 aB2DPolyPolygon.setClosed( true );
127 }
128
129 // create ObjectToDevice transformation
130 const basegfx::B2DHomMatrix aFullTransform(ImplGetDeviceTransformation() * rObjectTransform);
131 // TODO: this must not drop transparency for mpAlphaVDev case, but instead use premultiplied
132 // alpha... but that requires using premultiplied alpha also for already drawn data
133 const double fAdjustedTransparency = mpAlphaVDev ? 0 : fTransparency;
134 bool bDrawnOk(true);
135
136 if( IsFillColor() )
137 {
138 bDrawnOk = mpGraphics->DrawPolyPolygon(
139 aFullTransform,
140 aB2DPolyPolygon,
141 fAdjustedTransparency,
142 *this);
143 }
144
145 if( bDrawnOk && IsLineColor() )
146 {
147 const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline);
148
149 for(auto const& rPolygon : std::as_const(aB2DPolyPolygon))
150 {
152 aFullTransform,
153 rPolygon,
154 fAdjustedTransparency,
155 0.0, // tdf#124848 hairline
156 nullptr, // MM01
158 css::drawing::LineCap_BUTT,
159 basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
160 bPixelSnapHairline,
161 *this );
162 }
163 }
164
165 if( bDrawnOk )
166 {
167 if( mpMetaFile )
168 {
169 // tdf#119843 need transformed Polygon here
170 basegfx::B2DPolyPolygon aB2DPolyPoly(rB2DPolyPoly);
171 aB2DPolyPoly.transform(rObjectTransform);
174 tools::PolyPolygon(aB2DPolyPoly),
175 static_cast< sal_uInt16 >(fTransparency * 100.0)));
176 }
177
178 if (mpAlphaVDev)
179 mpAlphaVDev->DrawTransparent(rObjectTransform, rB2DPolyPoly, fTransparency);
180
181 return;
182 }
183 }
184
185 // fallback to old polygon drawing if needed
186 // tdf#119843 need transformed Polygon here
187 basegfx::B2DPolyPolygon aB2DPolyPoly(rB2DPolyPoly);
188 aB2DPolyPoly.transform(rObjectTransform);
190 toPolyPolygon(aB2DPolyPoly),
191 static_cast<sal_uInt16>(fTransparency * 100.0));
192}
193
195 sal_uInt16 nTransparencePercent )
196{
197 assert(!is_double_buffered_window());
198
199 bool bDrawn = false;
200
202#if defined UNX && ! defined MACOSX && ! defined IOS
203 && GetBitCount() > 8
204#endif
205#ifdef _WIN32
206 // workaround bad dithering on remote displaying when using GDI+ with toolbar button highlighting
207 && !rPolyPoly.IsRect()
208#endif
209 )
210 {
211 // prepare the graphics device
212 if( mbInitClipRegion )
214
215 if( mbOutputClipped )
216 return true;
217
218 if( mbInitLineColor )
220
221 if( mbInitFillColor )
223
224 // get the polygon in device coordinates
225 basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPoly.getB2DPolyPolygon());
227
228 const double fTransparency = 0.01 * nTransparencePercent;
229 if( mbFillColor )
230 {
231 // #i121591#
232 // CAUTION: Only non printing (pixel-renderer) VCL commands from OutputDevices
233 // should be used when printing. Normally this is avoided by the printer being
234 // non-AAed and thus e.g. on WIN GdiPlus calls are not used. It may be necessary
235 // to figure out a way of moving this code to its own function that is
236 // overridden by the Print class, which will mean we deliberately override the
237 // functionality and we use the fallback some lines below (which is not very good,
238 // though. For now, WinSalGraphics::drawPolyPolygon will detect printer usage and
239 // correct the wrong mapping (see there for details)
240 bDrawn = mpGraphics->DrawPolyPolygon(
241 aTransform,
242 aB2DPolyPolygon,
243 fTransparency,
244 *this);
245 }
246
247 if( mbLineColor )
248 {
249 // disable the fill color for now
251
252 // draw the border line
253 const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline);
254
255 for(auto const& rPolygon : std::as_const(aB2DPolyPolygon))
256 {
257 bDrawn = mpGraphics->DrawPolyLine(
258 aTransform,
259 rPolygon,
260 fTransparency,
261 0.0, // tdf#124848 hairline
262 nullptr, // MM01
264 css::drawing::LineCap_BUTT,
265 basegfx::deg2rad(15.0), // not used with B2DLineJoin::NONE, but the correct default
266 bPixelSnapHairline,
267 *this );
268 }
269
270 // prepare to restore the fill color
272 }
273 }
274
275 return bDrawn;
276}
277
279 sal_uInt16 nTransparencePercent )
280{
281 // #110958# Disable alpha VDev, we perform the necessary
282 VirtualDevice* pOldAlphaVDev = mpAlphaVDev;
283
284 // operation explicitly further below.
285 if( mpAlphaVDev )
286 mpAlphaVDev = nullptr;
287
288 GDIMetaFile* pOldMetaFile = mpMetaFile;
289 mpMetaFile = nullptr;
290
291 tools::PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) );
292 tools::Rectangle aPolyRect( aPolyPoly.GetBoundRect() );
294
295 aDstRect.Intersection( aPolyRect );
296
297 ClipToPaintRegion( aDstRect );
298
299 if( !aDstRect.IsEmpty() )
300 {
301 bool bDrawn = false;
302
303 // #i66849# Added fast path for exactly rectangular
304 // polygons
305 // #i83087# Naturally, system alpha blending cannot
306 // work with separate alpha VDev
307 if( !mpAlphaVDev && aPolyPoly.IsRect() )
308 {
309 // setup Graphics only here (other cases delegate
310 // to basic OutDev methods)
311 if ( mbInitClipRegion )
313
314 if ( mbInitLineColor )
316
317 if ( mbInitFillColor )
319
320 tools::Rectangle aLogicPolyRect( rPolyPoly.GetBoundRect() );
321 tools::Rectangle aPixelRect( ImplLogicToDevicePixel( aLogicPolyRect ) );
322
323 if( !mbOutputClipped )
324 {
325 bDrawn = mpGraphics->DrawAlphaRect( aPixelRect.Left(), aPixelRect.Top(),
326 // #i98405# use methods with small g, else one pixel too much will be painted.
327 // This is because the source is a polygon which when painted would not paint
328 // the rightmost and lowest pixel line(s), so use one pixel less for the
329 // rectangle, too.
330 aPixelRect.getOpenWidth(), aPixelRect.getOpenHeight(),
331 sal::static_int_cast<sal_uInt8>(nTransparencePercent),
332 *this );
333 }
334 else
335 {
336 bDrawn = true;
337 }
338 }
339
340 if( !bDrawn )
341 {
343 const Size aDstSz( aDstRect.GetSize() );
344 const sal_uInt8 cTrans = static_cast<sal_uInt8>(MinMax( FRound( nTransparencePercent * 2.55 ), 0, 255 ));
345
346 if( aDstRect.Left() || aDstRect.Top() )
347 aPolyPoly.Move( -aDstRect.Left(), -aDstRect.Top() );
348
349 if( aVDev->SetOutputSizePixel( aDstSz ) )
350 {
351 const bool bOldMap = mbMap;
352
353 EnableMapMode( false );
354
355 aVDev->SetLineColor( COL_BLACK );
356 aVDev->SetFillColor( COL_BLACK );
357 aVDev->DrawPolyPolygon( aPolyPoly );
358
359 Bitmap aPaint( GetBitmap( aDstRect.TopLeft(), aDstSz ) );
360 Bitmap aPolyMask( aVDev->GetBitmap( Point(), aDstSz ) );
361
362 // #107766# check for non-empty bitmaps before accessing them
363 if( !aPaint.IsEmpty() && !aPolyMask.IsEmpty() )
364 {
365 BitmapScopedWriteAccess pW(aPaint);
366 Bitmap::ScopedReadAccess pR(aPolyMask);
367
368 if( pW && pR )
369 {
370 BitmapColor aPixCol;
371 const BitmapColor aFillCol( GetFillColor() );
372 const BitmapColor aBlack( pR->GetBestMatchingColor( COL_BLACK ) );
373 const tools::Long nWidth = pW->Width();
374 const tools::Long nHeight = pW->Height();
375 const tools::Long nR = aFillCol.GetRed();
376 const tools::Long nG = aFillCol.GetGreen();
377 const tools::Long nB = aFillCol.GetBlue();
378 tools::Long nX, nY;
379
381 {
382 const BitmapPalette& rPal = pW->GetPalette();
383 const sal_uInt16 nCount = rPal.GetEntryCount();
384 std::unique_ptr<sal_uInt8[]> xMap(new sal_uInt8[ nCount * sizeof( BitmapColor )]);
385 BitmapColor* pMap = reinterpret_cast<BitmapColor*>(xMap.get());
386
387 for( sal_uInt16 i = 0; i < nCount; i++ )
388 {
389 BitmapColor aCol( rPal[ i ] );
390 aCol.Merge( aFillCol, cTrans );
391 pMap[ i ] = BitmapColor( static_cast<sal_uInt8>(rPal.GetBestIndex( aCol )) );
392 }
393
395 pW->GetScanlineFormat() == ScanlineFormat::N8BitPal )
396 {
397 const sal_uInt8 cBlack = aBlack.GetIndex();
398
399 for( nY = 0; nY < nHeight; nY++ )
400 {
401 Scanline pWScan = pW->GetScanline( nY );
402 Scanline pRScan = pR->GetScanline( nY );
403 sal_uInt8 cBit = 128;
404
405 for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan++ )
406 {
407 if( !cBit )
408 {
409 cBit = 128;
410 pRScan += 1;
411 }
412 if( ( *pRScan & cBit ) == cBlack )
413 {
414 *pWScan = pMap[ *pWScan ].GetIndex();
415 }
416 }
417 }
418 }
419 else
420 {
421 for( nY = 0; nY < nHeight; nY++ )
422 {
423 Scanline pScanline = pW->GetScanline(nY);
424 Scanline pScanlineRead = pR->GetScanline(nY);
425 for( nX = 0; nX < nWidth; nX++ )
426 {
427 if( pR->GetPixelFromData( pScanlineRead, nX ) == aBlack )
428 {
429 pW->SetPixelOnData( pScanline, nX, pMap[ pW->GetIndexFromData( pScanline, nX ) ] );
430 }
431 }
432 }
433 }
434 }
435 else
436 {
438 pW->GetScanlineFormat() == ScanlineFormat::N24BitTcBgr )
439 {
440 const sal_uInt8 cBlack = aBlack.GetIndex();
441
442 for( nY = 0; nY < nHeight; nY++ )
443 {
444 Scanline pWScan = pW->GetScanline( nY );
445 Scanline pRScan = pR->GetScanline( nY );
446 sal_uInt8 cBit = 128;
447
448 for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan += 3 )
449 {
450 if( !cBit )
451 {
452 cBit = 128;
453 pRScan += 1;
454 }
455 if( ( *pRScan & cBit ) == cBlack )
456 {
457 pWScan[ 0 ] = color::ColorChannelMerge( pWScan[ 0 ], nB, cTrans );
458 pWScan[ 1 ] = color::ColorChannelMerge( pWScan[ 1 ], nG, cTrans );
459 pWScan[ 2 ] = color::ColorChannelMerge( pWScan[ 2 ], nR, cTrans );
460 }
461 }
462 }
463 }
464 else
465 {
466 for( nY = 0; nY < nHeight; nY++ )
467 {
468 Scanline pScanline = pW->GetScanline(nY);
469 Scanline pScanlineRead = pR->GetScanline(nY);
470 for( nX = 0; nX < nWidth; nX++ )
471 {
472 if( pR->GetPixelFromData( pScanlineRead, nX ) == aBlack )
473 {
474 aPixCol = pW->GetColor( nY, nX );
475 aPixCol.Merge(aFillCol, cTrans);
476 pW->SetPixelOnData(pScanline, nX, aPixCol);
477 }
478 }
479 }
480 }
481 }
482 }
483
484 pR.reset();
485 pW.reset();
486
487 DrawBitmap( aDstRect.TopLeft(), aPaint );
488
489 EnableMapMode( bOldMap );
490
491 if( mbLineColor )
492 {
494 SetFillColor();
495 DrawPolyPolygon( rPolyPoly );
496 Pop();
497 }
498 }
499 }
500 else
501 {
502 DrawPolyPolygon( rPolyPoly );
503 }
504 }
505 }
506
507 mpMetaFile = pOldMetaFile;
508
509 // #110958# Restore disabled alpha VDev
510 mpAlphaVDev = pOldAlphaVDev;
511}
512
514 sal_uInt16 nTransparencePercent )
515{
516 assert(!is_double_buffered_window());
517
518 // short circuit for drawing an opaque polygon
519 if( (nTransparencePercent < 1) || (mnDrawMode & DrawModeFlags::NoTransparency) )
520 {
521 DrawPolyPolygon( rPolyPoly );
522 return;
523 }
524
525 // short circuit for drawing an invisible polygon
526 if( (!mbFillColor && !mbLineColor) || (nTransparencePercent >= 100) )
527 return; // tdf#84294: do not record it in metafile
528
529 // handle metafile recording
530 if( mpMetaFile )
531 mpMetaFile->AddAction( new MetaTransparentAction( rPolyPoly, nTransparencePercent ) );
532
533 bool bDrawn = !IsDeviceOutputNecessary() || ImplIsRecordLayout();
534 if( bDrawn )
535 return;
536
537 // get the device graphics as drawing target
538 if( !mpGraphics && !AcquireGraphics() )
539 return;
540 assert(mpGraphics);
541
542 // try hard to draw it directly, because the emulation layers are slower
543 bDrawn = DrawTransparentNatively( rPolyPoly, nTransparencePercent );
544
545 if (!bDrawn)
546 EmulateDrawTransparent( rPolyPoly, nTransparencePercent );
547
548 // #110958# Apply alpha value also to VDev alpha channel
549 if( mpAlphaVDev )
550 {
551 const Color aFillCol( mpAlphaVDev->GetFillColor() );
552 mpAlphaVDev->SetFillColor( Color(sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100),
553 sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100),
554 sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100)) );
555
556 mpAlphaVDev->DrawTransparent( rPolyPoly, nTransparencePercent );
557
558 mpAlphaVDev->SetFillColor( aFillCol );
559 }
560}
561
562void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos,
563 const Size& rSize, const Gradient& rTransparenceGradient )
564{
565 assert(!is_double_buffered_window());
566
567 const Color aBlack( COL_BLACK );
568
569 if( mpMetaFile )
570 {
571 // missing here is to map the data using the DeviceTransformation
572 mpMetaFile->AddAction( new MetaFloatTransparentAction( rMtf, rPos, rSize, rTransparenceGradient ) );
573 }
574
576 return;
577
578 if( ( rTransparenceGradient.GetStartColor() == aBlack && rTransparenceGradient.GetEndColor() == aBlack ) ||
580 {
581 const_cast<GDIMetaFile&>(rMtf).WindStart();
582 const_cast<GDIMetaFile&>(rMtf).Play(*this, rPos, rSize);
583 const_cast<GDIMetaFile&>(rMtf).WindStart();
584 }
585 else
586 {
587 GDIMetaFile* pOldMetaFile = mpMetaFile;
588 tools::Rectangle aOutRect( LogicToPixel( rPos ), LogicToPixel( rSize ) );
589 Point aPoint;
590 tools::Rectangle aDstRect( aPoint, GetOutputSizePixel() );
591
592 mpMetaFile = nullptr;
593 aDstRect.Intersection( aOutRect );
594
595 ClipToPaintRegion( aDstRect );
596
597 if( !aDstRect.IsEmpty() )
598 {
599 // Create transparent buffer
601
602 xVDev->mnDPIX = mnDPIX;
603 xVDev->mnDPIY = mnDPIY;
604
605 if( xVDev->SetOutputSizePixel( aDstRect.GetSize() ) )
606 {
608 {
609 // #i102109#
610 // For MetaFile replay (see task) it may now be necessary to take
611 // into account that the content is AntiAlialiased and needs to be masked
612 // like that. Instead of masking, i will use a copy-modify-paste cycle
613 // here (as i already use in the VclPrimiziveRenderer with success)
614 xVDev->SetAntialiasing(GetAntialiasing());
615
616 // create MapMode for buffer (offset needed) and set
618 const Point aOutPos(PixelToLogic(aDstRect.TopLeft()));
619 aMap.SetOrigin(Point(-aOutPos.X(), -aOutPos.Y()));
620 xVDev->SetMapMode(aMap);
621
622 // copy MapMode state and disable for target
623 const bool bOrigMapModeEnabled(IsMapModeEnabled());
624 EnableMapMode(false);
625
626 // copy MapMode state and disable for buffer
627 const bool bBufferMapModeEnabled(xVDev->IsMapModeEnabled());
628 xVDev->EnableMapMode(false);
629
630 // copy content from original to buffer
631 xVDev->DrawOutDev( aPoint, xVDev->GetOutputSizePixel(), // dest
632 aDstRect.TopLeft(), xVDev->GetOutputSizePixel(), // source
633 *this);
634
635 // draw MetaFile to buffer
636 xVDev->EnableMapMode(bBufferMapModeEnabled);
637 const_cast<GDIMetaFile&>(rMtf).WindStart();
638 const_cast<GDIMetaFile&>(rMtf).Play(*xVDev, rPos, rSize);
639 const_cast<GDIMetaFile&>(rMtf).WindStart();
640
641 // get content bitmap from buffer
642 xVDev->EnableMapMode(false);
643
644 const Bitmap aPaint(xVDev->GetBitmap(aPoint, xVDev->GetOutputSizePixel()));
645
646 // create alpha mask from gradient and get as Bitmap
647 xVDev->EnableMapMode(bBufferMapModeEnabled);
648 xVDev->SetDrawMode(DrawModeFlags::GrayGradient);
649 xVDev->DrawGradient(tools::Rectangle(rPos, rSize), rTransparenceGradient);
650 xVDev->SetDrawMode(DrawModeFlags::Default);
651 xVDev->EnableMapMode(false);
652
653 const AlphaMask aAlpha(xVDev->GetBitmap(aPoint, xVDev->GetOutputSizePixel()));
654
655 xVDev.disposeAndClear();
656
657 // draw masked content to target and restore MapMode
658 DrawBitmapEx(aDstRect.TopLeft(), BitmapEx(aPaint, aAlpha));
659 EnableMapMode(bOrigMapModeEnabled);
660 }
661 else
662 {
664 Point aOutPos( PixelToLogic( aDstRect.TopLeft() ) );
665 const bool bOldMap = mbMap;
666
667 aMap.SetOrigin( Point( -aOutPos.X(), -aOutPos.Y() ) );
668 xVDev->SetMapMode( aMap );
669 const bool bVDevOldMap = xVDev->IsMapModeEnabled();
670
671 // create paint bitmap
672 const_cast<GDIMetaFile&>(rMtf).WindStart();
673 const_cast<GDIMetaFile&>(rMtf).Play(*xVDev, rPos, rSize);
674 const_cast<GDIMetaFile&>(rMtf).WindStart();
675 xVDev->EnableMapMode( false );
676 BitmapEx aPaint = xVDev->GetBitmapEx(Point(), xVDev->GetOutputSizePixel());
677 xVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( sal_True ) here!
678
679 // create alpha mask from gradient
680 xVDev->SetDrawMode( DrawModeFlags::GrayGradient );
681 xVDev->DrawGradient( tools::Rectangle( rPos, rSize ), rTransparenceGradient );
682 xVDev->SetDrawMode( DrawModeFlags::Default );
683 xVDev->EnableMapMode( false );
684
685 AlphaMask aAlpha(xVDev->GetBitmap(Point(), xVDev->GetOutputSizePixel()));
686 aAlpha.BlendWith(aPaint.GetAlphaMask());
687
688 xVDev.disposeAndClear();
689
690 EnableMapMode( false );
691 DrawBitmapEx(aDstRect.TopLeft(), BitmapEx(aPaint.GetBitmap(), aAlpha));
692 EnableMapMode( bOldMap );
693 }
694 }
695 }
696
697 mpMetaFile = pOldMetaFile;
698 }
699}
700
701typedef ::std::pair< MetaAction*, int > Component; // MetaAction plus index in metafile
702
703namespace {
704
705// List of (intersecting) actions, plus overall bounds
706struct ConnectedComponents
707{
708 ConnectedComponents() :
709 aComponentList(),
710 aBounds(),
711 aBgColor(COL_WHITE),
712 bIsSpecial(false),
713 bIsFullyTransparent(false)
714 {}
715
716 ::std::list< Component > aComponentList;
717 tools::Rectangle aBounds;
718 Color aBgColor;
719 bool bIsSpecial;
720 bool bIsFullyTransparent;
721};
722
723}
724
725namespace {
726
731bool DoesActionHandleTransparency( const MetaAction& rAct )
732{
733 // MetaActionType::FLOATTRANSPARENT can contain a whole metafile,
734 // which is to be rendered with the given transparent gradient. We
735 // currently cannot emulate transparent painting on a white
736 // background reliably.
737
738 // the remainder can handle printing itself correctly on a uniform
739 // white background.
740 switch( rAct.GetType() )
741 {
746 return true;
747
748 default:
749 return false;
750 }
751}
752
753bool doesRectCoverWithUniformColor(
754 tools::Rectangle const & rPrevRect,
755 tools::Rectangle const & rCurrRect,
756 OutputDevice const & rMapModeVDev)
757{
758 // shape needs to fully cover previous content, and have uniform
759 // color
760 return (rMapModeVDev.LogicToPixel(rCurrRect).Contains(rPrevRect) &&
761 rMapModeVDev.IsFillColor());
762}
763
767bool checkRect( tools::Rectangle& io_rPrevRect,
768 Color& o_rBgColor,
769 const tools::Rectangle& rCurrRect,
770 OutputDevice const & rMapModeVDev )
771{
772 bool bRet = doesRectCoverWithUniformColor(io_rPrevRect, rCurrRect, rMapModeVDev);
773
774 if( bRet )
775 {
776 io_rPrevRect = rCurrRect;
777 o_rBgColor = rMapModeVDev.GetFillColor();
778 }
779
780 return bRet;
781}
782
790void ImplConvertTransparentAction( GDIMetaFile& o_rMtf,
791 const MetaAction& rAct,
792 const OutputDevice& rStateOutDev,
793 Color aBgColor )
794{
796 {
797 const MetaTransparentAction* pTransAct = static_cast<const MetaTransparentAction*>(&rAct);
798 sal_uInt16 nTransparency( pTransAct->GetTransparence() );
799
800 // #i10613# Respect transparency for draw color
801 if (nTransparency)
802 {
804
805 // assume white background for alpha blending
806 Color aLineColor(rStateOutDev.GetLineColor());
807 aLineColor.SetRed(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency) * aLineColor.GetRed()) / 100));
808 aLineColor.SetGreen(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency) * aLineColor.GetGreen()) / 100));
809 aLineColor.SetBlue(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency) * aLineColor.GetBlue()) / 100));
810 o_rMtf.AddAction(new MetaLineColorAction(aLineColor, true));
811
812 Color aFillColor(rStateOutDev.GetFillColor());
813 aFillColor.SetRed(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency)*aFillColor.GetRed()) / 100));
814 aFillColor.SetGreen(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency)*aFillColor.GetGreen()) / 100));
815 aFillColor.SetBlue(static_cast<sal_uInt8>((255*nTransparency + (100 - nTransparency)*aFillColor.GetBlue()) / 100));
816 o_rMtf.AddAction(new MetaFillColorAction(aFillColor, true));
817 }
818
819 o_rMtf.AddAction(new MetaPolyPolygonAction(pTransAct->GetPolyPolygon()));
820
821 if(nTransparency)
822 o_rMtf.AddAction(new MetaPopAction());
823 }
824 else
825 {
826 BitmapEx aBmpEx;
827
828 switch (rAct.GetType())
829 {
831 aBmpEx = static_cast<const MetaBmpExAction&>(rAct).GetBitmapEx();
832 break;
833
835 aBmpEx = static_cast<const MetaBmpExScaleAction&>(rAct).GetBitmapEx();
836 break;
837
839 aBmpEx = static_cast<const MetaBmpExScaleAction&>(rAct).GetBitmapEx();
840 break;
841
843
844 default:
845 OSL_FAIL("Printer::GetPreparedMetafile impossible state reached");
846 break;
847 }
848
849 Bitmap aBmp(aBmpEx.GetBitmap());
850 if (aBmpEx.IsAlpha())
851 {
852 // blend with alpha channel
853 aBmp.Convert(BmpConversion::N24Bit);
854 aBmp.Blend(aBmpEx.GetAlphaMask(), aBgColor);
855 }
856
857 // add corresponding action
858 switch (rAct.GetType())
859 {
861 o_rMtf.AddAction(new MetaBmpAction(
862 static_cast<const MetaBmpExAction&>(rAct).GetPoint(),
863 aBmp));
864 break;
866 o_rMtf.AddAction(new MetaBmpScaleAction(
867 static_cast<const MetaBmpExScaleAction&>(rAct).GetPoint(),
868 static_cast<const MetaBmpExScaleAction&>(rAct).GetSize(),
869 aBmp));
870 break;
873 static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestPoint(),
874 static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestSize(),
875 static_cast<const MetaBmpExScalePartAction&>(rAct).GetSrcPoint(),
876 static_cast<const MetaBmpExScalePartAction&>(rAct).GetSrcSize(),
877 aBmp));
878 break;
879 default:
880 OSL_FAIL("Unexpected case");
881 break;
882 }
883 }
884}
885
886// #i10613# Extracted from ImplCheckRect::ImplCreate
887// Returns true, if given action creates visible (i.e. non-transparent) output
888bool ImplIsNotTransparent( const MetaAction& rAct, const OutputDevice& rOut )
889{
890 const bool bLineTransparency( !rOut.IsLineColor() || rOut.GetLineColor().IsFullyTransparent() );
891 const bool bFillTransparency( !rOut.IsFillColor() || rOut.GetFillColor().IsFullyTransparent() );
892 bool bRet( false );
893
894 switch( rAct.GetType() )
895 {
897 if( !bLineTransparency )
898 bRet = true;
899 break;
900
902 if( !bLineTransparency )
903 bRet = true;
904 break;
905
907 if( !bLineTransparency || !bFillTransparency )
908 bRet = true;
909 break;
910
912 if( !bLineTransparency || !bFillTransparency )
913 bRet = true;
914 break;
915
917 if( !bLineTransparency || !bFillTransparency )
918 bRet = true;
919 break;
920
922 if( !bLineTransparency || !bFillTransparency )
923 bRet = true;
924 break;
925
927 if( !bLineTransparency || !bFillTransparency )
928 bRet = true;
929 break;
930
932 if( !bLineTransparency || !bFillTransparency )
933 bRet = true;
934 break;
935
937 if( !bLineTransparency )
938 bRet = true;
939 break;
940
942 if( !bLineTransparency || !bFillTransparency )
943 bRet = true;
944 break;
945
947 if( !bLineTransparency || !bFillTransparency )
948 bRet = true;
949 break;
950
952 {
953 const MetaTextAction& rTextAct = static_cast<const MetaTextAction&>(rAct);
954 const OUString aString( rTextAct.GetText().copy(rTextAct.GetIndex(), rTextAct.GetLen()) );
955 if (!aString.isEmpty())
956 bRet = true;
957 }
958 break;
959
961 {
962 const MetaTextArrayAction& rTextAct = static_cast<const MetaTextArrayAction&>(rAct);
963 const OUString aString( rTextAct.GetText().copy(rTextAct.GetIndex(), rTextAct.GetLen()) );
964 if (!aString.isEmpty())
965 bRet = true;
966 }
967 break;
968
989 // all other actions: generate non-transparent output
990 bRet = true;
991 break;
992
993 default:
994 break;
995 }
996
997 return bRet;
998}
999
1000// #i10613# Extracted from ImplCheckRect::ImplCreate
1001tools::Rectangle ImplCalcActionBounds( const MetaAction& rAct, const OutputDevice& rOut )
1002{
1003 tools::Rectangle aActionBounds;
1004
1005 switch( rAct.GetType() )
1006 {
1008 aActionBounds = tools::Rectangle( static_cast<const MetaPixelAction&>(rAct).GetPoint(), Size( 1, 1 ) );
1009 break;
1010
1012 aActionBounds = tools::Rectangle( static_cast<const MetaPointAction&>(rAct).GetPoint(), Size( 1, 1 ) );
1013 break;
1014
1016 {
1017 const MetaLineAction& rMetaLineAction = static_cast<const MetaLineAction&>(rAct);
1018 aActionBounds = tools::Rectangle( rMetaLineAction.GetStartPoint(), rMetaLineAction.GetEndPoint() );
1019 aActionBounds.Normalize();
1020 const tools::Long nLineWidth(rMetaLineAction.GetLineInfo().GetWidth());
1021 if(nLineWidth)
1022 {
1023 const tools::Long nHalfLineWidth((nLineWidth + 1) / 2);
1024 aActionBounds.AdjustLeft( -nHalfLineWidth );
1025 aActionBounds.AdjustTop( -nHalfLineWidth );
1026 aActionBounds.AdjustRight(nHalfLineWidth );
1027 aActionBounds.AdjustBottom(nHalfLineWidth );
1028 }
1029 break;
1030 }
1031
1033 aActionBounds = static_cast<const MetaRectAction&>(rAct).GetRect();
1034 break;
1035
1037 aActionBounds = tools::Polygon( static_cast<const MetaRoundRectAction&>(rAct).GetRect(),
1038 static_cast<const MetaRoundRectAction&>(rAct).GetHorzRound(),
1039 static_cast<const MetaRoundRectAction&>(rAct).GetVertRound() ).GetBoundRect();
1040 break;
1041
1043 {
1044 const tools::Rectangle& rRect = static_cast<const MetaEllipseAction&>(rAct).GetRect();
1045 aActionBounds = tools::Polygon( rRect.Center(),
1046 rRect.GetWidth() >> 1,
1047 rRect.GetHeight() >> 1 ).GetBoundRect();
1048 break;
1049 }
1050
1052 aActionBounds = tools::Polygon( static_cast<const MetaArcAction&>(rAct).GetRect(),
1053 static_cast<const MetaArcAction&>(rAct).GetStartPoint(),
1054 static_cast<const MetaArcAction&>(rAct).GetEndPoint(), PolyStyle::Arc ).GetBoundRect();
1055 break;
1056
1058 aActionBounds = tools::Polygon( static_cast<const MetaPieAction&>(rAct).GetRect(),
1059 static_cast<const MetaPieAction&>(rAct).GetStartPoint(),
1060 static_cast<const MetaPieAction&>(rAct).GetEndPoint(), PolyStyle::Pie ).GetBoundRect();
1061 break;
1062
1064 aActionBounds = tools::Polygon( static_cast<const MetaChordAction&>(rAct).GetRect(),
1065 static_cast<const MetaChordAction&>(rAct).GetStartPoint(),
1066 static_cast<const MetaChordAction&>(rAct).GetEndPoint(), PolyStyle::Chord ).GetBoundRect();
1067 break;
1068
1070 {
1071 const MetaPolyLineAction& rMetaPolyLineAction = static_cast<const MetaPolyLineAction&>(rAct);
1072 aActionBounds = rMetaPolyLineAction.GetPolygon().GetBoundRect();
1073 const tools::Long nLineWidth(rMetaPolyLineAction.GetLineInfo().GetWidth());
1074 if(nLineWidth)
1075 {
1076 const tools::Long nHalfLineWidth((nLineWidth + 1) / 2);
1077 aActionBounds.AdjustLeft( -nHalfLineWidth );
1078 aActionBounds.AdjustTop( -nHalfLineWidth );
1079 aActionBounds.AdjustRight(nHalfLineWidth );
1080 aActionBounds.AdjustBottom(nHalfLineWidth );
1081 }
1082 break;
1083 }
1084
1086 aActionBounds = static_cast<const MetaPolygonAction&>(rAct).GetPolygon().GetBoundRect();
1087 break;
1088
1090 aActionBounds = static_cast<const MetaPolyPolygonAction&>(rAct).GetPolyPolygon().GetBoundRect();
1091 break;
1092
1094 aActionBounds = tools::Rectangle( static_cast<const MetaBmpAction&>(rAct).GetPoint(),
1095 rOut.PixelToLogic( static_cast<const MetaBmpAction&>(rAct).GetBitmap().GetSizePixel() ) );
1096 break;
1097
1099 aActionBounds = tools::Rectangle( static_cast<const MetaBmpScaleAction&>(rAct).GetPoint(),
1100 static_cast<const MetaBmpScaleAction&>(rAct).GetSize() );
1101 break;
1102
1104 aActionBounds = tools::Rectangle( static_cast<const MetaBmpScalePartAction&>(rAct).GetDestPoint(),
1105 static_cast<const MetaBmpScalePartAction&>(rAct).GetDestSize() );
1106 break;
1107
1109 aActionBounds = tools::Rectangle( static_cast<const MetaBmpExAction&>(rAct).GetPoint(),
1110 rOut.PixelToLogic( static_cast<const MetaBmpExAction&>(rAct).GetBitmapEx().GetSizePixel() ) );
1111 break;
1112
1114 aActionBounds = tools::Rectangle( static_cast<const MetaBmpExScaleAction&>(rAct).GetPoint(),
1115 static_cast<const MetaBmpExScaleAction&>(rAct).GetSize() );
1116 break;
1117
1119 aActionBounds = tools::Rectangle( static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestPoint(),
1120 static_cast<const MetaBmpExScalePartAction&>(rAct).GetDestSize() );
1121 break;
1122
1124 aActionBounds = tools::Rectangle( static_cast<const MetaMaskAction&>(rAct).GetPoint(),
1125 rOut.PixelToLogic( static_cast<const MetaMaskAction&>(rAct).GetBitmap().GetSizePixel() ) );
1126 break;
1127
1129 aActionBounds = tools::Rectangle( static_cast<const MetaMaskScaleAction&>(rAct).GetPoint(),
1130 static_cast<const MetaMaskScaleAction&>(rAct).GetSize() );
1131 break;
1132
1134 aActionBounds = tools::Rectangle( static_cast<const MetaMaskScalePartAction&>(rAct).GetDestPoint(),
1135 static_cast<const MetaMaskScalePartAction&>(rAct).GetDestSize() );
1136 break;
1137
1139 aActionBounds = static_cast<const MetaGradientAction&>(rAct).GetRect();
1140 break;
1141
1143 aActionBounds = static_cast<const MetaGradientExAction&>(rAct).GetPolyPolygon().GetBoundRect();
1144 break;
1145
1147 aActionBounds = static_cast<const MetaHatchAction&>(rAct).GetPolyPolygon().GetBoundRect();
1148 break;
1149
1151 aActionBounds = static_cast<const MetaWallpaperAction&>(rAct).GetRect();
1152 break;
1153
1155 aActionBounds = static_cast<const MetaTransparentAction&>(rAct).GetPolyPolygon().GetBoundRect();
1156 break;
1157
1159 aActionBounds = tools::Rectangle( static_cast<const MetaFloatTransparentAction&>(rAct).GetPoint(),
1160 static_cast<const MetaFloatTransparentAction&>(rAct).GetSize() );
1161 break;
1162
1164 aActionBounds = tools::Rectangle( static_cast<const MetaEPSAction&>(rAct).GetPoint(),
1165 static_cast<const MetaEPSAction&>(rAct).GetSize() );
1166 break;
1167
1169 {
1170 const MetaTextAction& rTextAct = static_cast<const MetaTextAction&>(rAct);
1171 const OUString aString( rTextAct.GetText().copy(rTextAct.GetIndex(), rTextAct.GetLen()) );
1172
1173 if (!aString.isEmpty())
1174 {
1175 const Point aPtLog( rTextAct.GetPoint() );
1176
1177 // #105987# Use API method instead of Impl* methods
1178 // #107490# Set base parameter equal to index parameter
1179 rOut.GetTextBoundRect( aActionBounds, rTextAct.GetText(), rTextAct.GetIndex(),
1180 rTextAct.GetIndex(), rTextAct.GetLen() );
1181 aActionBounds.Move( aPtLog.X(), aPtLog.Y() );
1182 }
1183 }
1184 break;
1185
1187 {
1188 const MetaTextArrayAction& rTextAct = static_cast<const MetaTextArrayAction&>(rAct);
1189 const OUString aString( rTextAct.GetText().copy(rTextAct.GetIndex(), rTextAct.GetLen()) );
1190
1191 if( !aString.isEmpty() )
1192 {
1193 // #105987# ImplLayout takes everything in logical coordinates
1194 std::unique_ptr<SalLayout> pSalLayout = rOut.ImplLayout( rTextAct.GetText(), rTextAct.GetIndex(),
1195 rTextAct.GetLen(), rTextAct.GetPoint(),
1196 0, rTextAct.GetDXArray(), rTextAct.GetKashidaArray() );
1197 if( pSalLayout )
1198 {
1199 tools::Rectangle aBoundRect( rOut.ImplGetTextBoundRect( *pSalLayout ) );
1200 aActionBounds = rOut.PixelToLogic( aBoundRect );
1201 }
1202 }
1203 }
1204 break;
1205
1207 aActionBounds = static_cast<const MetaTextRectAction&>(rAct).GetRect();
1208 break;
1209
1211 {
1212 const MetaStretchTextAction& rTextAct = static_cast<const MetaStretchTextAction&>(rAct);
1213 const OUString aString( rTextAct.GetText().copy(rTextAct.GetIndex(), rTextAct.GetLen()) );
1214
1215 // #i16195# Literate copy from TextArray action, the
1216 // semantics for the ImplLayout call are copied from the
1217 // OutDev::DrawStretchText() code. Unfortunately, also in
1218 // this case, public outdev methods such as GetTextWidth()
1219 // don't provide enough info.
1220 if( !aString.isEmpty() )
1221 {
1222 // #105987# ImplLayout takes everything in logical coordinates
1223 std::unique_ptr<SalLayout> pSalLayout = rOut.ImplLayout( rTextAct.GetText(), rTextAct.GetIndex(),
1224 rTextAct.GetLen(), rTextAct.GetPoint(),
1225 rTextAct.GetWidth() );
1226 if( pSalLayout )
1227 {
1228 tools::Rectangle aBoundRect( rOut.ImplGetTextBoundRect( *pSalLayout ) );
1229 aActionBounds = rOut.PixelToLogic( aBoundRect );
1230 }
1231 }
1232 }
1233 break;
1234
1236 OSL_FAIL("MetaActionType::TEXTLINE not supported");
1237 break;
1238
1239 default:
1240 break;
1241 }
1242
1243 if( !aActionBounds.IsEmpty() )
1244 {
1245 // fdo#40421 limit current action's output to clipped area
1246 if( rOut.IsClipRegion() )
1247 return rOut.LogicToPixel(
1248 rOut.GetClipRegion().GetBoundRect().Intersection( aActionBounds ) );
1249 else
1250 return rOut.LogicToPixel( aActionBounds );
1251 }
1252 else
1253 return tools::Rectangle();
1254}
1255
1256} // end anon namespace
1257
1258// TODO: this massive function operates on metafiles, so eventually it should probably
1259// be shifted to the GDIMetaFile class
1261 tools::Long nMaxBmpDPIX, tools::Long nMaxBmpDPIY,
1262 bool bReduceTransparency, bool bTransparencyAutoMode,
1263 bool bDownsampleBitmaps,
1264 const Color& rBackground
1265 )
1266{
1267 MetaAction* pCurrAct;
1268 bool bTransparent( false );
1269
1270 rOutMtf.Clear();
1271
1272 if(!bReduceTransparency || bTransparencyAutoMode)
1273 bTransparent = rInMtf.HasTransparentActions();
1274
1275 // #i10613# Determine set of connected components containing transparent objects. These are
1276 // then processed as bitmaps, the original actions are removed from the metafile.
1277 if( !bTransparent )
1278 {
1279 // nothing transparent -> just copy
1280 rOutMtf = rInMtf;
1281 }
1282 else
1283 {
1284 // #i10613#
1285 // This works as follows: we want a number of distinct sets of
1286 // connected components, where each set contains metafile
1287 // actions that are intersecting (note: there are possibly
1288 // more actions contained as are directly intersecting,
1289 // because we can only produce rectangular bitmaps later
1290 // on. Thus, each set of connected components is the smallest
1291 // enclosing, axis-aligned rectangle that completely bounds a
1292 // number of intersecting metafile actions, plus any action
1293 // that would otherwise be cut in two). Therefore, we
1294 // iteratively add metafile actions from the original metafile
1295 // to this connected components list (aCCList), by checking
1296 // each element's bounding box against intersection with the
1297 // metaaction at hand.
1298 // All those intersecting elements are removed from aCCList
1299 // and collected in a temporary list (aCCMergeList). After all
1300 // elements have been checked, the aCCMergeList elements are
1301 // merged with the metaaction at hand into one resulting
1302 // connected component, with one big bounding box, and
1303 // inserted into aCCList again.
1304 // The time complexity of this algorithm is O(n^3), where n is
1305 // the number of metafile actions, and it finds all distinct
1306 // regions of rectangle-bounded connected components. This
1307 // algorithm was designed by AF.
1308
1309 // STAGE 1: Detect background
1310
1311 // Receives uniform background content, and is _not_ merged
1312 // nor checked for intersection against other aCCList elements
1313 ConnectedComponents aBackgroundComponent;
1314
1315 // Read the configuration value of minimal object area where transparency will be removed
1316 double fReduceTransparencyMinArea = officecfg::Office::Common::VCL::ReduceTransparencyMinArea::get() / 100.0;
1317 SAL_WARN_IF(fReduceTransparencyMinArea > 1.0, "vcl",
1318 "Value of ReduceTransparencyMinArea config option is too high");
1319 SAL_WARN_IF(fReduceTransparencyMinArea < 0.0, "vcl",
1320 "Value of ReduceTransparencyMinArea config option is too low");
1321 fReduceTransparencyMinArea = std::clamp(fReduceTransparencyMinArea, 0.0, 1.0);
1322
1323 // create an OutputDevice to record mapmode changes and the like
1325 aMapModeVDev->mnDPIX = mnDPIX;
1326 aMapModeVDev->mnDPIY = mnDPIY;
1327 aMapModeVDev->EnableOutput(false);
1328
1329 // weed out page-filling background objects (if they are
1330 // uniformly coloured). Keeping them outside the other
1331 // connected components often prevents whole-page bitmap
1332 // generation.
1333 bool bStillBackground=true; // true until first non-bg action
1334 int nActionNum = 0, nLastBgAction = -1;
1335 pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction();
1336 if( rBackground != COL_TRANSPARENT )
1337 {
1338 aBackgroundComponent.aBgColor = rBackground;
1339 aBackgroundComponent.aBounds = GetBackgroundComponentBounds();
1340 }
1341 while( pCurrAct && bStillBackground )
1342 {
1343 switch( pCurrAct->GetType() )
1344 {
1346 {
1347 if( !checkRect(
1348 aBackgroundComponent.aBounds,
1349 aBackgroundComponent.aBgColor,
1350 static_cast<const MetaRectAction*>(pCurrAct)->GetRect(),
1351 *aMapModeVDev) )
1352 bStillBackground=false; // incomplete occlusion of background
1353 else
1354 nLastBgAction=nActionNum; // this _is_ background
1355 break;
1356 }
1358 {
1359 const tools::Polygon aPoly(
1360 static_cast<const MetaPolygonAction*>(pCurrAct)->GetPolygon());
1362 aPoly.getB2DPolygon()) ||
1363 !checkRect(
1364 aBackgroundComponent.aBounds,
1365 aBackgroundComponent.aBgColor,
1366 aPoly.GetBoundRect(),
1367 *aMapModeVDev) )
1368 bStillBackground=false; // incomplete occlusion of background
1369 else
1370 nLastBgAction=nActionNum; // this _is_ background
1371 break;
1372 }
1374 {
1375 const tools::PolyPolygon aPoly(
1376 static_cast<const MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon());
1377 if( aPoly.Count() != 1 ||
1379 aPoly[0].getB2DPolygon()) ||
1380 !checkRect(
1381 aBackgroundComponent.aBounds,
1382 aBackgroundComponent.aBgColor,
1383 aPoly.GetBoundRect(),
1384 *aMapModeVDev) )
1385 bStillBackground=false; // incomplete occlusion of background
1386 else
1387 nLastBgAction=nActionNum; // this _is_ background
1388 break;
1389 }
1391 {
1392 if( !checkRect(
1393 aBackgroundComponent.aBounds,
1394 aBackgroundComponent.aBgColor,
1395 static_cast<const MetaWallpaperAction*>(pCurrAct)->GetRect(),
1396 *aMapModeVDev) )
1397 bStillBackground=false; // incomplete occlusion of background
1398 else
1399 nLastBgAction=nActionNum; // this _is_ background
1400 break;
1401 }
1402 default:
1403 {
1404 if( ImplIsNotTransparent( *pCurrAct,
1405 *aMapModeVDev ) )
1406 bStillBackground=false; // non-transparent action, possibly
1407 // not uniform
1408 else
1409 // extend current bounds (next uniform action
1410 // needs to fully cover this area)
1411 aBackgroundComponent.aBounds.Union(
1412 ImplCalcActionBounds(*pCurrAct, *aMapModeVDev) );
1413 break;
1414 }
1415 }
1416
1417 // execute action to get correct MapModes etc.
1418 pCurrAct->Execute( aMapModeVDev.get() );
1419
1420 pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction();
1421 ++nActionNum;
1422 }
1423
1424 if (nLastBgAction != -1)
1425 {
1426 size_t nActionSize = rInMtf.GetActionSize();
1427 // tdf#134736 move nLastBgAction to also include any trailing pops
1428 for (size_t nPostLastBgAction = nLastBgAction + 1; nPostLastBgAction < nActionSize; ++nPostLastBgAction)
1429 {
1430 if (rInMtf.GetAction(nPostLastBgAction)->GetType() != MetaActionType::POP)
1431 break;
1432 nLastBgAction = nPostLastBgAction;
1433 }
1434 }
1435
1436 aMapModeVDev->ClearStack(); // clean up aMapModeVDev
1437
1438 // fast-forward until one after the last background action
1439 // (need to reconstruct map mode vdev state)
1440 nActionNum=0;
1441 pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction();
1442 while( pCurrAct && nActionNum<=nLastBgAction )
1443 {
1444 // up to and including last ink-generating background
1445 // action go to background component
1446 aBackgroundComponent.aComponentList.emplace_back(
1447 pCurrAct, nActionNum );
1448
1449 // execute action to get correct MapModes etc.
1450 pCurrAct->Execute( aMapModeVDev.get() );
1451 pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction();
1452 ++nActionNum;
1453 }
1454
1455 // STAGE 2: Generate connected components list
1456
1457 ::std::vector<ConnectedComponents> aCCList; // contains distinct sets of connected components as elements.
1458
1459 // iterate over all actions (start where background action
1460 // search left off)
1461 for( ;
1462 pCurrAct;
1463 pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
1464 {
1465 // execute action to get correct MapModes etc.
1466 pCurrAct->Execute( aMapModeVDev.get() );
1467
1468 // cache bounds of current action
1469 const tools::Rectangle aBBCurrAct( ImplCalcActionBounds(*pCurrAct, *aMapModeVDev) );
1470
1471 // accumulate collected bounds here, initialize with current action
1472 tools::Rectangle aTotalBounds( aBBCurrAct ); // thus, aTotalComponents.aBounds is empty
1473 // for non-output-generating actions
1474 bool bTreatSpecial( false );
1475 ConnectedComponents aTotalComponents;
1476
1477 // STAGE 2.1: Search for intersecting cc entries
1478
1479 // if aBBCurrAct is empty, it will intersect with no
1480 // aCCList member. Thus, we can save the check.
1481 // Furthermore, this ensures that non-output-generating
1482 // actions get their own aCCList entry, which is necessary
1483 // when copying them to the output metafile (see stage 4
1484 // below).
1485
1486 // #107169# Wholly transparent objects need
1487 // not be considered for connected components,
1488 // too. Just put each of them into a separate
1489 // component.
1490 aTotalComponents.bIsFullyTransparent = !ImplIsNotTransparent(*pCurrAct, *aMapModeVDev);
1491
1492 if( !aBBCurrAct.IsEmpty() &&
1493 !aTotalComponents.bIsFullyTransparent )
1494 {
1495 if( !aBackgroundComponent.aComponentList.empty() &&
1496 !aBackgroundComponent.aBounds.Contains(aTotalBounds) )
1497 {
1498 // it seems the background is not large enough. to
1499 // be on the safe side, combine with this component.
1500 aTotalBounds.Union( aBackgroundComponent.aBounds );
1501
1502 // extract all aCurr actions to aTotalComponents
1503 aTotalComponents.aComponentList.splice( aTotalComponents.aComponentList.end(),
1504 aBackgroundComponent.aComponentList );
1505
1506 if( aBackgroundComponent.bIsSpecial )
1507 bTreatSpecial = true;
1508 }
1509
1510 bool bSomeComponentsChanged;
1511
1512 // now, this is unfortunate: since changing anyone of
1513 // the aCCList elements (e.g. by merging or addition
1514 // of an action) might generate new intersection with
1515 // other aCCList elements, have to repeat the whole
1516 // element scanning, until nothing changes anymore.
1517 // Thus, this loop here makes us O(n^3) in the worst
1518 // case.
1519 do
1520 {
1521 // only loop here if 'intersects' branch below was hit
1522 bSomeComponentsChanged = false;
1523
1524 // iterate over all current members of aCCList
1525 for( auto aCurrCC=aCCList.begin(); aCurrCC != aCCList.end(); )
1526 {
1527 // first check if current element's bounds are
1528 // empty. This ensures that empty actions are not
1529 // merged into one component, as a matter of fact,
1530 // they have no position.
1531
1532 // #107169# Wholly transparent objects need
1533 // not be considered for connected components,
1534 // too. Just put each of them into a separate
1535 // component.
1536 if( !aCurrCC->aBounds.IsEmpty() &&
1537 !aCurrCC->bIsFullyTransparent &&
1538 aCurrCC->aBounds.Overlaps( aTotalBounds ) )
1539 {
1540 // union the intersecting aCCList element into aTotalComponents
1541
1542 // calc union bounding box
1543 aTotalBounds.Union( aCurrCC->aBounds );
1544
1545 // extract all aCurr actions to aTotalComponents
1546 aTotalComponents.aComponentList.splice( aTotalComponents.aComponentList.end(),
1547 aCurrCC->aComponentList );
1548
1549 if( aCurrCC->bIsSpecial )
1550 bTreatSpecial = true;
1551
1552 // remove and delete aCurrCC element from list (we've now merged its content)
1553 aCurrCC = aCCList.erase( aCurrCC );
1554
1555 // at least one component changed, need to rescan everything
1556 bSomeComponentsChanged = true;
1557 }
1558 else
1559 {
1560 ++aCurrCC;
1561 }
1562 }
1563 }
1564 while( bSomeComponentsChanged );
1565 }
1566
1567 // STAGE 2.2: Determine special state for cc element
1568
1569 // now test whether the whole connected component must be
1570 // treated specially (i.e. rendered as a bitmap): if the
1571 // added action is the very first action, or all actions
1572 // before it are completely transparent, the connected
1573 // component need not be treated specially, not even if
1574 // the added action contains transparency. This is because
1575 // painting of transparent objects on _white background_
1576 // works without alpha compositing (you just calculate the
1577 // color). Note that for the test "all objects before me
1578 // are transparent" no sorting is necessary, since the
1579 // added metaaction pCurrAct is always in the order the
1580 // metafile is painted. Generally, the order of the
1581 // metaactions in the ConnectedComponents are not
1582 // guaranteed to be the same as in the metafile.
1583 if( bTreatSpecial )
1584 {
1585 // prev component(s) special -> this one, too
1586 aTotalComponents.bIsSpecial = true;
1587 }
1588 else if(!pCurrAct->IsTransparent())
1589 {
1590 // added action and none of prev components special ->
1591 // this one normal, too
1592 aTotalComponents.bIsSpecial = false;
1593 }
1594 else
1595 {
1596 // added action is special and none of prev components
1597 // special -> do the detailed tests
1598
1599 // can the action handle transparency correctly
1600 // (i.e. when painted on white background, does the
1601 // action still look correct)?
1602 if( !DoesActionHandleTransparency( *pCurrAct ) )
1603 {
1604 // no, action cannot handle its transparency on
1605 // a printer device, render to bitmap
1606 aTotalComponents.bIsSpecial = true;
1607 }
1608 else
1609 {
1610 // yes, action can handle its transparency, so
1611 // check whether we're on white background
1612 if( aTotalComponents.aComponentList.empty() )
1613 {
1614 // nothing between pCurrAct and page
1615 // background -> don't be special
1616 aTotalComponents.bIsSpecial = false;
1617 }
1618 else
1619 {
1620 // #107169# Fixes above now ensure that _no_
1621 // object in the list is fully transparent. Thus,
1622 // if the component list is not empty above, we
1623 // must assume that we have to treat this
1624 // component special.
1625
1626 // there are non-transparent objects between
1627 // pCurrAct and the empty sheet of paper -> be
1628 // special, then
1629 aTotalComponents.bIsSpecial = true;
1630 }
1631 }
1632 }
1633
1634 // STAGE 2.3: Add newly generated CC list element
1635
1636 // set new bounds and add action to list
1637 aTotalComponents.aBounds = aTotalBounds;
1638 aTotalComponents.aComponentList.emplace_back(
1639 pCurrAct, nActionNum );
1640
1641 // add aTotalComponents as a new entry to aCCList
1642 aCCList.push_back( aTotalComponents );
1643
1644 SAL_WARN_IF( aTotalComponents.aComponentList.empty(), "vcl",
1645 "Printer::GetPreparedMetaFile empty component" );
1646 SAL_WARN_IF( aTotalComponents.aBounds.IsEmpty() && (aTotalComponents.aComponentList.size() != 1), "vcl",
1647 "Printer::GetPreparedMetaFile non-output generating actions must be solitary");
1648 SAL_WARN_IF( aTotalComponents.bIsFullyTransparent && (aTotalComponents.aComponentList.size() != 1), "vcl",
1649 "Printer::GetPreparedMetaFile fully transparent actions must be solitary");
1650 }
1651
1652 // well now, we've got the list of disjunct connected
1653 // components. Now we've got to create a map, which contains
1654 // the corresponding aCCList element for every
1655 // metaaction. Later on, we always process the complete
1656 // metafile for each bitmap to be generated, but switch on
1657 // output only for actions contained in the then current
1658 // aCCList element. This ensures correct mapmode and attribute
1659 // settings for all cases.
1660
1661 // maps mtf actions to CC list entries
1662 ::std::vector< const ConnectedComponents* > aCCList_MemberMap( rInMtf.GetActionSize() );
1663
1664 // iterate over all aCCList members and their contained metaactions
1665 for (auto const& currentItem : aCCList)
1666 {
1667 for (auto const& currentAction : currentItem.aComponentList)
1668 {
1669 // set pointer to aCCList element for corresponding index
1670 aCCList_MemberMap[ currentAction.second ] = &currentItem;
1671 }
1672 }
1673
1674 // STAGE 3.1: Output background mtf actions (if there are any)
1675
1676 for (auto & component : aBackgroundComponent.aComponentList)
1677 {
1678 // simply add this action (above, we inserted the actions
1679 // starting at index 0 up to and including nLastBgAction)
1680 rOutMtf.AddAction( component.first );
1681 }
1682
1683 // STAGE 3.2: Generate banded bitmaps for special regions
1684
1685 Point aPageOffset;
1686 Size aTmpSize( GetOutputSizePixel() );
1687 if( meOutDevType == OUTDEV_PDF )
1688 {
1689 auto pPdfWriter = static_cast<vcl::PDFWriterImpl*>(this);
1690 aTmpSize = LogicToPixel(pPdfWriter->getCurPageSize(), MapMode(MapUnit::MapPoint));
1691
1692 // also add error code to PDFWriter
1693 pPdfWriter->insertError(vcl::PDFWriter::Warning_Transparency_Converted);
1694 }
1695 else if( meOutDevType == OUTDEV_PRINTER )
1696 {
1697 Printer* pThis = dynamic_cast<Printer*>(this);
1698 assert(pThis);
1699 aPageOffset = pThis->GetPageOffsetPixel();
1700 aPageOffset = Point( 0, 0 ) - aPageOffset;
1701 aTmpSize = pThis->GetPaperSizePixel();
1702 }
1703 const tools::Rectangle aOutputRect( aPageOffset, aTmpSize );
1704 bool bTiling = dynamic_cast<Printer*>(this) != nullptr;
1705
1706 // iterate over all aCCList members and generate bitmaps for the special ones
1707 for (auto & currentItem : aCCList)
1708 {
1709 if( currentItem.bIsSpecial )
1710 {
1711 tools::Rectangle aBoundRect( currentItem.aBounds );
1712 aBoundRect.Intersection( aOutputRect );
1713
1714 const double fBmpArea( static_cast<double>(aBoundRect.GetWidth()) * aBoundRect.GetHeight() );
1715 const double fOutArea( static_cast<double>(aOutputRect.GetWidth()) * aOutputRect.GetHeight() );
1716
1717 // check if output doesn't exceed given size
1718 if( bReduceTransparency && bTransparencyAutoMode && ( fBmpArea > ( fReduceTransparencyMinArea * fOutArea ) ) )
1719 {
1720 // output normally. Therefore, we simply clear the
1721 // special attribute, as everything non-special is
1722 // copied to rOutMtf further below.
1723 currentItem.bIsSpecial = false;
1724 }
1725 else
1726 {
1727 // create new bitmap action first
1728 if( aBoundRect.GetWidth() && aBoundRect.GetHeight() )
1729 {
1730 Point aDstPtPix( aBoundRect.TopLeft() );
1731 Size aDstSzPix;
1732
1733 ScopedVclPtrInstance<VirtualDevice> aMapVDev; // here, we record only mapmode information
1734 aMapVDev->EnableOutput(false);
1735
1736 ScopedVclPtrInstance<VirtualDevice> aPaintVDev; // into this one, we render.
1737 aPaintVDev->SetBackground( aBackgroundComponent.aBgColor );
1738
1740 rOutMtf.AddAction( new MetaMapModeAction() );
1741
1742 aPaintVDev->SetDrawMode( GetDrawMode() );
1743
1744 while( aDstPtPix.Y() <= aBoundRect.Bottom() )
1745 {
1746 aDstPtPix.setX( aBoundRect.Left() );
1747 aDstSzPix = bTiling ? Size( MAX_TILE_WIDTH, MAX_TILE_HEIGHT ) : aBoundRect.GetSize();
1748
1749 if( ( aDstPtPix.Y() + aDstSzPix.Height() - 1 ) > aBoundRect.Bottom() )
1750 aDstSzPix.setHeight( aBoundRect.Bottom() - aDstPtPix.Y() + 1 );
1751
1752 while( aDstPtPix.X() <= aBoundRect.Right() )
1753 {
1754 if( ( aDstPtPix.X() + aDstSzPix.Width() - 1 ) > aBoundRect.Right() )
1755 aDstSzPix.setWidth( aBoundRect.Right() - aDstPtPix.X() + 1 );
1756
1757 if( !tools::Rectangle( aDstPtPix, aDstSzPix ).Intersection( aBoundRect ).IsEmpty() &&
1758 aPaintVDev->SetOutputSizePixel( aDstSzPix ) )
1759 {
1760 aPaintVDev->Push();
1761 aMapVDev->Push();
1762
1763 aMapVDev->mnDPIX = aPaintVDev->mnDPIX = mnDPIX;
1764 aMapVDev->mnDPIY = aPaintVDev->mnDPIY = mnDPIY;
1765
1766 aPaintVDev->EnableOutput(false);
1767
1768 // iterate over all actions
1769 for( pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction(), nActionNum=0;
1770 pCurrAct;
1771 pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
1772 {
1773 // enable output only for
1774 // actions that are members of
1775 // the current aCCList element
1776 // (currentItem)
1777 if( aCCList_MemberMap[nActionNum] == &currentItem )
1778 aPaintVDev->EnableOutput();
1779
1780 // but process every action
1781 const MetaActionType nType( pCurrAct->GetType() );
1782
1784 {
1785 pCurrAct->Execute( aMapVDev.get() );
1786
1787 MapMode aMtfMap( aMapVDev->GetMapMode() );
1788 const Point aNewOrg( aMapVDev->PixelToLogic( aDstPtPix ) );
1789
1790 aMtfMap.SetOrigin( Point( -aNewOrg.X(), -aNewOrg.Y() ) );
1791 aPaintVDev->SetMapMode( aMtfMap );
1792 }
1793 else if( ( MetaActionType::PUSH == nType ) || MetaActionType::POP == nType )
1794 {
1795 pCurrAct->Execute( aMapVDev.get() );
1796 pCurrAct->Execute( aPaintVDev.get() );
1797 }
1798 else if( MetaActionType::GRADIENT == nType )
1799 {
1800 MetaGradientAction* pGradientAction = static_cast<MetaGradientAction*>(pCurrAct);
1801 Printer* pPrinter = dynamic_cast< Printer* >(this);
1802 if( pPrinter )
1803 pPrinter->DrawGradientEx( aPaintVDev.get(), pGradientAction->GetRect(), pGradientAction->GetGradient() );
1804 else
1805 DrawGradient( pGradientAction->GetRect(), pGradientAction->GetGradient() );
1806 }
1807 else
1808 {
1809 pCurrAct->Execute( aPaintVDev.get() );
1810 }
1811
1813 }
1814
1815 const bool bOldMap = mbMap;
1816 mbMap = aPaintVDev->mbMap = false;
1817
1818 Bitmap aBandBmp( aPaintVDev->GetBitmap( Point(), aDstSzPix ) );
1819
1820 // scale down bitmap, if requested
1821 if( bDownsampleBitmaps )
1822 aBandBmp = vcl::bitmap::GetDownsampledBitmap(PixelToLogic(LogicToPixel(aDstSzPix), MapMode(MapUnit::MapTwip)),
1823 Point(), aBandBmp.GetSizePixel(),
1824 aBandBmp, nMaxBmpDPIX, nMaxBmpDPIY);
1825
1826 rOutMtf.AddAction( new MetaCommentAction( "PRNSPOOL_TRANSPARENTBITMAP_BEGIN" ) );
1827 rOutMtf.AddAction( new MetaBmpScaleAction( aDstPtPix, aDstSzPix, aBandBmp ) );
1828 rOutMtf.AddAction( new MetaCommentAction( "PRNSPOOL_TRANSPARENTBITMAP_END" ) );
1829
1830 aPaintVDev->mbMap = true;
1831 mbMap = bOldMap;
1832 aMapVDev->Pop();
1833 aPaintVDev->Pop();
1834 }
1835
1836 // overlapping bands to avoid missing lines (e.g. PostScript)
1837 aDstPtPix.AdjustX(aDstSzPix.Width() );
1838 }
1839
1840 // overlapping bands to avoid missing lines (e.g. PostScript)
1841 aDstPtPix.AdjustY(aDstSzPix.Height() );
1842 }
1843
1844 rOutMtf.AddAction( new MetaPopAction() );
1845 }
1846 }
1847 }
1848 }
1849
1850 aMapModeVDev->ClearStack(); // clean up aMapModeVDev
1851
1852 // STAGE 4: Copy actions to output metafile
1853
1854 // iterate over all actions and duplicate the ones not in a
1855 // special aCCList member into rOutMtf
1856 for( pCurrAct=const_cast<GDIMetaFile&>(rInMtf).FirstAction(), nActionNum=0;
1857 pCurrAct;
1858 pCurrAct=const_cast<GDIMetaFile&>(rInMtf).NextAction(), ++nActionNum )
1859 {
1860 const ConnectedComponents* pCurrAssociatedComponent = aCCList_MemberMap[nActionNum];
1861
1862 // NOTE: This relies on the fact that map-mode or draw
1863 // mode changing actions are solitary aCCList elements and
1864 // have empty bounding boxes, see comment on stage 2.1
1865 // above
1866 if( pCurrAssociatedComponent &&
1867 (pCurrAssociatedComponent->aBounds.IsEmpty() ||
1868 !pCurrAssociatedComponent->bIsSpecial) )
1869 {
1870 // #107169# Treat transparent bitmaps special, if they
1871 // are the first (or sole) action in their bounds
1872 // list. Note that we previously ensured that no
1873 // fully-transparent objects are before us here.
1874 if( DoesActionHandleTransparency( *pCurrAct ) &&
1875 pCurrAssociatedComponent->aComponentList.begin()->first == pCurrAct )
1876 {
1877 // convert actions, where masked-out parts are of
1878 // given background color
1879 ImplConvertTransparentAction(rOutMtf,
1880 *pCurrAct,
1881 *aMapModeVDev,
1882 aBackgroundComponent.aBgColor);
1883 }
1884 else
1885 {
1886 // simply add this action
1887 rOutMtf.AddAction( pCurrAct );
1888 }
1889
1890 pCurrAct->Execute(aMapModeVDev.get());
1891 }
1892 }
1893
1894 rOutMtf.SetPrefMapMode( rInMtf.GetPrefMapMode() );
1895 rOutMtf.SetPrefSize( rInMtf.GetPrefSize() );
1896
1897#if OSL_DEBUG_LEVEL > 1
1898 // iterate over all aCCList members and generate rectangles for the bounding boxes
1899 rOutMtf.AddAction( new MetaFillColorAction( COL_WHITE, false ) );
1900 for(auto const& aCurr:aCCList)
1901 {
1902 if( aCurr.bIsSpecial )
1903 rOutMtf.AddAction( new MetaLineColorAction( COL_RED, true) );
1904 else
1905 rOutMtf.AddAction( new MetaLineColorAction( COL_BLUE, true) );
1906
1907 rOutMtf.AddAction( new MetaRectAction( aMapModeVDev->PixelToLogic( aCurr.aBounds ) ) );
1908 }
1909#endif
1910 }
1911 return bTransparent;
1912}
1913
1914/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 nLineWidth
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
void BlendWith(const Bitmap &rOther)
Definition: alpha.cxx:83
static bool Reschedule(bool bHandleAllCurrentEvents=false)
Attempt to process current pending event(s)
Definition: svapp.cxx:492
sal_uInt8 GetIndex() const
Definition: BitmapColor.hxx:70
const AlphaMask & GetAlphaMask() const
Definition: bitmapex.hxx:70
bool IsAlpha() const
Definition: BitmapEx.cxx:193
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:203
const Size & GetSizePixel() const
Definition: bitmapex.hxx:72
BitmapColor GetBestMatchingColor(const BitmapColor &rBitmapColor) const
ScanlineFormat GetScanlineFormat() const
sal_uInt16 GetEntryCount() const
sal_uInt16 GetBestIndex(const BitmapColor &rCol) const
BitmapColor GetPixelFromData(const sal_uInt8 *pData, tools::Long nX) const
Scanline GetScanline(tools::Long nY) const
Size GetSizePixel() const
bool IsEmpty() const
vcl::PixelFormat getPixelFormat() const
sal_uInt8 GetBlue() const
bool IsFullyTransparent() const
void Merge(const Color &rMergeColor, sal_uInt8 cTransparency)
sal_uInt8 GetRed() const
sal_uInt8 GetGreen() const
bool HasTransparentActions() const
Definition: gdimtf.cxx:154
size_t GetActionSize() const
Definition: gdimtf.cxx:179
const Size & GetPrefSize() const
Definition: gdimtf.hxx:172
MetaAction * GetAction(size_t nAction) const
Definition: gdimtf.cxx:184
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:581
void Clear()
Definition: gdimtf.cxx:270
void SetPrefMapMode(const MapMode &rMapMode)
Definition: gdimtf.hxx:176
const MapMode & GetPrefMapMode() const
Definition: gdimtf.hxx:175
void SetPrefSize(const Size &rSize)
Definition: gdimtf.hxx:173
const Color & GetEndColor() const
const Color & GetStartColor() const
void SetOrigin(const Point &rOrigin)
Definition: mapmod.cxx:103
virtual bool IsTransparent() const
#i10613# Extracted from Printer::GetPreparedMetaFile.
Definition: metaact.hxx:99
MetaActionType GetType() const
Definition: metaact.hxx:95
virtual void Execute(OutputDevice *pOut)
Definition: metaact.cxx:99
const Bitmap & GetBitmap() const
Definition: metaact.hxx:692
const BitmapEx & GetBitmapEx() const
Definition: metaact.hxx:797
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:1021
const Gradient & GetGradient() const
Definition: metaact.hxx:1022
const LineInfo & GetLineInfo() const
Definition: metaact.hxx:186
const Point & GetEndPoint() const
Definition: metaact.hxx:185
const Point & GetStartPoint() const
Definition: metaact.hxx:184
const Bitmap & GetBitmap() const
Definition: metaact.hxx:908
const LineInfo & GetLineInfo() const
Definition: metaact.hxx:408
const tools::Polygon & GetPolygon() const
Definition: metaact.hxx:407
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:215
sal_uInt32 GetWidth() const
Definition: metaact.hxx:583
sal_Int32 GetLen() const
Definition: metaact.hxx:585
sal_Int32 GetIndex() const
Definition: metaact.hxx:584
const OUString & GetText() const
Definition: metaact.hxx:582
const Point & GetPoint() const
Definition: metaact.hxx:581
const Point & GetPoint() const
Definition: metaact.hxx:494
sal_Int32 GetLen() const
Definition: metaact.hxx:497
const OUString & GetText() const
Definition: metaact.hxx:495
sal_Int32 GetIndex() const
Definition: metaact.hxx:496
sal_Int32 GetIndex() const
Definition: metaact.hxx:540
const KernArray & GetDXArray() const
Definition: metaact.hxx:542
sal_Int32 GetLen() const
Definition: metaact.hxx:541
const OUString & GetText() const
Definition: metaact.hxx:539
const Point & GetPoint() const
Definition: metaact.hxx:538
const std::vector< sal_Bool > & GetKashidaArray() const
Definition: metaact.hxx:543
sal_uInt16 GetTransparence() const
Definition: metaact.hxx:1565
const tools::PolyPolygon & GetPolyPolygon() const
Definition: metaact.hxx:1564
const tools::Rectangle & GetRect() const
Definition: metaact.hxx:1112
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:170
virtual void InitClipRegion()
void EnableMapMode(bool bEnable=true)
Definition: map.cxx:602
vcl::Region GetClipRegion() const
sal_Int32 mnDPIY
Definition: outdev.hxx:213
void DrawBitmapEx(const Point &rDestPt, const BitmapEx &rBitmapEx)
Definition: bitmapex.cxx:33
SAL_DLLPRIVATE bool is_double_buffered_window() const
DrawModeFlags mnDrawMode
Definition: outdev.hxx:220
SAL_DLLPRIVATE void InitLineColor()
Definition: line.cxx:85
bool mbOutputClipped
Definition: outdev.hxx:245
RasterOp GetRasterOp() const
Definition: outdev.hxx:496
SAL_DLLPRIVATE tools::Rectangle ImplLogicToDevicePixel(const tools::Rectangle &rLogicRect) const
Convert a logical rectangle to a rectangle in physical device pixel units.
Definition: map.cxx:347
bool mbFillColor
Definition: outdev.hxx:247
virtual bool AcquireGraphics() const =0
Acquire a graphics device that the output device uses to draw on.
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1123
Size GetOutputSizePixel() const
Definition: outdev.hxx:314
SAL_DLLPRIVATE bool ImplIsRecordLayout() const
Definition: outdev.cxx:708
bool IsFillColor() const
Definition: outdev.hxx:516
GDIMetaFile * mpMetaFile
Definition: outdev.hxx:185
SAL_DLLPRIVATE void InitFillColor()
Definition: fill.cxx:76
bool mbMap
Definition: outdev.hxx:240
bool GetTextBoundRect(tools::Rectangle &rRect, const OUString &rStr, sal_Int32 nBase=0, sal_Int32 nIndex=0, sal_Int32 nLen=-1, sal_uLong nLayoutWidth=0, KernArraySpan aDXArray=KernArraySpan(), o3tl::span< const sal_Bool > pKashidaArray={}, const SalLayoutGlyphs *pGlyphs=nullptr) const
Return the exact bounding rectangle of rStr.
Definition: text.cxx:2323
bool IsClipRegion() const
Definition: outdev.hxx:555
virtual void ClipToPaintRegion(tools::Rectangle &rDstRect)
virtual sal_uInt16 GetBitCount() const
Definition: outdev.cxx:372
bool mbInitLineColor
Definition: outdev.hxx:248
SalGraphics * mpGraphics
Graphics context to draw on.
Definition: outdev.hxx:182
bool IsLineColor() const
Definition: outdev.hxx:511
bool RemoveTransparenciesFromMetaFile(const GDIMetaFile &rInMtf, GDIMetaFile &rOutMtf, tools::Long nMaxBmpDPIX, tools::Long nMaxBmpDPIY, bool bReduceTransparency, bool bTransparencyAutoMode, bool bDownsampleBitmaps, const Color &rBackground=COL_TRANSPARENT)
helper method removing transparencies from a metafile (e.g.
SAL_DLLPRIVATE bool DrawTransparentNatively(const tools::PolyPolygon &rPolyPoly, sal_uInt16 nTransparencePercent)
tools::Rectangle ImplGetTextBoundRect(const SalLayout &) const
Definition: text.cxx:190
void DrawBitmap(const Point &rDestPt, const Bitmap &rBitmap)
bool mbInitClipRegion
Definition: outdev.hxx:252
void SetFillColor()
Definition: fill.cxx:29
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:892
AntialiasingFlags mnAntialiasing
Definition: outdev.hxx:237
const Color & GetLineColor() const
Definition: outdev.hxx:510
virtual Bitmap GetBitmap(const Point &rSrcPt, const Size &rSize) const
bool IsDeviceOutputNecessary() const
Definition: outdev.hxx:481
VclPtr< VirtualDevice > mpAlphaVDev
Definition: outdev.hxx:196
const MapMode & GetMapMode() const
Definition: outdev.hxx:1557
void Push(vcl::PushFlags nFlags=vcl::PushFlags::ALL)
Definition: stack.cxx:32
void DrawGradient(const tools::Rectangle &rRect, const Gradient &rGradient)
void DrawPolyPolygon(const tools::PolyPolygon &rPolyPoly)
Render the given poly-polygon.
Definition: polygon.cxx:34
void Pop()
Definition: stack.cxx:91
std::unique_ptr< SalLayout > ImplLayout(const OUString &, sal_Int32 nIndex, sal_Int32 nLen, const Point &rLogicPos=Point(0, 0), tools::Long nLogicWidth=0, KernArraySpan aKernArray=KernArraySpan(), o3tl::span< const sal_Bool > pKashidaArray={}, SalLayoutFlags flags=SalLayoutFlags::NONE, vcl::text::TextLayoutCache const *=nullptr, const SalLayoutGlyphs *pGlyphs=nullptr) const
Definition: text.cxx:1302
AntialiasingFlags GetAntialiasing() const
Definition: outdev.hxx:484
SAL_DLLPRIVATE basegfx::B2DHomMatrix ImplGetDeviceTransformation() const
Get device transformation.
Definition: map.cxx:883
virtual void EmulateDrawTransparent(const tools::PolyPolygon &rPolyPoly, sal_uInt16 nTransparencePercent)
DrawModeFlags GetDrawMode() const
Definition: outdev.hxx:487
void DrawTransparent(const tools::PolyPolygon &rPolyPoly, sal_uInt16 nTransparencePercent)
bool mbLineColor
Definition: outdev.hxx:246
virtual tools::Rectangle GetBackgroundComponentBounds() const
Definition: outdev.cxx:640
sal_Int32 mnDPIX
Definition: outdev.hxx:212
bool mbInitFillColor
Definition: outdev.hxx:249
bool IsMapModeEnabled() const
Definition: outdev.hxx:1551
const Color & GetFillColor() const
Definition: outdev.hxx:515
const OutDevType meOutDevType
Definition: outdev.hxx:223
const Point & GetPageOffsetPixel() const
Definition: print.hxx:252
void DrawGradientEx(OutputDevice *pOut, const tools::Rectangle &rRect, const Gradient &rGradient)
Definition: print2.cxx:29
const Size & GetPaperSizePixel() const
Definition: print.hxx:249
virtual void SetFillColor()=0
virtual bool supportsOperation(OutDevSupportType) const =0
bool DrawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt8 nTransparency, const OutputDevice &rOutDev)
void DrawPolyLine(sal_uInt32 nPoints, Point const *pPtAry, const OutputDevice &rOutDev)
void DrawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32 *pPoints, const Point **pPtAry, const OutputDevice &rOutDev)
constexpr tools::Long Height() const
void setWidth(tools::Long nWidth)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
void disposeAndClear()
Definition: vclptr.hxx:200
reference_type * get() const
Get the body.
Definition: vclptr.hxx:143
void transform(const basegfx::B2DHomMatrix &rMatrix)
void setClosed(bool bNew)
sal_uInt32 count() const
B2DRange const & getB2DRange() const
TYPE getWidth() const
TYPE getMinX() const
TYPE getMinY() const
TYPE getHeight() const
sal_uInt16 Count() const
::basegfx::B2DPolyPolygon getB2DPolyPolygon() const
bool IsRect() const
void Move(tools::Long nHorzMove, tools::Long nVertMove)
void Insert(const tools::Polygon &rPoly, sal_uInt16 nPos=POLYPOLY_APPEND)
tools::Rectangle GetBoundRect() const
void Insert(sal_uInt16 nPos, const Point &rPt)
::basegfx::B2DPolygon getB2DPolygon() const
tools::Rectangle GetBoundRect() const
constexpr Point Center() const
constexpr tools::Long GetWidth() const
constexpr tools::Long Top() const
constexpr Point TopLeft() const
tools::Long getOpenHeight() const
constexpr Size GetSize() const
void Move(tools::Long nHorzMoveDelta, tools::Long nVertMoveDelta)
constexpr tools::Long Right() const
tools::Long AdjustTop(tools::Long nVertMoveDelta)
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
constexpr tools::Long GetHeight() const
tools::Rectangle & Union(const tools::Rectangle &rRect)
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
tools::Long getOpenWidth() const
tools::Rectangle & Intersection(const tools::Rectangle &rRect)
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
constexpr bool IsEmpty() const
@ Warning_Transparency_Converted
Definition: pdfwriter.hxx:225
tools::Rectangle GetBoundRect() const
Definition: region.cxx:1219
This template handles BitmapAccess the RAII way.
constexpr ::Color COL_WHITE(0xFF, 0xFF, 0xFF)
constexpr ::Color COL_RED(0x80, 0x00, 0x00)
constexpr ::Color COL_BLUE(0x00, 0x00, 0x80)
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
constexpr ::Color COL_TRANSPARENT(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
int nCount
tools::Long FRound(double fVal)
std::enable_if< std::is_signed< T >::value||std::is_floating_point< T >::value, long >::type MinMax(T nVal, tools::Long nMin, tools::Long nMax)
#define SAL_WARN_IF(condition, area, stream)
MetaActionType
bool isRectangle(const B2DPolygon &rPoly)
constexpr double deg2rad(double v)
constexpr sal_uInt8 ColorChannelMerge(sal_uInt8 nDst, sal_uInt8 nSrc, sal_uInt8 nSrcTrans)
int i
long Long
Bitmap GetDownsampledBitmap(Size const &rDstSizeTwip, Point const &rSrcPt, Size const &rSrcSz, Bitmap const &rBmp, tools::Long nMaxBmpDPIX, tools::Long nMaxBmpDPIY)
Retrieve downsampled and cropped bitmap.
BitmapEx GetBitmapEx(BitmapEx const &rBitmapEx, DrawModeFlags nDrawMode)
Definition: drawmode.cxx:242
constexpr bool isPalettePixelFormat(PixelFormat ePixelFormat)
Is it a pixel format that forces creation of a palette.
Definition: BitmapTypes.hxx:28
HashMap_OWString_Interface aMap
@ OUTDEV_PDF
Definition: outdev.hxx:145
@ OUTDEV_PRINTER
Definition: outdev.hxx:145
QPRO_FUNC_TYPE nType
#define MAX_TILE_HEIGHT
Definition: transparent.cxx:42
::std::pair< MetaAction *, int > Component
#define MAX_TILE_WIDTH
Definition: transparent.cxx:41
unsigned char sal_uInt8