diff options
Diffstat (limited to 'vcl/unx/generic/gdi/salgdi2.cxx')
-rw-r--r-- | vcl/unx/generic/gdi/salgdi2.cxx | 1154 |
1 files changed, 1154 insertions, 0 deletions
diff --git a/vcl/unx/generic/gdi/salgdi2.cxx b/vcl/unx/generic/gdi/salgdi2.cxx new file mode 100644 index 000000000000..49dd7174d583 --- /dev/null +++ b/vcl/unx/generic/gdi/salgdi2.cxx @@ -0,0 +1,1154 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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" +#include "vcl/outdata.hxx" + +#undef SALGDI2_TESTTRANS + +// -=-= debugging =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +// ----------------------------------------------------------------------------- + +#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 *pPosAry, + SalGraphics *pSSrcGraphics ) +{ + X11SalGraphics* pSrcGraphics = pSSrcGraphics + ? static_cast<X11SalGraphics*>(pSSrcGraphics) + : this; + + if( pPosAry->mnSrcWidth <= 0 + || pPosAry->mnSrcHeight <= 0 + || pPosAry->mnDestWidth <= 0 + || pPosAry->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 + && pPosAry->mnSrcWidth == pPosAry->mnDestWidth + && pPosAry->mnSrcHeight == pPosAry->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 + pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, + pSrcGraphics->GetBitCount() ); + + pCopyGC = GetDisplay()->GetCopyGC( m_nScreen ); + + if( bNeedGraphicsExposures ) + XSetGraphicsExposures( GetXDisplay(), + pCopyGC, + True ); + + XCopyArea( GetXDisplay(), + pSrcGraphics->GetDrawable(), // source + hPixmap, // destination + pCopyGC, // no clipping + pPosAry->mnSrcX, pPosAry->mnSrcY, + pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, + 0, 0 ); // destination + XCopyArea( GetXDisplay(), + hPixmap, // source + GetDrawable(), // destination + GetInvertGC(), // destination clipping + 0, 0, // source + pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, + pPosAry->mnDestX, pPosAry->mnDestY ); + XFreePixmap( GetXDisplay(), hPixmap ); + } + else + { + pCopyGC = GetCopyGC(); + + if( bNeedGraphicsExposures ) + XSetGraphicsExposures( GetXDisplay(), + pCopyGC, + True ); + + XCopyArea( GetXDisplay(), + pSrcGraphics->GetDrawable(), // source + GetDrawable(), // destination + pCopyGC, // destination clipping + pPosAry->mnSrcX, pPosAry->mnSrcY, + pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, + pPosAry->mnDestX, pPosAry->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( pPosAry->mnSrcX, + pPosAry->mnSrcY, + pPosAry->mnSrcWidth, + pPosAry->mnSrcHeight ); + + if( !pDDB ) + { + stderr0( "SalGraphics::CopyBits !pSrcGraphics->GetBitmap()\n" ); + return; + } + + SalTwoRect aPosAry( *pPosAry ); + + 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* pPosAry, 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(); + + //fdo#33455 handle 1 bit depth pngs with palette entries + //to set fore/back colors + if (const BitmapBuffer* pBitmapBuffer = const_cast<SalBitmap&>(rSalBitmap).AcquireBuffer(true)) + { + const BitmapPalette& rPalette = pBitmapBuffer->maPalette; + if (rPalette.GetEntryCount() == 2) + { + aNewVal.foreground = rColMap.GetPixel(ImplColorToSal(rPalette[0])); + aNewVal.background = rColMap.GetPixel(ImplColorToSal(rPalette[1])); + } + } + + XChangeGC( pXDisp, aGC, nValues, &aNewVal ); + } + + static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aDrawable, m_nScreen, nDepth, *pPosAry, aGC ); + + if( rSalBitmap.GetBitCount() == 1 ) + XChangeGC( pXDisp, aGC, nValues, &aOldVal ); + XFlush( pXDisp ); +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +void X11SalGraphics::drawBitmap( const SalTwoRect* pPosAry, + 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( *pPosAry, rSrcBitmap, rMaskBitmap ); + } + + drawMaskedBitmap( pPosAry, rSrcBitmap, rMaskBitmap ); +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +void X11SalGraphics::drawMaskedBitmap( const SalTwoRect* pPosAry, + 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, pPosAry->mnDestWidth, + pPosAry->mnDestHeight, nDepth ) ); + Pixmap aBG( XCreatePixmap( pXDisp, aDrawable, pPosAry->mnDestWidth, + pPosAry->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( *pPosAry ); 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, + pPosAry->mnDestX, pPosAry->mnDestY, + pPosAry->mnDestWidth, pPosAry->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, + pPosAry->mnDestWidth, pPosAry->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, + pPosAry->mnDestWidth, pPosAry->mnDestHeight, + pPosAry->mnDestX, pPosAry->mnDestY ); + + DBG_TESTTRANS( aBG ); + + bXORMode_ = bOldXORMode; + + XFreeGC( pXDisp, aTmpGC ); + XFlush( pXDisp ); + } + else + drawBitmap( pPosAry, 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::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 ) +{ + OSL_FAIL( "::DrawBitmap with transparent color not supported" ); +} + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +void X11SalGraphics::drawMask( const SalTwoRect* pPosAry, + const SalBitmap &rSalBitmap, + SalColor nMaskColor ) +{ + const SalDisplay* pSalDisp = GetDisplay(); + Display* pXDisp = pSalDisp->GetDisplay(); + Drawable aDrawable( GetDrawable() ); + Pixmap aStipple( XCreatePixmap( pXDisp, aDrawable, + pPosAry->mnDestWidth, + pPosAry->mnDestHeight, 1 ) ); + + if( aStipple ) + { + SalTwoRect aTwoRect( *pPosAry ); 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 = pPosAry->mnDestX, nY = pPosAry->mnDestY; + + XSetStipple( pXDisp, aStippleGC, aStipple ); + XSetTSOrigin( pXDisp, aStippleGC, nX, nY ); + XSetForeground( pXDisp, aStippleGC, GetPixel( nMaskColor ) ); + XFillRectangle( pXDisp, aDrawable, aStippleGC, + nX, nY, + pPosAry->mnDestWidth, pPosAry->mnDestHeight ); + XFreePixmap( pXDisp, aStipple ); + XFlush( pXDisp ); + } + else + drawBitmap( pPosAry, 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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |