update emoji autocorrect entries from po-files
[LibreOffice.git] / vcl / source / outdev / transparent.cxx
blob7f3b355b6f8aab3cb5b82a6dddb4c24d3bd2573f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <cassert>
22 #include <sal/types.h>
24 #include <basegfx/matrix/b2dhommatrixtools.hxx>
25 #include <boost/scoped_array.hpp>
27 #include <vcl/bmpacc.hxx>
28 #include <vcl/outdev.hxx>
29 #include <vcl/settings.hxx>
30 #include <vcl/virdev.hxx>
31 #include <vcl/window.hxx>
33 #include "outdata.hxx"
34 #include "salgdi.hxx"
36 namespace
38 /**
39 * Perform a safe approximation of a polygon from double-precision
40 * coordinates to integer coordinates, to ensure that it has at least 2
41 * pixels in both X and Y directions.
43 Polygon toPolygon( const basegfx::B2DPolygon& rPoly )
45 basegfx::B2DRange aRange = rPoly.getB2DRange();
46 double fW = aRange.getWidth(), fH = aRange.getHeight();
47 if (0.0 < fW && 0.0 < fH && (fW <= 1.0 || fH <= 1.0))
49 // This polygon not empty but is too small to display. Approximate it
50 // with a rectangle large enough to be displayed.
51 double nX = aRange.getMinX(), nY = aRange.getMinY();
52 double nW = std::max<double>(1.0, rtl::math::round(fW));
53 double nH = std::max<double>(1.0, rtl::math::round(fH));
55 Polygon aTarget;
56 aTarget.Insert(0, Point(nX, nY));
57 aTarget.Insert(1, Point(nX+nW, nY));
58 aTarget.Insert(2, Point(nX+nW, nY+nH));
59 aTarget.Insert(3, Point(nX, nY+nH));
60 aTarget.Insert(4, Point(nX, nY));
61 return aTarget;
63 return Polygon(rPoly);
66 tools::PolyPolygon toPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly )
68 tools::PolyPolygon aTarget;
69 for (sal_uInt32 i = 0; i < rPolyPoly.count(); ++i)
70 aTarget.Insert(toPolygon(rPolyPoly.getB2DPolygon(i)));
72 return aTarget;
76 Color OutputDevice::ImplDrawModeToColor( const Color& rColor ) const
78 Color aColor( rColor );
79 DrawModeFlags nDrawMode = GetDrawMode();
81 if( nDrawMode & ( DrawModeFlags::BlackLine | DrawModeFlags::WhiteLine |
82 DrawModeFlags::GrayLine | DrawModeFlags::GhostedLine |
83 DrawModeFlags::SettingsLine ) )
85 if( !ImplIsColorTransparent( aColor ) )
87 if( nDrawMode & DrawModeFlags::BlackLine )
89 aColor = Color( COL_BLACK );
91 else if( nDrawMode & DrawModeFlags::WhiteLine )
93 aColor = Color( COL_WHITE );
95 else if( nDrawMode & DrawModeFlags::GrayLine )
97 const sal_uInt8 cLum = aColor.GetLuminance();
98 aColor = Color( cLum, cLum, cLum );
100 else if( nDrawMode & DrawModeFlags::SettingsLine )
102 aColor = GetSettings().GetStyleSettings().GetFontColor();
105 if( nDrawMode & DrawModeFlags::GhostedLine )
107 aColor = Color( ( aColor.GetRed() >> 1 ) | 0x80,
108 ( aColor.GetGreen() >> 1 ) | 0x80,
109 ( aColor.GetBlue() >> 1 ) | 0x80);
113 return aColor;
116 sal_uInt16 OutputDevice::GetAlphaBitCount() const
118 return 0;
121 bool OutputDevice::HasAlpha()
123 return mpAlphaVDev != nullptr;
126 void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask,
127 const Point& rDestPt, const Size& rDestSize,
128 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
130 Point aPt;
131 Point aDestPt( LogicToPixel( rDestPt ) );
132 Size aDestSz( LogicToPixel( rDestSize ) );
133 Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
135 aSrcRect.Justify();
137 if( !rBmp.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() )
139 Bitmap aPaint( rBmp ), aMask( rMask );
140 BmpMirrorFlags nMirrFlags = BmpMirrorFlags::NONE;
142 if( aMask.GetBitCount() > 1 )
143 aMask.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
145 // mirrored horizontically
146 if( aDestSz.Width() < 0L )
148 aDestSz.Width() = -aDestSz.Width();
149 aDestPt.X() -= ( aDestSz.Width() - 1L );
150 nMirrFlags |= BmpMirrorFlags::Horizontal;
153 // mirrored vertically
154 if( aDestSz.Height() < 0L )
156 aDestSz.Height() = -aDestSz.Height();
157 aDestPt.Y() -= ( aDestSz.Height() - 1L );
158 nMirrFlags |= BmpMirrorFlags::Vertical;
161 // source cropped?
162 if( aSrcRect != Rectangle( aPt, aPaint.GetSizePixel() ) )
164 aPaint.Crop( aSrcRect );
165 aMask.Crop( aSrcRect );
168 // destination mirrored
169 if( nMirrFlags != BmpMirrorFlags::NONE )
171 aPaint.Mirror( nMirrFlags );
172 aMask.Mirror( nMirrFlags );
175 // we always want to have a mask
176 if( aMask.IsEmpty() )
178 aMask = Bitmap( aSrcRect.GetSize(), 1 );
179 aMask.Erase( Color( COL_BLACK ) );
182 // do painting
183 const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
184 long nX, nY; // , nWorkX, nWorkY, nWorkWidth, nWorkHeight;
185 boost::scoped_array<long> pMapX(new long[ nSrcWidth + 1 ]);
186 boost::scoped_array<long> pMapY(new long[ nSrcHeight + 1 ]);
187 const bool bOldMap = mbMap;
189 mbMap = false;
191 // create forward mapping tables
192 for( nX = 0L; nX <= nSrcWidth; nX++ )
193 pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth );
195 for( nY = 0L; nY <= nSrcHeight; nY++ )
196 pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight );
198 // walk through all rectangles of mask
199 const vcl::Region aWorkRgn(aMask.CreateRegion(COL_BLACK, Rectangle(Point(), aMask.GetSizePixel())));
200 RectangleVector aRectangles;
201 aWorkRgn.GetRegionRectangles(aRectangles);
203 for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
205 const Point aMapPt(pMapX[aRectIter->Left()], pMapY[aRectIter->Top()]);
206 const Size aMapSz( pMapX[aRectIter->Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1
207 pMapY[aRectIter->Bottom() + 1] - aMapPt.Y()); // same for Y
208 Bitmap aBandBmp(aPaint);
210 aBandBmp.Crop(*aRectIter);
211 DrawBitmap(aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp, MetaActionType::BMPSCALEPART);
214 mbMap = bOldMap;
218 // Caution: This method is nearly the same as
219 // void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly )
220 // so when changes are made here do not forget to make changes there, too
222 void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency)
224 assert(!is_double_buffered_window());
226 // AW: Do NOT paint empty PolyPolygons
227 if(!rB2DPolyPoly.count())
228 return;
230 // we need a graphics
231 if( !mpGraphics && !AcquireGraphics() )
232 return;
234 if( mbInitClipRegion )
235 InitClipRegion();
237 if( mbOutputClipped )
238 return;
240 if( mbInitLineColor )
241 InitLineColor();
243 if( mbInitFillColor )
244 InitFillColor();
246 if((mnAntialiasing & AntialiasingFlags::EnableB2dDraw) &&
247 mpGraphics->supportsOperation(OutDevSupport_B2DDraw) &&
248 (ROP_OVERPAINT == GetRasterOp()) )
250 // b2dpolygon support not implemented yet on non-UNX platforms
251 const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
252 basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly);
254 // transform the polygon into device space and ensure it is closed
255 aB2DPolyPolygon.transform( aTransform );
256 aB2DPolyPolygon.setClosed( true );
258 bool bDrawnOk = true;
259 if( IsFillColor() )
260 bDrawnOk = mpGraphics->DrawPolyPolygon( aB2DPolyPolygon, fTransparency, this );
262 if( bDrawnOk && IsLineColor() )
264 const basegfx::B2DVector aHairlineWidth(1,1);
265 const int nPolyCount = aB2DPolyPolygon.count();
266 for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
268 const ::basegfx::B2DPolygon aOnePoly = aB2DPolyPolygon.getB2DPolygon( nPolyIdx );
269 mpGraphics->DrawPolyLine( aOnePoly, fTransparency, aHairlineWidth, ::basegfx::B2DLINEJOIN_NONE, com::sun::star::drawing::LineCap_BUTT, this );
273 if( bDrawnOk )
275 if( mpMetaFile )
276 mpMetaFile->AddAction( new MetaTransparentAction( tools::PolyPolygon( rB2DPolyPoly ), static_cast< sal_uInt16 >(fTransparency * 100.0)));
278 return;
282 // fallback to old polygon drawing if needed
283 DrawTransparent(toPolyPolygon(rB2DPolyPoly), static_cast<sal_uInt16>(fTransparency * 100.0));
286 void OutputDevice::DrawInvisiblePolygon( const tools::PolyPolygon& rPolyPoly )
288 assert(!is_double_buffered_window());
290 // short circuit if the polygon border is invisible too
291 if( !mbLineColor )
292 return;
294 // we assume that the border is NOT to be drawn transparently???
295 Push( PushFlags::FILLCOLOR );
296 SetFillColor();
297 DrawPolyPolygon( rPolyPoly );
298 Pop();
301 bool OutputDevice::DrawTransparentNatively ( const tools::PolyPolygon& rPolyPoly,
302 sal_uInt16 nTransparencePercent )
304 assert(!is_double_buffered_window());
306 bool bDrawn = false;
308 // debug helper:
309 static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA");
311 if( !pDisableNative &&
312 mpGraphics->supportsOperation( OutDevSupport_B2DDraw )
313 #if defined UNX && ! defined MACOSX && ! defined IOS
314 && GetBitCount() > 8
315 #endif
316 #ifdef WIN32
317 // workaround bad dithering on remote displaying when using GDI+ with toolbar button highlighting
318 && !rPolyPoly.IsRect()
319 #endif
322 // prepare the graphics device
323 if( mbInitClipRegion )
324 InitClipRegion();
326 if( mbOutputClipped )
327 return false;
329 if( mbInitLineColor )
330 InitLineColor();
332 if( mbInitFillColor )
333 InitFillColor();
335 // get the polygon in device coordinates
336 basegfx::B2DPolyPolygon aB2DPolyPolygon( rPolyPoly.getB2DPolyPolygon() );
337 const ::basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
338 aB2DPolyPolygon.transform( aTransform );
340 const double fTransparency = 0.01 * nTransparencePercent;
341 if( mbFillColor )
343 // #i121591#
344 // CAUTION: Only non printing (pixel-renderer) VCL commands from OutputDevices
345 // should be used when printing. Normally this is avoided by the printer being
346 // non-AAed and thus e.g. on WIN GdiPlus calls are not used. It may be necessary
347 // to figure out a way of moving this code to it's own function that is
348 // overriden by the Print class, which will mean we deliberately override the
349 // functionality and we use the fallback some lines below (which is not very good,
350 // though. For now, WinSalGraphics::drawPolyPolygon will detect printer usage and
351 // correct the wrong mapping (see there for details)
352 bDrawn = mpGraphics->DrawPolyPolygon( aB2DPolyPolygon, fTransparency, this );
355 if( mbLineColor )
357 // disable the fill color for now
358 mpGraphics->SetFillColor();
359 // draw the border line
360 const basegfx::B2DVector aLineWidths( 1, 1 );
361 const int nPolyCount = aB2DPolyPolygon.count();
362 for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
364 const ::basegfx::B2DPolygon& rPolygon = aB2DPolyPolygon.getB2DPolygon( nPolyIdx );
365 bDrawn = mpGraphics->DrawPolyLine( rPolygon, fTransparency, aLineWidths,
366 ::basegfx::B2DLINEJOIN_NONE, css::drawing::LineCap_BUTT, this );
368 // prepare to restore the fill color
369 mbInitFillColor = mbFillColor;
373 return bDrawn;
376 void OutputDevice::EmulateDrawTransparent ( const tools::PolyPolygon& rPolyPoly,
377 sal_uInt16 nTransparencePercent )
379 // debug helper:
380 static const char* pDisableNative = getenv( "SAL_DISABLE_NATIVE_ALPHA" );
382 // #110958# Disable alpha VDev, we perform the necessary
383 VirtualDevice* pOldAlphaVDev = mpAlphaVDev;
385 // operation explicitly further below.
386 if( mpAlphaVDev )
387 mpAlphaVDev = NULL;
389 GDIMetaFile* pOldMetaFile = mpMetaFile;
390 mpMetaFile = NULL;
392 tools::PolyPolygon aPolyPoly( LogicToPixel( rPolyPoly ) );
393 Rectangle aPolyRect( aPolyPoly.GetBoundRect() );
394 Point aPoint;
395 Rectangle aDstRect( aPoint, GetOutputSizePixel() );
397 aDstRect.Intersection( aPolyRect );
399 ClipToPaintRegion( aDstRect );
401 if( !aDstRect.IsEmpty() )
403 bool bDrawn = false;
405 // #i66849# Added fast path for exactly rectangular
406 // polygons
407 // #i83087# Naturally, system alpha blending cannot
408 // work with separate alpha VDev
409 if( !mpAlphaVDev && !pDisableNative && aPolyPoly.IsRect() )
411 // setup Graphics only here (other cases delegate
412 // to basic OutDev methods)
413 if ( mbInitClipRegion )
414 InitClipRegion();
416 if ( mbInitLineColor )
417 InitLineColor();
419 if ( mbInitFillColor )
420 InitFillColor();
422 Rectangle aLogicPolyRect( rPolyPoly.GetBoundRect() );
423 Rectangle aPixelRect( ImplLogicToDevicePixel( aLogicPolyRect ) );
425 if( !mbOutputClipped )
427 bDrawn = mpGraphics->DrawAlphaRect( aPixelRect.Left(), aPixelRect.Top(),
428 // #i98405# use methods with small g, else one pixel too much will be painted.
429 // This is because the source is a polygon which when painted would not paint
430 // the rightmost and lowest pixel line(s), so use one pixel less for the
431 // rectangle, too.
432 aPixelRect.getWidth(), aPixelRect.getHeight(),
433 sal::static_int_cast<sal_uInt8>(nTransparencePercent),
434 this );
436 else
438 bDrawn = true;
442 if( !bDrawn )
444 ScopedVclPtrInstance< VirtualDevice > aVDev( *this, 1 );
445 const Size aDstSz( aDstRect.GetSize() );
446 const sal_uInt8 cTrans = (sal_uInt8) MinMax( FRound( nTransparencePercent * 2.55 ), 0, 255 );
448 if( aDstRect.Left() || aDstRect.Top() )
449 aPolyPoly.Move( -aDstRect.Left(), -aDstRect.Top() );
451 if( aVDev->SetOutputSizePixel( aDstSz ) )
453 const bool bOldMap = mbMap;
455 EnableMapMode( false );
457 aVDev->SetLineColor( COL_BLACK );
458 aVDev->SetFillColor( COL_BLACK );
459 aVDev->DrawPolyPolygon( aPolyPoly );
461 Bitmap aPaint( GetBitmap( aDstRect.TopLeft(), aDstSz ) );
462 Bitmap aPolyMask( aVDev->GetBitmap( Point(), aDstSz ) );
464 // #107766# check for non-empty bitmaps before accessing them
465 if( !!aPaint && !!aPolyMask )
467 BitmapWriteAccess* pW = aPaint.AcquireWriteAccess();
468 BitmapReadAccess* pR = aPolyMask.AcquireReadAccess();
470 if( pW && pR )
472 BitmapColor aPixCol;
473 const BitmapColor aFillCol( GetFillColor() );
474 const BitmapColor aWhite( pR->GetBestMatchingColor( Color( COL_WHITE ) ) );
475 const BitmapColor aBlack( pR->GetBestMatchingColor( Color( COL_BLACK ) ) );
476 const long nWidth = pW->Width();
477 const long nHeight = pW->Height();
478 const long nR = aFillCol.GetRed();
479 const long nG = aFillCol.GetGreen();
480 const long nB = aFillCol.GetBlue();
481 long nX, nY;
483 if( aPaint.GetBitCount() <= 8 )
485 const BitmapPalette& rPal = pW->GetPalette();
486 const sal_uInt16 nCount = rPal.GetEntryCount();
487 BitmapColor* pMap = reinterpret_cast<BitmapColor*>(new sal_uInt8[ nCount * sizeof( BitmapColor ) ]);
489 for( sal_uInt16 i = 0; i < nCount; i++ )
491 BitmapColor aCol( rPal[ i ] );
492 pMap[ i ] = BitmapColor( (sal_uInt8) rPal.GetBestIndex( aCol.Merge( aFillCol, cTrans ) ) );
495 if( pR->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
496 pW->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
498 const sal_uInt8 cBlack = aBlack.GetIndex();
500 for( nY = 0; nY < nHeight; nY++ )
502 Scanline pWScan = pW->GetScanline( nY );
503 Scanline pRScan = pR->GetScanline( nY );
504 sal_uInt8 cBit = 128;
506 for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan++ )
508 if( !cBit )
510 cBit = 128;
511 pRScan += 1;
513 if( ( *pRScan & cBit ) == cBlack )
515 *pWScan = (sal_uInt8) pMap[ *pWScan ].GetIndex();
520 else
522 for( nY = 0; nY < nHeight; nY++ )
524 for( nX = 0; nX < nWidth; nX++ )
526 if( pR->GetPixel( nY, nX ) == aBlack )
528 pW->SetPixel( nY, nX, pMap[ pW->GetPixel( nY, nX ).GetIndex() ] );
533 delete[] reinterpret_cast<sal_uInt8*>(pMap);
535 else
537 if( pR->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
538 pW->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
540 const sal_uInt8 cBlack = aBlack.GetIndex();
542 for( nY = 0; nY < nHeight; nY++ )
544 Scanline pWScan = pW->GetScanline( nY );
545 Scanline pRScan = pR->GetScanline( nY );
546 sal_uInt8 cBit = 128;
548 for( nX = 0; nX < nWidth; nX++, cBit >>= 1, pWScan += 3 )
550 if( !cBit )
552 cBit = 128;
553 pRScan += 1;
555 if( ( *pRScan & cBit ) == cBlack )
557 pWScan[ 0 ] = COLOR_CHANNEL_MERGE( pWScan[ 0 ], nB, cTrans );
558 pWScan[ 1 ] = COLOR_CHANNEL_MERGE( pWScan[ 1 ], nG, cTrans );
559 pWScan[ 2 ] = COLOR_CHANNEL_MERGE( pWScan[ 2 ], nR, cTrans );
564 else
566 for( nY = 0; nY < nHeight; nY++ )
568 for( nX = 0; nX < nWidth; nX++ )
570 if( pR->GetPixel( nY, nX ) == aBlack )
572 aPixCol = pW->GetColor( nY, nX );
573 pW->SetPixel( nY, nX, aPixCol.Merge( aFillCol, cTrans ) );
581 Bitmap::ReleaseAccess( pR );
582 Bitmap::ReleaseAccess( pW );
584 DrawBitmap( aDstRect.TopLeft(), aPaint );
586 EnableMapMode( bOldMap );
588 if( mbLineColor )
590 Push( PushFlags::FILLCOLOR );
591 SetFillColor();
592 DrawPolyPolygon( rPolyPoly );
593 Pop();
597 else
599 DrawPolyPolygon( rPolyPoly );
604 mpMetaFile = pOldMetaFile;
606 // #110958# Restore disabled alpha VDev
607 mpAlphaVDev = pOldAlphaVDev;
610 void OutputDevice::DrawTransparent( const tools::PolyPolygon& rPolyPoly,
611 sal_uInt16 nTransparencePercent )
613 assert(!is_double_buffered_window());
615 // short circuit for drawing an opaque polygon
616 if( (nTransparencePercent < 1) || (mnDrawMode & DrawModeFlags::NoTransparency) )
618 DrawPolyPolygon( rPolyPoly );
619 return;
622 // short circuit for drawing an invisible polygon
623 if( !mbFillColor || (nTransparencePercent >= 100) )
625 DrawInvisiblePolygon( rPolyPoly );
626 return; // tdf#84294: do not record it in metafile
629 // handle metafile recording
630 if( mpMetaFile )
631 mpMetaFile->AddAction( new MetaTransparentAction( rPolyPoly, nTransparencePercent ) );
633 bool bDrawn = !IsDeviceOutputNecessary() || ImplIsRecordLayout();
634 if( bDrawn )
635 return;
637 // get the device graphics as drawing target
638 if( !mpGraphics && !AcquireGraphics() )
639 return;
641 // try hard to draw it directly, because the emulation layers are slower
642 bDrawn = DrawTransparentNatively( rPolyPoly, nTransparencePercent );
643 if( bDrawn )
644 return;
646 EmulateDrawTransparent( rPolyPoly, nTransparencePercent );
648 // #110958# Apply alpha value also to VDev alpha channel
649 if( mpAlphaVDev )
651 const Color aFillCol( mpAlphaVDev->GetFillColor() );
652 mpAlphaVDev->SetFillColor( Color(sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100),
653 sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100),
654 sal::static_int_cast<sal_uInt8>(255*nTransparencePercent/100)) );
656 mpAlphaVDev->DrawTransparent( rPolyPoly, nTransparencePercent );
658 mpAlphaVDev->SetFillColor( aFillCol );
662 void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos,
663 const Size& rSize, const Gradient& rTransparenceGradient )
665 assert(!is_double_buffered_window());
667 const Color aBlack( COL_BLACK );
669 if( mpMetaFile )
671 // missing here is to map the data using the DeviceTransformation
672 mpMetaFile->AddAction( new MetaFloatTransparentAction( rMtf, rPos, rSize, rTransparenceGradient ) );
675 if ( !IsDeviceOutputNecessary() )
676 return;
678 if( ( rTransparenceGradient.GetStartColor() == aBlack && rTransparenceGradient.GetEndColor() == aBlack ) ||
679 ( mnDrawMode & ( DrawModeFlags::NoTransparency ) ) )
681 ( (GDIMetaFile&) rMtf ).WindStart();
682 ( (GDIMetaFile&) rMtf ).Play( this, rPos, rSize );
683 ( (GDIMetaFile&) rMtf ).WindStart();
685 else
687 GDIMetaFile* pOldMetaFile = mpMetaFile;
688 Rectangle aOutRect( LogicToPixel( rPos ), LogicToPixel( rSize ) );
689 Point aPoint;
690 Rectangle aDstRect( aPoint, GetOutputSizePixel() );
692 mpMetaFile = NULL;
693 aDstRect.Intersection( aOutRect );
695 ClipToPaintRegion( aDstRect );
697 if( !aDstRect.IsEmpty() )
699 ScopedVclPtrInstance< VirtualDevice > xVDev;
701 ((OutputDevice*)xVDev.get())->mnDPIX = mnDPIX;
702 ((OutputDevice*)xVDev.get())->mnDPIY = mnDPIY;
704 if( xVDev->SetOutputSizePixel( aDstRect.GetSize() ) )
706 if(GetAntialiasing() != AntialiasingFlags::NONE)
708 // #i102109#
709 // For MetaFile replay (see task) it may now be necessary to take
710 // into account that the content is AntiAlialised and needs to be masked
711 // like that. Instead of masking, i will use a copy-modify-paste cycle
712 // here (as i already use in the VclPrimiziveRenderer with successs)
713 xVDev->SetAntialiasing(GetAntialiasing());
715 // create MapMode for buffer (offset needed) and set
716 MapMode aMap(GetMapMode());
717 const Point aOutPos(PixelToLogic(aDstRect.TopLeft()));
718 aMap.SetOrigin(Point(-aOutPos.X(), -aOutPos.Y()));
719 xVDev->SetMapMode(aMap);
721 // copy MapMode state and disable for target
722 const bool bOrigMapModeEnabled(IsMapModeEnabled());
723 EnableMapMode(false);
725 // copy MapMode state and disable for buffer
726 const bool bBufferMapModeEnabled(xVDev->IsMapModeEnabled());
727 xVDev->EnableMapMode(false);
729 // copy content from original to buffer
730 xVDev->DrawOutDev( aPoint, xVDev->GetOutputSizePixel(), // dest
731 aDstRect.TopLeft(), xVDev->GetOutputSizePixel(), // source
732 *this);
734 // draw MetaFile to buffer
735 xVDev->EnableMapMode(bBufferMapModeEnabled);
736 ((GDIMetaFile&)rMtf).WindStart();
737 ((GDIMetaFile&)rMtf).Play(xVDev.get(), rPos, rSize);
738 ((GDIMetaFile&)rMtf).WindStart();
740 // get content bitmap from buffer
741 xVDev->EnableMapMode(false);
743 const Bitmap aPaint(xVDev->GetBitmap(aPoint, xVDev->GetOutputSizePixel()));
745 // create alpha mask from gradient and get as Bitmap
746 xVDev->EnableMapMode(bBufferMapModeEnabled);
747 xVDev->SetDrawMode(DrawModeFlags::GrayGradient);
748 xVDev->DrawGradient(Rectangle(rPos, rSize), rTransparenceGradient);
749 xVDev->SetDrawMode(DrawModeFlags::Default);
750 xVDev->EnableMapMode(false);
752 const AlphaMask aAlpha(xVDev->GetBitmap(aPoint, xVDev->GetOutputSizePixel()));
754 xVDev.disposeAndClear();
756 // draw masked content to target and restore MapMode
757 DrawBitmapEx(aDstRect.TopLeft(), BitmapEx(aPaint, aAlpha));
758 EnableMapMode(bOrigMapModeEnabled);
760 else
762 Bitmap aPaint, aMask;
763 AlphaMask aAlpha;
764 MapMode aMap( GetMapMode() );
765 Point aOutPos( PixelToLogic( aDstRect.TopLeft() ) );
766 const bool bOldMap = mbMap;
768 aMap.SetOrigin( Point( -aOutPos.X(), -aOutPos.Y() ) );
769 xVDev->SetMapMode( aMap );
770 const bool bVDevOldMap = xVDev->IsMapModeEnabled();
772 // create paint bitmap
773 ( (GDIMetaFile&) rMtf ).WindStart();
774 ( (GDIMetaFile&) rMtf ).Play( xVDev.get(), rPos, rSize );
775 ( (GDIMetaFile&) rMtf ).WindStart();
776 xVDev->EnableMapMode( false );
777 aPaint = xVDev->GetBitmap( Point(), xVDev->GetOutputSizePixel() );
778 xVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( sal_True ) here!
780 // create mask bitmap
781 xVDev->SetLineColor( COL_BLACK );
782 xVDev->SetFillColor( COL_BLACK );
783 xVDev->DrawRect( Rectangle( xVDev->PixelToLogic( Point() ), xVDev->GetOutputSize() ) );
784 xVDev->SetDrawMode( DrawModeFlags::WhiteLine | DrawModeFlags::WhiteFill | DrawModeFlags::WhiteText |
785 DrawModeFlags::WhiteBitmap | DrawModeFlags::WhiteGradient );
786 ( (GDIMetaFile&) rMtf ).WindStart();
787 ( (GDIMetaFile&) rMtf ).Play( xVDev.get(), rPos, rSize );
788 ( (GDIMetaFile&) rMtf ).WindStart();
789 xVDev->EnableMapMode( false );
790 aMask = xVDev->GetBitmap( Point(), xVDev->GetOutputSizePixel() );
791 xVDev->EnableMapMode( bVDevOldMap ); // #i35331#: MUST NOT use EnableMapMode( sal_True ) here!
793 // create alpha mask from gradient
794 xVDev->SetDrawMode( DrawModeFlags::GrayGradient );
795 xVDev->DrawGradient( Rectangle( rPos, rSize ), rTransparenceGradient );
796 xVDev->SetDrawMode( DrawModeFlags::Default );
797 xVDev->EnableMapMode( false );
798 xVDev->DrawMask( Point(), xVDev->GetOutputSizePixel(), aMask, Color( COL_WHITE ) );
800 aAlpha = xVDev->GetBitmap( Point(), xVDev->GetOutputSizePixel() );
802 xVDev.disposeAndClear();
804 EnableMapMode( false );
805 DrawBitmapEx( aDstRect.TopLeft(), BitmapEx( aPaint, aAlpha ) );
806 EnableMapMode( bOldMap );
811 mpMetaFile = pOldMetaFile;
815 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */