summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-26 23:18:22 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-26 23:18:22 +0000
commit8ab8ff072cbfb539f594425233a3805367733e42 (patch)
tree4e55550442aca6b6a3729ca0b121864ca9710735 /chrome
parent76d2816ad27088432ce9d946facfaa091151dcf6 (diff)
downloadchromium_src-8ab8ff072cbfb539f594425233a3805367733e42.zip
chromium_src-8ab8ff072cbfb539f594425233a3805367733e42.tar.gz
chromium_src-8ab8ff072cbfb539f594425233a3805367733e42.tar.bz2
Linux: support displays without Xrender support.
VNC servers don't support Xrender. For this use case, we implement a slow fallback which byte-fiddles the Skia bitmaps as needed to support 32 and 24 bit visuals. Review URL: http://codereview.chromium.org/27227 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10523 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/renderer_host/backing_store.h15
-rw-r--r--chrome/browser/renderer_host/backing_store_x.cc100
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.cc3
-rw-r--r--chrome/common/x11_util.cc38
-rw-r--r--chrome/common/x11_util.h4
5 files changed, 151 insertions, 9 deletions
diff --git a/chrome/browser/renderer_host/backing_store.h b/chrome/browser/renderer_host/backing_store.h
index a74fe5d..14d1e38 100644
--- a/chrome/browser/renderer_host/backing_store.h
+++ b/chrome/browser/renderer_host/backing_store.h
@@ -37,9 +37,11 @@ class BackingStore {
// depth: the depth of the X window which will be drawn into
// visual: An Xlib Visual describing the format of the target window
// root_window: The X id of the root window
+ // use_render: if true, the X server supports Xrender
// use_shared_memory: if true, the X server is local
BackingStore(const gfx::Size& size, Display* x_connection, int depth,
- void* visual, XID root_window, bool use_shared_memory);
+ void* visual, XID root_window, bool use_render,
+ bool use_shared_memory);
// This is for unittesting only. An object constructed using this constructor
// will silently ignore all paints
explicit BackingStore(const gfx::Size& size);
@@ -98,11 +100,22 @@ class BackingStore {
#elif defined(OS_MACOSX)
skia::PlatformCanvas canvas_;
#elif defined(OS_LINUX)
+ // Paints the bitmap from the renderer onto the backing store without
+ // using Xrender to composite the pixmaps.
+ void PaintRectWithoutXrender(TransportDIB* bitmap,
+ const gfx::Rect& bitmap_rect);
+
// This is the connection to the X server where this backing store will be
// displayed.
Display *const display_;
// If this is true, then |connection_| is good for MIT-SHM (X shared memory).
const bool use_shared_memory_;
+ // If this is true, then we can use Xrender to composite our pixmaps.
+ const bool use_render_;
+ // If |use_render_| is false, this is the number of bits-per-pixel for |depth|
+ int pixmap_bpp_;
+ // This is the depth of the target window.
+ const int visual_depth_;
// The parent window (probably a GtkDrawingArea) for this backing store.
const XID root_window_;
// This is a handle to the server side pixmap which is our backing store.
diff --git a/chrome/browser/renderer_host/backing_store_x.cc b/chrome/browser/renderer_host/backing_store_x.cc
index e37fe77..75406fa 100644
--- a/chrome/browser/renderer_host/backing_store_x.cc
+++ b/chrome/browser/renderer_host/backing_store_x.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/compiler_specific.h"
#include "base/logging.h"
#include "chrome/common/transport_dib.h"
#include "chrome/common/x11_util.h"
@@ -27,19 +28,31 @@ BackingStore::BackingStore(const gfx::Size& size,
int depth,
void* visual,
Drawable root_window,
+ bool use_render,
bool use_shared_memory)
: size_(size),
display_(display),
use_shared_memory_(use_shared_memory),
+ use_render_(use_render),
+ visual_depth_(depth),
root_window_(root_window) {
const int width = size.width();
const int height = size.height();
+ COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, assumes_little_endian);
+
pixmap_ = XCreatePixmap(display_, root_window, width, height, depth);
- picture_ = XRenderCreatePicture(
- display_, pixmap_,
- x11_util::GetRenderVisualFormat(display_, static_cast<Visual*>(visual)),
- 0, NULL);
+
+ if (use_render_) {
+ picture_ = XRenderCreatePicture(
+ display_, pixmap_,
+ x11_util::GetRenderVisualFormat(display_, static_cast<Visual*>(visual)),
+ 0, NULL);
+ } else {
+ picture_ = 0;
+ pixmap_bpp_ = x11_util::BitsPerPixelForPixmapDepth(display, depth);
+ }
+
pixmap_gc_ = XCreateGC(display_, pixmap_, 0, NULL);
}
@@ -47,6 +60,8 @@ BackingStore::BackingStore(const gfx::Size& size)
: size_(size),
display_(NULL),
use_shared_memory_(false),
+ use_render_(false),
+ visual_depth_(-1),
root_window_(0) {
}
@@ -60,12 +75,89 @@ BackingStore::~BackingStore() {
XFreeGC(display_, static_cast<GC>(pixmap_gc_));
}
+void BackingStore::PaintRectWithoutXrender(TransportDIB* bitmap,
+ const gfx::Rect &bitmap_rect) {
+ const int width = bitmap_rect.width();
+ const int height = bitmap_rect.height();
+ Pixmap pixmap = XCreatePixmap(display_, root_window_, width, height,
+ visual_depth_);
+
+ XImage image;
+ memset(&image, 0, sizeof(image));
+
+ image.width = width;
+ image.height = height;
+ image.format = ZPixmap;
+ image.byte_order = LSBFirst;
+ image.bitmap_unit = 8;
+ image.bitmap_bit_order = LSBFirst;
+ image.red_mask = 0xff;
+ image.green_mask = 0xff00;
+ image.blue_mask = 0xff0000;
+
+ if (pixmap_bpp_ == 32) {
+ // If the X server depth is already 32-bits, then our job is easy.
+ image.depth = visual_depth_;
+ image.bits_per_pixel = 32;
+ image.bytes_per_line = width * 4;
+ image.data = static_cast<char*>(bitmap->memory());
+
+ XPutImage(display_, pixmap, static_cast<GC>(pixmap_gc_), &image,
+ 0, 0 /* source x, y */, 0, 0 /* dest x, y */,
+ width, height);
+ } else if (pixmap_bpp_ == 24) {
+ // In this case we just need to strip the alpha channel out of each
+ // pixel. This is the case which covers VNC servers since they don't
+ // support Xrender but typically have 24-bit visuals.
+ //
+ // It's possible to use some fancy SSE tricks here, but since this is the
+ // slow path anyway, we do it slowly.
+
+ uint8_t* bitmap24 = static_cast<uint8_t*>(malloc(3 * width * height));
+ const uint32_t* bitmap_in = static_cast<const uint32_t*>(bitmap->memory());
+ for (int y = 0; y < height; ++y) {
+ for (int x = 0; x < width; ++x) {
+ const uint32_t pixel = *(bitmap_in++);
+ bitmap24[0] = (pixel >> 16) & 0xff;
+ bitmap24[1] = (pixel >> 8) & 0xff;
+ bitmap24[2] = pixel & 0xff;
+ bitmap24 += 3;
+ }
+ }
+
+ image.depth = visual_depth_;
+ image.bits_per_pixel = 24;
+ image.bytes_per_line = width * 3;
+ image.data = reinterpret_cast<char*>(bitmap24);
+
+ XPutImage(display_, pixmap, static_cast<GC>(pixmap_gc_), &image,
+ 0, 0 /* source x, y */, 0, 0 /* dest x, y */,
+ width, height);
+
+ free(bitmap24);
+ } else {
+ CHECK(false) << "Sorry, we don't support your visual depth without "
+ "Xrender support (depth:" << visual_depth_
+ << " bpp:" << pixmap_bpp_ << ")";
+ }
+
+ XCopyArea(display_, pixmap /* source */, pixmap_ /* target */,
+ static_cast<GC>(pixmap_gc_),
+ 0, 0 /* source x, y */, bitmap_rect.width(), bitmap_rect.height(),
+ bitmap_rect.x(), bitmap_rect.y() /* dest x, y */);
+
+ XFreePixmap(display_, pixmap);
+}
+
void BackingStore::PaintRect(base::ProcessHandle process,
TransportDIB* bitmap,
const gfx::Rect& bitmap_rect) {
if (!display_)
return;
+ if (!use_render_)
+ return PaintRectWithoutXrender(bitmap, bitmap_rect);
+
const int width = bitmap_rect.width();
const int height = bitmap_rect.height();
Picture picture;
diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
index 4b5f19e..23f3067 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
@@ -288,11 +288,12 @@ BackingStore* RenderWidgetHostViewGtk::AllocBackingStore(
Display* display = x11_util::GetXDisplay();
void* visual = x11_util::GetVisualFromGtkWidget(view_);
XID root_window = x11_util::GetX11RootWindow();
+ bool use_render = x11_util::QueryRenderSupport(display);
bool use_shared_memory = x11_util::QuerySharedMemorySupport(display);
int depth = gtk_widget_get_visual(view_)->depth;
return new BackingStore(size, display, depth, visual, root_window,
- use_shared_memory);
+ use_render, use_shared_memory);
}
void RenderWidgetHostViewGtk::Paint(const gfx::Rect& damage_rect) {
diff --git a/chrome/common/x11_util.cc b/chrome/common/x11_util.cc
index 264ab9c..d10c320 100644
--- a/chrome/common/x11_util.cc
+++ b/chrome/common/x11_util.cc
@@ -82,6 +82,22 @@ bool QuerySharedMemorySupport(Display* dpy) {
return shared_memory_support;
}
+bool QueryRenderSupport(Display* dpy) {
+ static bool render_supported = false;
+ static bool render_supported_cached = false;
+
+ if (render_supported_cached)
+ return render_supported;
+
+ // We don't care about the version of Xrender since all the features which
+ // we use are included in every version.
+ int dummy;
+ render_supported = XRenderQueryExtension(dpy, &dummy, &dummy);
+ render_supported_cached = true;
+
+ return render_supported;
+}
+
XID GetX11RootWindow() {
return GDK_WINDOW_XID(gdk_get_default_root_window());
}
@@ -94,14 +110,30 @@ void* GetVisualFromGtkWidget(GtkWidget* widget) {
return GDK_VISUAL_XVISUAL(gtk_widget_get_visual(widget));
}
+int BitsPerPixelForPixmapDepth(Display* dpy, int depth) {
+ int count;
+ XPixmapFormatValues* formats = XListPixmapFormats(dpy, &count);
+ if (!formats)
+ return -1;
+
+ int bits_per_pixel = -1;
+ for (int i = 0; i < count; ++i) {
+ if (formats[i].depth == depth) {
+ bits_per_pixel = formats[i].bits_per_pixel;
+ break;
+ }
+ }
+
+ XFree(formats);
+ return bits_per_pixel;
+}
+
XRenderPictFormat* GetRenderVisualFormat(Display* dpy, Visual* visual) {
static XRenderPictFormat* pictformat = NULL;
if (pictformat)
return pictformat;
- int dummy;
- if (!XRenderQueryExtension(dpy, &dummy, &dummy))
- CHECK(false) << "XRENDER not supported on display";
+ DCHECK(QueryRenderSupport(dpy));
pictformat = XRenderFindVisualFormat(dpy, visual);
CHECK(pictformat) << "XRENDER does not support default visual";
diff --git a/chrome/common/x11_util.h b/chrome/common/x11_util.h
index 6e5072b..4800a69 100644
--- a/chrome/common/x11_util.h
+++ b/chrome/common/x11_util.h
@@ -27,6 +27,8 @@ namespace x11_util {
Display* GetXDisplay();
// Return true iff the connection supports X shared memory
bool QuerySharedMemorySupport(Display* dpy);
+ // Return true iff the display supports Xrender
+ bool QueryRenderSupport(Display* dpy);
// These functions do not cache their results
@@ -37,6 +39,8 @@ namespace x11_util {
// Get a Visual from the given widget. Since we don't include the Xlib
// headers, this is returned as a void*.
void* GetVisualFromGtkWidget(GtkWidget*);
+ // Return the number of bits-per-pixel for a pixmap of the given depth
+ int BitsPerPixelForPixmapDepth(Display*, int depth);
// Return a handle to a server side pixmap. |shared_memory_key| is a SysV
// IPC key. The shared memory region must contain 32-bit pixels.