QPixmap FX::tint(const QPixmap &mask, const QColor &color) { QPixmap pix = mask.copy(); pix.fill(Qt::transparent); #ifndef QT_NO_XRENDER if (useRender) { Q2XRenderColor(c, color); OXPicture tnt = createFill (dpy, &c); if (tnt == X::None) return pix; XRenderComposite( dpy, PictOpOver, tnt, mask.x11PictureHandle(), pix.x11PictureHandle(), 0, 0, 0, 0, 0, 0, mask.width(), mask.height()); XRenderFreePicture (dpy, tnt); } else #endif { QPainter p(&pix); p.setPen(Qt::NoPen); p.setBrush(color); p.drawRect(pix.rect()); p.end(); pix = FX::applyAlpha(pix, mask); } return pix; }
void FX::composite(const QPixmap &src, OXPicture mask, const QPixmap &dst, int sx, int sy, int mx, int my, int dx, int dy, uint w, uint h, int op) { XRenderComposite( dpy, op, src.x11PictureHandle(), mask, dst.x11PictureHandle(), sx, sy, mx, my, dx, dy, w, h ); }
void // TODO: would be cool to get this working - doesn't, though... FX::setAlpha(QPixmap &pix, const OXPicture &alpha) { XRenderPictureAttributes pa; pa.alpha_map = alpha; pa.alpha_x_origin = pa.alpha_y_origin = 0; XRenderChangePicture(dpy, pix.x11PictureHandle(), CPAlphaMap|CPAlphaXOrigin|CPAlphaYOrigin, &pa); }
bool FX::blend(const QPixmap &upper, QPixmap &lower, double opacity, int x, int y) { if (opacity == 0.0) return false; // haha... #ifndef QT_NO_XRENDER if (useRender) { OXPicture alpha = (opacity == 1.0) ? 0 : blendPicture(opacity); XRenderComposite (dpy, PictOpOver, upper.x11PictureHandle(), alpha, lower.x11PictureHandle(), 0, 0, 0, 0, x, y, upper.width(), upper.height()); } else #endif { QPixmap tmp; if ( useRaster ) // raster engine is broken... :-( { tmp = QPixmap(upper.size()); tmp.fill(Qt::transparent); QPainter p(&tmp); p.drawPixmap(0,0, upper); p.end(); } else tmp = upper; QPainter p; if (opacity < 1.0) { p.begin(&tmp); p.setCompositionMode(QPainter::CompositionMode_DestinationIn); p.fillRect(tmp.rect(), QColor(0,0,0, opacity*255.0)); p.end(); } p.begin(&lower); p.setCompositionMode(QPainter::CompositionMode_SourceOver); p.drawPixmap(x, y, tmp); p.end(); } return true; }
QPixmap FX::applyAlpha(const QPixmap &toThisPix, const QPixmap &fromThisPix, const QRect &rect, const QRect &alphaRect) { QPixmap pix; int sx,sy,ax,ay,w,h; if (rect.isNull()) { sx = sy = 0; w = toThisPix.width(); h = toThisPix.height(); } else rect.getRect(&sx,&sy,&w,&h); if (alphaRect.isNull()) { ax = ay = 0; } else { ax = alphaRect.x(); ay = alphaRect.y(); w = qMin(alphaRect.width(),w); h = qMin(alphaRect.height(),h); } if (w > fromThisPix.width() || h > fromThisPix.height()) pix = QPixmap(w, h); else pix = fromThisPix.copy(0,0,w,h); // cause slow depth conversion... pix.fill(Qt::transparent); #ifndef QT_NO_XRENDER if (useRender) { XRenderComposite( dpy, PictOpOver, toThisPix.x11PictureHandle(), fromThisPix.x11PictureHandle(), pix.x11PictureHandle(), sx, sy, ax, ay, 0, 0, w, h ); } else #endif { QPainter p(&pix); p.drawPixmap(0, 0, toThisPix, sx, sy, w, h); p.setCompositionMode(QPainter::CompositionMode_DestinationIn); p.drawPixmap(0, 0, fromThisPix, ax, ay, w, h); p.end(); } return pix; }
void PixmapRenderer::drawPixmap( QPainter& painter, QPixmap const& pixmap) { #if !defined(Q_WS_X11) drawPixmapNoXRender(painter, pixmap); #else QPaintDevice* const dev = painter.device(); QPoint offset; // Both x and y will be either zero or negative. QPaintDevice* const redir_dev = QPainter::redirected(painter.device(), &offset); QPaintDevice* const paint_dev = redir_dev ? redir_dev : dev; #if defined(ENABLE_OPENGL) if (dynamic_cast<QGLWidget*>(paint_dev)) { drawPixmapNoXRender(painter, pixmap); return; } #endif QRect const device_rect( QRect(0, 0, dev->width(), dev->height()).translated(-offset) ); QRectF const src_rect(pixmap.rect()); Display* const dpy = QX11Info::display(); Picture const src_pict = pixmap.x11PictureHandle(); Picture dst_pict = 0; if (QWidget* widget = dynamic_cast<QWidget*>(paint_dev)) { dst_pict = widget->x11PictureHandle(); } else if (QPixmap* pixmap = dynamic_cast<QPixmap*>(paint_dev)) { dst_pict = pixmap->x11PictureHandle(); } if (!dst_pict) { drawPixmapNoXRender(painter, pixmap); return; } // Note that device transform already accounts for offset // within a destination surface. QTransform const src_to_dst(painter.deviceTransform()); QTransform const dst_to_src(src_to_dst.inverted()); QPolygonF const dst_poly(src_to_dst.map(src_rect)); XTransform xform = {{ { XDoubleToFixed(dst_to_src.m11()), XDoubleToFixed(dst_to_src.m21()), XDoubleToFixed(dst_to_src.m31()) }, { XDoubleToFixed(dst_to_src.m12()), XDoubleToFixed(dst_to_src.m22()), XDoubleToFixed(dst_to_src.m32()) }, { XDoubleToFixed(dst_to_src.m13()), XDoubleToFixed(dst_to_src.m23()), XDoubleToFixed(dst_to_src.m33()) } }}; XRenderSetPictureTransform(dpy, src_pict, &xform); char const* filter = "fast"; if (painter.testRenderHint(QPainter::SmoothPixmapTransform)) { filter = "good"; } XRenderSetPictureFilter(dpy, src_pict, filter, 0, 0); QRectF const dst_rect_precise(dst_poly.boundingRect()); QRect const dst_rect_fitting( QPoint( int(ceil(dst_rect_precise.left())), int(ceil(dst_rect_precise.top())) ), QPoint( int(floor(dst_rect_precise.right())) - 1, int(floor(dst_rect_precise.bottom())) - 1 ) ); QRect dst_bounding_rect(device_rect); if (painter.hasClipping()) { QRect const clip_rect( src_to_dst.map(painter.clipPath()).boundingRect().toRect() ); dst_bounding_rect = dst_bounding_rect.intersected(clip_rect); } QRect const dst_rect(dst_rect_fitting.intersect(dst_bounding_rect)); // Note that XRenderComposite() expects destination coordinates // everywhere, even for source picture origin. XRenderComposite( dpy, PictOpSrc, src_pict, 0, dst_pict, dst_rect.left(), dst_rect.top(), 0, 0, dst_rect.left(), dst_rect.top(), dst_rect.width(), dst_rect.height() ); #endif }
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); }