From ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features. BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- kdeui/kpixmapio.cpp | 908 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 908 insertions(+) create mode 100644 kdeui/kpixmapio.cpp (limited to 'kdeui/kpixmapio.cpp') diff --git a/kdeui/kpixmapio.cpp b/kdeui/kpixmapio.cpp new file mode 100644 index 000000000..fd2854fb0 --- /dev/null +++ b/kdeui/kpixmapio.cpp @@ -0,0 +1,908 @@ +/* vi: ts=8 sts=4 sw=4 + * + * + * This file is part of the KDE project, module kdeui. + * Copyright (C) 2000 Geert Jansen . + * + * You can Freely distribute this program under the GNU Library General + * Public License. See the file "COPYING.LIB" for the exact licensing terms. + * + * kpixmapio.cpp: Fast pixmap <-> image conversion. + */ + +#include "kpixmapio.h" +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#ifdef Q_OS_UNIX +#include +#include +#endif + +#ifdef Q_WS_X11 +#include +#include +#include +#ifdef HAVE_MITSHM +#include +#endif +#ifdef __osf__ +extern "C" int XShmQueryExtension(Display *display); +#endif +#else +#undef HAVE_MITSHM +#endif + +// d pointer + +struct KPixmapIOPrivate +{ + int shmsize; + int shmpolicy; + int threshold; + int bpp; + int byteorder; +#ifdef Q_WS_X11 + XImage *ximage; +#ifdef HAVE_MITSHM + XShmSegmentInfo *shminfo; + bool first_try; +#endif +#else + void *ximage; +#endif +}; + + +// From Qt: Returns the position of the lowest set bit in val. + +typedef unsigned char uchar; +typedef unsigned int uint; + +#ifdef HAVE_MITSHM +static int lowest_bit(uint val) +{ + int i; + uint test = 1; + for (i=0; (!(val & test)) && i<32; i++, test<<=1); + return (i == 32) ? -1 : i; +} +#endif + +/*** KPixmapIO ***/ + +KPixmapIO::KPixmapIO() +{ + m_bShm = false; + d = new KPixmapIOPrivate; + +#ifdef HAVE_MITSHM + setShmPolicy(ShmDontKeep); + KConfig *config = KGlobal::config(); + if (!config->readBoolEntry("UseMitShm", true)) + return; + + int ignore; + if (XQueryExtension(qt_xdisplay(), "MIT-SHM", &ignore, &ignore, &ignore)) + { + if (XShmQueryExtension(qt_xdisplay())) + m_bShm = true; + } + if (!m_bShm) + { + kdDebug(290) << k_lineinfo << "MIT-SHM not available!\n"; + d->ximage = 0; + d->shminfo = 0; + d->shmsize = 0; + return; + } + + // Sort out bit format. Create a temporary XImage for this. + d->shminfo = new XShmSegmentInfo; + d->ximage = XShmCreateImage(qt_xdisplay(), (Visual *) QPaintDevice::x11AppVisual(), + QPaintDevice::x11AppDepth(), ZPixmap, 0L, d->shminfo, 10, 10); + d->bpp = d->ximage->bits_per_pixel; + d->first_try = true; + int bpp = d->bpp; + if (d->ximage->byte_order == LSBFirst) + bpp++; + int red_shift = lowest_bit(d->ximage->red_mask); + int green_shift = lowest_bit(d->ximage->green_mask); + int blue_shift = lowest_bit(d->ximage->blue_mask); + XDestroyImage(d->ximage); d->ximage = 0L; + d->shmsize = 0; + + // Offer discrete possibilities for the bitformat. Each will have its + // own routine. The general algorithm using bitshifts is much too slow; + // this has to be done for every pixel! + + if ((bpp == 32) && (red_shift == 16) && (green_shift == 8) && + (blue_shift == 0)) + d->byteorder = bo32_ARGB; + else if ((bpp == 32) && (red_shift == 0) && (green_shift == 8) && + (blue_shift == 16)) + d->byteorder = bo32_BGRA; + else if ((bpp == 33) && (red_shift == 16) && (green_shift == 8) && + (blue_shift == 0)) + d->byteorder = bo32_BGRA; + else if ((bpp == 24) && (red_shift == 16) && (green_shift == 8) && + (blue_shift == 0)) + d->byteorder = bo24_RGB; + else if ((bpp == 24) && (red_shift == 0) && (green_shift == 8) && + (blue_shift == 16)) + d->byteorder = bo24_BGR; + else if ((bpp == 25) && (red_shift == 16) && (green_shift == 8) && + (blue_shift == 0)) + d->byteorder = bo24_BGR; + else if ((bpp == 16) && (red_shift == 11) && (green_shift == 5) && + (blue_shift == 0)) + d->byteorder = bo16_RGB_565; + else if ((bpp == 16) && (red_shift == 10) && (green_shift == 5) && + (blue_shift == 0)) + d->byteorder = bo16_RGB_555; + else if ((bpp == 17) && (red_shift == 11) && (green_shift == 5) && + (blue_shift == 0)) + d->byteorder = bo16_BGR_565; + else if ((bpp == 17) && (red_shift == 10) && (green_shift == 5) && + (blue_shift == 0)) + d->byteorder = bo16_BGR_555; + else if ((bpp == 8) || (bpp == 9)) + d->byteorder = bo8; + else + { + m_bShm = false; + kdWarning(290) << "Byte order not supported!" << endl; + kdWarning(290) << "red = " << red_shift + << ", green = " << green_shift + << ", blue = " << blue_shift << endl; + kdWarning(290) << "Please report to \n"; + } +#else + d->shmsize = 0; + d->ximage = 0; +#endif +} + + +KPixmapIO::~KPixmapIO() +{ + destroyXImage(); + destroyShmSegment(); +#ifdef HAVE_MITSHM + delete d->shminfo; +#endif + delete d; +} + + +QPixmap KPixmapIO::convertToPixmap(const QImage &img) +{ + int size = img.width() * img.height(); + if (m_bShm && (img.depth() > 1) && (d->bpp > 8) && (size > d->threshold)) + { + QPixmap dst(img.width(), img.height()); + putImage(&dst, 0, 0, &img); + return dst; + } else + { + QPixmap dst; + dst.convertFromImage(img); + return dst; + } + +} + + +QImage KPixmapIO::convertToImage(const QPixmap &pm) +{ + QImage image; + int size = pm.width() * pm.height(); + if (m_bShm && (d->bpp >= 8) && (size > d->threshold)) + image = getImage(&pm, 0, 0, pm.width(), pm.height()); + else + image = pm.convertToImage(); + return image; +} + + +void KPixmapIO::putImage(QPixmap *dst, const QPoint &offset, + const QImage *src) +{ + putImage(dst, offset.x(), offset.y(), src); +} + + +void KPixmapIO::putImage(QPixmap *dst, int dx, int dy, const QImage *src) +{ + int size = src->width() * src->height(); + bool fallback = true; + if (m_bShm && (src->depth() > 1) && (d->bpp > 8) && (size > d->threshold)) + { +#ifdef HAVE_MITSHM + if( initXImage(src->width(), src->height())) + { + convertToXImage(*src); + XShmPutImage(qt_xdisplay(), dst->handle(), qt_xget_temp_gc(qt_xscreen(), false), d->ximage, + dx, dy, 0, 0, src->width(), src->height(), false); + // coolo: do we really need this here? I see no good for it + XSync(qt_xdisplay(), false); + doneXImage(); + fallback = false; + } +#endif + } + if( fallback ) + { + QPixmap pix; + pix.convertFromImage(*src); + bitBlt(dst, dx, dy, &pix, 0, 0, pix.width(), pix.height()); + } +} + + +QImage KPixmapIO::getImage(const QPixmap *src, const QRect &rect) +{ + return getImage(src, rect.x(), rect.y(), rect.width(), rect.height()); +} + + +QImage KPixmapIO::getImage(const QPixmap *src, int sx, int sy, int sw, int sh) +{ + QImage image; + int size = src->width() * src->height(); + bool fallback = true; + if ((m_bShm) && (d->bpp >= 8) && (size > d->threshold)) + { +#ifdef HAVE_MITSHM + if( initXImage(sw, sh)) + { + XShmGetImage(qt_xdisplay(), src->handle(), d->ximage, sx, sy, AllPlanes); + image = convertFromXImage(); + doneXImage(); + fallback = false; + } +#endif + } + if( fallback ) + { + QPixmap pix(sw, sh); + bitBlt(&pix, 0, 0, src, sx, sy, sw, sh); + image = pix.convertToImage(); + } + return image; +} + + +#ifdef HAVE_MITSHM + +void KPixmapIO::preAllocShm(int size) +{ + destroyXImage(); + createShmSegment(size); +} + + +void KPixmapIO::setShmPolicy(int policy) +{ + switch (policy) + { + case ShmDontKeep: + d->shmpolicy = ShmDontKeep; + d->threshold = 5000; + break; + case ShmKeepAndGrow: + d->shmpolicy = ShmKeepAndGrow; + d->threshold = 2000; + break; + default: + break; + } +} + + +bool KPixmapIO::initXImage(int w, int h) +{ + if (d->ximage && (w == d->ximage->width) && (h == d->ximage->height)) + return true; + + if( !createXImage(w, h)) + return false; + int size = d->ximage->bytes_per_line * d->ximage->height; + if (size > d->shmsize) + { + if( !createShmSegment(size)) + { + destroyXImage(); + return false; + } + } + d->ximage->data = d->shminfo->shmaddr; + return true; +} + + +void KPixmapIO::doneXImage() +{ + if (d->shmpolicy == ShmDontKeep) + { + destroyXImage(); + destroyShmSegment(); + } +} + + +void KPixmapIO::destroyXImage() +{ + if (d->ximage) + { + XDestroyImage(d->ximage); + d->ximage = 0L; + } +} + + +bool KPixmapIO::createXImage(int w, int h) +{ + destroyXImage(); + d->ximage = XShmCreateImage(qt_xdisplay(), (Visual *) QPaintDevice::x11AppVisual(), + QPaintDevice::x11AppDepth(), ZPixmap, 0L, d->shminfo, w, h); + return d->ximage != None; +} + + +void KPixmapIO::destroyShmSegment() +{ + if (d->shmsize) + { + XShmDetach(qt_xdisplay(), d->shminfo); + shmdt(d->shminfo->shmaddr); + shmctl(d->shminfo->shmid, IPC_RMID, 0); + d->shmsize = 0; + } +} + +static bool use_xshm = true; +static unsigned long kpixmapio_serial; +static int (*old_errhandler)(Display *dpy, XErrorEvent *ev) = 0; + +static int kpixmapio_errorhandler(Display *dpy, XErrorEvent *ev) +{ + if(ev->serial == kpixmapio_serial) { + /* assuming that xshm errors mean it can't be used at all + (e.g. remote display) */ + use_xshm = false; + kdDebug(290) << "Disabling Xshm" << endl; + return 0; + } else { + // another error + return old_errhandler(dpy, ev); + } +} + +bool KPixmapIO::createShmSegment(int size) +{ + destroyShmSegment(); + d->shminfo->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0600); + if ( d->shminfo->shmid < 0) + { + kdWarning(290) << "Could not get shared memory segment.\n"; + m_bShm = false; + return false; + } + + d->shminfo->shmaddr = (char *) shmat(d->shminfo->shmid, 0, 0); + if (d->shminfo->shmaddr == (char *)-1) + { + kdWarning(290) << "Could not attach shared memory segment.\n"; + m_bShm = false; + shmctl(d->shminfo->shmid, IPC_RMID, 0); + return false; + } + + d->shminfo->readOnly = false; + + if (d->first_try) { + // make sure that we don't get errors of old stuff + XSync(qt_xdisplay(), False); + old_errhandler = XSetErrorHandler(kpixmapio_errorhandler); + kpixmapio_serial = NextRequest(qt_xdisplay()); + } + + if ( !XShmAttach(qt_xdisplay(), d->shminfo)) + { + kdWarning() << "X-Server could not attach shared memory segment.\n"; + m_bShm = false; + shmdt(d->shminfo->shmaddr); + shmctl(d->shminfo->shmid, IPC_RMID, 0); + } + + if (d->first_try) { + XSync(qt_xdisplay(), false); + + if (!use_xshm) + m_bShm = false; + + XSetErrorHandler(old_errhandler); + d->first_try = false; + } + d->shmsize = size; + + return m_bShm; +} + + +/* + * The following functions convertToXImage/convertFromXImage are a little + * long. This is because of speed, I want to get as much out of the inner + * loop as possible. + */ + +QImage KPixmapIO::convertFromXImage() +{ + int x, y; + int width = d->ximage->width, height = d->ximage->height; + int bpl = d->ximage->bytes_per_line; + char *data = d->ximage->data; + + QImage image; + if (d->bpp == 8) + { + image.create(width, height, 8); + + // Query color map. Don't remove unused entries as a speed + // optmization. + int i, ncells = 256; + XColor *cmap = new XColor[ncells]; + for (i=0; i> 8)); + } else + image.create(width, height, 32); + + switch (d->byteorder) + { + + case bo8: + { + for (y=0; y>= 16; + val = ((pixel & 0xf800) << 8) | ((pixel & 0x7e0) << 5) | + ((pixel & 0x1f) << 3); + *dst++ = val; + } + if (width%2) + { + pixel = *src++; + val = ((pixel & 0xf800) << 8) | ((pixel & 0x7e0) << 5) | + ((pixel & 0x1f) << 3); + *dst++ = val; + } + } + break; + } + + case bo16_RGB_555: + case bo16_BGR_555: + { + Q_INT32 pixel, *src; + QRgb *dst, val; + for (y=0; y>= 16; + val = ((pixel & 0x7c00) << 9) | ((pixel & 0x3e0) << 6) | + ((pixel & 0x1f) << 3); + *dst++ = val; + } + if (width%2) + { + pixel = *src++; + val = ((pixel & 0x7c00) << 9) | ((pixel & 0x3e0) << 6) | + ((pixel & 0x1f) << 3); + *dst++ = val; + } + } + break; + } + + case bo24_RGB: + { + char *src; + QRgb *dst; + int w1 = width/4; + Q_INT32 d1, d2, d3; + for (y=0; y> 24) | (d2 << 8); + *dst++ = (d3 << 16) | (d2 >> 16); + *dst++ = d3 >> 8; + } + for (x=w1*4; x> 24) | (d2 << 8); + *dst++ = (d3 << 16) | (d2 >> 16); + *dst++ = d3 >> 8; + } + for (x=w1*4; xximage->width, height = d->ximage->height; + int bpl = d->ximage->bytes_per_line; + char *data = d->ximage->data; + + switch (d->byteorder) + { + + case bo16_RGB_555: + case bo16_BGR_555: + + if (img.depth() == 32) + { + QRgb *src, pixel; + Q_INT32 *dst, val; + for (y=0; y> 9) | ((pixel & 0xf800) >> 6) | + ((pixel & 0xff) >> 3); + pixel = *src++; + val |= (((pixel & 0xf80000) >> 9) | ((pixel & 0xf800) >> 6) | + ((pixel & 0xff) >> 3)) << 16; + *dst++ = val; + } + if (width%2) + { + pixel = *src++; + *((Q_INT16 *)dst) = ((pixel & 0xf80000) >> 9) | + ((pixel & 0xf800) >> 6) | ((pixel & 0xff) >> 3); + } + } + } else + { + uchar *src; + Q_INT32 val, *dst; + QRgb pixel, *clut = img.colorTable(); + for (y=0; y> 9) | ((pixel & 0xf800) >> 6) | + ((pixel & 0xff) >> 3); + pixel = clut[*src++]; + val |= (((pixel & 0xf80000) >> 9) | ((pixel & 0xf800) >> 6) | + ((pixel & 0xff) >> 3)) << 16; + *dst++ = val; + } + if (width%2) + { + pixel = clut[*src++]; + *((Q_INT16 *)dst) = ((pixel & 0xf80000) >> 9) | + ((pixel & 0xf800) >> 6) | ((pixel & 0xff) >> 3); + } + } + } + break; + + case bo16_RGB_565: + case bo16_BGR_565: + + if (img.depth() == 32) + { + QRgb *src, pixel; + Q_INT32 *dst, val; + for (y=0; y> 8) | ((pixel & 0xfc00) >> 5) | + ((pixel & 0xff) >> 3); + pixel = *src++; + val |= (((pixel & 0xf80000) >> 8) | ((pixel & 0xfc00) >> 5) | + ((pixel & 0xff) >> 3)) << 16; + *dst++ = val; + } + if (width%2) + { + pixel = *src++; + *((Q_INT16 *)dst) = ((pixel & 0xf80000) >> 8) | + ((pixel & 0xfc00) >> 5) | ((pixel & 0xff) >> 3); + } + } + } else + { + uchar *src; + Q_INT32 val, *dst; + QRgb pixel, *clut = img.colorTable(); + for (y=0; y> 8) | ((pixel & 0xfc00) >> 5) | + ((pixel & 0xff) >> 3); + pixel = clut[*src++]; + val |= (((pixel & 0xf80000) >> 8) | ((pixel & 0xfc00) >> 5) | + ((pixel & 0xff) >> 3)) << 16; + *dst++ = val; + } + if (width%2) + { + pixel = clut[*src++]; + *((Q_INT16 *)dst) = ((pixel & 0xf80000) >> 8) | + ((pixel & 0xfc00) >> 5) | ((pixel & 0xff) >> 3); + } + } + } + break; + + case bo24_RGB: + + if (img.depth() == 32) + { + char *dst; + int w1 = width/4; + QRgb *src, d1, d2, d3, d4; + for (y=0; y> 8) | (d3 << 16); + *((Q_INT32 *)dst+2) = (d4 << 8) | (d3 >> 16); + dst += 12; + } + for (x=w1*4; x> 8) | (d3 << 16); + *((Q_INT32 *)dst+2) = (d4 << 8) | (d3 >> 16); + dst += 12; + } + for (x=w1*4; x> 8) | (d3 << 16); + *((Q_INT32 *)dst+2) = (d4 << 8) | (d3 >> 16); + dst += 12; + } + for (x=w1*4; x> 8) | (d3 << 16); + *((Q_INT32 *)dst+2) = (d4 << 8) | (d3 >> 16); + dst += 12; + } + for (x=w1*4; x