blob: d2e6606166f84cd7be982a5384da8c42ed23642e [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/compositor/software_output_device_x11.h"
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "content/public/browser/browser_thread.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "ui/base/x/x11_util.h"
#include "ui/base/x/x11_util_internal.h"
#include "ui/compositor/compositor.h"
#include "ui/gfx/x/x11_types.h"
namespace content {
SoftwareOutputDeviceX11::SoftwareOutputDeviceX11(ui::Compositor* compositor)
: compositor_(compositor), display_(gfx::GetXDisplay()), gc_(NULL) {
// TODO(skaslev) Remove this when crbug.com/180702 is fixed.
DCHECK_CURRENTLY_ON(BrowserThread::UI);
gc_ = XCreateGC(display_, compositor_->widget(), 0, NULL);
if (!XGetWindowAttributes(display_, compositor_->widget(), &attributes_)) {
LOG(ERROR) << "XGetWindowAttributes failed for window "
<< compositor_->widget();
return;
}
}
SoftwareOutputDeviceX11::~SoftwareOutputDeviceX11() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
XFreeGC(display_, gc_);
}
void SoftwareOutputDeviceX11::EndPaint() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
SoftwareOutputDevice::EndPaint();
if (!surface_)
return;
gfx::Rect rect = damage_rect_;
rect.Intersect(gfx::Rect(viewport_pixel_size_));
if (rect.IsEmpty())
return;
int bpp = gfx::BitsPerPixelForPixmapDepth(display_, attributes_.depth);
if (bpp != 32 && bpp != 16 && ui::QueryRenderSupport(display_)) {
// gfx::PutARGBImage only supports 16 and 32 bpp, but Xrender can do other
// conversions.
Pixmap pixmap = XCreatePixmap(
display_, compositor_->widget(), rect.width(), rect.height(), 32);
GC gc = XCreateGC(display_, pixmap, 0, NULL);
XImage image;
memset(&image, 0, sizeof(image));
SkPixmap skia_pixmap;
surface_->peekPixels(&skia_pixmap);
image.width = viewport_pixel_size_.width();
image.height = viewport_pixel_size_.height();
image.depth = 32;
image.bits_per_pixel = 32;
image.format = ZPixmap;
image.byte_order = LSBFirst;
image.bitmap_unit = 8;
image.bitmap_bit_order = LSBFirst;
image.bytes_per_line = skia_pixmap.rowBytes();
image.red_mask = 0xff;
image.green_mask = 0xff00;
image.blue_mask = 0xff0000;
image.data = const_cast<char*>(static_cast<const char*>(
skia_pixmap.addr()));
XPutImage(display_,
pixmap,
gc,
&image,
rect.x(),
rect.y() /* source x, y */,
0,
0 /* dest x, y */,
rect.width(),
rect.height());
XFreeGC(display_, gc);
Picture picture = XRenderCreatePicture(
display_, pixmap, ui::GetRenderARGB32Format(display_), 0, NULL);
XRenderPictFormat* pictformat =
XRenderFindVisualFormat(display_, attributes_.visual);
Picture dest_picture = XRenderCreatePicture(
display_, compositor_->widget(), pictformat, 0, NULL);
XRenderComposite(display_,
PictOpSrc, // op
picture, // src
0, // mask
dest_picture, // dest
0, // src_x
0, // src_y
0, // mask_x
0, // mask_y
rect.x(), // dest_x
rect.y(), // dest_y
rect.width(), // width
rect.height()); // height
XRenderFreePicture(display_, picture);
XRenderFreePicture(display_, dest_picture);
XFreePixmap(display_, pixmap);
return;
}
// TODO(jbauman): Switch to XShmPutImage since it's async.
SkPixmap pixmap;
surface_->peekPixels(&pixmap);
gfx::PutARGBImage(
display_, attributes_.visual, attributes_.depth, compositor_->widget(),
gc_, static_cast<const uint8_t*>(pixmap.addr()),
viewport_pixel_size_.width(), viewport_pixel_size_.height(), rect.x(),
rect.y(), rect.x(), rect.y(), rect.width(), rect.height());
}
} // namespace content