summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/SConscript4
-rw-r--r--chrome/browser/browser.scons2
-rw-r--r--chrome/browser/renderer_host/backing_store.cc16
-rw-r--r--chrome/browser/renderer_host/backing_store.h51
-rw-r--r--chrome/browser/renderer_host/backing_store_posix.cc3
-rw-r--r--chrome/browser/renderer_host/backing_store_win.cc4
-rw-r--r--chrome/browser/renderer_host/backing_store_x.cc169
-rw-r--r--chrome/browser/renderer_host/backing_store_xcb.cc40
-rw-r--r--chrome/browser/renderer_host/render_widget_host.cc13
-rw-r--r--chrome/browser/renderer_host/render_widget_host.h4
-rw-r--r--chrome/browser/renderer_host/render_widget_host_unittest.cc5
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view.h4
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.cc36
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_gtk.h1
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.h1
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_mac.mm5
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_win.cc5
-rw-r--r--chrome/browser/renderer_host/render_widget_host_view_win.h3
-rw-r--r--chrome/browser/renderer_host/test_render_view_host.cc7
-rw-r--r--chrome/browser/renderer_host/test_render_view_host.h1
-rw-r--r--chrome/common/common.scons3
-rw-r--r--chrome/common/transport_dib.h14
-rw-r--r--chrome/common/transport_dib_linux.cc20
-rw-r--r--chrome/common/x11_util.cc181
-rw-r--r--chrome/common/x11_util.h52
-rw-r--r--chrome/common/x11_util_internal.h31
-rw-r--r--chrome/test/perf/perftests.scons4
-rw-r--r--chrome/test/unit/unit_tests.scons5
28 files changed, 596 insertions, 88 deletions
diff --git a/chrome/SConscript b/chrome/SConscript
index 1ce30e2..ced7536 100644
--- a/chrome/SConscript
+++ b/chrome/SConscript
@@ -129,6 +129,10 @@ env_dll.Append(
'sdch',
'sqlite',
'v8_snapshot',
+
+ 'X11',
+ 'Xrender',
+ 'Xext',
],
)
diff --git a/chrome/browser/browser.scons b/chrome/browser/browser.scons
index 789cab1..9be39b9 100644
--- a/chrome/browser/browser.scons
+++ b/chrome/browser/browser.scons
@@ -745,7 +745,7 @@ if not env.Bit('windows'):
# Add files shared across non-Windows platforms.
input_files.Append(
'importer/firefox_profile_lock_posix.cc',
- 'renderer_host/backing_store_posix.cc',
+ 'renderer_host/backing_store_x.cc',
)
diff --git a/chrome/browser/renderer_host/backing_store.cc b/chrome/browser/renderer_host/backing_store.cc
index a68e785..8f8a1c9 100644
--- a/chrome/browser/renderer_host/backing_store.cc
+++ b/chrome/browser/renderer_host/backing_store.cc
@@ -4,7 +4,7 @@
#include "chrome/browser/renderer_host/backing_store.h"
-class RenderWidgetHost;
+#include "chrome/browser/renderer_host/render_widget_host.h"
namespace {
@@ -22,10 +22,10 @@ static int GetBackingStoreCacheSize() {
// Creates the backing store for the host based on the dimensions passed in.
// Removes the existing backing store if there is one.
BackingStore* CreateBackingStore(RenderWidgetHost* host,
- const gfx::Rect& backing_store_rect) {
+ const gfx::Size& backing_store_size) {
BackingStoreManager::RemoveBackingStore(host);
- BackingStore* backing_store = new BackingStore(backing_store_rect.size());
+ BackingStore* backing_store = host->AllocBackingStore(backing_store_size);
int backing_store_cache_size = GetBackingStoreCacheSize();
if (backing_store_cache_size > 0) {
if (!cache)
@@ -58,21 +58,21 @@ BackingStore* BackingStoreManager::GetBackingStore(
// static
BackingStore* BackingStoreManager::PrepareBackingStore(
RenderWidgetHost* host,
- const gfx::Rect& backing_store_rect,
+ const gfx::Size& backing_store_size,
base::ProcessHandle process_handle,
TransportDIB* bitmap,
const gfx::Rect& bitmap_rect,
bool* needs_full_paint) {
- BackingStore* backing_store = GetBackingStore(host,
- backing_store_rect.size());
+ BackingStore* backing_store = GetBackingStore(host, backing_store_size);
if (!backing_store) {
// We need to get Webkit to generate a new paint here, as we
// don't have a previous snapshot.
- if (bitmap_rect != backing_store_rect) {
+ if (bitmap_rect.size() != backing_store_size ||
+ bitmap_rect.x() != 0 || bitmap_rect.y() != 0) {
DCHECK(needs_full_paint != NULL);
*needs_full_paint = true;
}
- backing_store = CreateBackingStore(host, backing_store_rect);
+ backing_store = CreateBackingStore(host, backing_store_size);
}
DCHECK(backing_store != NULL);
diff --git a/chrome/browser/renderer_host/backing_store.h b/chrome/browser/renderer_host/backing_store.h
index e6113f5..ce18c7d 100644
--- a/chrome/browser/renderer_host/backing_store.h
+++ b/chrome/browser/renderer_host/backing_store.h
@@ -14,8 +14,10 @@
#if defined(OS_WIN)
#include <windows.h>
-#elif defined(OS_POSIX)
+#elif defined(OS_MACOSX)
#include "skia/ext/platform_canvas.h"
+#elif defined(OS_LINUX)
+#include "chrome/common/x11_util.h"
#endif
class RenderWidgetHost;
@@ -26,19 +28,40 @@ class TransportDIB;
// Represents a backing store for the pixels in a RenderWidgetHost.
class BackingStore {
public:
+#if defined(OS_WIN) || defined(OS_MACOSX)
explicit BackingStore(const gfx::Size& size);
+#elif defined(OS_LINUX)
+ // Create a backing store on the X server.
+ // size: the size of the server-side pixmap
+ // x_connection: the display to target
+ // depth: the depth of the X window which will be drawn into
+ // visual: An Xlib Visual describing the format of the target window
+ // parent_window: The X id of the target window
+ // use_shared_memory: if true, the X server is local
+ BackingStore(const gfx::Size& size, Display* x_connection, int depth,
+ void* visual, XID parent_window, 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);
+#endif
~BackingStore();
const gfx::Size& size() { return size_; }
#if defined(OS_WIN)
HDC hdc() { return hdc_; }
-#elif defined(OS_POSIX)
+#elif defined(OS_MACOSX)
skia::PlatformCanvas* canvas() { return &canvas_; }
+#elif defined(OS_LINUX)
+ // Copy from the server-side backing store to the target window
+ // display: the display of the backing store and target window
+ // damage: the area to copy
+ // target: the X id of the target window
+ void ShowRect(const gfx::Rect& damage);
#endif
// Paints the bitmap from the renderer onto the backing store.
- bool PaintRect(base::ProcessHandle process,
+ void PaintRect(base::ProcessHandle process,
TransportDIB* bitmap,
const gfx::Rect& bitmap_rect);
@@ -72,9 +95,23 @@ class BackingStore {
// Handle to the original bitmap in the dc.
HANDLE original_bitmap_;
-#elif defined(OS_POSIX)
+#elif defined(OS_MACOSX)
skia::PlatformCanvas canvas_;
-#endif // defined(OS_WIN)
+#elif defined(OS_LINUX)
+ // 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_;
+ // The parent window (probably a GtkDrawingArea) for this backing store.
+ const XID parent_window_;
+ // This is a handle to the server side pixmap which is our backing store.
+ XID pixmap_;
+ // This is the RENDER picture pointing at |pixmap_|.
+ XID picture_;
+ // This is a default graphic context, used in XCopyArea
+ void* pixmap_gc_;
+#endif
DISALLOW_COPY_AND_ASSIGN(BackingStore);
};
@@ -99,7 +136,7 @@ class BackingStoreManager {
// bitmap from the renderer has been copied into the backing store dc, or the
// bitmap in the backing store dc references the renderer bitmap.
//
- // backing_store_rect
+ // backing_store_size
// The desired backing store dimensions.
// process_handle
// The renderer process handle.
@@ -111,7 +148,7 @@ class BackingStoreManager {
// Set if we need to send out a request to paint the view
// to the renderer.
static BackingStore* PrepareBackingStore(RenderWidgetHost* host,
- const gfx::Rect& backing_store_rect,
+ const gfx::Size& backing_store_size,
base::ProcessHandle process_handle,
TransportDIB* bitmap,
const gfx::Rect& bitmap_rect,
diff --git a/chrome/browser/renderer_host/backing_store_posix.cc b/chrome/browser/renderer_host/backing_store_posix.cc
index 1d195fb..cacc6f0 100644
--- a/chrome/browser/renderer_host/backing_store_posix.cc
+++ b/chrome/browser/renderer_host/backing_store_posix.cc
@@ -19,7 +19,7 @@ BackingStore::BackingStore(const gfx::Size& size)
BackingStore::~BackingStore() {
}
-bool BackingStore::PaintRect(base::ProcessHandle process,
+void BackingStore::PaintRect(base::ProcessHandle process,
TransportDIB* bitmap,
const gfx::Rect& bitmap_rect) {
SkBitmap skbitmap;
@@ -29,7 +29,6 @@ bool BackingStore::PaintRect(base::ProcessHandle process,
skbitmap.setPixels(bitmap->memory());
canvas_.drawBitmap(skbitmap, bitmap_rect.x(), bitmap_rect.y());
- return true;
}
void BackingStore::ScrollRect(base::ProcessHandle process,
diff --git a/chrome/browser/renderer_host/backing_store_win.cc b/chrome/browser/renderer_host/backing_store_win.cc
index dcc1ad4..c4a5510 100644
--- a/chrome/browser/renderer_host/backing_store_win.cc
+++ b/chrome/browser/renderer_host/backing_store_win.cc
@@ -30,7 +30,7 @@ BackingStore::~BackingStore() {
}
}
-bool BackingStore::PaintRect(base::ProcessHandle process,
+void BackingStore::PaintRect(base::ProcessHandle process,
TransportDIB* bitmap,
const gfx::Rect& bitmap_rect) {
if (!backing_store_dib_) {
@@ -62,8 +62,6 @@ bool BackingStore::PaintRect(base::ProcessHandle process,
reinterpret_cast<BITMAPINFO*>(&hdr),
DIB_RGB_COLORS,
SRCCOPY);
-
- return true;
}
void BackingStore::ScrollRect(base::ProcessHandle process,
diff --git a/chrome/browser/renderer_host/backing_store_x.cc b/chrome/browser/renderer_host/backing_store_x.cc
new file mode 100644
index 0000000..b4a7cae
--- /dev/null
+++ b/chrome/browser/renderer_host/backing_store_x.cc
@@ -0,0 +1,169 @@
+// Copyright (c) 2006-2008 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 "chrome/browser/renderer_host/backing_store.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "chrome/common/transport_dib.h"
+#include "chrome/common/x11_util.h"
+#include "chrome/common/x11_util_internal.h"
+
+// X Backing Stores:
+//
+// Unlike Windows, where the backing store is kept in heap memory, we keep our
+// backing store in the X server, as a pixmap. Thus expose events just require
+// instructing the X server to copy from the backing store to the window.
+//
+// The backing store is in the same format as the visual which our main window
+// is using. Bitmaps from the renderer are uploaded to the X server, either via
+// shared memory or over the wire, and XRENDER is used to convert them to the
+// correct format for the backing store.
+
+BackingStore::BackingStore(const gfx::Size& size,
+ Display* display,
+ int depth,
+ void* visual,
+ Drawable parent_window,
+ bool use_shared_memory)
+ : size_(size),
+ display_(display),
+ use_shared_memory_(use_shared_memory),
+ parent_window_(parent_window) {
+ const int width = size.width();
+ const int height = size.height();
+
+ pixmap_ = XCreatePixmap(display_, parent_window, width, height, depth);
+ picture_ = XRenderCreatePicture(
+ display_, pixmap_,
+ x11_util::GetRenderVisualFormat(display_, static_cast<Visual*>(visual)),
+ 0, NULL);
+ pixmap_gc_ = XCreateGC(display_, pixmap_, 0, NULL);
+}
+
+BackingStore::BackingStore(const gfx::Size& size)
+ : size_(size),
+ display_(NULL),
+ use_shared_memory_(false),
+ parent_window_(0) {
+}
+
+BackingStore::~BackingStore() {
+ // In unit tests, display_ may be NULL.
+ if (!display_)
+ return;
+
+ XRenderFreePicture(display_, picture_);
+ XFreePixmap(display_, pixmap_);
+ XFreeGC(display_, static_cast<GC>(pixmap_gc_));
+}
+
+void BackingStore::PaintRect(base::ProcessHandle process,
+ TransportDIB* bitmap,
+ const gfx::Rect& bitmap_rect) {
+ if (!display_)
+ return;
+
+ const int width = bitmap_rect.width();
+ const int height = bitmap_rect.height();
+ Picture picture;
+ Pixmap pixmap;
+
+ if (use_shared_memory_) {
+ const XID shmseg = bitmap->MapToX(display_);
+
+ XShmSegmentInfo shminfo;
+ memset(&shminfo, 0, sizeof(shminfo));
+ shminfo.shmseg = shmseg;
+
+ // The NULL in the following is the |data| pointer: this is an artifact of
+ // Xlib trying to be helpful, rather than just exposing the X protocol. It
+ // assumes that we have the shared memory segment mapped into our memory,
+ // which we don't, and it's trying to calculate an offset by taking the
+ // difference between the |data| pointer and the address of the mapping in
+ // |shminfo|. Since both are NULL, the offset will be calculated to be 0,
+ // which is correct for us.
+ pixmap = XShmCreatePixmap(display_, parent_window_, NULL, &shminfo, width,
+ height, 32);
+ } else {
+ // No shared memory support, we have to copy the bitmap contents to the X
+ // server. Xlib wraps the underlying PutImage call behind several layers of
+ // functions which try to convert the image into the format which the X
+ // server expects. The following values hopefully disable all conversions.
+ XImage image;
+ memset(&image, 0, sizeof(image));
+
+ image.width = width;
+ image.height = 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 = width * 4;
+ image.red_mask = 0xff;
+ image.green_mask = 0xff00;
+ image.blue_mask = 0xff0000;
+ image.data = static_cast<char*>(bitmap->memory());
+
+ pixmap = XCreatePixmap(display_, parent_window_, width, height, 32);
+ GC gc = XCreateGC(display_, pixmap, 0, NULL);
+ XPutImage(display_, pixmap, gc, &image,
+ 0, 0 /* source x, y */, 0, 0 /* dest x, y */,
+ width, height);
+ XFreeGC(display_, gc);
+ }
+
+ picture = x11_util::CreatePictureFromSkiaPixmap(display_, pixmap);
+ XRenderComposite(display_, PictOpSrc, picture /* source */, 0 /* mask */,
+ picture_ /* dest */, 0, 0 /* source x, y */,
+ 0, 0 /* mask x, y */,
+ bitmap_rect.x(), bitmap_rect.y() /* target x, y */,
+ width, height);
+
+ // In the case of shared memory, we wait for the composite to complete so that
+ // we are sure that the X server has finished reading.
+ if (use_shared_memory_)
+ XSync(display_, False);
+
+ XRenderFreePicture(display_, picture);
+ XFreePixmap(display_, pixmap);
+}
+
+void BackingStore::ScrollRect(base::ProcessHandle process,
+ TransportDIB* bitmap,
+ const gfx::Rect& bitmap_rect,
+ int dx, int dy,
+ const gfx::Rect& clip_rect,
+ const gfx::Size& view_size) {
+ if (!display_)
+ return;
+
+ // We only support scrolling in one direction at a time.
+ DCHECK(dx == 0 || dy == 0);
+
+ if (dy) {
+ // Positive values of |dy| scroll up
+ XCopyArea(display_, pixmap_, pixmap_, static_cast<GC>(pixmap_gc_),
+ 0, std::max(0, -dy) /* source x, y */,
+ size_.width(), size_.height() - abs(dy),
+ 0, std::max(0, dy) /* dest x, y */);
+ } else if (dx) {
+ // Positive values of |dx| scroll right
+ XCopyArea(display_, pixmap_, pixmap_, static_cast<GC>(pixmap_gc_),
+ std::max(0, -dx), 0 /* source x, y */,
+ size_.width() - abs(dx), size_.height(),
+ std::max(0, dx), 0 /* dest x, y */);
+ }
+
+ PaintRect(process, bitmap, bitmap_rect);
+}
+
+void BackingStore::ShowRect(const gfx::Rect& rect) {
+ XCopyArea(display_, pixmap_, parent_window_, static_cast<GC>(pixmap_gc_),
+ rect.x(), rect.y(), rect.width(), rect.height(),
+ rect.x(), rect.y());
+}
diff --git a/chrome/browser/renderer_host/backing_store_xcb.cc b/chrome/browser/renderer_host/backing_store_xcb.cc
deleted file mode 100644
index ba6a12b..0000000
--- a/chrome/browser/renderer_host/backing_store_xcb.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2006-2008 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 "chrome/browser/renderer_host/backing_store.h"
-
-#include <xcb/xcb.h>
-
-#include "base/logging.h"
-#include "chrome/common/transport_dib.h"
-
-#ifdef NDEBUG
-#define XCB_CALL(func, ...) func(__VA_ARGS__)
-#else
-#define XCB_CALL(func, ...) do { \
- xcb_void_cookie_t cookie = func##_checked(__VA_ARGS__); \
- xcb_generic_error_t* error = xcb_request_check(connection_, cookie); \
- if (error) { \
- CHECK(false) << "XCB error" \
- << " code:" << error->error_code \
- << " type:" << error->response_type \
- << " sequence:" << error->sequence; \
- } \
-} while(false);
-#endif
-
-BackingStore::BackingStore(const gfx::Size& size,
- xcb_connection_t* connection,
- xcb_window_t window,
- bool use_shared_memory)
- : connection_(connection),
- use_shared_memory_(use_shared_memory),
- pixmap_(xcb_generate_id(connection)) {
- XCB_CALL(xcb_create_pixmap, connection_, 32, pixmap, window, size.width(),
- size.height());
-}
-
-BackingStore::~BackingStore() {
- XCB_CALL(xcb_free_pixmap, pixmap_);
-}
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc
index b27f835..7e0c465 100644
--- a/chrome/browser/renderer_host/render_widget_host.cc
+++ b/chrome/browser/renderer_host/render_widget_host.cc
@@ -230,6 +230,13 @@ BackingStore* RenderWidgetHost::GetBackingStore() {
return backing_store;
}
+BackingStore* RenderWidgetHost::AllocBackingStore(const gfx::Size& size) {
+ if (!view_)
+ return NULL;
+
+ return view_->AllocBackingStore(size);
+}
+
void RenderWidgetHost::StartHangMonitorTimeout(TimeDelta delay) {
time_when_considered_hung_ = Time::Now() + delay;
@@ -592,13 +599,9 @@ void RenderWidgetHost::PaintBackingStoreRect(TransportDIB* bitmap,
return;
}
- // We use the view size according to the render view, which may not be
- // quite the same as the size of our window.
- gfx::Rect view_rect(0, 0, view_size.width(), view_size.height());
-
bool needs_full_paint = false;
BackingStore* backing_store =
- BackingStoreManager::PrepareBackingStore(this, view_rect,
+ BackingStoreManager::PrepareBackingStore(this, view_size,
process_->process().handle(),
bitmap, bitmap_rect,
&needs_full_paint);
diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h
index df0c417..31a467a 100644
--- a/chrome/browser/renderer_host/render_widget_host.h
+++ b/chrome/browser/renderer_host/render_widget_host.h
@@ -174,6 +174,10 @@ class RenderWidgetHost : public IPC::Channel::Listener {
// not be created.
BackingStore* GetBackingStore();
+ // Allocate a new backing store of the given size. Returns NULL on failure
+ // (for example, if we don't currently have a RenderWidgetHostView.)
+ BackingStore* AllocBackingStore(const gfx::Size& size);
+
// Checks to see if we can give up focus to this widget through a JS call.
virtual bool CanBlur() const { return true; }
diff --git a/chrome/browser/renderer_host/render_widget_host_unittest.cc b/chrome/browser/renderer_host/render_widget_host_unittest.cc
index 3713f80..c2dba12 100644
--- a/chrome/browser/renderer_host/render_widget_host_unittest.cc
+++ b/chrome/browser/renderer_host/render_widget_host_unittest.cc
@@ -6,6 +6,7 @@
#include "base/scoped_ptr.h"
#include "base/shared_memory.h"
#include "build/build_config.h"
+#include "chrome/browser/renderer_host/backing_store.h"
#include "chrome/browser/renderer_host/test_render_view_host.h"
#include "chrome/common/render_messages.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -109,6 +110,10 @@ class TestView : public TestRenderWidgetHostView {
return bounds_;
}
+ BackingStore* AllocBackingStore(const gfx::Size& size) {
+ return new BackingStore(size);
+ }
+
protected:
gfx::Rect bounds_;
DISALLOW_COPY_AND_ASSIGN(TestView);
diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h
index 7b00158..3589427 100644
--- a/chrome/browser/renderer_host/render_widget_host_view.h
+++ b/chrome/browser/renderer_host/render_widget_host_view.h
@@ -17,6 +17,7 @@ namespace IPC {
class Message;
}
+class BackingStore;
class RenderProcessHost;
class RenderWidgetHost;
class WebCursor;
@@ -109,6 +110,9 @@ class RenderWidgetHostView {
// the page has changed.
virtual void SetTooltipText(const std::wstring& tooltip_text) = 0;
+ // Allocate a backing store for this view
+ virtual BackingStore* AllocBackingStore(const gfx::Size& size) = 0;
+
protected:
// Interface class only, do not construct.
RenderWidgetHostView() {}
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 1151152..f4ef560 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/string_util.h"
+#include "chrome/common/x11_util.h"
#include "chrome/browser/renderer_host/backing_store.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "skia/ext/bitmap_platform_device_linux.h"
@@ -24,6 +25,7 @@ class RenderWidgetHostViewGtkWidget {
public:
static GtkWidget* CreateNewWidget(RenderWidgetHostViewGtk* host_view) {
GtkWidget* widget = gtk_drawing_area_new();
+ gtk_widget_set_double_buffered(widget, FALSE);
gtk_widget_add_events(widget, GDK_EXPOSURE_MASK |
GDK_POINTER_MOTION_MASK |
@@ -281,34 +283,28 @@ void RenderWidgetHostViewGtk::SetTooltipText(const std::wstring& tooltip_text) {
}
}
+BackingStore* RenderWidgetHostViewGtk::AllocBackingStore(
+ const gfx::Size& size) {
+ Display* display = x11_util::GetXDisplay();
+ void* visual = x11_util::GetVisualFromGtkWidget(view_);
+ XID parent_window = x11_util::GetX11WindowFromGtkWidget(view_);
+ bool use_shared_memory = x11_util::QuerySharedMemorySupport(display);
+ int depth = gtk_widget_get_visual(view_)->depth;
+
+ return new BackingStore(size, display, depth, visual, parent_window,
+ use_shared_memory);
+}
+
void RenderWidgetHostViewGtk::Paint(const gfx::Rect& damage_rect) {
BackingStore* backing_store = host_->GetBackingStore();
if (backing_store) {
- GdkRectangle grect = {
- damage_rect.x(),
- damage_rect.y(),
- damage_rect.width(),
- damage_rect.height()
- };
-
// Only render the widget if it is attached to a window; there's a short
// period where this object isn't attached to a window but hasn't been
// Destroy()ed yet and it receives paint messages...
GdkWindow* window = view_->window;
- if (window) {
- gdk_window_begin_paint_rect(window, &grect);
-
- skia::PlatformDeviceLinux &platdev =
- backing_store->canvas()->getTopPlatformDevice();
- skia::BitmapPlatformDeviceLinux* const bitdev =
- static_cast<skia::BitmapPlatformDeviceLinux* >(&platdev);
- cairo_t* cairo_drawable = gdk_cairo_create(window);
- cairo_set_source_surface(cairo_drawable, bitdev->surface(), 0, 0);
- cairo_paint(cairo_drawable);
- cairo_destroy(cairo_drawable);
- gdk_window_end_paint(window);
- }
+ if (window)
+ backing_store->ShowRect(damage_rect);
} else {
NOTIMPLEMENTED();
diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.h b/chrome/browser/renderer_host/render_widget_host_view_gtk.h
index 9d342ff..9c74172 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_gtk.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.h
@@ -47,6 +47,7 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView {
void RenderViewGone();
void Destroy();
void SetTooltipText(const std::wstring& tooltip_text);
+ BackingStore* AllocBackingStore(const gfx::Size& size);
// ---------------------------------------------------------------------------
gfx::NativeView native_view() const { return view_; }
diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h
index 13d4fb6..54819e1 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h
@@ -78,6 +78,7 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView {
virtual void RenderViewGone();
virtual void Destroy();
virtual void SetTooltipText(const std::wstring& tooltip_text);
+ virtual BackingStore* AllocBackingStore(const gfx::Size& size);
private:
// Shuts down the render_widget_host_. This is a separate function so we can
diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
index e651ddb..bbb6a13 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm
@@ -208,6 +208,11 @@ void RenderWidgetHostViewMac::SetTooltipText(const std::wstring& tooltip_text) {
}
}
+BackingStore* RenderWidgetHostViewMac::AllocBackingStore(
+ const gfx::Size& size) {
+ return new BackingStore(size);
+}
+
void RenderWidgetHostViewMac::ShutdownHost() {
render_widget_host_->Shutdown();
// Do not touch any members at this point, |this| has been deleted.
diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.cc b/chrome/browser/renderer_host/render_widget_host_view_win.cc
index d0c11fc..66a1694 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_win.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_win.cc
@@ -444,6 +444,11 @@ void RenderWidgetHostViewWin::SetTooltipText(const std::wstring& tooltip_text) {
}
}
+BackingStore* RenderWidgetHostViewWin::AllocBackingStore(
+ const gfx::Size& size) {
+ return new BackingStore(size);
+}
+
///////////////////////////////////////////////////////////////////////////////
// RenderWidgetHostViewWin, private:
diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.h b/chrome/browser/renderer_host/render_widget_host_view_win.h
index dad1b5d..bb86d23 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_win.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_win.h
@@ -22,6 +22,8 @@ class Rect;
namespace IPC {
class Message;
}
+
+class BackingStore;
class RenderWidgetHost;
class WebMouseEvent;
@@ -137,6 +139,7 @@ class RenderWidgetHostViewWin :
virtual void RenderViewGone();
virtual void Destroy();
virtual void SetTooltipText(const std::wstring& tooltip_text);
+ virtual BackingStore* AllocBackingStore(const gfx::Size& size);
protected:
// Windows Message Handlers
diff --git a/chrome/browser/renderer_host/test_render_view_host.cc b/chrome/browser/renderer_host/test_render_view_host.cc
index dca7cfe..3246a4b 100644
--- a/chrome/browser/renderer_host/test_render_view_host.cc
+++ b/chrome/browser/renderer_host/test_render_view_host.cc
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "chrome/browser/renderer_host/test_render_view_host.h"
+
+#include "chrome/browser/renderer_host/backing_store.h"
#include "chrome/browser/tab_contents/test_web_contents.h"
#include "chrome/common/render_messages.h"
@@ -62,6 +64,11 @@ void TestRenderViewHost::SendNavigate(int page_id, const GURL& url) {
OnMsgNavigate(msg);
}
+BackingStore* TestRenderWidgetHostView::AllocBackingStore(
+ const gfx::Size& size) {
+ return new BackingStore(size);
+}
+
void RenderViewHostTestHarness::SetUp() {
// See comment above profile_ decl for why we check for NULL here.
if (!profile_.get())
diff --git a/chrome/browser/renderer_host/test_render_view_host.h b/chrome/browser/renderer_host/test_render_view_host.h
index b6d011e..a925c67 100644
--- a/chrome/browser/renderer_host/test_render_view_host.h
+++ b/chrome/browser/renderer_host/test_render_view_host.h
@@ -68,6 +68,7 @@ class TestRenderWidgetHostView : public RenderWidgetHostView {
virtual void Destroy() {}
virtual void PrepareToDestroy() {}
virtual void SetTooltipText(const std::wstring& tooltip_text) {}
+ virtual BackingStore* AllocBackingStore(const gfx::Size& size);
bool is_showing() const { return is_showing_; }
diff --git a/chrome/common/common.scons b/chrome/common/common.scons
index 85ae914..617c4c1 100644
--- a/chrome/common/common.scons
+++ b/chrome/common/common.scons
@@ -284,7 +284,8 @@ if env.Bit('windows'):
if env.Bit('linux'):
input_files.Append(
- 'transport_dib_linux.cc'
+ 'transport_dib_linux.cc',
+ 'x11_util.cc'
)
if env.Bit('mac'):
diff --git a/chrome/common/transport_dib.h b/chrome/common/transport_dib.h
index e5fc009..8f5be3a 100644
--- a/chrome/common/transport_dib.h
+++ b/chrome/common/transport_dib.h
@@ -13,8 +13,14 @@
#if defined(OS_WIN)
#include <windows.h>
+#elif defined(OS_LINUX)
+#include "chrome/common/x11_util.h"
#endif
+namespace gfx {
+class Size;
+}
+
// -----------------------------------------------------------------------------
// A TransportDIB is a block of memory that is used to transport pixels
// from the renderer process to the browser.
@@ -94,6 +100,12 @@ class TransportDIB {
// wire to give this transport DIB to another process.
Handle handle() const;
+#if defined(OS_LINUX)
+ // Map the shared memory into the X server and return an id for the shared
+ // segment.
+ XID MapToX(Display* connection);
+#endif
+
private:
TransportDIB();
#if defined(OS_WIN) || defined(OS_MACOSX)
@@ -103,6 +115,8 @@ class TransportDIB {
#elif defined(OS_LINUX)
int key_; // SysV shared memory id
void* address_; // mapped address
+ XID x_shm_; // X id for the shared segment
+ Display* display_; // connection to the X server
#endif
size_t size_; // length, in bytes
};
diff --git a/chrome/common/transport_dib_linux.cc b/chrome/common/transport_dib_linux.cc
index adecf1d..be673d9 100644
--- a/chrome/common/transport_dib_linux.cc
+++ b/chrome/common/transport_dib_linux.cc
@@ -7,8 +7,10 @@
#include <sys/ipc.h>
#include <sys/shm.h>
+#include "base/gfx/size.h"
#include "base/logging.h"
#include "chrome/common/transport_dib.h"
+#include "chrome/common/x11_util.h"
// The shmat system call uses this as it's invalid return address
static void *const kInvalidAddress = (void*) -1;
@@ -16,6 +18,8 @@ static void *const kInvalidAddress = (void*) -1;
TransportDIB::TransportDIB()
: key_(-1),
address_(kInvalidAddress),
+ x_shm_(0),
+ display_(NULL),
size_(0) {
}
@@ -24,6 +28,11 @@ TransportDIB::~TransportDIB() {
shmdt(address_);
address_ = kInvalidAddress;
}
+
+ if (x_shm_) {
+ DCHECK(display_);
+ x11_util::DetachSharedMemory(display_, x_shm_);
+ }
}
// static
@@ -59,7 +68,7 @@ TransportDIB* TransportDIB::Map(Handle shmkey) {
if (shmctl(shmkey, IPC_STAT, &shmst) == -1)
return NULL;
- void* address = shmat(shmkey, NULL /* desired address */, 0 /* flags */);
+ void* address = shmat(shmkey, NULL /* desired address */, SHM_RDONLY);
if (address == kInvalidAddress)
return NULL;
@@ -83,3 +92,12 @@ TransportDIB::Id TransportDIB::id() const {
TransportDIB::Handle TransportDIB::handle() const {
return key_;
}
+
+XID TransportDIB::MapToX(Display* display) {
+ if (!x_shm_) {
+ x_shm_ = x11_util::AttachSharedMemory(display, key_);
+ display_ = display;
+ }
+
+ return x_shm_;
+}
diff --git a/chrome/common/x11_util.cc b/chrome/common/x11_util.cc
new file mode 100644
index 0000000..5a23878
--- /dev/null
+++ b/chrome/common/x11_util.cc
@@ -0,0 +1,181 @@
+// Copyright (c) 2009 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.
+
+// This file defines utility functions for X11 (Linux only). This code has been
+// ported from XCB since we can't use XCB on Ubuntu while its 32-bit support
+// remains woefully incomplete.
+
+#include "chrome/common/x11_util.h"
+#include "chrome/common/x11_util_internal.h"
+
+#include <string.h>
+
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include "base/logging.h"
+#include "base/gfx/size.h"
+
+namespace x11_util {
+
+Display* GetXDisplay() {
+ static Display* display = NULL;
+
+ if (!display)
+ display = gdk_x11_get_default_xdisplay();
+
+ return display;
+}
+
+static bool DoQuerySharedMemorySupport(Display* dpy) {
+ int dummy;
+ Bool pixmaps_supported;
+ // Query the server's support for shared memory
+ if (!XShmQueryVersion(dpy, &dummy, &dummy, &pixmaps_supported))
+ return false;
+ // If the server doesn't support shared memory, give up. (Note that if
+ // |shared_pixmaps| is true, it just means that the server /supports/ shared
+ // memory, not that it will work on this connection.)
+ if (!pixmaps_supported)
+ return false;
+
+ // Next we probe to see if shared memory will really work
+ int shmkey = shmget(IPC_PRIVATE, 1, 0666);
+ if (shmkey == -1)
+ return false;
+ void* address = shmat(shmkey, NULL, 0);
+ // Mark the shared memory region for deletion
+ shmctl(shmkey, IPC_RMID, NULL);
+
+ XShmSegmentInfo shminfo;
+ memset(&shminfo, 0, sizeof(shminfo));
+ shminfo.shmid = shmkey;
+
+ gdk_error_trap_push();
+ bool result = XShmAttach(dpy, &shminfo);
+ XSync(dpy, False);
+ if (gdk_error_trap_pop())
+ result = false;
+ shmdt(address);
+ if (!result)
+ return false;
+
+ XShmDetach(dpy, &shminfo);
+ return true;
+}
+
+bool QuerySharedMemorySupport(Display* dpy) {
+ static bool shared_memory_support = false;
+ static bool shared_memory_support_cached = false;
+
+ if (shared_memory_support_cached)
+ return shared_memory_support;
+
+ shared_memory_support = DoQuerySharedMemorySupport(dpy);
+ shared_memory_support_cached = true;
+
+ return shared_memory_support;
+}
+
+XID GetX11WindowFromGtkWidget(GtkWidget* widget) {
+ return GDK_WINDOW_XID(widget->window);
+}
+
+void* GetVisualFromGtkWidget(GtkWidget* widget) {
+ return GDK_VISUAL_XVISUAL(gtk_widget_get_visual(widget));
+}
+
+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";
+
+ pictformat = XRenderFindVisualFormat(dpy, visual);
+ CHECK(pictformat) << "XRENDER does not support default visual";
+
+ return pictformat;
+}
+
+XRenderPictFormat* GetRenderARGB32Format(Display* dpy) {
+ static XRenderPictFormat* pictformat = NULL;
+ if (pictformat)
+ return pictformat;
+
+ // First look for a 32-bit format which ignores the alpha value
+ XRenderPictFormat templ;
+ templ.depth = 32;
+ templ.type = PictTypeDirect;
+ templ.direct.red = 0;
+ templ.direct.green = 8;
+ templ.direct.blue = 16;
+ templ.direct.redMask = 0xff;
+ templ.direct.greenMask = 0xff;
+ templ.direct.blueMask = 0xff;
+ templ.direct.alphaMask = 0;
+
+ static const unsigned long kMask =
+ PictFormatType | PictFormatDepth |
+ PictFormatRed | PictFormatRedMask |
+ PictFormatGreen | PictFormatGreenMask |
+ PictFormatBlue | PictFormatBlueMask |
+ PictFormatAlphaMask;
+
+ pictformat = XRenderFindFormat(dpy, kMask, &templ, 0 /* first result */);
+ CHECK(pictformat) << "XRENDER doesn't not support a Skia compatable format";
+ // TODO(agl): fallback to a picture format with an alpha channel
+
+ return pictformat;
+}
+
+XID AttachSharedMemory(Display* display, int shared_memory_key) {
+ DCHECK(QuerySharedMemorySupport(display));
+
+ XShmSegmentInfo shminfo;
+ memset(&shminfo, 0, sizeof(shminfo));
+ shminfo.shmid = shared_memory_key;
+
+ // This function is only called if QuerySharedMemorySupport returned true. In
+ // which case we've already succeeded in having the X server attach to one of
+ // our shared memory segments.
+ if (!XShmAttach(display, &shminfo))
+ NOTREACHED();
+
+ return shminfo.shmseg;
+}
+
+void DetachSharedMemory(Display* display, XID shmseg) {
+ DCHECK(QuerySharedMemorySupport(display));
+
+ XShmSegmentInfo shminfo;
+ memset(&shminfo, 0, sizeof(shminfo));
+ shminfo.shmseg = shmseg;
+
+ if (!XShmDetach(display, &shminfo))
+ NOTREACHED();
+}
+
+XID CreatePictureFromSkiaPixmap(Display* display, XID pixmap) {
+ XID picture = XRenderCreatePicture(
+ display, pixmap, GetRenderARGB32Format(display), 0, NULL);
+
+ return picture;
+}
+
+void FreePicture(Display* display, XID picture) {
+ XRenderFreePicture(display, picture);
+}
+
+void FreePixmap(Display* display, XID pixmap) {
+ XFreePixmap(display, pixmap);
+}
+
+} // namespace x11_util
diff --git a/chrome/common/x11_util.h b/chrome/common/x11_util.h
new file mode 100644
index 0000000..130ecc7
--- /dev/null
+++ b/chrome/common/x11_util.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_COMMON_X11_UTIL_H_
+#define CHROME_COMMON_X11_UTIL_H_
+
+// This file declares utility functions for X11 (Linux only).
+//
+// These functions do not require the Xlib headers to be included (which is why
+// we use a void* for Visual*). The Xlib headers are highly polluting so we try
+// hard to limit their spread into the rest of the code.
+
+typedef struct _GtkWidget GtkWidget;
+typedef unsigned long XID;
+typedef struct _XDisplay Display;
+
+namespace gfx {
+class Size;
+}
+
+namespace x11_util {
+ // These functions cache their results and must be called from the UI thread.
+ // Currently they don't support multiple screens/displays.
+
+ // Return an X11 connection for the current, primary display.
+ Display* GetXDisplay();
+ // Return true iff the connection supports X shared memory
+ bool QuerySharedMemorySupport(Display* dpy);
+
+ // These functions do not cache their results
+
+ // Get the X window id for the given GTK widget.
+ XID GetX11WindowFromGtkWidget(GtkWidget*);
+ // 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 a handle to a server side pixmap. |shared_memory_key| is a SysV
+ // IPC key. The shared memory region must contain 32-bit pixels.
+ XID AttachSharedMemory(Display* display, int shared_memory_support);
+ void DetachSharedMemory(Display* display, XID shmseg);
+
+ // Return a handle to an XRender picture where |pixmap| is a handle to a
+ // pixmap containing Skia ARGB data.
+ XID CreatePictureFromSkiaPixmap(Display* display, XID pixmap);
+
+ void FreePicture(Display* display, XID picture);
+ void FreePixmap(Display* display, XID pixmap);
+};
+
+#endif // CHROME_COMMON_X11_UTIL_H_
diff --git a/chrome/common/x11_util_internal.h b/chrome/common/x11_util_internal.h
new file mode 100644
index 0000000..1a7b604
--- /dev/null
+++ b/chrome/common/x11_util_internal.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_COMMON_X11_UTIL_INTERNAL_H_
+#define CHROME_COMMON_X11_UTIL_INTERNAL_H_
+
+// This file declares utility functions for X11 (Linux only).
+//
+// These functions require the inclusion of the Xlib headers. Since the Xlib
+// headers pollute so much of the namespace, this should only be included
+// when needed.
+
+extern "C" {
+#include <X11/Xlib.h>
+#include <X11/extensions/XShm.h>
+#include <X11/extensions/Xrender.h>
+}
+
+namespace x11_util {
+ // These functions cache their results and must be called from the UI thread.
+ // Currently they don't support multiple screens/displays.
+
+ // Get the XRENDER format id for ARGB32 (Skia's format).
+ XRenderPictFormat* GetRenderARGB32Format(Display* dpy);
+ // Get the XRENDER format id for the default visual on the first screen. This
+ // is the format which our GTK window will have.
+ XRenderPictFormat* GetRenderVisualFormat(Display* dpy, Visual* visual);
+};
+
+#endif // CHROME_COMMON_X11_UTIL_H_
diff --git a/chrome/test/perf/perftests.scons b/chrome/test/perf/perftests.scons
index a0eadcf..e0ab596 100644
--- a/chrome/test/perf/perftests.scons
+++ b/chrome/test/perf/perftests.scons
@@ -52,6 +52,10 @@ env.Prepend(
'glue',
'port',
'renderer',
+
+ 'X11',
+ 'Xrender',
+ 'Xext',
],
)
diff --git a/chrome/test/unit/unit_tests.scons b/chrome/test/unit/unit_tests.scons
index 74bb036..9add75c 100644
--- a/chrome/test/unit/unit_tests.scons
+++ b/chrome/test/unit/unit_tests.scons
@@ -53,6 +53,10 @@ env.Prepend(
'JavaScriptCore_pcre',
'port',
'WebCore',
+
+ 'X11',
+ 'Xrender',
+ 'Xext',
],
)
@@ -155,6 +159,7 @@ input_files = ChromeFileList([
'$CHROME_DIR/browser/history/query_parser_unittest.cc',
'$CHROME_DIR/browser/renderer_host/renderer_security_policy_unittest.cc',
'$CHROME_DIR/browser/renderer_host/resource_dispatcher_host_unittest.cc',
+ '$CHROME_DIR/browser/renderer_host/test_render_view_host.cc',
'$CHROME_DIR/browser/rlz/rlz_unittest.cc',
'$CHROME_DIR/browser/safe_browsing/safe_browsing_database_unittest.cc',
'$CHROME_DIR/browser/safe_browsing/safe_browsing_util_unittest.cc',