You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2477 lines
69 KiB
2477 lines
69 KiB
/****************************************************************************
|
|
**
|
|
** Implementation of TQPixmap class for X11
|
|
**
|
|
** Created : 940501
|
|
**
|
|
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
|
|
**
|
|
** This file is part of the kernel module of the TQt GUI Toolkit.
|
|
**
|
|
** This file may be used under the terms of the GNU General
|
|
** Public License versions 2.0 or 3.0 as published by the Free
|
|
** Software Foundation and appearing in the files LICENSE.GPL2
|
|
** and LICENSE.GPL3 included in the packaging of this file.
|
|
** Alternatively you may (at your option) use any later version
|
|
** of the GNU General Public License if such license has been
|
|
** publicly approved by Trolltech ASA (or its successors, if any)
|
|
** and the KDE Free TQt Foundation.
|
|
**
|
|
** Please review the following information to ensure GNU General
|
|
** Public Licensing requirements will be met:
|
|
** http://trolltech.com/products/qt/licenses/licensing/opensource/.
|
|
** If you are unsure which license is appropriate for your use, please
|
|
** review the following information:
|
|
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
|
|
** or contact the sales department at sales@trolltech.com.
|
|
**
|
|
** This file may be used under the terms of the Q Public License as
|
|
** defined by Trolltech ASA and appearing in the file LICENSE.TQPL
|
|
** included in the packaging of this file. Licensees holding valid TQt
|
|
** Commercial licenses may use this file in accordance with the TQt
|
|
** Commercial License Agreement provided with the Software.
|
|
**
|
|
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
|
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
|
** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
|
|
** herein.
|
|
**
|
|
**********************************************************************/
|
|
|
|
// NOT REVISED
|
|
|
|
#include "qplatformdefs.h"
|
|
|
|
#if defined(Q_OS_WIN32) && defined(QT_MITSHM)
|
|
#undef QT_MITSHM
|
|
#endif
|
|
|
|
#ifdef QT_MITSHM
|
|
|
|
// Use the MIT Shared Memory extension for pixmap<->image conversions
|
|
#define QT_MITSHM_CONVERSIONS
|
|
|
|
// Uncomment the next line to enable the MIT Shared Memory extension
|
|
// for TQPixmap::xForm()
|
|
//
|
|
// WARNING: This has some problems:
|
|
//
|
|
// 1. Consumes a 800x600 pixmap
|
|
// 2. TQt does not handle the ShmCompletion message, so you will
|
|
// get strange effects if you xForm() repeatedly.
|
|
//
|
|
// #define QT_MITSHM_XFORM
|
|
|
|
#else
|
|
#undef QT_MITSHM_CONVERSIONS
|
|
#undef QT_MITSHM_XFORM
|
|
#endif
|
|
|
|
#include "ntqbitmap.h"
|
|
#include "ntqpaintdevicemetrics.h"
|
|
#include "ntqimage.h"
|
|
#include "ntqwmatrix.h"
|
|
#include "ntqapplication.h"
|
|
#include "qt_x11_p.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#if defined(Q_CC_MIPS)
|
|
# define for if(0){}else for
|
|
#endif
|
|
|
|
|
|
/*!
|
|
\class TQPixmap::TQPixmapData
|
|
\brief The TQPixmap::TQPixmapData class is an internal class.
|
|
\internal
|
|
*/
|
|
|
|
|
|
// For thread-safety:
|
|
// image->data does not belong to X11, so we must free it ourselves.
|
|
|
|
inline static void qSafeXDestroyImage( XImage *x )
|
|
{
|
|
if ( x->data ) {
|
|
free( x->data );
|
|
x->data = 0;
|
|
}
|
|
XDestroyImage( x );
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
MIT Shared Memory Extension support: makes xForm noticeably (~20%) faster.
|
|
*****************************************************************************/
|
|
|
|
#if defined(QT_MITSHM_XFORM)
|
|
|
|
static bool xshminit = FALSE;
|
|
static XShmSegmentInfo xshminfo;
|
|
static XImage *xshmimg = 0;
|
|
static Pixmap xshmpm = 0;
|
|
|
|
static void tqt_cleanup_mitshm()
|
|
{
|
|
if ( xshmimg == 0 )
|
|
return;
|
|
Display *dpy = TQPaintDevice::x11AppDisplay();
|
|
if ( xshmpm ) {
|
|
XFreePixmap( dpy, xshmpm );
|
|
xshmpm = 0;
|
|
}
|
|
XShmDetach( dpy, &xshminfo ); xshmimg->data = 0;
|
|
qSafeXDestroyImage( xshmimg ); xshmimg = 0;
|
|
shmdt( xshminfo.shmaddr );
|
|
shmctl( xshminfo.shmid, IPC_RMID, 0 );
|
|
}
|
|
|
|
|
|
static bool qt_create_mitshm_buffer( const TQPaintDevice* dev, int w, int h )
|
|
{
|
|
static int major, minor;
|
|
static Bool pixmaps_ok;
|
|
Display *dpy = dev->x11Display();
|
|
int dd = dev->x11Depth();
|
|
Visual *vis = (Visual*)dev->x11Visual();
|
|
|
|
if ( xshminit ) {
|
|
tqt_cleanup_mitshm();
|
|
} else {
|
|
if ( !XShmQueryVersion(dpy, &major, &minor, &pixmaps_ok) )
|
|
return FALSE; // MIT Shm not supported
|
|
tqAddPostRoutine( tqt_cleanup_mitshm );
|
|
xshminit = TRUE;
|
|
}
|
|
|
|
xshmimg = XShmCreateImage( dpy, vis, dd, ZPixmap, 0, &xshminfo, w, h );
|
|
if ( !xshmimg )
|
|
return FALSE;
|
|
|
|
bool ok;
|
|
xshminfo.shmid = shmget( IPC_PRIVATE,
|
|
xshmimg->bytes_per_line * xshmimg->height,
|
|
IPC_CREAT | 0777 );
|
|
ok = xshminfo.shmid != -1;
|
|
if ( ok ) {
|
|
xshmimg->data = (char*)shmat( xshminfo.shmid, 0, 0 );
|
|
xshminfo.shmaddr = xshmimg->data;
|
|
ok = ( xshminfo.shmaddr != (char*)-1 );
|
|
}
|
|
xshminfo.readOnly = FALSE;
|
|
if ( ok )
|
|
ok = XShmAttach( dpy, &xshminfo );
|
|
if ( !ok ) {
|
|
qSafeXDestroyImage( xshmimg );
|
|
xshmimg = 0;
|
|
if ( xshminfo.shmaddr )
|
|
shmdt( xshminfo.shmaddr );
|
|
if ( xshminfo.shmid != -1 )
|
|
shmctl( xshminfo.shmid, IPC_RMID, 0 );
|
|
return FALSE;
|
|
}
|
|
if ( pixmaps_ok )
|
|
xshmpm = XShmCreatePixmap( dpy, DefaultRootWindow(dpy), xshmimg->data,
|
|
&xshminfo, w, h, dd );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#else
|
|
|
|
// If extern, need a dummy.
|
|
//
|
|
// static bool qt_create_mitshm_buffer( TQPaintDevice*, int, int )
|
|
// {
|
|
// return FALSE;
|
|
// }
|
|
|
|
#endif // QT_MITSHM_XFORM
|
|
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
|
|
static bool qt_mitshm_error = false;
|
|
static int qt_mitshm_errorhandler( Display*, XErrorEvent* )
|
|
{
|
|
qt_mitshm_error = true;
|
|
return 0;
|
|
}
|
|
|
|
static XImage* qt_XShmCreateImage( Display* dpy, Visual* visual, unsigned int depth,
|
|
int format, int /*offset*/, char* /*data*/, unsigned int width, unsigned int height,
|
|
int /*bitmap_pad*/, int /*bytes_per_line*/, XShmSegmentInfo* shminfo )
|
|
{
|
|
if( width * height * depth < 100*100*32 )
|
|
return NULL;
|
|
static int shm_inited = -1;
|
|
if( shm_inited == -1 ) {
|
|
if( XShmQueryExtension( dpy ))
|
|
shm_inited = 1;
|
|
else
|
|
shm_inited = 0;
|
|
}
|
|
if( shm_inited == 0 )
|
|
return NULL;
|
|
XImage* xi = XShmCreateImage( dpy, visual, depth, format, NULL, shminfo, width,
|
|
height );
|
|
if( xi == NULL )
|
|
return NULL;
|
|
shminfo->shmid = shmget( IPC_PRIVATE, xi->bytes_per_line * xi->height,
|
|
IPC_CREAT|0600);
|
|
if( shminfo->shmid < 0 ) {
|
|
XDestroyImage( xi );
|
|
return NULL;
|
|
}
|
|
shminfo->readOnly = False;
|
|
shminfo->shmaddr = (char*)shmat( shminfo->shmid, 0, 0 );
|
|
if( shminfo->shmaddr == (char*)-1 ) {
|
|
XDestroyImage( xi );
|
|
shmctl( shminfo->shmid, IPC_RMID, 0 );
|
|
return NULL;
|
|
}
|
|
xi->data = shminfo->shmaddr;
|
|
#ifndef QT_MITSHM_RMID_IGNORES_REFCOUNT
|
|
// mark as deleted to automatically free the memory in case
|
|
// of a crash (but this doesn't work e.g. on Solaris)
|
|
shmctl( shminfo->shmid, IPC_RMID, 0 );
|
|
#endif
|
|
if( shm_inited == 1 ) { // first time
|
|
XErrorHandler old_h = XSetErrorHandler( qt_mitshm_errorhandler );
|
|
XShmAttach( dpy, shminfo );
|
|
shm_inited = 2;
|
|
XSync( dpy, False );
|
|
XSetErrorHandler( old_h );
|
|
if( qt_mitshm_error ) { // oops ... perhaps we are remote?
|
|
shm_inited = 0;
|
|
XDestroyImage( xi );
|
|
shmdt( shminfo->shmaddr );
|
|
#ifdef QT_MITSHM_RMID_IGNORES_REFCOUNT
|
|
shmctl( shminfo->shmid, IPC_RMID, 0 );
|
|
#endif
|
|
return NULL;
|
|
}
|
|
} else
|
|
XShmAttach( dpy, shminfo );
|
|
return xi;
|
|
}
|
|
|
|
static void qt_XShmDestroyImage( XImage* xi, XShmSegmentInfo* shminfo )
|
|
{
|
|
XShmDetach( TQPaintDevice::x11AppDisplay(), shminfo );
|
|
XDestroyImage( xi );
|
|
shmdt( shminfo->shmaddr );
|
|
#ifdef QT_MITSHM_RMID_IGNORES_REFCOUNT
|
|
shmctl( shminfo->shmid, IPC_RMID, 0 );
|
|
#endif
|
|
}
|
|
|
|
static XImage* qt_XShmGetImage( const TQPixmap* pix, int format,
|
|
XShmSegmentInfo* shminfo )
|
|
{
|
|
XImage* xi = qt_XShmCreateImage( pix->x11Display(), (Visual*)pix->x11Visual(),
|
|
pix->depth(), format, 0, 0, pix->width(), pix->height(), 32, 0, shminfo );
|
|
if( xi == NULL )
|
|
return NULL;
|
|
if( XShmGetImage( pix->x11Display(), pix->handle(), xi, 0, 0, AllPlanes ) == False ) {
|
|
qt_XShmDestroyImage( xi, shminfo );
|
|
return NULL;
|
|
}
|
|
return xi;
|
|
}
|
|
|
|
#endif // QT_MITSHM_CONVERSIONS
|
|
|
|
/*****************************************************************************
|
|
Internal functions
|
|
*****************************************************************************/
|
|
|
|
extern const uchar *qt_get_bitflip_array(); // defined in qimage.cpp
|
|
|
|
static uchar *flip_bits( const uchar *bits, int len )
|
|
{
|
|
register const uchar *p = bits;
|
|
const uchar *end = p + len;
|
|
uchar *newdata = new uchar[len];
|
|
uchar *b = newdata;
|
|
const uchar *f = qt_get_bitflip_array();
|
|
while ( p < end )
|
|
*b++ = f[*p++];
|
|
return newdata;
|
|
}
|
|
|
|
// Returns position of highest bit set or -1 if none
|
|
static int highest_bit( uint v )
|
|
{
|
|
int i;
|
|
uint b = (uint)1 << 31;
|
|
for ( i=31; ((b & v) == 0) && i>=0; i-- )
|
|
b >>= 1;
|
|
return i;
|
|
}
|
|
|
|
// Returns position of lowest set bit in 'v' as an integer (0-31), or -1
|
|
static int lowest_bit( uint v )
|
|
{
|
|
int i;
|
|
ulong lb;
|
|
lb = 1;
|
|
for (i=0; ((v & lb) == 0) && i<32; i++, lb<<=1);
|
|
return i==32 ? -1 : i;
|
|
}
|
|
|
|
// Counts the number of bits set in 'v'
|
|
static uint n_bits( uint v )
|
|
{
|
|
int i = 0;
|
|
while ( v ) {
|
|
v = v & (v - 1);
|
|
i++;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
static uint *red_scale_table = 0;
|
|
static uint *green_scale_table = 0;
|
|
static uint *blue_scale_table = 0;
|
|
|
|
static void cleanup_scale_tables()
|
|
{
|
|
delete[] red_scale_table;
|
|
delete[] green_scale_table;
|
|
delete[] blue_scale_table;
|
|
}
|
|
|
|
/*
|
|
Could do smart bitshifting, but the "obvious" algorithm only works for
|
|
nBits >= 4. This is more robust.
|
|
*/
|
|
static void build_scale_table( uint **table, uint nBits )
|
|
{
|
|
if ( nBits > 7 ) {
|
|
#if defined(QT_CHECK_RANGE)
|
|
tqWarning( "build_scale_table: internal error, nBits = %i", nBits );
|
|
#endif
|
|
return;
|
|
}
|
|
if (!*table) {
|
|
static bool firstTable = TRUE;
|
|
if ( firstTable ) {
|
|
tqAddPostRoutine( cleanup_scale_tables );
|
|
firstTable = FALSE;
|
|
}
|
|
*table = new uint[256];
|
|
}
|
|
int maxVal = (1 << nBits) - 1;
|
|
int valShift = 8 - nBits;
|
|
int i;
|
|
for( i = 0 ; i < maxVal + 1 ; i++ )
|
|
(*table)[i << valShift] = i*255/maxVal;
|
|
}
|
|
|
|
static int defaultScreen = -1;
|
|
|
|
extern bool tqt_use_xrender; // defined in qapplication_x11.cpp
|
|
extern bool tqt_has_xft; // defined in qfont_x11.cpp
|
|
|
|
#ifndef QT_NO_XFTFREETYPE
|
|
#ifndef QT_XFT2
|
|
// Xft1 doesn't have XftDrawCreateAlpha, so we fake it in qtaddons_x11.cpp
|
|
extern "C" XftDraw *XftDrawCreateAlpha( Display *, TQt::HANDLE, int );
|
|
#endif // QT_XFT2
|
|
#endif // QT_NO_XFTFREETYPE
|
|
|
|
/*****************************************************************************
|
|
TQPixmap member functions
|
|
*****************************************************************************/
|
|
|
|
/*!
|
|
\internal
|
|
Initializes the pixmap data.
|
|
*/
|
|
|
|
void TQPixmap::init( int w, int h, int d, bool bitmap, Optimization optim )
|
|
{
|
|
#if defined(QT_CHECK_STATE)
|
|
if ( tqApp->type() == TQApplication::Tty ) {
|
|
tqWarning( "TQPixmap: Cannot create a TQPixmap when no GUI "
|
|
"is being used" );
|
|
}
|
|
#endif
|
|
|
|
static int serial = 0;
|
|
|
|
if ( defaultScreen >= 0 && defaultScreen != x11Screen() ) {
|
|
TQPaintDeviceX11Data* xd = getX11Data( TRUE );
|
|
xd->x_screen = defaultScreen;
|
|
xd->x_depth = TQPaintDevice::x11AppDepth( xd->x_screen );
|
|
xd->x_cells = TQPaintDevice::x11AppCells( xd->x_screen );
|
|
xd->x_colormap = TQPaintDevice::x11AppColormap( xd->x_screen );
|
|
xd->x_defcolormap = TQPaintDevice::x11AppDefaultColormap( xd->x_screen );
|
|
xd->x_visual = TQPaintDevice::x11AppVisual( xd->x_screen );
|
|
xd->x_defvisual = TQPaintDevice::x11AppDefaultVisual( xd->x_screen );
|
|
setX11Data( xd );
|
|
}
|
|
|
|
int dd = x11Depth();
|
|
|
|
if ( d != -1 )
|
|
dd = d;
|
|
|
|
if ( optim == DefaultOptim ) // use default optimization
|
|
optim = defOptim;
|
|
|
|
data = new TQPixmapData;
|
|
TQ_CHECK_PTR( data );
|
|
|
|
memset( data, 0, sizeof(TQPixmapData) );
|
|
data->count = 1;
|
|
data->uninit = TRUE;
|
|
data->bitmap = bitmap;
|
|
data->ser_no = ++serial;
|
|
data->optim = optim;
|
|
|
|
bool make_null = w == 0 || h == 0; // create null pixmap
|
|
if ( d == 1 ) // monocrome pixmap
|
|
data->d = 1;
|
|
else if ( d < 0 || d == dd ) // def depth pixmap
|
|
data->d = dd;
|
|
if ( make_null || w < 0 || h < 0 || data->d == 0 ) {
|
|
hd = 0;
|
|
rendhd = 0;
|
|
#if defined(QT_CHECK_RANGE)
|
|
if ( !make_null )
|
|
tqWarning( "TQPixmap: Invalid pixmap parameters" );
|
|
#endif
|
|
return;
|
|
}
|
|
data->w = w;
|
|
data->h = h;
|
|
hd = (HANDLE)XCreatePixmap( x11Display(), RootWindow(x11Display(), x11Screen() ),
|
|
w, h, data->d );
|
|
|
|
#ifndef QT_NO_XFTFREETYPE
|
|
if ( tqt_has_xft ) {
|
|
if ( data->d == 1 ) {
|
|
rendhd = (HANDLE) XftDrawCreateBitmap( x11Display(), hd );
|
|
} else {
|
|
rendhd = (HANDLE) XftDrawCreate( x11Display(), hd,
|
|
(Visual *) x11Visual(),
|
|
x11Colormap() );
|
|
}
|
|
}
|
|
#endif // QT_NO_XFTFREETYPE
|
|
|
|
}
|
|
|
|
|
|
void TQPixmap::deref()
|
|
{
|
|
if ( data && data->deref() ) { // last reference lost
|
|
delete data->mask;
|
|
delete data->alphapm;
|
|
if ( data->ximage )
|
|
qSafeXDestroyImage( (XImage*)data->ximage );
|
|
if ( data->maskgc )
|
|
XFreeGC( x11Display(), (GC)data->maskgc );
|
|
if ( tqApp && hd) {
|
|
|
|
#ifndef QT_NO_XFTFREETYPE
|
|
if (rendhd) {
|
|
XftDrawDestroy( (XftDraw *) rendhd );
|
|
rendhd = 0;
|
|
}
|
|
#endif // QT_NO_XFTFREETYPE
|
|
|
|
XFreePixmap( x11Display(), hd );
|
|
hd = 0;
|
|
}
|
|
delete data;
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
Constructs a monochrome pixmap, with width \a w and height \a h,
|
|
that is initialized with the data in \a bits. The \a isXbitmap
|
|
indicates whether the data is an X bitmap and defaults to FALSE.
|
|
This constructor is protected and used by the TQBitmap class.
|
|
*/
|
|
|
|
TQPixmap::TQPixmap( int w, int h, const uchar *bits, bool isXbitmap)
|
|
: TQPaintDevice( TQInternal::Pixmap )
|
|
{ // for bitmaps only
|
|
init( 0, 0, 0, FALSE, defOptim );
|
|
if ( w <= 0 || h <= 0 ) // create null pixmap
|
|
return;
|
|
|
|
data->uninit = FALSE;
|
|
data->w = w;
|
|
data->h = h;
|
|
data->d = 1;
|
|
uchar *flipped_bits;
|
|
if ( isXbitmap ) {
|
|
flipped_bits = 0;
|
|
} else { // not X bitmap -> flip bits
|
|
flipped_bits = flip_bits( bits, ((w+7)/8)*h );
|
|
bits = flipped_bits;
|
|
}
|
|
hd = (HANDLE)XCreateBitmapFromData( x11Display(),
|
|
RootWindow(x11Display(), x11Screen() ),
|
|
(char *)bits, w, h );
|
|
|
|
#ifndef QT_NO_XFTFREETYPE
|
|
if ( tqt_has_xft )
|
|
rendhd = (HANDLE) XftDrawCreateBitmap (x11Display (), hd);
|
|
#endif // QT_NO_XFTFREETYPE
|
|
|
|
if ( flipped_bits ) // Avoid purify complaint
|
|
delete [] flipped_bits;
|
|
}
|
|
|
|
|
|
/*!
|
|
This is a special-purpose function that detaches the pixmap from
|
|
shared pixmap data.
|
|
|
|
A pixmap is automatically detached by TQt whenever its contents is
|
|
about to change. This is done in all TQPixmap member functions
|
|
that modify the pixmap (fill(), resize(), convertFromImage(),
|
|
load(), etc.), in bitBlt() for the destination pixmap and in
|
|
TQPainter::begin() on a pixmap.
|
|
|
|
It is possible to modify a pixmap without letting TQt know. You can
|
|
first obtain the system-dependent handle() and then call
|
|
system-specific functions (for instance, BitBlt under Windows)
|
|
that modify the pixmap contents. In such cases, you can call
|
|
detach() to cut the pixmap loose from other pixmaps that share
|
|
data with this one.
|
|
|
|
detach() returns immediately if there is just a single reference
|
|
or if the pixmap has not been initialized yet.
|
|
*/
|
|
|
|
void TQPixmap::detach()
|
|
{
|
|
if ( data->count != 1 )
|
|
*this = copy();
|
|
data->uninit = FALSE;
|
|
|
|
// reset cached data
|
|
if ( data->ximage ) {
|
|
qSafeXDestroyImage( (XImage*)data->ximage );
|
|
data->ximage = 0;
|
|
}
|
|
if ( data->maskgc ) {
|
|
XFreeGC( x11Display(), (GC)data->maskgc );
|
|
data->maskgc = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
Returns the default pixmap depth, i.e. the depth a pixmap gets if
|
|
-1 is specified.
|
|
|
|
\sa depth()
|
|
*/
|
|
|
|
int TQPixmap::defaultDepth()
|
|
{
|
|
return x11AppDepth();
|
|
}
|
|
|
|
|
|
/*!
|
|
\fn TQPixmap::Optimization TQPixmap::optimization() const
|
|
|
|
Returns the optimization setting for this pixmap.
|
|
|
|
The default optimization setting is \c TQPixmap::NormalOptim. You
|
|
can change this setting in two ways:
|
|
\list
|
|
\i Call setDefaultOptimization() to set the default optimization
|
|
for all new pixmaps.
|
|
\i Call setOptimization() to set the optimization for individual
|
|
pixmaps.
|
|
\endlist
|
|
|
|
\sa setOptimization(), setDefaultOptimization(), defaultOptimization()
|
|
*/
|
|
|
|
/*!
|
|
Sets pixmap drawing optimization for this pixmap.
|
|
|
|
The \a optimization setting affects pixmap operations, in
|
|
particular drawing of transparent pixmaps (bitBlt() a pixmap with
|
|
a mask set) and pixmap transformations (the xForm() function).
|
|
|
|
Pixmap optimization involves keeping intermediate results in a
|
|
cache buffer and using the cache to speed up bitBlt() and xForm().
|
|
The cost is more memory consumption, up to twice as much as an
|
|
unoptimized pixmap.
|
|
|
|
Use the setDefaultOptimization() to change the default
|
|
optimization for all new pixmaps.
|
|
|
|
\sa optimization(), setDefaultOptimization(), defaultOptimization()
|
|
*/
|
|
|
|
void TQPixmap::setOptimization( Optimization optimization )
|
|
{
|
|
if ( optimization == data->optim )
|
|
return;
|
|
detach();
|
|
data->optim = optimization == DefaultOptim ?
|
|
defOptim : optimization;
|
|
if ( data->optim == MemoryOptim && data->ximage ) {
|
|
qSafeXDestroyImage( (XImage*)data->ximage );
|
|
data->ximage = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
Fills the pixmap with the color \a fillColor.
|
|
*/
|
|
|
|
void TQPixmap::fill( const TQColor &fillColor )
|
|
{
|
|
if ( isNull() )
|
|
return;
|
|
detach(); // detach other references
|
|
GC gc = tqt_xget_temp_gc( x11Screen(), depth()==1 );
|
|
XSetForeground( x11Display(), gc, fillColor.pixel(x11Screen()) );
|
|
XFillRectangle( x11Display(), hd, gc, 0, 0, width(), height() );
|
|
}
|
|
|
|
|
|
/*!
|
|
Internal implementation of the virtual TQPaintDevice::metric() function.
|
|
|
|
Use the TQPaintDeviceMetrics class instead.
|
|
|
|
\a m is the metric to get.
|
|
*/
|
|
|
|
int TQPixmap::metric( int m ) const
|
|
{
|
|
int val;
|
|
if ( m == TQPaintDeviceMetrics::PdmWidth )
|
|
val = width();
|
|
else if ( m == TQPaintDeviceMetrics::PdmHeight ) {
|
|
val = height();
|
|
} else {
|
|
Display *dpy = x11Display();
|
|
int scr = x11Screen();
|
|
switch ( m ) {
|
|
case TQPaintDeviceMetrics::PdmDpiX:
|
|
case TQPaintDeviceMetrics::PdmPhysicalDpiX:
|
|
val = TQPaintDevice::x11AppDpiX( scr );
|
|
break;
|
|
case TQPaintDeviceMetrics::PdmDpiY:
|
|
case TQPaintDeviceMetrics::PdmPhysicalDpiY:
|
|
val = TQPaintDevice::x11AppDpiY( scr );
|
|
break;
|
|
case TQPaintDeviceMetrics::PdmWidthMM:
|
|
val = (DisplayWidthMM(dpy,scr)*width())/
|
|
DisplayWidth(dpy,scr);
|
|
break;
|
|
case TQPaintDeviceMetrics::PdmHeightMM:
|
|
val = (DisplayHeightMM(dpy,scr)*height())/
|
|
DisplayHeight(dpy,scr);
|
|
break;
|
|
case TQPaintDeviceMetrics::PdmNumColors:
|
|
val = 1 << depth();
|
|
break;
|
|
case TQPaintDeviceMetrics::PdmDepth:
|
|
val = depth();
|
|
break;
|
|
default:
|
|
val = 0;
|
|
#if defined(QT_CHECK_RANGE)
|
|
tqWarning( "TQPixmap::metric: Invalid metric command" );
|
|
#endif
|
|
}
|
|
}
|
|
return val;
|
|
}
|
|
|
|
/*!
|
|
Converts the pixmap to a TQImage. Returns a null image if it fails.
|
|
|
|
If the pixmap has 1-bit depth, the returned image will also be 1
|
|
bit deep. If the pixmap has 2- to 8-bit depth, the returned image
|
|
has 8-bit depth. If the pixmap has greater than 8-bit depth, the
|
|
returned image has 32-bit depth.
|
|
|
|
Note that for the moment, alpha masks on monochrome images are
|
|
ignored.
|
|
|
|
\sa convertFromImage()
|
|
*/
|
|
|
|
TQImage TQPixmap::convertToImage() const
|
|
{
|
|
TQImage image;
|
|
if ( isNull() )
|
|
return image; // null image
|
|
|
|
int w = width();
|
|
int h = height();
|
|
int d = depth();
|
|
bool mono = d == 1;
|
|
Visual *visual = (Visual *)x11Visual();
|
|
bool trucol = (visual->c_class == TrueColor || visual->c_class == DirectColor) && !mono && d > 8;
|
|
|
|
if ( d > 1 && d <= 8 ) // set to nearest valid depth
|
|
d = 8; // 2..8 ==> 8
|
|
// we could run into the situation where d == 8 AND trucol is true, which can
|
|
// cause problems when converting to and from images. in this case, always treat
|
|
// the depth as 32... from Klaus Schmidinger and qt-bugs/arc-15/31333.
|
|
if ( d > 8 || trucol )
|
|
d = 32; // > 8 ==> 32
|
|
|
|
XImage *xi = (XImage *)data->ximage; // any cached ximage?
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
bool mitshm_ximage = false;
|
|
XShmSegmentInfo shminfo;
|
|
#endif
|
|
if ( !xi ) { // fetch data from X server
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
xi = qt_XShmGetImage( this, mono ? XYPixmap : ZPixmap, &shminfo );
|
|
if( xi ) {
|
|
mitshm_ximage = true;
|
|
} else
|
|
#endif
|
|
xi = XGetImage( x11Display(), hd, 0, 0, w, h, AllPlanes,
|
|
mono ? XYPixmap : ZPixmap );
|
|
}
|
|
TQ_CHECK_PTR( xi );
|
|
if (!xi)
|
|
return image; // null image
|
|
|
|
TQImage::Endian bitOrder = TQImage::IgnoreEndian;
|
|
if ( mono ) {
|
|
bitOrder = xi->bitmap_bit_order == LSBFirst ?
|
|
TQImage::LittleEndian : TQImage::BigEndian;
|
|
}
|
|
image.create( w, h, d, 0, bitOrder );
|
|
if ( image.isNull() ) { // could not create image
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
if( mitshm_ximage )
|
|
qt_XShmDestroyImage( xi, &shminfo );
|
|
else
|
|
#endif
|
|
qSafeXDestroyImage( xi );
|
|
return image;
|
|
}
|
|
|
|
const TQPixmap* msk = mask();
|
|
const TQPixmap *alf = data->alphapm;
|
|
|
|
TQImage alpha;
|
|
if (alf) {
|
|
XImage* axi;
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
bool mitshm_aximage = false;
|
|
XShmSegmentInfo ashminfo;
|
|
axi = qt_XShmGetImage( alf, ZPixmap, &ashminfo );
|
|
if( axi ) {
|
|
mitshm_aximage = true;
|
|
} else
|
|
#endif
|
|
axi = XGetImage(x11Display(), alf->hd, 0, 0, w, h, AllPlanes, ZPixmap);
|
|
|
|
if (axi) {
|
|
image.setAlphaBuffer( TRUE );
|
|
alpha.create(w, h, 8);
|
|
|
|
// copy each scanline
|
|
char *src = axi->data;
|
|
int bpl = TQMIN(alpha.bytesPerLine(), axi->bytes_per_line);
|
|
for (int y = 0; y < h; y++ ) {
|
|
memcpy( alpha.scanLine(y), src, bpl );
|
|
src += axi->bytes_per_line;
|
|
}
|
|
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
if( mitshm_aximage )
|
|
qt_XShmDestroyImage( axi, &ashminfo );
|
|
else
|
|
#endif
|
|
qSafeXDestroyImage( axi );
|
|
}
|
|
} else if (msk) {
|
|
image.setAlphaBuffer( TRUE );
|
|
alpha = msk->convertToImage();
|
|
}
|
|
bool ale = alpha.bitOrder() == TQImage::LittleEndian;
|
|
|
|
if ( trucol ) { // truecolor
|
|
const uint red_mask = (uint)visual->red_mask;
|
|
const uint green_mask = (uint)visual->green_mask;
|
|
const uint blue_mask = (uint)visual->blue_mask;
|
|
const int red_shift = highest_bit( red_mask ) - 7;
|
|
const int green_shift = highest_bit( green_mask ) - 7;
|
|
const int blue_shift = highest_bit( blue_mask ) - 7;
|
|
|
|
const uint red_bits = n_bits( red_mask );
|
|
const uint green_bits = n_bits( green_mask );
|
|
const uint blue_bits = n_bits( blue_mask );
|
|
|
|
static uint red_table_bits = 0;
|
|
static uint green_table_bits = 0;
|
|
static uint blue_table_bits = 0;
|
|
|
|
if ( red_bits < 8 && red_table_bits != red_bits) {
|
|
build_scale_table( &red_scale_table, red_bits );
|
|
red_table_bits = red_bits;
|
|
}
|
|
if ( blue_bits < 8 && blue_table_bits != blue_bits) {
|
|
build_scale_table( &blue_scale_table, blue_bits );
|
|
blue_table_bits = blue_bits;
|
|
}
|
|
if ( green_bits < 8 && green_table_bits != green_bits) {
|
|
build_scale_table( &green_scale_table, green_bits );
|
|
green_table_bits = green_bits;
|
|
}
|
|
|
|
int r, g, b;
|
|
|
|
TQRgb *dst;
|
|
uchar *src;
|
|
uint pixel;
|
|
int bppc = xi->bits_per_pixel;
|
|
|
|
if ( bppc > 8 && xi->byte_order == LSBFirst )
|
|
bppc++;
|
|
|
|
for ( int y=0; y<h; y++ ) {
|
|
uchar* asrc = alf || msk ? alpha.scanLine( y ) : 0;
|
|
dst = (TQRgb *)image.scanLine( y );
|
|
src = (uchar *)xi->data + xi->bytes_per_line*y;
|
|
for ( int x=0; x<w; x++ ) {
|
|
switch ( bppc ) {
|
|
case 8:
|
|
pixel = *src++;
|
|
break;
|
|
case 16: // 16 bit MSB
|
|
pixel = src[1] | (ushort)src[0] << 8;
|
|
src += 2;
|
|
break;
|
|
case 17: // 16 bit LSB
|
|
pixel = src[0] | (ushort)src[1] << 8;
|
|
src += 2;
|
|
break;
|
|
case 24: // 24 bit MSB
|
|
pixel = src[2] | (ushort)src[1] << 8 |
|
|
(uint)src[0] << 16;
|
|
src += 3;
|
|
break;
|
|
case 25: // 24 bit LSB
|
|
pixel = src[0] | (ushort)src[1] << 8 |
|
|
(uint)src[2] << 16;
|
|
src += 3;
|
|
break;
|
|
case 32: // 32 bit MSB
|
|
pixel = src[3] | (ushort)src[2] << 8 |
|
|
(uint)src[1] << 16 | (uint)src[0] << 24;
|
|
src += 4;
|
|
break;
|
|
case 33: // 32 bit LSB
|
|
pixel = src[0] | (ushort)src[1] << 8 |
|
|
(uint)src[2] << 16 | (uint)src[3] << 24;
|
|
src += 4;
|
|
break;
|
|
default: // should not really happen
|
|
x = w; // leave loop
|
|
y = h;
|
|
pixel = 0; // eliminate compiler warning
|
|
#if defined(QT_CHECK_RANGE)
|
|
tqWarning( "TQPixmap::convertToImage: Invalid depth %d",
|
|
bppc );
|
|
#endif
|
|
}
|
|
if ( red_shift > 0 )
|
|
r = (pixel & red_mask) >> red_shift;
|
|
else
|
|
r = (pixel & red_mask) << -red_shift;
|
|
if ( green_shift > 0 )
|
|
g = (pixel & green_mask) >> green_shift;
|
|
else
|
|
g = (pixel & green_mask) << -green_shift;
|
|
if ( blue_shift > 0 )
|
|
b = (pixel & blue_mask) >> blue_shift;
|
|
else
|
|
b = (pixel & blue_mask) << -blue_shift;
|
|
|
|
if ( red_bits < 8 )
|
|
r = red_scale_table[r];
|
|
if ( green_bits < 8 )
|
|
g = green_scale_table[g];
|
|
if ( blue_bits < 8 )
|
|
b = blue_scale_table[b];
|
|
|
|
if (alf) {
|
|
*dst++ = tqRgba(r, g, b, asrc[x]);
|
|
} else if (msk) {
|
|
if ( ale ) {
|
|
*dst++ = (asrc[x >> 3] & (1 << (x & 7)))
|
|
? tqRgba(r, g, b, 0xff) : tqRgba(r, g, b, 0x00);
|
|
} else {
|
|
*dst++ = (asrc[x >> 3] & (1 << (7 -(x & 7))))
|
|
? tqRgba(r, g, b, 0xff) : tqRgba(r, g, b, 0x00);
|
|
}
|
|
} else {
|
|
*dst++ = tqRgb(r, g, b);
|
|
}
|
|
}
|
|
}
|
|
} else if ( xi->bits_per_pixel == d ) { // compatible depth
|
|
char *xidata = xi->data; // copy each scanline
|
|
int bpl = TQMIN(image.bytesPerLine(),xi->bytes_per_line);
|
|
for ( int y=0; y<h; y++ ) {
|
|
memcpy( image.scanLine(y), xidata, bpl );
|
|
xidata += xi->bytes_per_line;
|
|
}
|
|
} else {
|
|
/* Typically 2 or 4 bits display depth */
|
|
#if defined(QT_CHECK_RANGE)
|
|
tqWarning( "TQPixmap::convertToImage: Display not supported (bpp=%d)",
|
|
xi->bits_per_pixel );
|
|
#endif
|
|
image.reset();
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
if( mitshm_ximage )
|
|
qt_XShmDestroyImage( xi, &shminfo );
|
|
else
|
|
#endif
|
|
qSafeXDestroyImage( xi );
|
|
return image;
|
|
}
|
|
|
|
if ( mono ) { // bitmap
|
|
image.setNumColors( 2 );
|
|
image.setColor( 0, tqRgb(255,255,255) );
|
|
image.setColor( 1, tqRgb(0,0,0) );
|
|
} else if ( !trucol ) { // pixmap with colormap
|
|
register uchar *p;
|
|
uchar *end;
|
|
uchar use[256]; // pixel-in-use table
|
|
uchar pix[256]; // pixel translation table
|
|
int ncols, i, bpl;
|
|
memset( use, 0, 256 );
|
|
memset( pix, 0, 256 );
|
|
bpl = image.bytesPerLine();
|
|
|
|
if (msk) { // which pixels are used?
|
|
for ( i=0; i<h; i++ ) {
|
|
uchar* asrc = alpha.scanLine( i );
|
|
p = image.scanLine( i );
|
|
for ( int x = 0; x < w; x++ ) {
|
|
if ( ale ) {
|
|
if (asrc[x >> 3] & (1 << (x & 7)))
|
|
use[*p] = 1;
|
|
} else {
|
|
if (asrc[x >> 3] & (1 << (7 -(x & 7))))
|
|
use[*p] = 1;
|
|
}
|
|
++p;
|
|
}
|
|
}
|
|
} else {
|
|
for ( i=0; i<h; i++ ) {
|
|
p = image.scanLine( i );
|
|
end = p + bpl;
|
|
while ( p < end )
|
|
use[*p++] = 1;
|
|
}
|
|
}
|
|
ncols = 0;
|
|
for ( i=0; i<256; i++ ) { // build translation table
|
|
if ( use[i] )
|
|
pix[i] = ncols++;
|
|
}
|
|
for ( i=0; i<h; i++ ) { // translate pixels
|
|
p = image.scanLine( i );
|
|
end = p + bpl;
|
|
while ( p < end ) {
|
|
*p = pix[*p];
|
|
p++;
|
|
}
|
|
}
|
|
|
|
Colormap cmap = x11Colormap();
|
|
int ncells = x11Cells();
|
|
XColor *carr = new XColor[ncells];
|
|
for ( i=0; i<ncells; i++ )
|
|
carr[i].pixel = i;
|
|
// Get default colormap
|
|
XQueryColors( x11Display(), cmap, carr, ncells );
|
|
|
|
if (msk) {
|
|
int trans;
|
|
if (ncols < 256) {
|
|
trans = ncols++;
|
|
image.setNumColors( ncols ); // create color table
|
|
image.setColor( trans, 0x00000000 );
|
|
} else {
|
|
image.setNumColors( ncols ); // create color table
|
|
// oh dear... no spare "transparent" pixel.
|
|
// use first pixel in image (as good as any).
|
|
trans = image.scanLine( i )[0];
|
|
}
|
|
for ( i=0; i<h; i++ ) {
|
|
uchar* asrc = alpha.scanLine( i );
|
|
p = image.scanLine( i );
|
|
for ( int x = 0; x < w; x++ ) {
|
|
if ( ale ) {
|
|
if (!(asrc[x >> 3] & (1 << (x & 7))))
|
|
*p = trans;
|
|
} else {
|
|
if (!(asrc[x >> 3] & (1 << (7 -(x & 7)))))
|
|
*p = trans;
|
|
}
|
|
++p;
|
|
}
|
|
}
|
|
} else {
|
|
image.setNumColors( ncols ); // create color table
|
|
}
|
|
int j = 0;
|
|
for ( i=0; i<256; i++ ) { // translate pixels
|
|
if ( use[i] ) {
|
|
image.setColor( j++,
|
|
( msk ? 0xff000000 : 0 )
|
|
| tqRgb( (carr[i].red >> 8) & 255,
|
|
(carr[i].green >> 8) & 255,
|
|
(carr[i].blue >> 8) & 255 ) );
|
|
}
|
|
}
|
|
|
|
delete [] carr;
|
|
}
|
|
if ( data->optim != BestOptim ) { // throw away image data
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
if( mitshm_ximage )
|
|
qt_XShmDestroyImage( xi, &shminfo );
|
|
else
|
|
#endif
|
|
qSafeXDestroyImage( xi );
|
|
((TQPixmap*)this)->data->ximage = 0;
|
|
} else { // keep ximage data
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
if( mitshm_ximage ) { // copy the XImage?
|
|
qt_XShmDestroyImage( xi, &shminfo );
|
|
xi = 0;
|
|
}
|
|
#endif
|
|
((TQPixmap*)this)->data->ximage = xi;
|
|
}
|
|
|
|
return image;
|
|
}
|
|
|
|
|
|
/*!
|
|
Converts image \a img and sets this pixmap. Returns TRUE if
|
|
successful; otherwise returns FALSE.
|
|
|
|
The \a conversion_flags argument is a bitwise-OR of the
|
|
\l{TQt::ImageConversionFlags}. Passing 0 for \a conversion_flags
|
|
sets all the default options.
|
|
|
|
Note that even though a TQPixmap with depth 1 behaves much like a
|
|
TQBitmap, isTQBitmap() returns FALSE.
|
|
|
|
If a pixmap with depth 1 is painted with color0 and color1 and
|
|
converted to an image, the pixels painted with color0 will produce
|
|
pixel index 0 in the image and those painted with color1 will
|
|
produce pixel index 1.
|
|
|
|
\sa convertToImage(), isTQBitmap(), TQImage::convertDepth(),
|
|
defaultDepth(), TQImage::hasAlphaBuffer()
|
|
*/
|
|
|
|
bool TQPixmap::convertFromImage( const TQImage &img, int conversion_flags )
|
|
{
|
|
if ( img.isNull() ) {
|
|
#if defined(QT_CHECK_NULL)
|
|
tqWarning( "TQPixmap::convertFromImage: Cannot convert a null image" );
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
detach(); // detach other references
|
|
TQImage image = img;
|
|
const uint w = image.width();
|
|
const uint h = image.height();
|
|
int d = image.depth();
|
|
const int dd = x11Depth();
|
|
bool force_mono = (dd == 1 || isTQBitmap() ||
|
|
(conversion_flags & ColorMode_Mask)==MonoOnly );
|
|
|
|
if ( w >= 32768 || h >= 32768 )
|
|
return FALSE;
|
|
|
|
// get rid of the mask
|
|
delete data->mask;
|
|
data->mask = 0;
|
|
|
|
// get rid of alpha pixmap
|
|
delete data->alphapm;
|
|
data->alphapm = 0;
|
|
|
|
// must be monochrome
|
|
if ( force_mono ) {
|
|
if ( d != 1 ) {
|
|
// dither
|
|
image = image.convertDepth( 1, conversion_flags );
|
|
d = 1;
|
|
}
|
|
} else { // can be both
|
|
bool conv8 = FALSE;
|
|
if ( d > 8 && dd <= 8 ) { // convert to 8 bit
|
|
if ( (conversion_flags & DitherMode_Mask) == AutoDither )
|
|
conversion_flags = (conversion_flags & ~DitherMode_Mask)
|
|
| PreferDither;
|
|
conv8 = TRUE;
|
|
} else if ( (conversion_flags & ColorMode_Mask) == ColorOnly ) {
|
|
conv8 = d == 1; // native depth wanted
|
|
} else if ( d == 1 ) {
|
|
if ( image.numColors() == 2 ) {
|
|
TQRgb c0 = image.color(0); // Auto: convert to best
|
|
TQRgb c1 = image.color(1);
|
|
conv8 = TQMIN(c0,c1) != tqRgb(0,0,0) || TQMAX(c0,c1) != tqRgb(255,255,255);
|
|
} else {
|
|
// eg. 1-color monochrome images (they do exist).
|
|
conv8 = TRUE;
|
|
}
|
|
}
|
|
if ( conv8 ) {
|
|
image = image.convertDepth( 8, conversion_flags );
|
|
d = 8;
|
|
}
|
|
}
|
|
|
|
if ( d == 1 ) { // 1 bit pixmap (bitmap)
|
|
if ( hd ) { // delete old X pixmap
|
|
|
|
#ifndef QT_NO_XFTFREETYPE
|
|
if (rendhd) {
|
|
XftDrawDestroy( (XftDraw *) rendhd );
|
|
rendhd = 0;
|
|
}
|
|
#endif // QT_NO_XFTFREETYPE
|
|
|
|
XFreePixmap( x11Display(), hd );
|
|
}
|
|
|
|
// make sure image.color(0) == color0 (white) and image.color(1) == color1 (black)
|
|
if (image.color(0) == TQt::black.rgb() && image.color(1) == TQt::white.rgb()) {
|
|
image.invertPixels();
|
|
image.setColor(0, TQt::white.rgb());
|
|
image.setColor(1, TQt::black.rgb());
|
|
}
|
|
|
|
char *bits;
|
|
uchar *tmp_bits;
|
|
int bpl = (w+7)/8;
|
|
int ibpl = image.bytesPerLine();
|
|
if ( image.bitOrder() == TQImage::BigEndian || bpl != ibpl ) {
|
|
tmp_bits = new uchar[bpl*h];
|
|
TQ_CHECK_PTR( tmp_bits );
|
|
bits = (char *)tmp_bits;
|
|
uchar *p, *b, *end;
|
|
uint y, count;
|
|
if ( image.bitOrder() == TQImage::BigEndian ) {
|
|
const uchar *f = qt_get_bitflip_array();
|
|
b = tmp_bits;
|
|
for ( y=0; y<h; y++ ) {
|
|
p = image.scanLine( y );
|
|
end = p + bpl;
|
|
count = bpl;
|
|
while ( count > 4 ) {
|
|
*b++ = f[*p++];
|
|
*b++ = f[*p++];
|
|
*b++ = f[*p++];
|
|
*b++ = f[*p++];
|
|
count -= 4;
|
|
}
|
|
while ( p < end )
|
|
*b++ = f[*p++];
|
|
}
|
|
} else { // just copy
|
|
b = tmp_bits;
|
|
p = image.scanLine( 0 );
|
|
for ( y=0; y<h; y++ ) {
|
|
memcpy( b, p, bpl );
|
|
b += bpl;
|
|
p += ibpl;
|
|
}
|
|
}
|
|
} else {
|
|
bits = (char *)image.bits();
|
|
tmp_bits = 0;
|
|
}
|
|
hd = (HANDLE)XCreateBitmapFromData( x11Display(),
|
|
RootWindow(x11Display(), x11Screen() ),
|
|
bits, w, h );
|
|
|
|
#ifndef QT_NO_XFTFREETYPE
|
|
if ( tqt_has_xft )
|
|
rendhd = (HANDLE) XftDrawCreateBitmap( x11Display(), hd );
|
|
#endif // QT_NO_XFTFREETYPE
|
|
|
|
if ( tmp_bits ) // Avoid purify complaint
|
|
delete [] tmp_bits;
|
|
data->w = w; data->h = h; data->d = 1;
|
|
|
|
if ( image.hasAlphaBuffer() ) {
|
|
TQBitmap m;
|
|
m = image.createAlphaMask( conversion_flags );
|
|
setMask( m );
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
Display *dpy = x11Display();
|
|
Visual *visual = (Visual *)x11Visual();
|
|
XImage *xi = 0;
|
|
bool trucol = (visual->c_class == TrueColor || visual->c_class == DirectColor);
|
|
int nbytes = image.numBytes();
|
|
uchar *newbits= 0;
|
|
int newbits_size = 0;
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
bool mitshm_ximage = false;
|
|
XShmSegmentInfo shminfo;
|
|
#endif
|
|
|
|
if ( trucol ) { // truecolor display
|
|
TQRgb pix[256]; // pixel translation table
|
|
const bool d8 = d == 8;
|
|
const uint red_mask = (uint)visual->red_mask;
|
|
const uint green_mask = (uint)visual->green_mask;
|
|
const uint blue_mask = (uint)visual->blue_mask;
|
|
const int red_shift = highest_bit( red_mask ) - 7;
|
|
const int green_shift = highest_bit( green_mask ) - 7;
|
|
const int blue_shift = highest_bit( blue_mask ) - 7;
|
|
const uint rbits = highest_bit(red_mask) - lowest_bit(red_mask) + 1;
|
|
const uint gbits = highest_bit(green_mask) - lowest_bit(green_mask) + 1;
|
|
const uint bbits = highest_bit(blue_mask) - lowest_bit(blue_mask) + 1;
|
|
|
|
if ( d8 ) { // setup pixel translation
|
|
TQRgb *ctable = image.colorTable();
|
|
for ( int i=0; i<image.numColors(); i++ ) {
|
|
int r = tqRed (ctable[i]);
|
|
int g = tqGreen(ctable[i]);
|
|
int b = tqBlue (ctable[i]);
|
|
r = red_shift > 0 ? r << red_shift : r >> -red_shift;
|
|
g = green_shift > 0 ? g << green_shift : g >> -green_shift;
|
|
b = blue_shift > 0 ? b << blue_shift : b >> -blue_shift;
|
|
pix[i] = (b & blue_mask) | (g & green_mask) | (r & red_mask)
|
|
| ~(blue_mask | green_mask | red_mask);
|
|
}
|
|
}
|
|
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
xi = qt_XShmCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0, &shminfo );
|
|
if( xi != NULL ) {
|
|
mitshm_ximage = true;
|
|
newbits = (uchar*)xi->data;
|
|
}
|
|
else
|
|
#endif
|
|
xi = XCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0 );
|
|
if (!xi)
|
|
return false;
|
|
if( newbits == NULL )
|
|
newbits = (uchar *)malloc( xi->bytes_per_line*h );
|
|
TQ_CHECK_PTR( newbits );
|
|
if ( !newbits ) // no memory
|
|
return FALSE;
|
|
int bppc = xi->bits_per_pixel;
|
|
|
|
bool contig_bits = n_bits(red_mask) == rbits &&
|
|
n_bits(green_mask) == gbits &&
|
|
n_bits(blue_mask) == bbits;
|
|
bool dither_tc =
|
|
// Want it?
|
|
(conversion_flags & Dither_Mask) != ThresholdDither &&
|
|
(conversion_flags & DitherMode_Mask) != AvoidDither &&
|
|
// Need it?
|
|
bppc < 24 && !d8 &&
|
|
// Can do it? (Contiguous bits?)
|
|
contig_bits;
|
|
|
|
static bool init=FALSE;
|
|
static int D[16][16];
|
|
if ( dither_tc && !init ) {
|
|
// I also contributed this code to XV - WWA.
|
|
/*
|
|
The dither matrix, D, is obtained with this formula:
|
|
|
|
D2 = [ 0 2 ]
|
|
[ 3 1 ]
|
|
|
|
|
|
D2*n = [ 4*Dn 4*Dn+2*Un ]
|
|
[ 4*Dn+3*Un 4*Dn+1*Un ]
|
|
*/
|
|
int n,i,j;
|
|
init=1;
|
|
|
|
/* Set D2 */
|
|
D[0][0]=0;
|
|
D[1][0]=2;
|
|
D[0][1]=3;
|
|
D[1][1]=1;
|
|
|
|
/* Expand using recursive definition given above */
|
|
for (n=2; n<16; n*=2) {
|
|
for (i=0; i<n; i++) {
|
|
for (j=0; j<n; j++) {
|
|
D[i][j]*=4;
|
|
D[i+n][j]=D[i][j]+2;
|
|
D[i][j+n]=D[i][j]+3;
|
|
D[i+n][j+n]=D[i][j]+1;
|
|
}
|
|
}
|
|
}
|
|
init=TRUE;
|
|
}
|
|
|
|
enum { BPP8,
|
|
BPP16_8_3_M3, BPP16_7_2_M3, BPP16_MSB, BPP16_LSB,
|
|
BPP24_MSB, BPP24_LSB,
|
|
BPP32_16_8_0, BPP32_MSB, BPP32_LSB
|
|
} mode = BPP8;
|
|
|
|
if ( bppc > 8 && xi->byte_order == LSBFirst )
|
|
bppc++;
|
|
|
|
int wordsize;
|
|
bool bigendian;
|
|
tqSysInfo( &wordsize, &bigendian );
|
|
bool same_msb_lsb = ( xi->byte_order == MSBFirst ) == ( bigendian );
|
|
|
|
if( bppc == 8 ) // 8 bit
|
|
mode = BPP8;
|
|
else if( bppc == 16 || bppc == 17 ) { // 16 bit MSB/LSB
|
|
if( red_shift == 8 && green_shift == 3 && blue_shift == -3
|
|
&& !d8 && same_msb_lsb )
|
|
mode = BPP16_8_3_M3;
|
|
else if( red_shift == 7 && green_shift == 2 && blue_shift == -3
|
|
&& !d8 && same_msb_lsb )
|
|
mode = BPP16_7_2_M3;
|
|
else
|
|
mode = bppc == 17 ? BPP16_LSB : BPP16_MSB;
|
|
} else if( bppc == 24 || bppc == 25 ) { // 24 bit MSB/LSB
|
|
mode = bppc == 25 ? BPP24_LSB : BPP24_MSB;
|
|
} else if( bppc == 32 || bppc == 33 ) { // 32 bit MSB/LSB
|
|
if( red_shift == 16 && green_shift == 8 && blue_shift == 0
|
|
&& !d8 && same_msb_lsb )
|
|
mode = BPP32_16_8_0;
|
|
else
|
|
mode = bppc == 33 ? BPP32_LSB : BPP32_MSB;
|
|
} else
|
|
tqFatal("Logic error 3");
|
|
|
|
#define GET_PIXEL \
|
|
int pixel; \
|
|
if ( d8 ) pixel = pix[*src++]; \
|
|
else { \
|
|
int r = tqRed ( *p ); \
|
|
int g = tqGreen( *p ); \
|
|
int b = tqBlue ( *p++ ); \
|
|
r = red_shift > 0 \
|
|
? r << red_shift : r >> -red_shift; \
|
|
g = green_shift > 0 \
|
|
? g << green_shift : g >> -green_shift; \
|
|
b = blue_shift > 0 \
|
|
? b << blue_shift : b >> -blue_shift; \
|
|
pixel = (r & red_mask)|(g & green_mask) | (b & blue_mask) \
|
|
| ~(blue_mask | green_mask | red_mask); \
|
|
}
|
|
|
|
// optimized case - no d8 case, shift only once instead of twice, mask only once instead of twice,
|
|
// use direct values instead of variables, and use only one statement
|
|
// (*p >> 16), (*p >> 8 ) and (*p) are tqRed(),tqGreen() and tqBlue() without masking
|
|
// shifts have to be passed including the shift operator (e.g. '>>3'), because of the direction
|
|
#define GET_PIXEL_OPT(red_shift,green_shift,blue_shift,red_mask,green_mask,blue_mask) \
|
|
int pixel = ((( *p >> 16 ) red_shift ) & red_mask ) \
|
|
| ((( *p >> 8 ) green_shift ) & green_mask ) \
|
|
| ((( *p ) blue_shift ) & blue_mask ); \
|
|
++p;
|
|
|
|
#define GET_PIXEL_DITHER_TC \
|
|
int r = tqRed ( *p ); \
|
|
int g = tqGreen( *p ); \
|
|
int b = tqBlue ( *p++ ); \
|
|
const int thres = D[x%16][y%16]; \
|
|
if ( r <= (255-(1<<(8-rbits))) && ((r<<rbits) & 255) \
|
|
> thres) \
|
|
r += (1<<(8-rbits)); \
|
|
if ( g <= (255-(1<<(8-gbits))) && ((g<<gbits) & 255) \
|
|
> thres) \
|
|
g += (1<<(8-gbits)); \
|
|
if ( b <= (255-(1<<(8-bbits))) && ((b<<bbits) & 255) \
|
|
> thres) \
|
|
b += (1<<(8-bbits)); \
|
|
r = red_shift > 0 \
|
|
? r << red_shift : r >> -red_shift; \
|
|
g = green_shift > 0 \
|
|
? g << green_shift : g >> -green_shift; \
|
|
b = blue_shift > 0 \
|
|
? b << blue_shift : b >> -blue_shift; \
|
|
int pixel = (r & red_mask)|(g & green_mask) | (b & blue_mask);
|
|
|
|
// again, optimized case
|
|
// can't be optimized that much :(
|
|
#define GET_PIXEL_DITHER_TC_OPT(red_shift,green_shift,blue_shift,red_mask,green_mask,blue_mask, \
|
|
rbits,gbits,bbits) \
|
|
const int thres = D[x%16][y%16]; \
|
|
int r = tqRed ( *p ); \
|
|
if ( r <= (255-(1<<(8-rbits))) && ((r<<rbits) & 255) \
|
|
> thres) \
|
|
r += (1<<(8-rbits)); \
|
|
int g = tqGreen( *p ); \
|
|
if ( g <= (255-(1<<(8-gbits))) && ((g<<gbits) & 255) \
|
|
> thres) \
|
|
g += (1<<(8-gbits)); \
|
|
int b = tqBlue ( *p++ ); \
|
|
if ( b <= (255-(1<<(8-bbits))) && ((b<<bbits) & 255) \
|
|
> thres) \
|
|
b += (1<<(8-bbits)); \
|
|
int pixel = (( r red_shift ) & red_mask ) \
|
|
| (( g green_shift ) & green_mask ) \
|
|
| (( b blue_shift ) & blue_mask );
|
|
|
|
#define CYCLE(body) \
|
|
for ( uint y=0; y<h; y++ ) { \
|
|
uchar* src = image.scanLine( y ); \
|
|
uchar* dst = newbits + xi->bytes_per_line*y; \
|
|
TQRgb* p = (TQRgb *)src; \
|
|
body \
|
|
}
|
|
|
|
if ( dither_tc ) {
|
|
switch ( mode ) {
|
|
case BPP16_8_3_M3:
|
|
CYCLE(
|
|
TQ_INT16* dst16 = (TQ_INT16*)dst;
|
|
for ( uint x=0; x<w; x++ ) {
|
|
GET_PIXEL_DITHER_TC_OPT(<<8,<<3,>>3,0xf800,0x7e0,0x1f,5,6,5)
|
|
*dst16++ = pixel;
|
|
}
|
|
)
|
|
break;
|
|
case BPP16_7_2_M3:
|
|
CYCLE(
|
|
TQ_INT16* dst16 = (TQ_INT16*)dst;
|
|
for ( uint x=0; x<w; x++ ) {
|
|
GET_PIXEL_DITHER_TC_OPT(<<7,<<2,>>3,0x7c00,0x3e0,0x1f,5,5,5)
|
|
*dst16++ = pixel;
|
|
}
|
|
)
|
|
break;
|
|
case BPP16_MSB: // 16 bit MSB
|
|
CYCLE(
|
|
for ( uint x=0; x<w; x++ ) {
|
|
GET_PIXEL_DITHER_TC
|
|
*dst++ = (pixel >> 8);
|
|
*dst++ = pixel;
|
|
}
|
|
)
|
|
break;
|
|
case BPP16_LSB: // 16 bit LSB
|
|
CYCLE(
|
|
for ( uint x=0; x<w; x++ ) {
|
|
GET_PIXEL_DITHER_TC
|
|
*dst++ = pixel;
|
|
*dst++ = pixel >> 8;
|
|
}
|
|
)
|
|
break;
|
|
default:
|
|
tqFatal("Logic error");
|
|
}
|
|
} else {
|
|
switch ( mode ) {
|
|
case BPP8: // 8 bit
|
|
CYCLE(
|
|
Q_UNUSED(p);
|
|
for ( uint x=0; x<w; x++ ) {
|
|
int pixel = pix[*src++];
|
|
*dst++ = pixel;
|
|
}
|
|
)
|
|
break;
|
|
case BPP16_8_3_M3:
|
|
CYCLE(
|
|
TQ_INT16* dst16 = (TQ_INT16*)dst;
|
|
for ( uint x=0; x<w; x++ ) {
|
|
GET_PIXEL_OPT(<<8,<<3,>>3,0xf800,0x7e0,0x1f)
|
|
*dst16++ = pixel;
|
|
}
|
|
)
|
|
break;
|
|
case BPP16_7_2_M3:
|
|
CYCLE(
|
|
TQ_INT16* dst16 = (TQ_INT16*)dst;
|
|
for ( uint x=0; x<w; x++ ) {
|
|
GET_PIXEL_OPT(<<7,<<2,>>3,0x7c00,0x3e0,0x1f)
|
|
*dst16++ = pixel;
|
|
}
|
|
)
|
|
break;
|
|
case BPP16_MSB: // 16 bit MSB
|
|
CYCLE(
|
|
for ( uint x=0; x<w; x++ ) {
|
|
GET_PIXEL
|
|
*dst++ = (pixel >> 8);
|
|
*dst++ = pixel;
|
|
}
|
|
)
|
|
break;
|
|
case BPP16_LSB: // 16 bit LSB
|
|
CYCLE(
|
|
for ( uint x=0; x<w; x++ ) {
|
|
GET_PIXEL
|
|
*dst++ = pixel;
|
|
*dst++ = pixel >> 8;
|
|
}
|
|
)
|
|
break;
|
|
case BPP24_MSB: // 24 bit MSB
|
|
CYCLE(
|
|
for ( uint x=0; x<w; x++ ) {
|
|
GET_PIXEL
|
|
*dst++ = pixel >> 16;
|
|
*dst++ = pixel >> 8;
|
|
*dst++ = pixel;
|
|
}
|
|
)
|
|
break;
|
|
case BPP24_LSB: // 24 bit LSB
|
|
CYCLE(
|
|
for ( uint x=0; x<w; x++ ) {
|
|
GET_PIXEL
|
|
*dst++ = pixel;
|
|
*dst++ = pixel >> 8;
|
|
*dst++ = pixel >> 16;
|
|
}
|
|
)
|
|
break;
|
|
case BPP32_16_8_0:
|
|
CYCLE(
|
|
memcpy( dst, p, w * 4 );
|
|
)
|
|
break;
|
|
case BPP32_MSB: // 32 bit MSB
|
|
CYCLE(
|
|
for ( uint x=0; x<w; x++ ) {
|
|
GET_PIXEL
|
|
*dst++ = pixel >> 24;
|
|
*dst++ = pixel >> 16;
|
|
*dst++ = pixel >> 8;
|
|
*dst++ = pixel;
|
|
}
|
|
)
|
|
break;
|
|
case BPP32_LSB: // 32 bit LSB
|
|
CYCLE(
|
|
for ( uint x=0; x<w; x++ ) {
|
|
GET_PIXEL
|
|
*dst++ = pixel;
|
|
*dst++ = pixel >> 8;
|
|
*dst++ = pixel >> 16;
|
|
*dst++ = pixel >> 24;
|
|
}
|
|
)
|
|
break;
|
|
default:
|
|
tqFatal("Logic error 2");
|
|
}
|
|
}
|
|
xi->data = (char *)newbits;
|
|
}
|
|
|
|
if ( d == 8 && !trucol ) { // 8 bit pixmap
|
|
int pop[256]; // pixel popularity
|
|
|
|
if ( image.numColors() == 0 )
|
|
image.setNumColors( 1 );
|
|
|
|
memset( pop, 0, sizeof(int)*256 ); // reset popularity array
|
|
uint i;
|
|
for ( i=0; i<h; i++ ) { // for each scanline...
|
|
uchar* p = image.scanLine( i );
|
|
uchar *end = p + w;
|
|
while ( p < end ) // compute popularity
|
|
pop[*p++]++;
|
|
}
|
|
|
|
newbits = (uchar *)malloc( nbytes ); // copy image into newbits
|
|
newbits_size = nbytes;
|
|
TQ_CHECK_PTR( newbits );
|
|
if ( !newbits ) // no memory
|
|
return FALSE;
|
|
uchar* p = newbits;
|
|
memcpy( p, image.bits(), nbytes ); // copy image data into newbits
|
|
|
|
/*
|
|
* The code below picks the most important colors. It is based on the
|
|
* diversity algorithm, implemented in XV 3.10. XV is (C) by John Bradley.
|
|
*/
|
|
|
|
struct PIX { // pixel sort element
|
|
uchar r,g,b,n; // color + pad
|
|
int use; // popularity
|
|
int index; // index in colormap
|
|
int mindist;
|
|
};
|
|
int ncols = 0;
|
|
for ( i=0; i< (uint) image.numColors(); i++ ) { // compute number of colors
|
|
if ( pop[i] > 0 )
|
|
ncols++;
|
|
}
|
|
for ( i=image.numColors(); i<256; i++ ) // ignore out-of-range pixels
|
|
pop[i] = 0;
|
|
|
|
// works since we make sure above to have at least
|
|
// one color in the image
|
|
if ( ncols == 0 )
|
|
ncols = 1;
|
|
|
|
PIX pixarr[256]; // pixel array
|
|
PIX pixarr_sorted[256]; // pixel array (sorted)
|
|
memset( pixarr, 0, ncols*sizeof(PIX) );
|
|
PIX *px = &pixarr[0];
|
|
int maxpop = 0;
|
|
int maxpix = 0;
|
|
TQ_CHECK_PTR( pixarr );
|
|
uint j = 0;
|
|
TQRgb* ctable = image.colorTable();
|
|
for ( i=0; i<256; i++ ) { // init pixel array
|
|
if ( pop[i] > 0 ) {
|
|
px->r = tqRed ( ctable[i] );
|
|
px->g = tqGreen( ctable[i] );
|
|
px->b = tqBlue ( ctable[i] );
|
|
px->n = 0;
|
|
px->use = pop[i];
|
|
if ( pop[i] > maxpop ) { // select most popular entry
|
|
maxpop = pop[i];
|
|
maxpix = j;
|
|
}
|
|
px->index = i;
|
|
px->mindist = 1000000;
|
|
px++;
|
|
j++;
|
|
}
|
|
}
|
|
pixarr_sorted[0] = pixarr[maxpix];
|
|
pixarr[maxpix].use = 0;
|
|
|
|
for ( i=1; i< (uint) ncols; i++ ) { // sort pixels
|
|
int minpix = -1, mindist = -1;
|
|
px = &pixarr_sorted[i-1];
|
|
int r = px->r;
|
|
int g = px->g;
|
|
int b = px->b;
|
|
int dist;
|
|
if ( (i & 1) || i<10 ) { // sort on max distance
|
|
for ( int j=0; j<ncols; j++ ) {
|
|
px = &pixarr[j];
|
|
if ( px->use ) {
|
|
dist = (px->r - r)*(px->r - r) +
|
|
(px->g - g)*(px->g - g) +
|
|
(px->b - b)*(px->b - b);
|
|
if ( px->mindist > dist )
|
|
px->mindist = dist;
|
|
if ( px->mindist > mindist ) {
|
|
mindist = px->mindist;
|
|
minpix = j;
|
|
}
|
|
}
|
|
}
|
|
} else { // sort on max popularity
|
|
for ( int j=0; j<ncols; j++ ) {
|
|
px = &pixarr[j];
|
|
if ( px->use ) {
|
|
dist = (px->r - r)*(px->r - r) +
|
|
(px->g - g)*(px->g - g) +
|
|
(px->b - b)*(px->b - b);
|
|
if ( px->mindist > dist )
|
|
px->mindist = dist;
|
|
if ( px->use > mindist ) {
|
|
mindist = px->use;
|
|
minpix = j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pixarr_sorted[i] = pixarr[minpix];
|
|
pixarr[minpix].use = 0;
|
|
}
|
|
|
|
uint pix[256]; // pixel translation table
|
|
px = &pixarr_sorted[0];
|
|
for ( i=0; i< (uint) ncols; i++ ) { // allocate colors
|
|
TQColor c( px->r, px->g, px->b );
|
|
pix[px->index] = c.pixel(x11Screen());
|
|
px++;
|
|
}
|
|
|
|
p = newbits;
|
|
for ( i=0; i< (uint) nbytes; i++ ) { // translate pixels
|
|
*p = pix[*p];
|
|
p++;
|
|
}
|
|
}
|
|
|
|
if ( !xi ) { // X image not created
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
xi = qt_XShmCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0, &shminfo );
|
|
if( xi != NULL )
|
|
mitshm_ximage = true;
|
|
else
|
|
#endif
|
|
xi = XCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0 );
|
|
if ( xi->bits_per_pixel == 16 ) { // convert 8 bpp ==> 16 bpp
|
|
ushort *p2;
|
|
int p2inc = xi->bytes_per_line/sizeof(ushort);
|
|
ushort *newerbits = (ushort *)malloc( xi->bytes_per_line * h );
|
|
newbits_size = xi->bytes_per_line * h;
|
|
TQ_CHECK_PTR( newerbits );
|
|
if ( !newerbits ) // no memory
|
|
return FALSE;
|
|
uchar* p = newbits;
|
|
for ( uint y=0; y<h; y++ ) { // OOPS: Do right byte order!!
|
|
p2 = newerbits + p2inc*y;
|
|
for ( uint x=0; x<w; x++ )
|
|
*p2++ = *p++;
|
|
}
|
|
free( newbits );
|
|
newbits = (uchar *)newerbits;
|
|
} else if ( xi->bits_per_pixel != 8 ) {
|
|
#if defined(QT_CHECK_RANGE)
|
|
tqWarning( "TQPixmap::convertFromImage: Display not supported "
|
|
"(bpp=%d)", xi->bits_per_pixel );
|
|
#endif
|
|
}
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
if( newbits_size > 0 && mitshm_ximage ) { // need to copy to shared memory
|
|
memcpy( xi->data, newbits, newbits_size );
|
|
free( newbits );
|
|
newbits = (uchar*)xi->data;
|
|
}
|
|
else
|
|
#endif
|
|
xi->data = (char *)newbits;
|
|
}
|
|
|
|
if ( hd && (width() != (int)w || height() != (int)h || this->depth() != dd) ) {
|
|
|
|
#ifndef QT_NO_XFTFREETYPE
|
|
if (rendhd) {
|
|
XftDrawDestroy( (XftDraw *) rendhd );
|
|
rendhd = 0;
|
|
}
|
|
#endif // QT_NO_XFTFREETYPE
|
|
|
|
XFreePixmap( dpy, hd ); // don't reuse old pixmap
|
|
hd = 0;
|
|
}
|
|
if ( !hd ) { // create new pixmap
|
|
hd = (HANDLE)XCreatePixmap( x11Display(),
|
|
RootWindow(x11Display(), x11Screen() ),
|
|
w, h, dd );
|
|
|
|
#ifndef QT_NO_XFTFREETYPE
|
|
if ( tqt_has_xft ) {
|
|
if ( data->d == 1 ) {
|
|
rendhd = (HANDLE) XftDrawCreateBitmap( x11Display (), hd );
|
|
} else {
|
|
rendhd = (HANDLE) XftDrawCreate( x11Display (), hd,
|
|
(Visual *) x11Visual(), x11Colormap() );
|
|
}
|
|
}
|
|
#endif // QT_NO_XFTFREETYPE
|
|
|
|
}
|
|
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
if( mitshm_ximage )
|
|
XShmPutImage( dpy, hd, tqt_xget_readonly_gc( x11Screen(), FALSE ),
|
|
xi, 0, 0, 0, 0, w, h, False );
|
|
else
|
|
#endif
|
|
XPutImage( dpy, hd, tqt_xget_readonly_gc( x11Screen(), FALSE ),
|
|
xi, 0, 0, 0, 0, w, h );
|
|
|
|
data->w = w;
|
|
data->h = h;
|
|
data->d = dd;
|
|
|
|
XImage* axi = NULL;
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
bool mitshm_aximage = false;
|
|
XShmSegmentInfo ashminfo;
|
|
#endif
|
|
if ( image.hasAlphaBuffer() ) {
|
|
TQBitmap m;
|
|
m = image.createAlphaMask( conversion_flags );
|
|
setMask( m );
|
|
|
|
#ifndef QT_NO_XFTFREETYPE
|
|
// does this image have an alphamap (and not just a 1bpp mask)?
|
|
bool alphamap = image.depth() == 32;
|
|
if (image.depth() == 8) {
|
|
const TQRgb * const rgb = image.colorTable();
|
|
for (int i = 0, count = image.numColors(); i < count; ++i) {
|
|
const int alpha = tqAlpha(rgb[i]);
|
|
if (alpha != 0 && alpha != 0xff) {
|
|
alphamap = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (tqt_use_xrender && tqt_has_xft && alphamap) {
|
|
data->alphapm = new TQPixmap; // create a null pixmap
|
|
|
|
// setup pixmap data
|
|
data->alphapm->data->w = w;
|
|
data->alphapm->data->h = h;
|
|
data->alphapm->data->d = 8;
|
|
|
|
// create 8bpp pixmap and render picture
|
|
data->alphapm->hd =
|
|
XCreatePixmap(x11Display(), RootWindow(x11Display(), x11Screen()),
|
|
w, h, 8);
|
|
|
|
data->alphapm->rendhd =
|
|
(HANDLE) XftDrawCreateAlpha( x11Display(), data->alphapm->hd, 8 );
|
|
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
axi = qt_XShmCreateImage( x11Display(), (Visual*)x11Visual(),
|
|
8, ZPixmap, 0, 0, w, h, 8, 0, &ashminfo );
|
|
if( axi != NULL )
|
|
mitshm_aximage = true;
|
|
else
|
|
#endif
|
|
axi = XCreateImage(x11Display(), (Visual *) x11Visual(),
|
|
8, ZPixmap, 0, 0, w, h, 8, 0);
|
|
|
|
if (axi) {
|
|
if( axi->data==NULL ) {
|
|
// the data is deleted by qSafeXDestroyImage
|
|
axi->data = (char *) malloc(h * axi->bytes_per_line);
|
|
TQ_CHECK_PTR( axi->data );
|
|
}
|
|
char *aptr = axi->data;
|
|
|
|
if (image.depth() == 32) {
|
|
const int *iptr = (const int *) image.bits();
|
|
if( axi->bytes_per_line == (int)w ) {
|
|
int max = w * h;
|
|
while (max--)
|
|
*aptr++ = *iptr++ >> 24; // stquirt
|
|
} else {
|
|
for (uint i = 0; i < h; ++i ) {
|
|
for (uint j = 0; j < w; ++j )
|
|
*aptr++ = *iptr++ >> 24; // stquirt
|
|
aptr += ( axi->bytes_per_line - w );
|
|
}
|
|
}
|
|
} else if (image.depth() == 8) {
|
|
const TQRgb * const rgb = image.colorTable();
|
|
for (uint y = 0; y < h; ++y) {
|
|
const uchar *iptr = image.scanLine(y);
|
|
for (uint x = 0; x < w; ++x)
|
|
*aptr++ = tqAlpha(rgb[*iptr++]);
|
|
aptr += ( axi->bytes_per_line - w );
|
|
}
|
|
}
|
|
|
|
GC gc = XCreateGC(x11Display(), data->alphapm->hd, 0, 0);
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
if( mitshm_aximage )
|
|
XShmPutImage( dpy, data->alphapm->hd, gc, axi, 0, 0, 0, 0, w, h, False );
|
|
else
|
|
#endif
|
|
XPutImage(dpy, data->alphapm->hd, gc, axi, 0, 0, 0, 0, w, h);
|
|
XFreeGC(x11Display(), gc);
|
|
}
|
|
}
|
|
#endif // QT_NO_XFTFREETYPE
|
|
}
|
|
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
if( mitshm_ximage || mitshm_aximage )
|
|
XSync( x11Display(), False ); // wait until processed
|
|
#endif
|
|
|
|
if ( data->optim != BestOptim ) { // throw away image
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
if( mitshm_ximage )
|
|
qt_XShmDestroyImage( xi, &shminfo );
|
|
else
|
|
#endif
|
|
qSafeXDestroyImage( xi );
|
|
data->ximage = 0;
|
|
} else { // keep ximage that we created
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
if( mitshm_ximage ) { // copy the XImage?
|
|
qt_XShmDestroyImage( xi, &shminfo );
|
|
xi = 0;
|
|
}
|
|
#endif
|
|
data->ximage = xi;
|
|
}
|
|
if( axi ) {
|
|
#ifdef QT_MITSHM_CONVERSIONS
|
|
if( mitshm_aximage )
|
|
qt_XShmDestroyImage( axi, &ashminfo );
|
|
else
|
|
#endif
|
|
qSafeXDestroyImage(axi);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*!
|
|
Grabs the contents of the window \a window and makes a pixmap out
|
|
of it. Returns the pixmap.
|
|
|
|
The arguments \a (x, y) specify the offset in the window, whereas
|
|
\a (w, h) specify the width and height of the area to be copied.
|
|
|
|
If \a w is negative, the function copies everything to the right
|
|
border of the window. If \a h is negative, the function copies
|
|
everything to the bottom of the window.
|
|
|
|
Note that grabWindow() grabs pixels from the screen, not from the
|
|
window. If there is another window partially or entirely over the
|
|
one you grab, you get pixels from the overlying window, too.
|
|
|
|
Note also that the mouse cursor is generally not grabbed.
|
|
|
|
The reason we use a window identifier and not a TQWidget is to
|
|
enable grabbing of windows that are not part of the application,
|
|
window system frames, and so on.
|
|
|
|
\warning Grabbing an area outside the screen is not safe in
|
|
general. This depends on the underlying window system.
|
|
|
|
\warning X11 only: If \a window is not the same depth as the root
|
|
window and another window partially or entirely obscures the one
|
|
you grab, you will \e not get pixels from the overlying window.
|
|
The contests of the obscured areas in the pixmap are undefined and
|
|
uninitialized.
|
|
|
|
\sa grabWidget()
|
|
*/
|
|
|
|
TQPixmap TQPixmap::grabWindow( WId window, int x, int y, int w, int h )
|
|
{
|
|
if ( w == 0 || h == 0 )
|
|
return TQPixmap();
|
|
|
|
Display *dpy = x11AppDisplay();
|
|
XWindowAttributes window_attr;
|
|
if ( ! XGetWindowAttributes( dpy, window, &window_attr ) )
|
|
return TQPixmap();
|
|
|
|
if ( w < 0 )
|
|
w = window_attr.width - x;
|
|
if ( h < 0 )
|
|
h = window_attr.height - y;
|
|
|
|
// determine the screen
|
|
int scr;
|
|
for ( scr = 0; scr < ScreenCount( dpy ); ++scr ) {
|
|
if ( window_attr.root == RootWindow( dpy, scr ) ) // found it
|
|
break;
|
|
}
|
|
if ( scr >= ScreenCount( dpy ) ) // sanity check
|
|
return TQPixmap();
|
|
|
|
|
|
// get the depth of the root window
|
|
XWindowAttributes root_attr;
|
|
if ( ! XGetWindowAttributes( dpy, window_attr.root, &root_attr ) )
|
|
return TQPixmap();
|
|
|
|
if ( window_attr.depth == root_attr.depth ) {
|
|
// if the depth of the specified window and the root window are the
|
|
// same, grab pixels from the root window (so that we get the any
|
|
// overlapping windows and window manager frames)
|
|
|
|
// map x and y to the root window
|
|
WId unused;
|
|
if ( ! XTranslateCoordinates( dpy, window, window_attr.root, x, y,
|
|
&x, &y, &unused ) )
|
|
return TQPixmap();
|
|
|
|
window = window_attr.root;
|
|
}
|
|
|
|
TQPixmap pm( w, h );
|
|
pm.data->uninit = FALSE;
|
|
pm.x11SetScreen( scr );
|
|
|
|
GC gc = tqt_xget_temp_gc( scr, FALSE );
|
|
XSetSubwindowMode( dpy, gc, IncludeInferiors );
|
|
XCopyArea( dpy, window, pm.handle(), gc, x, y, w, h, 0, 0 );
|
|
XSetSubwindowMode( dpy, gc, ClipByChildren );
|
|
|
|
return pm;
|
|
}
|
|
|
|
/*!
|
|
Returns a copy of the pixmap that is transformed using \a matrix.
|
|
The original pixmap is not changed.
|
|
|
|
The transformation \a matrix is internally adjusted to compensate
|
|
for unwanted translation, i.e. xForm() returns the smallest image
|
|
that contains all the transformed points of the original image.
|
|
|
|
This function is slow because it involves transformation to a
|
|
TQImage, non-trivial computations and a transformation back to a
|
|
TQPixmap.
|
|
|
|
\sa trueMatrix(), TQWMatrix, TQPainter::setWorldMatrix() TQImage::xForm()
|
|
*/
|
|
|
|
TQPixmap TQPixmap::xForm( const TQWMatrix &matrix ) const
|
|
{
|
|
uint w = 0;
|
|
uint h = 0; // size of target pixmap
|
|
uint ws, hs; // size of source pixmap
|
|
uchar *dptr; // data in target pixmap
|
|
uint dbpl, dbytes; // bytes per line/bytes total
|
|
uchar *sptr; // data in original pixmap
|
|
int sbpl; // bytes per line in original
|
|
int bpp; // bits per pixel
|
|
bool depth1 = depth() == 1;
|
|
Display *dpy = x11Display();
|
|
|
|
if ( isNull() ) // this is a null pixmap
|
|
return copy();
|
|
|
|
ws = width();
|
|
hs = height();
|
|
|
|
TQWMatrix mat( matrix.m11(), matrix.m12(), matrix.m21(), matrix.m22(), 0., 0. );
|
|
|
|
double scaledWidth;
|
|
double scaledHeight;
|
|
|
|
if ( matrix.m12() == 0.0F && matrix.m21() == 0.0F ) {
|
|
if ( matrix.m11() == 1.0F && matrix.m22() == 1.0F )
|
|
return *this; // identity matrix
|
|
scaledHeight = matrix.m22()*hs;
|
|
scaledWidth = matrix.m11()*ws;
|
|
h = TQABS( tqRound( scaledHeight ) );
|
|
w = TQABS( tqRound( scaledWidth ) );
|
|
} else { // rotation or shearing
|
|
TQPointArray a( TQRect(0,0,ws+1,hs+1) );
|
|
a = mat.map( a );
|
|
TQRect r = a.boundingRect().normalize();
|
|
w = r.width()-1;
|
|
h = r.height()-1;
|
|
scaledWidth = w;
|
|
scaledHeight = h;
|
|
}
|
|
|
|
mat = trueMatrix( mat, ws, hs ); // true matrix
|
|
|
|
|
|
bool invertible;
|
|
mat = mat.invert( &invertible ); // invert matrix
|
|
|
|
if ( h == 0 || w == 0 || !invertible
|
|
|| TQABS(scaledWidth) >= 32768 || TQABS(scaledHeight) >= 32768 ) { // error, return null pixmap
|
|
TQPixmap pm;
|
|
pm.data->bitmap = data->bitmap;
|
|
return pm;
|
|
}
|
|
|
|
#if defined(QT_MITSHM_XFORM)
|
|
static bool try_once = TRUE;
|
|
if (try_once) {
|
|
try_once = FALSE;
|
|
if ( !xshminit )
|
|
qt_create_mitshm_buffer( this, 800, 600 );
|
|
}
|
|
|
|
bool use_mitshm = xshmimg && !depth1 &&
|
|
xshmimg->width >= w && xshmimg->height >= h;
|
|
#endif
|
|
XImage *xi = (XImage*)data->ximage; // any cached ximage?
|
|
if ( !xi )
|
|
xi = XGetImage( x11Display(), handle(), 0, 0, ws, hs, AllPlanes,
|
|
depth1 ? XYPixmap : ZPixmap );
|
|
|
|
if ( !xi ) { // error, return null pixmap
|
|
TQPixmap pm;
|
|
pm.data->bitmap = data->bitmap;
|
|
pm.data->alphapm = data->alphapm;
|
|
return pm;
|
|
}
|
|
|
|
sbpl = xi->bytes_per_line;
|
|
sptr = (uchar *)xi->data;
|
|
bpp = xi->bits_per_pixel;
|
|
|
|
if ( depth1 )
|
|
dbpl = (w+7)/8;
|
|
else
|
|
dbpl = ((w*bpp+31)/32)*4;
|
|
dbytes = dbpl*h;
|
|
|
|
#if defined(QT_MITSHM_XFORM)
|
|
if ( use_mitshm ) {
|
|
dptr = (uchar *)xshmimg->data;
|
|
uchar fillbyte = bpp == 8 ? white.pixel() : 0xff;
|
|
for ( int y=0; y<h; y++ )
|
|
memset( dptr + y*xshmimg->bytes_per_line, fillbyte, dbpl );
|
|
} else {
|
|
#endif
|
|
dptr = (uchar *)malloc( dbytes ); // create buffer for bits
|
|
TQ_CHECK_PTR( dptr );
|
|
if ( depth1 ) // fill with zeros
|
|
memset( dptr, 0, dbytes );
|
|
else if ( bpp == 8 ) // fill with background color
|
|
memset( dptr, TQt::white.pixel( x11Screen() ), dbytes );
|
|
else
|
|
memset( dptr, 0xff, dbytes );
|
|
#if defined(QT_MITSHM_XFORM)
|
|
}
|
|
#endif
|
|
|
|
// #define QT_DEBUG_XIMAGE
|
|
#if defined(QT_DEBUG_XIMAGE)
|
|
tqDebug( "----IMAGE--INFO--------------" );
|
|
tqDebug( "width............. %d", xi->width );
|
|
tqDebug( "height............ %d", xi->height );
|
|
tqDebug( "xoffset........... %d", xi->xoffset );
|
|
tqDebug( "format............ %d", xi->format );
|
|
tqDebug( "byte order........ %d", xi->byte_order );
|
|
tqDebug( "bitmap unit....... %d", xi->bitmap_unit );
|
|
tqDebug( "bitmap bit order.. %d", xi->bitmap_bit_order );
|
|
tqDebug( "depth............. %d", xi->depth );
|
|
tqDebug( "bytes per line.... %d", xi->bytes_per_line );
|
|
tqDebug( "bits per pixel.... %d", xi->bits_per_pixel );
|
|
#endif
|
|
|
|
int type;
|
|
if ( xi->bitmap_bit_order == MSBFirst )
|
|
type = QT_XFORM_TYPE_MSBFIRST;
|
|
else
|
|
type = QT_XFORM_TYPE_LSBFIRST;
|
|
int xbpl, p_inc;
|
|
if ( depth1 ) {
|
|
xbpl = (w+7)/8;
|
|
p_inc = dbpl - xbpl;
|
|
} else {
|
|
xbpl = (w*bpp)/8;
|
|
p_inc = dbpl - xbpl;
|
|
#if defined(QT_MITSHM_XFORM)
|
|
if ( use_mitshm )
|
|
p_inc = xshmimg->bytes_per_line - xbpl;
|
|
#endif
|
|
}
|
|
|
|
if ( !qt_xForm_helper( mat, xi->xoffset, type, bpp, dptr, xbpl, p_inc, h, sptr, sbpl, ws, hs ) ){
|
|
#if defined(QT_CHECK_RANGE)
|
|
tqWarning( "TQPixmap::xForm: display not supported (bpp=%d)",bpp);
|
|
#endif
|
|
TQPixmap pm;
|
|
return pm;
|
|
}
|
|
|
|
if ( data->optim == NoOptim ) { // throw away ximage
|
|
qSafeXDestroyImage( xi );
|
|
data->ximage = 0;
|
|
} else { // keep ximage that we fetched
|
|
data->ximage = xi;
|
|
}
|
|
|
|
if ( depth1 ) { // mono bitmap
|
|
TQPixmap pm( w, h, dptr, TQImage::systemBitOrder() != TQImage::BigEndian );
|
|
pm.data->bitmap = data->bitmap;
|
|
free( dptr );
|
|
if ( data->mask ) {
|
|
if ( data->selfmask ) // pixmap == mask
|
|
pm.setMask( *((TQBitmap*)(&pm)) );
|
|
else
|
|
pm.setMask( data->mask->xForm(matrix) );
|
|
}
|
|
return pm;
|
|
} else { // color pixmap
|
|
GC gc = tqt_xget_readonly_gc( x11Screen(), FALSE );
|
|
TQPixmap pm( w, h );
|
|
pm.data->uninit = FALSE;
|
|
pm.x11SetScreen( x11Screen() );
|
|
#if defined(QT_MITSHM_XFORM)
|
|
if ( use_mitshm ) {
|
|
XCopyArea( dpy, xshmpm, pm.handle(), gc, 0, 0, w, h, 0, 0 );
|
|
} else {
|
|
#endif
|
|
xi = XCreateImage( dpy, (Visual *)x11Visual(), x11Depth(),
|
|
ZPixmap, 0, (char *)dptr, w, h, 32, 0 );
|
|
XPutImage( dpy, pm.handle(), gc, xi, 0, 0, 0, 0, w, h);
|
|
qSafeXDestroyImage( xi );
|
|
#if defined(QT_MITSHM_XFORM)
|
|
}
|
|
#endif
|
|
|
|
if ( data->mask ) // xform mask, too
|
|
pm.setMask( data->mask->xForm(matrix) );
|
|
|
|
#ifndef QT_NO_XFTFREETYPE
|
|
if ( tqt_use_xrender && tqt_has_xft && data->alphapm ) { // xform the alpha channel
|
|
XImage *axi = 0;
|
|
if ((axi = XGetImage(x11Display(), data->alphapm->handle(),
|
|
0, 0, ws, hs, AllPlanes, ZPixmap))) {
|
|
sbpl = axi->bytes_per_line;
|
|
sptr = (uchar *) axi->data;
|
|
bpp = axi->bits_per_pixel;
|
|
dbytes = dbpl * h;
|
|
dptr = (uchar *) malloc(dbytes);
|
|
TQ_CHECK_PTR( dptr );
|
|
memset(dptr, 0, dbytes);
|
|
if ( axi->bitmap_bit_order == MSBFirst )
|
|
type = QT_XFORM_TYPE_MSBFIRST;
|
|
else
|
|
type = QT_XFORM_TYPE_LSBFIRST;
|
|
|
|
if (qt_xForm_helper( mat, axi->xoffset, type, bpp, dptr, w,
|
|
0, h, sptr, sbpl, ws, hs )) {
|
|
delete pm.data->alphapm;
|
|
pm.data->alphapm = new TQPixmap; // create a null pixmap
|
|
|
|
// setup pixmap data
|
|
pm.data->alphapm->data->w = w;
|
|
pm.data->alphapm->data->h = h;
|
|
pm.data->alphapm->data->d = 8;
|
|
|
|
// create 8bpp pixmap and render picture
|
|
pm.data->alphapm->hd =
|
|
XCreatePixmap(x11Display(),
|
|
RootWindow(x11Display(), x11Screen()),
|
|
w, h, 8);
|
|
|
|
pm.data->alphapm->rendhd =
|
|
(HANDLE) XftDrawCreateAlpha( x11Display(),
|
|
pm.data->alphapm->hd, 8 );
|
|
|
|
XImage *axi2 = XCreateImage(x11Display(), (Visual *) x11Visual(),
|
|
8, ZPixmap, 0, (char *)dptr, w, h, 8, 0);
|
|
|
|
if (axi2) {
|
|
// the data is deleted by qSafeXDestroyImage
|
|
GC gc = XCreateGC(x11Display(), pm.data->alphapm->hd, 0, 0);
|
|
XPutImage(dpy, pm.data->alphapm->hd, gc, axi2, 0, 0, 0, 0, w, h);
|
|
XFreeGC(x11Display(), gc);
|
|
qSafeXDestroyImage(axi2);
|
|
}
|
|
}
|
|
qSafeXDestroyImage(axi);
|
|
}
|
|
}
|
|
#endif // QT_NO_XFTFREETYPE
|
|
|
|
return pm;
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
int TQPixmap::x11SetDefaultScreen( int screen )
|
|
{
|
|
int old = defaultScreen;
|
|
defaultScreen = screen;
|
|
return old;
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
void TQPixmap::x11SetScreen( int screen )
|
|
{
|
|
if ( screen < 0 )
|
|
screen = x11AppScreen();
|
|
|
|
if ( screen == x11Screen() )
|
|
return; // nothing to do
|
|
|
|
if ( isNull() ) {
|
|
TQPaintDeviceX11Data* xd = getX11Data( TRUE );
|
|
xd->x_screen = screen;
|
|
xd->x_depth = TQPaintDevice::x11AppDepth( screen );
|
|
xd->x_cells = TQPaintDevice::x11AppCells( screen );
|
|
xd->x_colormap = TQPaintDevice::x11AppColormap( screen );
|
|
xd->x_defcolormap = TQPaintDevice::x11AppDefaultColormap( screen );
|
|
xd->x_visual = TQPaintDevice::x11AppVisual( screen );
|
|
xd->x_defvisual = TQPaintDevice::x11AppDefaultVisual( screen );
|
|
setX11Data( xd );
|
|
return;
|
|
}
|
|
#if 0
|
|
tqDebug("TQPixmap::x11SetScreen for %p from %d to %d. Size is %d/%d", data, x11Screen(), screen, width(), height() );
|
|
#endif
|
|
|
|
TQImage img = convertToImage();
|
|
resize(0,0);
|
|
TQPaintDeviceX11Data* xd = getX11Data( TRUE );
|
|
xd->x_screen = screen;
|
|
xd->x_depth = TQPaintDevice::x11AppDepth( screen );
|
|
xd->x_cells = TQPaintDevice::x11AppCells( screen );
|
|
xd->x_colormap = TQPaintDevice::x11AppColormap( screen );
|
|
xd->x_defcolormap = TQPaintDevice::x11AppDefaultColormap( screen );
|
|
xd->x_visual = TQPaintDevice::x11AppVisual( screen );
|
|
xd->x_defvisual = TQPaintDevice::x11AppDefaultVisual( screen );
|
|
setX11Data( xd );
|
|
convertFromImage( img );
|
|
}
|
|
|
|
/*!
|
|
Returns TRUE this pixmap has an alpha channel or a mask.
|
|
|
|
\sa hasAlphaChannel() mask()
|
|
*/
|
|
bool TQPixmap::hasAlpha() const
|
|
{
|
|
return data->alphapm || data->mask;
|
|
}
|
|
|
|
/*!
|
|
Returns TRUE if the pixmap has an alpha channel; otherwise it
|
|
returns FALSE.
|
|
|
|
NOTE: If the pixmap has a mask but not alpha channel, this
|
|
function returns FALSE.
|
|
|
|
\sa hasAlpha() mask()
|
|
*/
|
|
bool TQPixmap::hasAlphaChannel() const
|
|
{
|
|
return data->alphapm != 0;
|
|
}
|
|
|
|
/*!
|
|
\relates TQPixmap
|
|
|
|
Copies a block of pixels from \a src to \a dst. The alpha channel
|
|
and mask data (if any) is also copied from \a src. NOTE: \a src
|
|
is \e not alpha blended or masked when copied to \a dst. Use
|
|
bitBlt() or TQPainter::drawPixmap() to perform alpha blending or
|
|
masked drawing.
|
|
|
|
\a sx, \a sy is the top-left pixel in \a src (0, 0 by default), \a
|
|
dx, \a dy is the top-left position in \a dst and \a sw, \sh is the
|
|
size of the copied block (all of \a src by default).
|
|
|
|
If \a src, \a dst, \a sw or \a sh is 0 (zero), copyBlt() does
|
|
nothing. If \a sw or \a sh is negative, copyBlt() copies starting
|
|
at \a sx (and respectively, \a sy) and ending at the right edge
|
|
(and respectively, the bottom edge) of \a src.
|
|
|
|
copyBlt() does nothing if \a src and \a dst have different depths.
|
|
*/
|
|
Q_EXPORT void copyBlt( TQPixmap *dst, int dx, int dy,
|
|
const TQPixmap *src, int sx, int sy, int sw, int sh )
|
|
{
|
|
if ( ! dst || ! src || sw == 0 || sh == 0 || dst->depth() != src->depth() ) {
|
|
#ifdef QT_CHECK_NULL
|
|
Q_ASSERT( dst != 0 );
|
|
Q_ASSERT( src != 0 );
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
// copy pixel data
|
|
bitBlt( dst, dx, dy, src, sx, sy, sw, sh, TQt::CopyROP, TRUE );
|
|
|
|
// copy mask data
|
|
if ( src->data->mask ) {
|
|
if ( ! dst->data->mask ) {
|
|
dst->data->mask = new TQBitmap( dst->width(), dst->height() );
|
|
|
|
// new masks are fully opaque by default
|
|
dst->data->mask->fill( TQt::color1 );
|
|
}
|
|
|
|
bitBlt( dst->data->mask, dx, dy,
|
|
src->data->mask, sx, sy, sw, sh, TQt::CopyROP, TRUE );
|
|
}
|
|
|
|
#ifndef QT_NO_XFTFREETYPE
|
|
// copy alpha data
|
|
extern bool tqt_use_xrender; // from qapplication_x11.cpp
|
|
if ( ! tqt_use_xrender || ! src->data->alphapm )
|
|
return;
|
|
|
|
if ( sw < 0 )
|
|
sw = src->width() - sx;
|
|
else
|
|
sw = TQMIN( src->width()-sx, sw );
|
|
sw = TQMIN( dst->width()-dx, sw );
|
|
|
|
if ( sh < 0 )
|
|
sh = src->height() - sy ;
|
|
else
|
|
sh = TQMIN( src->height()-sy, sh );
|
|
sh = TQMIN( dst->height()-dy, sh );
|
|
|
|
if ( sw <= 0 || sh <= 0 )
|
|
return;
|
|
|
|
// create an alpha pixmap for dst if it doesn't exist
|
|
bool do_init = FALSE;
|
|
if ( ! dst->data->alphapm ) {
|
|
dst->data->alphapm = new TQPixmap;
|
|
|
|
// setup pixmap d
|
|
dst->data->alphapm->data->w = dst->width();
|
|
dst->data->alphapm->data->h = dst->height();
|
|
dst->data->alphapm->data->d = 8;
|
|
|
|
// create 8bpp pixmap and render picture
|
|
dst->data->alphapm->hd =
|
|
XCreatePixmap(dst->x11Display(),
|
|
RootWindow(dst->x11Display(), dst->x11Screen()),
|
|
dst->width(), dst->height(), 8);
|
|
|
|
// new alpha pixmaps should be fully opaque by default
|
|
do_init = TRUE;
|
|
|
|
dst->data->alphapm->rendhd =
|
|
(TQt::HANDLE) XftDrawCreateAlpha( dst->x11Display(),
|
|
dst->data->alphapm->hd, 8 );
|
|
}
|
|
|
|
GC gc = XCreateGC(dst->x11Display(), dst->data->alphapm->hd, 0, 0);
|
|
|
|
if ( do_init ) {
|
|
// the alphapm was just created, make it fully opaque
|
|
XSetForeground( dst->x11Display(), gc, 255 );
|
|
XSetBackground( dst->x11Display(), gc, 255 );
|
|
XFillRectangle( dst->x11Display(), dst->data->alphapm->hd, gc,
|
|
0, 0, dst->data->alphapm->data->w,
|
|
dst->data->alphapm->data->h );
|
|
}
|
|
|
|
XCopyArea(dst->x11Display(), src->data->alphapm->hd, dst->data->alphapm->hd, gc,
|
|
sx, sy, sw, sh, dx, dy);
|
|
XFreeGC(dst->x11Display(), gc);
|
|
#endif // QT_NO_XFTFREETYPE
|
|
}
|