diff options
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', |