QImage ImageBufferDataPrivateUnaccelerated::toQImage() const { QPaintEngine* paintEngine = m_pixmap.paintEngine(); if (!paintEngine || paintEngine->type() != QPaintEngine::Raster) return m_pixmap.toImage(); // QRasterPixmapData::toImage() will deep-copy the backing QImage if there's an active QPainter on it. // For performance reasons, we don't want that here, so we temporarily redirect the paint engine. QPaintDevice* currentPaintDevice = paintEngine->paintDevice(); paintEngine->setPaintDevice(0); QImage image = m_pixmap.toImage(); paintEngine->setPaintDevice(currentPaintDevice); return image; }
void X11EmbedContainer::setBackgroundPixmap(QPixmap background) { if (!clientWinId()) { return; } //Prevent updating the background-image if possible. Updating can cause a very annoying flicker due to the XClearArea, and thus has to be kept to a minimum QImage image; if (background.paintEngine()->type() != QPaintEngine::X11) image = background.toImage(); // With the raster graphics system this call just returns the backing image, so the image data isn't copied. else image = background.copy().toImage(); //With the X11 graphics engine, we have to create a copy first, else we get a crash if(d->oldBackgroundImage == image) { return; } d->oldBackgroundImage = image; Display* display = QX11Info::display(); XSetWindowBackgroundPixmap(display, clientWinId(), toX11Pixmap(background).handle()); XClearArea(display, clientWinId(), 0, 0, 0, 0, True); }
QPixmap transition(const QPixmap &from, const QPixmap &to, qreal amount) { if (from.isNull() && to.isNull()) { return from; } if (qFuzzyCompare(amount + 1, qreal(1.0))) { return from; } QRect startRect(from.rect()); QRect targetRect(to.rect()); QSize pixmapSize = startRect.size().expandedTo(targetRect.size()); QRect toRect = QRect(QPoint(0,0), pixmapSize); targetRect.moveCenter(toRect.center()); startRect.moveCenter(toRect.center()); //paint to in the center of from QColor color; color.setAlphaF(amount); // If the native paint engine supports Porter/Duff compositing and CompositionMode_Plus QPaintEngine *paintEngine = from.paintEngine(); if (paintEngine && paintEngine->hasFeature(QPaintEngine::PorterDuff) && paintEngine->hasFeature(QPaintEngine::BlendModes)) { QPixmap startPixmap(pixmapSize); startPixmap.fill(Qt::transparent); QPixmap targetPixmap(pixmapSize); targetPixmap.fill(Qt::transparent); QPainter p; p.begin(&targetPixmap); p.drawPixmap(targetRect, to); p.setCompositionMode(QPainter::CompositionMode_DestinationIn); p.fillRect(targetRect, color); p.end(); p.begin(&startPixmap); p.drawPixmap(startRect, from); p.setCompositionMode(QPainter::CompositionMode_DestinationOut); p.fillRect(startRect, color); p.setCompositionMode(QPainter::CompositionMode_Plus); p.drawPixmap(targetRect, targetPixmap); p.end(); return startPixmap; } #if defined(Q_WS_X11) && defined(HAVE_XRENDER) // We have Xrender support else if (paintEngine && paintEngine->hasFeature(QPaintEngine::PorterDuff)) { // QX11PaintEngine doesn't implement CompositionMode_Plus in Qt 4.3, // which we need to be able to do a transition from one pixmap to // another. // // In order to avoid the overhead of converting the pixmaps to images // and doing the operation entirely in software, this function has a // specialized path for X11 that uses Xrender directly to do the // transition. This operation can be fully accelerated in HW. // // This specialization can be removed when QX11PaintEngine supports // CompositionMode_Plus. QPixmap source(targetPixmap), destination(startPixmap); source.detach(); destination.detach(); Display *dpy = QX11Info::display(); XRenderPictFormat *format = XRenderFindStandardFormat(dpy, PictStandardA8); XRenderPictureAttributes pa; pa.repeat = 1; // RepeatNormal // Create a 1x1 8 bit repeating alpha picture Pixmap pixmap = XCreatePixmap(dpy, destination.handle(), 1, 1, 8); Picture alpha = XRenderCreatePicture(dpy, pixmap, format, CPRepeat, &pa); XFreePixmap(dpy, pixmap); // Fill the alpha picture with the opacity value XRenderColor xcolor; xcolor.alpha = quint16(0xffff * amount); XRenderFillRectangle(dpy, PictOpSrc, alpha, &xcolor, 0, 0, 1, 1); // Reduce the alpha of the destination with 1 - opacity XRenderComposite(dpy, PictOpOutReverse, alpha, None, destination.x11PictureHandle(), 0, 0, 0, 0, 0, 0, destination.width(), destination.height()); // Add source * opacity to the destination XRenderComposite(dpy, PictOpAdd, source.x11PictureHandle(), alpha, destination.x11PictureHandle(), toRect.x(), toRect.y(), 0, 0, 0, 0, destination.width(), destination.height()); XRenderFreePicture(dpy, alpha); return destination; } #endif else { // Fall back to using QRasterPaintEngine to do the transition. QImage under(pixmapSize, QImage::Format_ARGB32_Premultiplied); under.fill(Qt::transparent); QImage over(pixmapSize, QImage::Format_ARGB32_Premultiplied); over.fill(Qt::transparent); QPainter p; p.begin(&over); p.drawPixmap(targetRect, to); p.setCompositionMode(QPainter::CompositionMode_DestinationIn); p.fillRect(over.rect(), color); p.end(); p.begin(&under); p.drawPixmap(startRect, from); p.setCompositionMode(QPainter::CompositionMode_DestinationOut); p.fillRect(startRect, color); p.setCompositionMode(QPainter::CompositionMode_Plus); p.drawImage(toRect.topLeft(), over); p.end(); return QPixmap::fromImage(under); } }
void X11EmbedContainer::setBackgroundPixmap(QPixmap background) { if (!clientWinId()) { return; } Display *display = QX11Info::display(); Pixmap bg = XCreatePixmap(display, clientWinId(), width(), height(), d->attr.depth); XRenderPictFormat *format = XRenderFindVisualFormat(display, d->attr.visual); Picture picture = XRenderCreatePicture(display, bg, format, 0, 0); //Prevent updating the background-image if possible. Updating can cause a very annoying flicker due to the XClearArea, and thus has to be kept to a minimum QImage image; if (background.paintEngine()->type() != QPaintEngine::X11) image = background.toImage(); // With the raster graphics system this call just returns the backing image, so the image data isn't copied. else image = background.copy().toImage(); //With the X11 graphics engine, we have to create a copy first, else we get a crash if(d->oldBackgroundImage == image) { XFreePixmap(display, bg); XRenderFreePicture(display, picture); return; } d->oldBackgroundImage = image; if (background.paintEngine()->type() != QPaintEngine::X11) { XRenderPictFormat *format = 0; int depth = 0; int bpp = 0; if (image.format() == QImage::Format_ARGB32_Premultiplied) { format = XRenderFindStandardFormat(display, PictStandardARGB32); depth = 32; bpp = 32; } else if (image.format() == QImage::Format_RGB32) { format = XRenderFindStandardFormat(display, PictStandardRGB24); depth = 24; bpp = 32; } else if (image.format() == QImage::Format_RGB16) { bpp = 16; depth = 16; // Try to find a picture format that matches the image format. // The Render spec doesn't require the X server to support 16bpp formats, // so this call can fail. XRenderPictFormat templ; templ.type = PictTypeDirect; templ.direct.alpha = 0; templ.direct.alphaMask = 0; templ.depth = 16; templ.direct.red = 11; templ.direct.redMask = 0x1f; templ.direct.green = 5; templ.direct.greenMask = 0x3f; templ.direct.blue = 0; templ.direct.blueMask = 0x1f; format = XRenderFindFormat(display, PictFormatType | PictFormatDepth | PictFormatAlpha | PictFormatAlphaMask | PictFormatRed | PictFormatRedMask | PictFormatGreen | PictFormatGreenMask | PictFormatBlue | PictFormatBlueMask, &templ, 0); } if (format == 0) { // Convert the image to a standard format. if (image.hasAlphaChannel()) { image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); format = XRenderFindStandardFormat(display, PictStandardARGB32); depth = 32; } else { image = image.convertToFormat(QImage::Format_RGB32); format = XRenderFindStandardFormat(display, PictStandardRGB24); depth = 24; } bpp = 32; } if (image.format() == QImage::Format_RGB32) { // Make sure the would be alpha bits are set to 1. quint32 * const pixels = (quint32*)(const_cast<const QImage*>(&image)->bits()); for (int i = 0; i < image.width() * image.height(); i++) { pixels[i] |= 0xff000000; } } Q_ASSERT(format != 0); // Get the image data into a pixmap XImage ximage; ximage.width = image.width(); ximage.height = image.height(); ximage.xoffset = 0; ximage.format = ZPixmap; // This is a hack to prevent the image data from detaching ximage.data = (char*) const_cast<const QImage*>(&image)->bits(); #if Q_BYTE_ORDER == Q_BIG_ENDIAN ximage.byte_order = MSBFirst; #else ximage.byte_order = LSBFirst; #endif ximage.bitmap_unit = bpp; ximage.bitmap_bit_order = ximage.byte_order; ximage.bitmap_pad = bpp; ximage.depth = depth; ximage.bytes_per_line = image.bytesPerLine(); ximage.bits_per_pixel = bpp; if (depth > 16) { ximage.red_mask = 0x00ff0000; ximage.green_mask = 0x0000ff00; ximage.blue_mask = 0x000000ff; } else { // r5g6b5 ximage.red_mask = 0xf800; ximage.green_mask = 0x07e0; ximage.blue_mask = 0x001f; } ximage.obdata = 0; if (XInitImage(&ximage) == 0) { XRenderFreePicture(display, picture); XFreePixmap(display, bg); return; } Pixmap pm = XCreatePixmap(display, clientWinId(), width(), height(), ximage.depth); GC gc = XCreateGC(display, pm, 0, 0); XPutImage(display, pm, gc, &ximage, 0, 0, 0, 0, width(), height()); XFreeGC(display, gc); Picture pict = XRenderCreatePicture(display, pm, format, 0, 0); XRenderComposite(display, PictOpSrc, pict, None, picture, 0, 0, 0, 0, 0, 0, width(), height()); XRenderFreePicture(display, pict); XFreePixmap(display, pm); } else { XRenderComposite(display, PictOpSrc, background.x11PictureHandle(), None, picture, 0, 0, 0, 0, 0, 0, width(), height()); } XSetWindowBackgroundPixmap(display, clientWinId(), bg); XRenderFreePicture(display, picture); XFreePixmap(display, bg); XClearArea(display, clientWinId(), 0, 0, 0, 0, True); }