blob: 714df7eab6579d94d911746c10c256662c358ee4 [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 <stdio.h>
#include <poll.h>
#include "vcl/salbtype.hxx"
#include "unx/salunx.h"
#include "unx/saldata.hxx"
#include "unx/saldisp.hxx"
#include "unx/salbmp.h"
#include "unx/salgdi.h"
#include "unx/salframe.h"
#include "unx/salvd.h"
#include "xrender_peer.hxx"
#include "printergfx.hxx"
#include "vcl/bmpacc.hxx"
#undef SALGDI2_TESTTRANS
// -=-= debugging =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#if 0
static void sal_PrintImage( char *s, XImage*p )
{
fprintf( stderr, "%s %d %d %d\n", s, p->depth, p->width, p->height );
int nW = Min( 64, p->width*p->bits_per_pixel >> 3 );
for( int i = 0; i < Min( 16, p->height ); i++ )
{
for( int j = 0; j < nW; j++ )
fprintf( stderr, "%02X", (UINT8)p->data[i*p->bytes_per_line+j] );
fprintf( stderr, "\n" );
}
}
#endif // DBG_UTIL
// -----------------------------------------------------------------------------
#if (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS
#define DBG_TESTTRANS( _def_drawable ) \
{ \
XCopyArea( pXDisp, _def_drawable, aDrawable, GetCopyGC(), \
0, 0, \
pPosAry->mnDestWidth, pPosAry->mnDestHeight, \
0, 0 ); \
}
#else // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS
#define DBG_TESTTRANS( _def_drawable )
#endif // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS
// -=-= X11SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::CopyScreenArea( Display* pDisplay,
Drawable aSrc, int nScreenSrc, int nSrcDepth,
Drawable aDest, int nScreenDest, int nDestDepth,
GC aDestGC,
int src_x, int src_y,
unsigned int w, unsigned int h,
int dest_x, int dest_y )
{
if( nSrcDepth == nDestDepth )
{
if( nScreenSrc == nScreenDest )
XCopyArea( pDisplay, aSrc, aDest, aDestGC,
src_x, src_y, w, h, dest_x, dest_y );
else
{
SalXLib* pLib = GetX11SalData()->GetDisplay()->GetXLib();
pLib->PushXErrorLevel( true );
XImage* pImage = XGetImage( pDisplay, aSrc, src_x, src_y, w, h,
AllPlanes, ZPixmap );
if( pImage )
{
if( pImage->data )
{
XPutImage( pDisplay, aDest, aDestGC, pImage,
0, 0, dest_x, dest_y, w, h );
}
XDestroyImage( pImage );
}
pLib->PopXErrorLevel();
}
}
else
{
X11SalBitmap aBM;
aBM.ImplCreateFromDrawable( aSrc, nScreenSrc, nSrcDepth, src_x, src_y, w, h );
SalTwoRect aTwoRect;
aTwoRect.mnSrcX = aTwoRect.mnSrcY = 0;
aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = w;
aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = h;
aTwoRect.mnDestX = dest_x;
aTwoRect.mnDestY = dest_y;
aBM.ImplDraw( aDest, nScreenDest, nDestDepth, aTwoRect,aDestGC );
}
}
GC X11SalGraphics::CreateGC( Drawable hDrawable, unsigned long nMask )
{
XGCValues values;
values.graphics_exposures = False;
values.foreground = m_pColormap->GetBlackPixel()
^ m_pColormap->GetWhitePixel();
values.function = GXxor;
values.line_width = 1;
values.fill_style = FillStippled;
values.stipple = GetDisplay()->GetInvert50( m_nScreen );
values.subwindow_mode = ClipByChildren;
return XCreateGC( GetXDisplay(), hDrawable, nMask | GCSubwindowMode, &values );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
inline GC X11SalGraphics::GetMonoGC( Pixmap hPixmap )
{
if( !pMonoGC_ )
pMonoGC_ = CreateGC( hPixmap );
if( !bMonoGC_ )
{
SetClipRegion( pMonoGC_ );
bMonoGC_ = sal_True;
}
return pMonoGC_;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
inline GC X11SalGraphics::GetCopyGC()
{
if( bXORMode_ ) return GetInvertGC();
if( !pCopyGC_ )
pCopyGC_ = CreateGC( GetDrawable() );
if( !bCopyGC_ )
{
SetClipRegion( pCopyGC_ );
bCopyGC_ = sal_True;
}
return pCopyGC_;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
GC X11SalGraphics::GetInvertGC()
{
if( !pInvertGC_ )
pInvertGC_ = CreateGC( GetDrawable(),
GCGraphicsExposures
| GCForeground
| GCFunction
| GCLineWidth );
if( !bInvertGC_ )
{
SetClipRegion( pInvertGC_ );
bInvertGC_ = sal_True;
}
return pInvertGC_;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
GC X11SalGraphics::GetInvert50GC()
{
if( !pInvert50GC_ )
{
XGCValues values;
values.graphics_exposures = False;
values.foreground = m_pColormap->GetWhitePixel();
values.background = m_pColormap->GetBlackPixel();
values.function = GXinvert;
values.line_width = 1;
values.line_style = LineSolid;
unsigned long nValueMask =
GCGraphicsExposures
| GCForeground
| GCBackground
| GCFunction
| GCLineWidth
| GCLineStyle
| GCFillStyle
| GCStipple;
char* pEnv = getenv( "SAL_DO_NOT_USE_INVERT50" );
if( pEnv && ! strcasecmp( pEnv, "true" ) )
{
values.fill_style = FillSolid;
nValueMask &= ~ GCStipple;
}
else
{
values.fill_style = FillStippled;
values.stipple = GetDisplay()->GetInvert50( m_nScreen );
}
pInvert50GC_ = XCreateGC( GetXDisplay(), GetDrawable(),
nValueMask,
&values );
}
if( !bInvert50GC_ )
{
SetClipRegion( pInvert50GC_ );
bInvert50GC_ = sal_True;
}
return pInvert50GC_;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
inline GC X11SalGraphics::GetStippleGC()
{
if( !pStippleGC_ )
pStippleGC_ = CreateGC( GetDrawable(),
GCGraphicsExposures
| GCFillStyle
| GCLineWidth );
if( !bStippleGC_ )
{
XSetFunction( GetXDisplay(), pStippleGC_, bXORMode_ ? GXxor : GXcopy );
SetClipRegion( pStippleGC_ );
bStippleGC_ = sal_True;
}
return pStippleGC_;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
int X11SalGraphics::Clip( XLIB_Region pRegion,
int &nX,
int &nY,
unsigned int &nDX,
unsigned int &nDY,
int &nSrcX,
int &nSrcY ) const
{
XRectangle aRect;
XClipBox( pRegion, &aRect );
if( int(nX + nDX) <= int(aRect.x) || nX >= int(aRect.x + aRect.width) )
return RectangleOut;
if( int(nY + nDY) <= int(aRect.y) || nY >= int(aRect.y + aRect.height) )
return RectangleOut;
if( nX < aRect.x )
{
nSrcX += aRect.x - nX;
nDX -= aRect.x - nX;
nX = aRect.x;
}
else if( int(nX + nDX) > int(aRect.x + aRect.width) )
nDX = aRect.x + aRect.width - nX;
if( nY < aRect.y )
{
nSrcY += aRect.y - nY;
nDY -= aRect.y - nY;
nY = aRect.y;
}
else if( int(nY + nDY) > int(aRect.y + aRect.height) )
nDY = aRect.y + aRect.height - nY;
return RectangleIn;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
int X11SalGraphics::Clip( int &nX,
int &nY,
unsigned int &nDX,
unsigned int &nDY,
int &nSrcX,
int &nSrcY ) const
{
if( pPaintRegion_
&& RectangleOut == Clip( pPaintRegion_, nX, nY, nDX, nDY, nSrcX, nSrcY ) )
return RectangleOut;
if( mpClipRegion
&& RectangleOut == Clip( mpClipRegion, nX, nY, nDX, nDY, nSrcX, nSrcY ) )
return RectangleOut;
int nPaint;
if( pPaintRegion_ )
{
nPaint = XRectInRegion( pPaintRegion_, nX, nY, nDX, nDY );
if( RectangleOut == nPaint )
return RectangleOut;
}
else
nPaint = RectangleIn;
int nClip;
if( mpClipRegion )
{
nClip = XRectInRegion( mpClipRegion, nX, nY, nDX, nDY );
if( RectangleOut == nClip )
return RectangleOut;
}
else
nClip = RectangleIn;
return RectangleIn == nClip && RectangleIn == nPaint
? RectangleIn
: RectanglePart;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
GC X11SalGraphics::SetMask( int &nX,
int &nY,
unsigned int &nDX,
unsigned int &nDY,
int &nSrcX,
int &nSrcY,
Pixmap hClipMask )
{
int n = Clip( nX, nY, nDX, nDY, nSrcX, nSrcY );
if( RectangleOut == n )
return NULL;
Display *pDisplay = GetXDisplay();
if( !pMaskGC_ )
pMaskGC_ = CreateGC( GetDrawable() );
if( RectangleIn == n )
{
XSetClipMask( pDisplay, pMaskGC_, hClipMask );
XSetClipOrigin( pDisplay, pMaskGC_, nX - nSrcX, nY - nSrcY );
return pMaskGC_;
}
// - - - - create alternate clip pixmap for region clipping - - - -
Pixmap hPixmap = XCreatePixmap( pDisplay, hClipMask, nDX, nDY, 1 );
if( !hPixmap )
{
#if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
fprintf( stderr, "X11SalGraphics::SetMask !hPixmap\n" );
#endif
return NULL;
}
// - - - - reset pixmap; all 0 - - - - - - - - - - - - - - - - - - -
XFillRectangle( pDisplay,
hPixmap,
GetDisplay()->GetMonoGC( m_nScreen ),
0, 0,
nDX, nDY );
// - - - - copy pixmap only within region - - - - - - - - - - - - -
GC pMonoGC = GetMonoGC( hPixmap );
XSetClipOrigin( pDisplay, pMonoGC, -nX, -nY );
XCopyArea( pDisplay,
hClipMask, // Source
hPixmap, // Destination
pMonoGC,
nSrcX, nSrcY, // Source
nDX, nDY, // Width & Height
0, 0 ); // Destination
XSetClipMask( pDisplay, pMaskGC_, hPixmap );
XSetClipOrigin( pDisplay, pMaskGC_, nX, nY );
XFreePixmap( pDisplay, hPixmap );
return pMaskGC_;
}
// -=-= SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
extern "C"
{
static Bool GraphicsExposePredicate( Display*, XEvent* pEvent, XPointer pFrameWindow )
{
Bool bRet = False;
if( (pEvent->type == GraphicsExpose || pEvent->type == NoExpose) &&
pEvent->xnoexpose.drawable == (Drawable)pFrameWindow )
{
bRet = True;
}
return bRet;
}
}
void X11SalGraphics::YieldGraphicsExpose()
{
// get frame if necessary
SalFrame* pFrame = m_pFrame;
Display* pDisplay = GetXDisplay();
XLIB_Window aWindow = GetDrawable();
if( ! pFrame )
{
const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames();
for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end() && ! pFrame; ++it )
{
const SystemEnvData* pEnvData = (*it)->GetSystemData();
if( Drawable(pEnvData->aWindow) == aWindow )
pFrame = *it;
}
if( ! pFrame )
return;
}
XEvent aEvent;
while( XCheckTypedWindowEvent( pDisplay, aWindow, Expose, &aEvent ) )
{
SalPaintEvent aPEvt( aEvent.xexpose.x, aEvent.xexpose.y, aEvent.xexpose.width+1, aEvent.xexpose.height+1 );
pFrame->CallCallback( SALEVENT_PAINT, &aPEvt );
}
do
{
if( ! GetDisplay()->XIfEventWithTimeout( &aEvent, (XPointer)aWindow, GraphicsExposePredicate ) )
// this should not happen at all; still sometimes it happens
break;
if( aEvent.type == NoExpose )
break;
if( pFrame )
{
SalPaintEvent aPEvt( aEvent.xgraphicsexpose.x, aEvent.xgraphicsexpose.y, aEvent.xgraphicsexpose.width+1, aEvent.xgraphicsexpose.height+1 );
pFrame->CallCallback( SALEVENT_PAINT, &aPEvt );
}
} while( aEvent.xgraphicsexpose.count != 0 );
}
void X11SalGraphics::copyBits( const SalTwoRect& rPosAry,
SalGraphics *pSSrcGraphics )
{
X11SalGraphics* pSrcGraphics = pSSrcGraphics
? static_cast<X11SalGraphics*>(pSSrcGraphics)
: this;
if( rPosAry.mnSrcWidth <= 0
|| rPosAry.mnSrcHeight <= 0
|| rPosAry.mnDestWidth <= 0
|| rPosAry.mnDestHeight <= 0 )
{
return;
}
int n;
if( pSrcGraphics == this )
{
n = 2;
}
else if( pSrcGraphics->bWindow_ )
{
// window or compatible virtual device
if( pSrcGraphics->GetDisplay() == GetDisplay() &&
pSrcGraphics->m_nScreen == m_nScreen &&
pSrcGraphics->GetVisual().GetDepth() == GetVisual().GetDepth()
)
n = 2; // same Display
else
n = 1; // printer or other display
}
else if( pSrcGraphics->bVirDev_ )
{
// printer compatible virtual device
if( bPrinter_ )
n = 2; // printer or compatible virtual device == same display
else
n = 1; // window or compatible virtual device
}
else
n = 0;
if( n == 2
&& rPosAry.mnSrcWidth == rPosAry.mnDestWidth
&& rPosAry.mnSrcHeight == rPosAry.mnDestHeight
)
{
// #i60699# Need to generate graphics exposures (to repaint
// obscured areas beneath overlapping windows), src and dest
// are the same window.
const bool bNeedGraphicsExposures( pSrcGraphics == this &&
!bVirDev_ &&
pSrcGraphics->bWindow_ );
GC pCopyGC;
if( bXORMode_
&& !pSrcGraphics->bVirDev_
&& (GetDisplay()->GetProperties() & PROPERTY_BUG_XCopyArea_GXxor) )
{
Pixmap hPixmap = XCreatePixmap( GetXDisplay(),
pSrcGraphics->GetDrawable(), // source
rPosAry.mnSrcWidth, rPosAry.mnSrcHeight,
pSrcGraphics->GetBitCount() );
pCopyGC = GetDisplay()->GetCopyGC( m_nScreen );
if( bNeedGraphicsExposures )
XSetGraphicsExposures( GetXDisplay(),
pCopyGC,
True );
XCopyArea( GetXDisplay(),
pSrcGraphics->GetDrawable(), // source
hPixmap, // destination
pCopyGC, // no clipping
rPosAry.mnSrcX, rPosAry.mnSrcY,
rPosAry.mnSrcWidth, rPosAry.mnSrcHeight,
0, 0 ); // destination
XCopyArea( GetXDisplay(),
hPixmap, // source
GetDrawable(), // destination
GetInvertGC(), // destination clipping
0, 0, // source
rPosAry.mnSrcWidth, rPosAry.mnSrcHeight,
rPosAry.mnDestX, rPosAry.mnDestY );
XFreePixmap( GetXDisplay(), hPixmap );
}
else
{
pCopyGC = GetCopyGC();
if( bNeedGraphicsExposures )
XSetGraphicsExposures( GetXDisplay(),
pCopyGC,
True );
XCopyArea( GetXDisplay(),
pSrcGraphics->GetDrawable(), // source
GetDrawable(), // destination
pCopyGC, // destination clipping
rPosAry.mnSrcX, rPosAry.mnSrcY,
rPosAry.mnSrcWidth, rPosAry.mnSrcHeight,
rPosAry.mnDestX, rPosAry.mnDestY );
}
if( bNeedGraphicsExposures )
{
YieldGraphicsExpose();
if( pCopyGC )
XSetGraphicsExposures( GetXDisplay(),
pCopyGC,
False );
}
}
else if( n )
{
// #i60699# No chance to handle graphics exposures - we copy
// to a temp bitmap first, into which no repaints are
// technically possible.
SalBitmap *pDDB = pSrcGraphics->getBitmap( rPosAry.mnSrcX,
rPosAry.mnSrcY,
rPosAry.mnSrcWidth,
rPosAry.mnSrcHeight );
if( !pDDB )
{
stderr0( "SalGraphics::CopyBits !pSrcGraphics->GetBitmap()\n" );
return;
}
SalTwoRect aPosAry( rPosAry );
aPosAry.mnSrcX = 0, aPosAry.mnSrcY = 0;
drawBitmap( aPosAry, *pDDB );
delete pDDB;
}
else {
stderr0( "X11SalGraphics::CopyBits from Printer not yet implemented\n" );
}
}
// --------------------------------------------------------------------------
void X11SalGraphics::copyArea ( long nDestX, long nDestY,
long nSrcX, long nSrcY,
long nSrcWidth, long nSrcHeight,
sal_uInt16 )
{
SalTwoRect aPosAry;
aPosAry.mnDestX = nDestX;
aPosAry.mnDestY = nDestY;
aPosAry.mnDestWidth = nSrcWidth;
aPosAry.mnDestHeight = nSrcHeight;
aPosAry.mnSrcX = nSrcX;
aPosAry.mnSrcY = nSrcY;
aPosAry.mnSrcWidth = nSrcWidth;
aPosAry.mnSrcHeight = nSrcHeight;
copyBits ( aPosAry, 0 );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap )
{
const SalDisplay* pSalDisp = GetDisplay();
Display* pXDisp = pSalDisp->GetDisplay();
const Drawable aDrawable( GetDrawable() );
const SalColormap& rColMap = pSalDisp->GetColormap( m_nScreen );
const long nDepth = GetDisplay()->GetVisual( m_nScreen ).GetDepth();
GC aGC( GetCopyGC() );
XGCValues aOldVal, aNewVal;
int nValues = GCForeground | GCBackground;
if( rSalBitmap.GetBitCount() == 1 )
{
// set foreground/background values for 1Bit bitmaps
XGetGCValues( pXDisp, aGC, nValues, &aOldVal );
aNewVal.foreground = rColMap.GetWhitePixel(), aNewVal.background = rColMap.GetBlackPixel();
XChangeGC( pXDisp, aGC, nValues, &aNewVal );
}
static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aDrawable, m_nScreen, nDepth, rPosAry, aGC );
if( rSalBitmap.GetBitCount() == 1 )
XChangeGC( pXDisp, aGC, nValues, &aOldVal );
XFlush( pXDisp );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::drawBitmap( const SalTwoRect& rPosAry,
const SalBitmap& rSrcBitmap,
const SalBitmap& rMaskBitmap )
{
DBG_ASSERT( !bPrinter_, "Drawing of transparent bitmaps on printer devices is strictly forbidden" );
// decide if alpha masking or transparency masking is needed
BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rMaskBitmap).AcquireBuffer( sal_True );
if( pAlphaBuffer != NULL )
{
int nMaskFormat = pAlphaBuffer->mnFormat;
const_cast<SalBitmap&>(rMaskBitmap).ReleaseBuffer( pAlphaBuffer, sal_True );
if( nMaskFormat == BMP_FORMAT_8BIT_PAL )
drawAlphaBitmap( rPosAry, rSrcBitmap, rMaskBitmap );
}
drawMaskedBitmap( rPosAry, rSrcBitmap, rMaskBitmap );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::drawMaskedBitmap( const SalTwoRect& rPosAry,
const SalBitmap& rSalBitmap,
const SalBitmap& rTransBitmap )
{
const SalDisplay* pSalDisp = GetDisplay();
Display* pXDisp = pSalDisp->GetDisplay();
Drawable aDrawable( GetDrawable() );
// figure work mode depth. If this is a VDev Drawable, use its
// bitdepth to create pixmaps for, otherwise, XCopyArea will
// refuse to work.
const sal_uInt16 nDepth( m_pVDev ?
m_pVDev->GetDepth() :
pSalDisp->GetVisual( m_nScreen ).GetDepth() );
Pixmap aFG( XCreatePixmap( pXDisp, aDrawable, rPosAry.mnDestWidth,
rPosAry.mnDestHeight, nDepth ) );
Pixmap aBG( XCreatePixmap( pXDisp, aDrawable, rPosAry.mnDestWidth,
rPosAry.mnDestHeight, nDepth ) );
if( aFG && aBG )
{
GC aTmpGC;
XGCValues aValues;
const SalColormap& rColMap = pSalDisp->GetColormap( m_nScreen );
const int nBlack = rColMap.GetBlackPixel(), nWhite = rColMap.GetWhitePixel();
const int nValues = GCFunction | GCForeground | GCBackground;
SalTwoRect aTmpRect( rPosAry ); aTmpRect.mnDestX = aTmpRect.mnDestY = 0;
// draw paint bitmap in pixmap #1
aValues.function = GXcopy, aValues.foreground = nWhite, aValues.background = nBlack;
aTmpGC = XCreateGC( pXDisp, aFG, nValues, &aValues );
static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aFG, m_nScreen, nDepth, aTmpRect, aTmpGC );
DBG_TESTTRANS( aFG );
// draw background in pixmap #2
XCopyArea( pXDisp, aDrawable, aBG, aTmpGC,
rPosAry.mnDestX, rPosAry.mnDestY,
rPosAry.mnDestWidth, rPosAry.mnDestHeight,
0, 0 );
DBG_TESTTRANS( aBG );
// mask out paint bitmap in pixmap #1 (transparent areas 0)
aValues.function = GXand, aValues.foreground = 0x00000000, aValues.background = 0xffffffff;
XChangeGC( pXDisp, aTmpGC, nValues, &aValues );
static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aFG, m_nScreen, 1, aTmpRect, aTmpGC );
DBG_TESTTRANS( aFG );
// #105055# For XOR mode, keep background behind bitmap intact
if( !bXORMode_ )
{
// mask out background in pixmap #2 (nontransparent areas 0)
aValues.function = GXand, aValues.foreground = 0xffffffff, aValues.background = 0x00000000;
XChangeGC( pXDisp, aTmpGC, nValues, &aValues );
static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aBG, m_nScreen, 1, aTmpRect, aTmpGC );
DBG_TESTTRANS( aBG );
}
// merge pixmap #1 and pixmap #2 in pixmap #2
aValues.function = GXxor, aValues.foreground = 0xffffffff, aValues.background = 0x00000000;
XChangeGC( pXDisp, aTmpGC, nValues, &aValues );
XCopyArea( pXDisp, aFG, aBG, aTmpGC,
0, 0,
rPosAry.mnDestWidth, rPosAry.mnDestHeight,
0, 0 );
DBG_TESTTRANS( aBG );
// #105055# Disable XOR temporarily
sal_Bool bOldXORMode( bXORMode_ );
bXORMode_ = sal_False;
// copy pixmap #2 (result) to background
XCopyArea( pXDisp, aBG, aDrawable, GetCopyGC(),
0, 0,
rPosAry.mnDestWidth, rPosAry.mnDestHeight,
rPosAry.mnDestX, rPosAry.mnDestY );
DBG_TESTTRANS( aBG );
bXORMode_ = bOldXORMode;
XFreeGC( pXDisp, aTmpGC );
XFlush( pXDisp );
}
else
drawBitmap( rPosAry, rSalBitmap );
if( aFG )
XFreePixmap( pXDisp, aFG );
if( aBG )
XFreePixmap( pXDisp, aBG );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool X11SalGraphics::drawAlphaBitmap( const SalTwoRect& rTR,
const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp )
{
// non 8-bit alpha not implemented yet
if( rAlphaBmp.GetBitCount() != 8 )
return false;
// horizontal mirroring not implemented yet
if( rTR.mnDestWidth < 0 )
return false;
// stretched conversion is not implemented yet
if( rTR.mnDestWidth != rTR.mnSrcWidth )
return false;
if( rTR.mnDestHeight!= rTR.mnSrcHeight )
return false;
XRenderPeer& rPeer = XRenderPeer::GetInstance();
if( rPeer.GetVersion() < 0x02 )
return false;
// create destination picture
Picture aDstPic = GetXRenderPicture();
if( !aDstPic )
return false;
const SalDisplay* pSalDisp = GetDisplay();
const SalVisual& rSalVis = pSalDisp->GetVisual( m_nScreen );
Display* pXDisplay = pSalDisp->GetDisplay();
// create source Picture
int nDepth = m_pVDev ? m_pVDev->GetDepth() : rSalVis.GetDepth();
const X11SalBitmap& rSrcX11Bmp = static_cast<const X11SalBitmap&>( rSrcBitmap );
ImplSalDDB* pSrcDDB = rSrcX11Bmp.ImplGetDDB( hDrawable_, m_nScreen, nDepth, rTR );
if( !pSrcDDB )
return false;
//#i75249# workaround for ImplGetDDB() giving us back a different depth than
// we requested. E.g. mask pixmaps are always compatible with the drawable
// TODO: find an appropriate picture format for these cases
// then remove the workaround below and the one for #i75531#
if( nDepth != pSrcDDB->ImplGetDepth() )
return false;
Pixmap aSrcPM = pSrcDDB->ImplGetPixmap();
if( !aSrcPM )
return false;
// create source picture
// TODO: use scoped picture
Visual* pSrcXVisual = rSalVis.GetVisual();
XRenderPictFormat* pSrcVisFmt = rPeer.FindVisualFormat( pSrcXVisual );
if( !pSrcVisFmt )
return false;
Picture aSrcPic = rPeer.CreatePicture( aSrcPM, pSrcVisFmt, 0, NULL );
if( !aSrcPic )
return false;
// create alpha Picture
// TODO: use SalX11Bitmap functionality and caching for the Alpha Pixmap
// problem is that they don't provide an 8bit Pixmap on a non-8bit display
BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rAlphaBmp).AcquireBuffer( sal_True );
// an XImage needs its data top_down
// TODO: avoid wrongly oriented images in upper layers!
const int nImageSize = pAlphaBuffer->mnHeight * pAlphaBuffer->mnScanlineSize;
const char* pSrcBits = (char*)pAlphaBuffer->mpBits;
char* pAlphaBits = new char[ nImageSize ];
if( BMP_SCANLINE_ADJUSTMENT( pAlphaBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN )
memcpy( pAlphaBits, pSrcBits, nImageSize );
else
{
char* pDstBits = pAlphaBits + nImageSize;
const int nLineSize = pAlphaBuffer->mnScanlineSize;
for(; (pDstBits -= nLineSize) >= pAlphaBits; pSrcBits += nLineSize )
memcpy( pDstBits, pSrcBits, nLineSize );
}
// the alpha values need to be inverted for XRender
// TODO: make upper layers use standard alpha
long* pLDst = (long*)pAlphaBits;
for( int i = nImageSize/sizeof(long); --i >= 0; ++pLDst )
*pLDst = ~*pLDst;
char* pCDst = (char*)pLDst;
for( int i = nImageSize & (sizeof(long)-1); --i >= 0; ++pCDst )
*pCDst = ~*pCDst;
const XRenderPictFormat* pAlphaFormat = rPeer.GetStandardFormatA8();
XImage* pAlphaImg = XCreateImage( pXDisplay, pSrcXVisual, 8, ZPixmap, 0,
pAlphaBits, pAlphaBuffer->mnWidth, pAlphaBuffer->mnHeight,
pAlphaFormat->depth, pAlphaBuffer->mnScanlineSize );
Pixmap aAlphaPM = XCreatePixmap( pXDisplay, hDrawable_,
rTR.mnDestWidth, rTR.mnDestHeight, 8 );
XGCValues aAlphaGCV;
aAlphaGCV.function = GXcopy;
GC aAlphaGC = XCreateGC( pXDisplay, aAlphaPM, GCFunction, &aAlphaGCV );
XPutImage( pXDisplay, aAlphaPM, aAlphaGC, pAlphaImg,
rTR.mnSrcX, rTR.mnSrcY, 0, 0, rTR.mnDestWidth, rTR.mnDestHeight );
XFreeGC( pXDisplay, aAlphaGC );
XFree( pAlphaImg );
if( pAlphaBits != (char*)pAlphaBuffer->mpBits )
delete[] pAlphaBits;
const_cast<SalBitmap&>(rAlphaBmp).ReleaseBuffer( pAlphaBuffer, sal_True );
XRenderPictureAttributes aAttr;
aAttr.repeat = true;
Picture aAlphaPic = rPeer.CreatePicture( aAlphaPM, pAlphaFormat, CPRepeat, &aAttr );
if( !aAlphaPic )
return false;
// set clipping
if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
rPeer.SetPictureClipRegion( aDstPic, mpClipRegion );
// paint source * mask over destination picture
rPeer.CompositePicture( PictOpOver, aSrcPic, aAlphaPic, aDstPic,
rTR.mnSrcX, rTR.mnSrcY, 0, 0,
rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight );
// TODO: used ScopedPic
rPeer.FreePicture( aAlphaPic );
XFreePixmap(pXDisplay, aAlphaPM);
rPeer.FreePicture( aSrcPic );
return true;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool X11SalGraphics::drawTransformedBitmap(
const basegfx::B2DPoint& rNull,
const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY,
const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap)
{
// here direct support for transformed bitmaps can be impemented
(void)rNull; (void)rX; (void)rY; (void)rSourceBitmap; (void)pAlphaBitmap;
return false;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
bool X11SalGraphics::drawAlphaRect( long nX, long nY, long nWidth,
long nHeight, sal_uInt8 nTransparency )
{
if( ! m_pFrame && ! m_pVDev )
return false;
if( bPenGC_ || !bBrushGC_ || bXORMode_ )
return false; // can only perform solid fills without XOR.
if( m_pVDev && m_pVDev->GetDepth() < 8 )
return false;
XRenderPeer& rPeer = XRenderPeer::GetInstance();
if( rPeer.GetVersion() < 0x02 ) // TODO: replace with better test
return false;
Picture aDstPic = GetXRenderPicture();
if( !aDstPic )
return false;
const double fTransparency = (100 - nTransparency) * (1.0/100);
const XRenderColor aRenderColor = GetXRenderColor( nBrushColor_ , fTransparency);
rPeer.FillRectangle( PictOpOver,
aDstPic,
&aRenderColor,
nX, nY,
nWidth, nHeight );
return true;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::drawBitmap( const SalTwoRect&,
const SalBitmap&,
SalColor )
{
DBG_ERROR( "::DrawBitmap with transparent color not supported" );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::drawMask( const SalTwoRect& rPosAry,
const SalBitmap &rSalBitmap,
SalColor nMaskColor )
{
const SalDisplay* pSalDisp = GetDisplay();
Display* pXDisp = pSalDisp->GetDisplay();
Drawable aDrawable( GetDrawable() );
Pixmap aStipple( XCreatePixmap( pXDisp, aDrawable,
rPosAry.mnDestWidth,
rPosAry.mnDestHeight, 1 ) );
if( aStipple )
{
SalTwoRect aTwoRect( rPosAry ); aTwoRect.mnDestX = aTwoRect.mnDestY = 0;
GC aTmpGC;
XGCValues aValues;
// create a stipple bitmap first (set bits are changed to unset bits and vice versa)
aValues.function = GXcopyInverted;
aValues.foreground = 1, aValues.background = 0;
aTmpGC = XCreateGC( pXDisp, aStipple, GCFunction | GCForeground | GCBackground, &aValues );
static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aStipple, m_nScreen, 1, aTwoRect, aTmpGC );
XFreeGC( pXDisp, aTmpGC );
// Set stipple and draw rectangle
GC aStippleGC( GetStippleGC() );
int nX = rPosAry.mnDestX, nY = rPosAry.mnDestY;
XSetStipple( pXDisp, aStippleGC, aStipple );
XSetTSOrigin( pXDisp, aStippleGC, nX, nY );
XSetForeground( pXDisp, aStippleGC, GetPixel( nMaskColor ) );
XFillRectangle( pXDisp, aDrawable, aStippleGC,
nX, nY,
rPosAry.mnDestWidth, rPosAry.mnDestHeight );
XFreePixmap( pXDisp, aStipple );
XFlush( pXDisp );
}
else
drawBitmap( rPosAry, rSalBitmap );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
SalBitmap *X11SalGraphics::getBitmap( long nX, long nY, long nDX, long nDY )
{
if( bPrinter_ && !bVirDev_ )
return NULL;
bool bFakeWindowBG = false;
// normalize
if( nDX < 0 )
{
nX += nDX;
nDX = -nDX;
}
if ( nDY < 0 )
{
nY += nDY;
nDY = -nDY;
}
if( bWindow_ && !bVirDev_ )
{
XWindowAttributes aAttrib;
XGetWindowAttributes( GetXDisplay(), GetDrawable(), &aAttrib );
if( aAttrib.map_state != IsViewable )
bFakeWindowBG = true;
else
{
long nOrgDX = nDX, nOrgDY = nDY;
// clip to window size
if ( nX < 0 )
{
nDX += nX;
nX = 0;
}
if ( nY < 0 )
{
nDY += nY;
nY = 0;
}
if( nX + nDX > aAttrib.width )
nDX = aAttrib.width - nX;
if( nY + nDY > aAttrib.height )
nDY = aAttrib.height - nY;
// inside ?
if( nDX <= 0 || nDY <= 0 )
{
bFakeWindowBG = true;
nDX = nOrgDX;
nDY = nOrgDY;
}
}
}
X11SalBitmap* pSalBitmap = new X11SalBitmap;
sal_uInt16 nBitCount = GetBitCount();
if( &GetDisplay()->GetColormap( m_nScreen ) != &GetColormap() )
nBitCount = 1;
if( ! bFakeWindowBG )
pSalBitmap->ImplCreateFromDrawable( GetDrawable(), m_nScreen, nBitCount, nX, nY, nDX, nDY );
else
pSalBitmap->Create( Size( nDX, nDY ), (nBitCount > 8) ? 24 : nBitCount, BitmapPalette( nBitCount > 8 ? nBitCount : 0 ) );
return pSalBitmap;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
SalColor X11SalGraphics::getPixel( long nX, long nY )
{
if( bWindow_ && !bVirDev_ )
{
XWindowAttributes aAttrib;
XGetWindowAttributes( GetXDisplay(), GetDrawable(), &aAttrib );
if( aAttrib.map_state != IsViewable )
{
stderr0( "X11SalGraphics::GetPixel drawable not viewable\n" );
return 0;
}
}
XImage *pXImage = XGetImage( GetXDisplay(),
GetDrawable(),
nX, nY,
1, 1,
AllPlanes,
ZPixmap );
if( !pXImage )
{
stderr0( "X11SalGraphics::GetPixel !XGetImage()\n" );
return 0;
}
XColor aXColor;
aXColor.pixel = XGetPixel( pXImage, 0, 0 );
XDestroyImage( pXImage );
return GetColormap().GetColor( aXColor.pixel );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void X11SalGraphics::invert( long nX,
long nY,
long nDX,
long nDY,
SalInvert nFlags )
{
GC pGC;
if( SAL_INVERT_50 & nFlags )
{
pGC = GetInvert50GC();
XFillRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY );
}
else
{
if ( SAL_INVERT_TRACKFRAME & nFlags )
{
pGC = GetTrackingGC();
XDrawRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY );
}
else
{
pGC = GetInvertGC();
XFillRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY );
}
}
}
bool X11SalGraphics::supportsOperation( OutDevSupportType eType ) const
{
bool bRet = false;
switch( eType )
{
case OutDevSupport_TransparentRect:
case OutDevSupport_B2DDraw:
{
XRenderPeer& rPeer = XRenderPeer::GetInstance();
if( rPeer.GetVersion() >= 0x02 )
{
const SalDisplay* pSalDisp = GetDisplay();
const SalVisual& rSalVis = pSalDisp->GetVisual( m_nScreen );
Visual* pDstXVisual = rSalVis.GetVisual();
XRenderPictFormat* pDstVisFmt = rPeer.FindVisualFormat( pDstXVisual );
if( pDstVisFmt )
bRet = true;
}
}
break;
default: break;
}
return bRet;
}