blob: a6d7896327a4b182f5d1d5e18d85858217934666 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"
#include <string.h>
#include <stdlib.h>
#include <tools/svwin.h>
#include <tools/debug.hxx>
#include <win/wincomp.hxx>
#include <win/salbmp.h>
#include <win/saldata.hxx>
#include <win/salids.hrc>
#include <win/salgdi.h>
#include <win/salframe.h>
bool WinSalGraphics::supportsOperation( OutDevSupportType eType ) const
{
static bool bAllowForTest(true);
bool bRet = false;
switch( eType )
{
case OutDevSupport_TransparentRect:
bRet = mbVirDev || mbWindow;
break;
case OutDevSupport_B2DClip:
bRet = true;
break;
case OutDevSupport_B2DDraw:
bRet = bAllowForTest;
default: break;
}
return bRet;
}
// =======================================================================
void WinSalGraphics::copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics )
{
HDC hSrcDC;
DWORD nRop;
if ( pSrcGraphics )
hSrcDC = static_cast<WinSalGraphics*>(pSrcGraphics)->getHDC();
else
hSrcDC = getHDC();
if ( mbXORMode )
nRop = SRCINVERT;
else
nRop = SRCCOPY;
if ( (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) &&
(rPosAry.mnSrcHeight == rPosAry.mnDestHeight) )
{
BitBlt( getHDC(),
(int)rPosAry.mnDestX, (int)rPosAry.mnDestY,
(int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight,
hSrcDC,
(int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY,
nRop );
}
else
{
int nOldStretchMode = SetStretchBltMode( getHDC(), STRETCH_DELETESCANS );
StretchBlt( getHDC(),
(int)rPosAry.mnDestX, (int)rPosAry.mnDestY,
(int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight,
hSrcDC,
(int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY,
(int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight,
nRop );
SetStretchBltMode( getHDC(), nOldStretchMode );
}
}
// -----------------------------------------------------------------------
void ImplCalcOutSideRgn( const RECT& rSrcRect,
int nLeft, int nTop, int nRight, int nBottom,
HRGN& rhInvalidateRgn )
{
HRGN hTempRgn;
// Bereiche ausserhalb des sichtbaren Bereiches berechnen
if ( rSrcRect.left < nLeft )
{
if ( !rhInvalidateRgn )
rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect );
hTempRgn = CreateRectRgn( -31999, 0, nLeft, 31999 );
CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF );
DeleteRegion( hTempRgn );
}
if ( rSrcRect.top < nTop )
{
if ( !rhInvalidateRgn )
rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect );
hTempRgn = CreateRectRgn( 0, -31999, 31999, nTop );
CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF );
DeleteRegion( hTempRgn );
}
if ( rSrcRect.right > nRight )
{
if ( !rhInvalidateRgn )
rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect );
hTempRgn = CreateRectRgn( nRight, 0, 31999, 31999 );
CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF );
DeleteRegion( hTempRgn );
}
if ( rSrcRect.bottom > nBottom )
{
if ( !rhInvalidateRgn )
rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect );
hTempRgn = CreateRectRgn( 0, nBottom, 31999, 31999 );
CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF );
DeleteRegion( hTempRgn );
}
}
// -----------------------------------------------------------------------
void WinSalGraphics::copyArea( long nDestX, long nDestY,
long nSrcX, long nSrcY,
long nSrcWidth, long nSrcHeight,
sal_uInt16 nFlags )
{
bool bRestoreClipRgn = false;
HRGN hOldClipRgn = 0;
int nOldClipRgnType = ERROR;
HRGN hInvalidateRgn = 0;
// Muessen die ueberlappenden Bereiche auch invalidiert werden?
if ( (nFlags & SAL_COPYAREA_WINDOWINVALIDATE) && mbWindow )
{
// compute and invalidate those parts that were either off-screen or covered by other windows
// while performing the above BitBlt
// those regions then have to be invalidated as they contain useless/wrong data
RECT aSrcRect;
RECT aClipRect;
RECT aTempRect;
RECT aTempRect2;
HRGN hTempRgn;
HWND hWnd;
int nRgnType;
// restrict srcRect to this window (calc intersection)
aSrcRect.left = (int)nSrcX;
aSrcRect.top = (int)nSrcY;
aSrcRect.right = aSrcRect.left+(int)nSrcWidth;
aSrcRect.bottom = aSrcRect.top+(int)nSrcHeight;
GetClientRect( mhWnd, &aClipRect );
if ( IntersectRect( &aSrcRect, &aSrcRect, &aClipRect ) )
{
// transform srcRect to screen coordinates
POINT aPt;
aPt.x = 0;
aPt.y = 0;
ClientToScreen( mhWnd, &aPt );
aSrcRect.left += aPt.x;
aSrcRect.top += aPt.y;
aSrcRect.right += aPt.x;
aSrcRect.bottom += aPt.y;
hInvalidateRgn = 0;
// compute the parts that are off screen (ie invisible)
RECT theScreen;
ImplSalGetWorkArea( NULL, &theScreen, NULL ); // find the screen area taking multiple monitors into account
ImplCalcOutSideRgn( aSrcRect, theScreen.left, theScreen.top, theScreen.right, theScreen.bottom, hInvalidateRgn );
// Bereiche die von anderen Fenstern ueberlagert werden berechnen
HRGN hTempRgn2 = 0;
HWND hWndTopWindow = mhWnd;
// Find the TopLevel Window, because only Windows which are in
// in the foreground of our TopLevel window must be considered
if ( GetWindowStyle( hWndTopWindow ) & WS_CHILD )
{
RECT aTempRect3 = aSrcRect;
do
{
hWndTopWindow = ::GetParent( hWndTopWindow );
// Test, if the Parent clips our window
GetClientRect( hWndTopWindow, &aTempRect );
POINT aPt2;
aPt2.x = 0;
aPt2.y = 0;
ClientToScreen( hWndTopWindow, &aPt2 );
aTempRect.left += aPt2.x;
aTempRect.top += aPt2.y;
aTempRect.right += aPt2.x;
aTempRect.bottom += aPt2.y;
IntersectRect( &aTempRect3, &aTempRect3, &aTempRect );
}
while ( GetWindowStyle( hWndTopWindow ) & WS_CHILD );
// If one or more Parents clip our window, than we must
// calculate the outside area
if ( !EqualRect( &aSrcRect, &aTempRect3 ) )
{
ImplCalcOutSideRgn( aSrcRect,
aTempRect3.left, aTempRect3.top,
aTempRect3.right, aTempRect3.bottom,
hInvalidateRgn );
}
}
// retrieve the top-most (z-order) child window
hWnd = GetWindow( GetDesktopWindow(), GW_CHILD );
while ( hWnd )
{
if ( hWnd == hWndTopWindow )
break;
if ( IsWindowVisible( hWnd ) && !IsIconic( hWnd ) )
{
GetWindowRect( hWnd, &aTempRect );
if ( IntersectRect( &aTempRect2, &aSrcRect, &aTempRect ) )
{
// hWnd covers part or all of aSrcRect
if ( !hInvalidateRgn )
hInvalidateRgn = CreateRectRgnIndirect( &aSrcRect );
// get full bounding box of hWnd
hTempRgn = CreateRectRgnIndirect( &aTempRect );
// get region of hWnd (the window may be shaped)
if ( !hTempRgn2 )
hTempRgn2 = CreateRectRgn( 0, 0, 0, 0 );
nRgnType = GetWindowRgn( hWnd, hTempRgn2 );
if ( (nRgnType != ERROR) && (nRgnType != NULLREGION) )
{
// convert window region to screen coordinates
OffsetRgn( hTempRgn2, aTempRect.left, aTempRect.top );
// and intersect with the window's bounding box
CombineRgn( hTempRgn, hTempRgn, hTempRgn2, RGN_AND );
}
// finally compute that part of aSrcRect which is not covered by any parts of hWnd
CombineRgn( hInvalidateRgn, hInvalidateRgn, hTempRgn, RGN_DIFF );
DeleteRegion( hTempRgn );
}
}
// retrieve the next window in the z-order, i.e. the window below hwnd
hWnd = GetWindow( hWnd, GW_HWNDNEXT );
}
if ( hTempRgn2 )
DeleteRegion( hTempRgn2 );
if ( hInvalidateRgn )
{
// hInvalidateRgn contains the fully visible parts of the original srcRect
hTempRgn = CreateRectRgnIndirect( &aSrcRect );
// substract it from the original rect to get the occluded parts
nRgnType = CombineRgn( hInvalidateRgn, hTempRgn, hInvalidateRgn, RGN_DIFF );
DeleteRegion( hTempRgn );
if ( (nRgnType != ERROR) && (nRgnType != NULLREGION) )
{
// move the occluded parts to the destination pos
int nOffX = (int)(nDestX-nSrcX);
int nOffY = (int)(nDestY-nSrcY);
OffsetRgn( hInvalidateRgn, nOffX-aPt.x, nOffY-aPt.y );
// by excluding hInvalidateRgn from the system's clip region
// we will prevent bitblt from copying useless data
// epsecially now shadows from overlapping windows will appear (#i36344)
hOldClipRgn = CreateRectRgn( 0, 0, 0, 0 );
nOldClipRgnType = GetClipRgn( getHDC(), hOldClipRgn );
bRestoreClipRgn = TRUE; // indicate changed clipregion and force invalidate
ExtSelectClipRgn( getHDC(), hInvalidateRgn, RGN_DIFF );
}
}
}
}
BitBlt( getHDC(),
(int)nDestX, (int)nDestY,
(int)nSrcWidth, (int)nSrcHeight,
getHDC(),
(int)nSrcX, (int)nSrcY,
SRCCOPY );
if( bRestoreClipRgn )
{
// restore old clip region
if( nOldClipRgnType != ERROR )
SelectClipRgn( getHDC(), hOldClipRgn);
DeleteRegion( hOldClipRgn );
// invalidate regions that were not copied
bool bInvalidate = true;
// Combine Invalidate Region with existing ClipRegion
HRGN hTempRgn = CreateRectRgn( 0, 0, 0, 0 );
if ( GetClipRgn( getHDC(), hTempRgn ) == 1 )
{
int nRgnType = CombineRgn( hInvalidateRgn, hTempRgn, hInvalidateRgn, RGN_AND );
if ( (nRgnType == ERROR) || (nRgnType == NULLREGION) )
bInvalidate = false;
}
DeleteRegion( hTempRgn );
if ( bInvalidate )
{
InvalidateRgn( mhWnd, hInvalidateRgn, TRUE );
// Hier loesen wir nur ein Update aus, wenn es der
// MainThread ist, damit es beim Bearbeiten der
// Paint-Message keinen Deadlock gibt, da der
// SolarMutex durch diesen Thread schon gelockt ist
SalData* pSalData = GetSalData();
DWORD nCurThreadId = GetCurrentThreadId();
if ( pSalData->mnAppThreadId == nCurThreadId )
UpdateWindow( mhWnd );
}
DeleteRegion( hInvalidateRgn );
}
}
// -----------------------------------------------------------------------
void ImplDrawBitmap( HDC hDC,
const SalTwoRect& rPosAry, const WinSalBitmap& rSalBitmap,
sal_Bool bPrinter, int nDrawMode )
{
if( hDC )
{
HGLOBAL hDrawDIB;
HBITMAP hDrawDDB = rSalBitmap.ImplGethDDB();
WinSalBitmap* pTmpSalBmp = NULL;
sal_Bool bPrintDDB = ( bPrinter && hDrawDDB );
if( bPrintDDB )
{
pTmpSalBmp = new WinSalBitmap;
pTmpSalBmp->Create( rSalBitmap, rSalBitmap.GetBitCount() );
hDrawDIB = pTmpSalBmp->ImplGethDIB();
}
else
hDrawDIB = rSalBitmap.ImplGethDIB();
if( hDrawDIB )
{
PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDrawDIB );
PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI;
PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI +
rSalBitmap.ImplGetDIBColorCount( hDrawDIB ) * sizeof( RGBQUAD );
const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS );
StretchDIBits( hDC,
(int)rPosAry.mnDestX, (int)rPosAry.mnDestY,
(int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight,
(int)rPosAry.mnSrcX, (int)(pBIH->biHeight - rPosAry.mnSrcHeight - rPosAry.mnSrcY),
(int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight,
pBits, pBI, DIB_RGB_COLORS, nDrawMode );
GlobalUnlock( hDrawDIB );
SetStretchBltMode( hDC, nOldStretchMode );
}
else if( hDrawDDB && !bPrintDDB )
{
HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_DRAW, hDrawDDB );
COLORREF nOldBkColor = RGB(0xFF,0xFF,0xFF);
COLORREF nOldTextColor = RGB(0,0,0);
sal_Bool bMono = ( rSalBitmap.GetBitCount() == 1 );
if( bMono )
{
nOldBkColor = SetBkColor( hDC, RGB( 0xFF, 0xFF, 0xFF ) );
nOldTextColor = ::SetTextColor( hDC, RGB( 0x00, 0x00, 0x00 ) );
}
if ( (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) &&
(rPosAry.mnSrcHeight == rPosAry.mnDestHeight) )
{
BitBlt( hDC,
(int)rPosAry.mnDestX, (int)rPosAry.mnDestY,
(int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight,
hBmpDC,
(int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY,
nDrawMode );
}
else
{
const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS );
StretchBlt( hDC,
(int)rPosAry.mnDestX, (int)rPosAry.mnDestY,
(int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight,
hBmpDC,
(int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY,
(int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight,
nDrawMode );
SetStretchBltMode( hDC, nOldStretchMode );
}
if( bMono )
{
SetBkColor( hDC, nOldBkColor );
::SetTextColor( hDC, nOldTextColor );
}
ImplReleaseCachedDC( CACHED_HDC_DRAW );
}
if( bPrintDDB )
delete pTmpSalBmp;
}
}
// -----------------------------------------------------------------------
void WinSalGraphics::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap)
{
bool bTryDirectPaint(!mbPrinter && !mbXORMode);
if(bTryDirectPaint)
{
// only paint direct when no scaling and no MapMode, else the
// more expensive conversions may be done for short-time Bitmap/BitmapEx
// used for buffering only
if(rPosAry.mnSrcWidth == rPosAry.mnDestWidth && rPosAry.mnSrcHeight == rPosAry.mnDestHeight)
{
bTryDirectPaint = false;
}
}
// try to draw using GdiPlus directly
if(bTryDirectPaint && tryDrawBitmapGdiPlus(rPosAry, rSalBitmap))
{
return;
}
// fall back old stuff
ImplDrawBitmap(getHDC(), rPosAry, static_cast<const WinSalBitmap&>(rSalBitmap),
mbPrinter,
mbXORMode ? SRCINVERT : SRCCOPY );
}
// -----------------------------------------------------------------------
void WinSalGraphics::drawBitmap( const SalTwoRect& rPosAry,
const SalBitmap& rSSalBitmap,
SalColor nTransparentColor )
{
DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
WinSalBitmap* pMask = new WinSalBitmap;
const Point aPoint;
const Size aSize( rSalBitmap.GetSize() );
HBITMAP hMaskBitmap = CreateBitmap( (int) aSize.Width(), (int) aSize.Height(), 1, 1, NULL );
HDC hMaskDC = ImplGetCachedDC( CACHED_HDC_1, hMaskBitmap );
const BYTE cRed = SALCOLOR_RED( nTransparentColor );
const BYTE cGreen = SALCOLOR_GREEN( nTransparentColor );
const BYTE cBlue = SALCOLOR_BLUE( nTransparentColor );
if( rSalBitmap.ImplGethDDB() )
{
HDC hSrcDC = ImplGetCachedDC( CACHED_HDC_2, rSalBitmap.ImplGethDDB() );
COLORREF aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) );
BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY );
SetBkColor( hSrcDC, aOldCol );
ImplReleaseCachedDC( CACHED_HDC_2 );
}
else
{
WinSalBitmap* pTmpSalBmp = new WinSalBitmap;
if( pTmpSalBmp->Create( rSalBitmap, this ) )
{
HDC hSrcDC = ImplGetCachedDC( CACHED_HDC_2, pTmpSalBmp->ImplGethDDB() );
COLORREF aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) );
BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY );
SetBkColor( hSrcDC, aOldCol );
ImplReleaseCachedDC( CACHED_HDC_2 );
}
delete pTmpSalBmp;
}
ImplReleaseCachedDC( CACHED_HDC_1 );
// hMaskBitmap is destroyed by new SalBitmap 'pMask' ( bDIB==FALSE, bCopy == FALSE )
if( pMask->Create( hMaskBitmap, FALSE, FALSE ) )
drawBitmap( rPosAry, rSalBitmap, *pMask );
delete pMask;
}
// -----------------------------------------------------------------------
void WinSalGraphics::drawBitmap( const SalTwoRect& rPosAry,
const SalBitmap& rSSalBitmap,
const SalBitmap& rSTransparentBitmap )
{
DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
bool bTryDirectPaint(!mbPrinter && !mbXORMode);
if(bTryDirectPaint)
{
// only paint direct when no scaling and no MapMode, else the
// more expensive conversions may be done for short-time Bitmap/BitmapEx
// used for buffering only
if(rPosAry.mnSrcWidth == rPosAry.mnDestWidth && rPosAry.mnSrcHeight == rPosAry.mnDestHeight)
{
bTryDirectPaint = false;
}
}
// try to draw using GdiPlus directly
if(bTryDirectPaint && drawAlphaBitmap(rPosAry, rSSalBitmap, rSTransparentBitmap))
{
return;
}
const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
const WinSalBitmap& rTransparentBitmap = static_cast<const WinSalBitmap&>(rSTransparentBitmap);
SalTwoRect aPosAry = rPosAry;
int nDstX = (int)aPosAry.mnDestX;
int nDstY = (int)aPosAry.mnDestY;
int nDstWidth = (int)aPosAry.mnDestWidth;
int nDstHeight = (int)aPosAry.mnDestHeight;
HDC hDC = getHDC();
HBITMAP hMemBitmap = 0;
HBITMAP hMaskBitmap = 0;
if( ( nDstWidth > CACHED_HDC_DEFEXT ) || ( nDstHeight > CACHED_HDC_DEFEXT ) )
{
hMemBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight );
hMaskBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight );
}
HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, hMemBitmap );
HDC hMaskDC = ImplGetCachedDC( CACHED_HDC_2, hMaskBitmap );
aPosAry.mnDestX = aPosAry.mnDestY = 0;
BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hDC, nDstX, nDstY, SRCCOPY );
// bei Paletten-Displays hat WIN/WNT offenbar ein kleines Problem,
// die Farben der Maske richtig auf die Palette abzubilden,
// wenn wir die DIB direkt ausgeben => DDB-Ausgabe
if( ( GetBitCount() <= 8 ) && rTransparentBitmap.ImplGethDIB() && rTransparentBitmap.GetBitCount() == 1 )
{
WinSalBitmap aTmp;
if( aTmp.Create( rTransparentBitmap, this ) )
ImplDrawBitmap( hMaskDC, aPosAry, aTmp, FALSE, SRCCOPY );
}
else
ImplDrawBitmap( hMaskDC, aPosAry, rTransparentBitmap, FALSE, SRCCOPY );
// now MemDC contains background, MaskDC the transparency mask
// #105055# Respect XOR mode
if( mbXORMode )
{
ImplDrawBitmap( hMaskDC, aPosAry, rSalBitmap, FALSE, SRCERASE );
// now MaskDC contains the bitmap area with black background
BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCINVERT );
// now MemDC contains background XORed bitmap area ontop
}
else
{
BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCAND );
// now MemDC contains background with masked-out bitmap area
ImplDrawBitmap( hMaskDC, aPosAry, rSalBitmap, FALSE, SRCERASE );
// now MaskDC contains the bitmap area with black background
BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCPAINT );
// now MemDC contains background and bitmap merged together
}
// copy to output DC
BitBlt( hDC, nDstX, nDstY, nDstWidth, nDstHeight, hMemDC, 0, 0, SRCCOPY );
ImplReleaseCachedDC( CACHED_HDC_1 );
ImplReleaseCachedDC( CACHED_HDC_2 );
// hMemBitmap != 0 ==> hMaskBitmap != 0
if( hMemBitmap )
{
DeleteObject( hMemBitmap );
DeleteObject( hMaskBitmap );
}
}
// -----------------------------------------------------------------------
bool WinSalGraphics::drawAlphaRect( long nX, long nY, long nWidth,
long nHeight, sal_uInt8 nTransparency )
{
if( mbPen || !mbBrush || mbXORMode )
return false; // can only perform solid fills without XOR.
HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, 0 );
SetPixel( hMemDC, (int)0, (int)0, mnBrushColor );
BLENDFUNCTION aFunc = {
AC_SRC_OVER,
0,
255 - 255L*nTransparency/100,
0
};
// hMemDC contains a 1x1 bitmap of the right color - stretch-blit
// that to dest hdc
bool bRet = AlphaBlend( getHDC(), nX, nY, nWidth, nHeight,
hMemDC, 0,0,1,1,
aFunc ) == TRUE;
ImplReleaseCachedDC( CACHED_HDC_1 );
return bRet;
}
// -----------------------------------------------------------------------
void WinSalGraphics::drawMask( const SalTwoRect& rPosAry,
const SalBitmap& rSSalBitmap,
SalColor nMaskColor )
{
DBG_ASSERT( !mbPrinter, "No transparency print possible!" );
const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap);
SalTwoRect aPosAry = rPosAry;
const BYTE cRed = SALCOLOR_RED( nMaskColor );
const BYTE cGreen = SALCOLOR_GREEN( nMaskColor );
const BYTE cBlue = SALCOLOR_BLUE( nMaskColor );
HDC hDC = getHDC();
HBRUSH hMaskBrush = CreateSolidBrush( RGB( cRed, cGreen, cBlue ) );
HBRUSH hOldBrush = SelectBrush( hDC, hMaskBrush );
// bei Paletten-Displays hat WIN/WNT offenbar ein kleines Problem,
// die Farben der Maske richtig auf die Palette abzubilden,
// wenn wir die DIB direkt ausgeben => DDB-Ausgabe
if( ( GetBitCount() <= 8 ) && rSalBitmap.ImplGethDIB() && rSalBitmap.GetBitCount() == 1 )
{
WinSalBitmap aTmp;
if( aTmp.Create( rSalBitmap, this ) )
ImplDrawBitmap( hDC, aPosAry, aTmp, FALSE, 0x00B8074AUL );
}
else
ImplDrawBitmap( hDC, aPosAry, rSalBitmap, FALSE, 0x00B8074AUL );
SelectBrush( hDC, hOldBrush );
DeleteBrush( hMaskBrush );
}
// -----------------------------------------------------------------------
SalBitmap* WinSalGraphics::getBitmap( long nX, long nY, long nDX, long nDY )
{
DBG_ASSERT( !mbPrinter, "No ::GetBitmap() from printer possible!" );
WinSalBitmap* pSalBitmap = NULL;
nDX = labs( nDX );
nDY = labs( nDY );
HDC hDC = getHDC();
HBITMAP hBmpBitmap = CreateCompatibleBitmap( hDC, nDX, nDY );
HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_1, hBmpBitmap );
sal_Bool bRet;
DWORD err = 0;
bRet = BitBlt( hBmpDC, 0, 0, (int) nDX, (int) nDY, hDC, (int) nX, (int) nY, SRCCOPY ) ? TRUE : FALSE;
ImplReleaseCachedDC( CACHED_HDC_1 );
if( bRet )
{
pSalBitmap = new WinSalBitmap;
if( !pSalBitmap->Create( hBmpBitmap, FALSE, FALSE ) )
{
delete pSalBitmap;
pSalBitmap = NULL;
}
}
else
{
err = GetLastError();
// #124826# avoid resource leak ! happens when runing without desktop access (remote desktop, service, may be screensavers)
DeleteBitmap( hBmpBitmap );
}
return pSalBitmap;
}
// -----------------------------------------------------------------------
SalColor WinSalGraphics::getPixel( long nX, long nY )
{
COLORREF aWinCol = ::GetPixel( getHDC(), (int) nX, (int) nY );
if ( CLR_INVALID == aWinCol )
return MAKE_SALCOLOR( 0, 0, 0 );
else
return MAKE_SALCOLOR( GetRValue( aWinCol ),
GetGValue( aWinCol ),
GetBValue( aWinCol ) );
}
// -----------------------------------------------------------------------
void WinSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags )
{
if ( nFlags & SAL_INVERT_TRACKFRAME )
{
HPEN hDotPen = CreatePen( PS_DOT, 0, 0 );
HPEN hOldPen = SelectPen( getHDC(), hDotPen );
HBRUSH hOldBrush = SelectBrush( getHDC(), GetStockBrush( NULL_BRUSH ) );
int nOldROP = SetROP2( getHDC(), R2_NOT );
WIN_Rectangle( getHDC(), (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) );
SetROP2( getHDC(), nOldROP );
SelectPen( getHDC(), hOldPen );
SelectBrush( getHDC(), hOldBrush );
DeletePen( hDotPen );
}
else if ( nFlags & SAL_INVERT_50 )
{
SalData* pSalData = GetSalData();
if ( !pSalData->mh50Brush )
{
if ( !pSalData->mh50Bmp )
pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 );
pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp );
}
COLORREF nOldTextColor = ::SetTextColor( getHDC(), 0 );
HBRUSH hOldBrush = SelectBrush( getHDC(), pSalData->mh50Brush );
PatBlt( getHDC(), nX, nY, nWidth, nHeight, PATINVERT );
::SetTextColor( getHDC(), nOldTextColor );
SelectBrush( getHDC(), hOldBrush );
}
else
{
RECT aRect;
aRect.left = (int)nX;
aRect.top = (int)nY;
aRect.right = (int)nX+nWidth;
aRect.bottom = (int)nY+nHeight;
::InvertRect( getHDC(), &aRect );
}
}
// -----------------------------------------------------------------------
void WinSalGraphics::invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nSalFlags )
{
HPEN hPen;
HPEN hOldPen;
HBRUSH hBrush;
HBRUSH hOldBrush = 0;
COLORREF nOldTextColor RGB(0,0,0);
int nOldROP = SetROP2( getHDC(), R2_NOT );
if ( nSalFlags & SAL_INVERT_TRACKFRAME )
hPen = CreatePen( PS_DOT, 0, 0 );
else
{
if ( nSalFlags & SAL_INVERT_50 )
{
SalData* pSalData = GetSalData();
if ( !pSalData->mh50Brush )
{
if ( !pSalData->mh50Bmp )
pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 );
pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp );
}
hBrush = pSalData->mh50Brush;
}
else
hBrush = GetStockBrush( BLACK_BRUSH );
hPen = GetStockPen( NULL_PEN );
nOldTextColor = ::SetTextColor( getHDC(), 0 );
hOldBrush = SelectBrush( getHDC(), hBrush );
}
hOldPen = SelectPen( getHDC(), hPen );
POINT* pWinPtAry;
// Unter NT koennen wir das Array direkt weiterreichen
DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ),
"WinSalGraphics::DrawPolyLine(): POINT != SalPoint" );
pWinPtAry = (POINT*)pPtAry;
// Wegen Windows 95 und der Beschraenkung auf eine maximale Anzahl
// von Punkten
if ( nSalFlags & SAL_INVERT_TRACKFRAME )
{
if ( !Polyline( getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
Polyline( getHDC(), pWinPtAry, MAX_64KSALPOINTS );
}
else
{
if ( !WIN_Polygon( getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) )
WIN_Polygon( getHDC(), pWinPtAry, MAX_64KSALPOINTS );
}
SetROP2( getHDC(), nOldROP );
SelectPen( getHDC(), hOldPen );
if ( nSalFlags & SAL_INVERT_TRACKFRAME )
DeletePen( hPen );
else
{
::SetTextColor( getHDC(), nOldTextColor );
SelectBrush( getHDC(), hOldBrush );
}
}