示例#1
0
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);
}
示例#3
0
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);
    }
}
示例#4
0
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);
}