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