summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorjhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-19 00:09:23 +0000
committerjhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-19 00:09:23 +0000
commit19132f5e56873a226220d41f01434b2fc52e3a85 (patch)
tree7713e30369408855ac11c4444d504c989eb68f6b /chrome
parent0a7800ee17acd0f383fac1a99d664ee6a12a878f (diff)
downloadchromium_src-19132f5e56873a226220d41f01434b2fc52e3a85.zip
chromium_src-19132f5e56873a226220d41f01434b2fc52e3a85.tar.gz
chromium_src-19132f5e56873a226220d41f01434b2fc52e3a85.tar.bz2
Render the dragged tab contents when detaching a tab from the tabstrip in gtk.
BUG=none TEST=Drag a tab out of the tabstrip. If the WM has compositing enabled, the dragged tab contents should be translucent; otherwise, the contents should be opaque. Review URL: http://codereview.chromium.org/131042 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18780 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc7
-rw-r--r--chrome/browser/gtk/tabs/dragged_tab_gtk.cc124
-rw-r--r--chrome/browser/gtk/tabs/dragged_tab_gtk.h33
-rw-r--r--chrome/browser/renderer_host/backing_store.h3
-rw-r--r--chrome/browser/renderer_host/backing_store_x.cc26
5 files changed, 174 insertions, 19 deletions
diff --git a/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc b/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc
index 5092f79..ed6d511 100644
--- a/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc
+++ b/chrome/browser/gtk/tabs/dragged_tab_controller_gtk.cc
@@ -398,8 +398,11 @@ void DraggedTabControllerGtk::Detach() {
// Update the dragged tab. This NULL check is necessary apparently in some
// conditions during automation where the view_ is destroyed inside a
// function call preceding this point but after it is created.
- if (dragged_tab_.get())
- dragged_tab_->Detach();
+ if (dragged_tab_.get()) {
+ RenderViewHost* host = dragged_contents_->render_view_host();
+ dragged_tab_->Detach(dragged_contents_->GetContentNativeView(),
+ host->GetBackingStore(false));
+ }
// Detaching resets the delegate, but we still want to be the delegate.
dragged_contents_->set_delegate(this);
diff --git a/chrome/browser/gtk/tabs/dragged_tab_gtk.cc b/chrome/browser/gtk/tabs/dragged_tab_gtk.cc
index b7ca602..b91cf7b 100644
--- a/chrome/browser/gtk/tabs/dragged_tab_gtk.cc
+++ b/chrome/browser/gtk/tabs/dragged_tab_gtk.cc
@@ -6,7 +6,7 @@
#include <gdk/gdk.h>
-#include "app/gfx/canvas.h"
+#include "app/gfx/canvas_paint.h"
#include "base/gfx/gtk_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tabs/tab_strip_model.h"
@@ -25,6 +25,10 @@ const float kScalingFactor = 0.5;
const int kAnimateToBoundsDurationMs = 150;
+const gdouble kTransparentAlpha = (200.0f / 255.0f);
+const gdouble kOpaqueAlpha = 1.0f;
+const SkColor kDraggedTabBorderColor = SkColorSetRGB(103, 129, 162);
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -69,10 +73,19 @@ void DraggedTabGtk::Attach(int selected_width) {
attached_tab_size_.set_width(selected_width);
ResizeContainer();
Update();
+
+ if (gtk_util::IsScreenComposited())
+ gdk_window_set_opacity(container_->window, kOpaqueAlpha);
}
-void DraggedTabGtk::Detach() {
+void DraggedTabGtk::Detach(GtkWidget* contents, BackingStore* backing_store) {
attached_ = false;
+ contents_ = contents;
+ backing_store_ = backing_store;
+ ResizeContainer();
+
+ if (gtk_util::IsScreenComposited())
+ gdk_window_set_opacity(container_->window, kTransparentAlpha);
}
void DraggedTabGtk::Update() {
@@ -121,6 +134,21 @@ void DraggedTabGtk::AnimationCanceled(const Animation* animation) {
////////////////////////////////////////////////////////////////////////////////
// DraggedTabGtk, private:
+void DraggedTabGtk::Layout() {
+ if (attached_) {
+ gfx::Size prefsize = GetPreferredSize();
+ renderer_->SetBounds(gfx::Rect(0, 0, prefsize.width(), prefsize.height()));
+ } else {
+ // TODO(jhawkins): RTL layout.
+
+ // The renderer_'s width should be attached_tab_size_.width() in both LTR
+ // and RTL locales. Wrong width will cause the wrong positioning of the tab
+ // view in dragging. Please refer to http://crbug.com/6223 for details.
+ renderer_->SetBounds(gfx::Rect(0, 0, attached_tab_size_.width(),
+ attached_tab_size_.height()));
+ }
+}
+
gfx::Size DraggedTabGtk::GetPreferredSize() {
if (attached_)
return attached_tab_size_;
@@ -136,10 +164,7 @@ void DraggedTabGtk::ResizeContainer() {
gfx::Size size = GetPreferredSize();
gtk_window_resize(GTK_WINDOW(container_),
ScaleValue(size.width()), ScaleValue(size.height()));
- gfx::Rect bounds = renderer_->bounds();
- bounds.set_width(ScaleValue(size.width()));
- bounds.set_height(ScaleValue(size.height()));
- renderer_->SetBounds(bounds);
+ Layout();
Update();
}
@@ -181,10 +206,8 @@ void DraggedTabGtk::SetContainerTransparency() {
cairo_destroy(cairo_context);
}
-void DraggedTabGtk::SetContainerShapeMask() {
- // Render the tab as a bitmap.
- SkBitmap tab = renderer_->PaintBitmap();
- GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&tab);
+void DraggedTabGtk::SetContainerShapeMask(const SkBitmap& dragged_contents) {
+ GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&dragged_contents);
// Create a 1bpp bitmap the size of |container_|.
gfx::Size size = bounds().size();
@@ -192,7 +215,7 @@ void DraggedTabGtk::SetContainerShapeMask() {
cairo_t* cairo_context = gdk_cairo_create(GDK_DRAWABLE(pixmap));
// Set the transparency.
- cairo_set_source_rgba(cairo_context, 1, 1, 1, 0);
+ cairo_set_source_rgba(cairo_context, 1.0f, 1.0f, 1.0f, 0.0f);
// Blit the rendered bitmap into a pixmap. Any pixel set in the pixmap will
// be opaque in the container window.
@@ -207,15 +230,90 @@ void DraggedTabGtk::SetContainerShapeMask() {
g_object_unref(pixmap);
}
+SkBitmap DraggedTabGtk::PaintAttachedTab() {
+ return renderer_->PaintBitmap();
+}
+
+SkBitmap DraggedTabGtk::PaintDetachedView() {
+ gfx::Size ps = GetPreferredSize();
+ gfx::Canvas scale_canvas(ps.width(), ps.height(), false);
+ SkBitmap& bitmap_device = const_cast<SkBitmap&>(
+ scale_canvas.getTopPlatformDevice().accessBitmap(true));
+ bitmap_device.eraseARGB(0, 0, 0, 0);
+
+ scale_canvas.FillRectInt(kDraggedTabBorderColor, 0,
+ attached_tab_size_.height() - kDragFrameBorderSize,
+ ps.width(), ps.height() - attached_tab_size_.height());
+ int image_x = kDragFrameBorderSize;
+ int image_y = attached_tab_size_.height();
+ int image_w = ps.width() - kTwiceDragFrameBorderSize;
+ int image_h =
+ ps.height() - kTwiceDragFrameBorderSize - attached_tab_size_.height();
+ scale_canvas.FillRectInt(SK_ColorBLACK, image_x, image_y, image_w, image_h);
+ PaintScreenshotIntoCanvas(&scale_canvas,
+ gfx::Rect(image_x, image_y, image_w, image_h));
+ renderer_->Paint(&scale_canvas);
+
+ SkIRect subset;
+ subset.set(0, 0, ps.width(), ps.height());
+ SkBitmap mipmap = scale_canvas.ExtractBitmap();
+ mipmap.buildMipMap(true);
+
+ SkShader* bitmap_shader =
+ SkShader::CreateBitmapShader(mipmap, SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode);
+
+ SkMatrix shader_scale;
+ shader_scale.setScale(kScalingFactor, kScalingFactor);
+ bitmap_shader->setLocalMatrix(shader_scale);
+
+ SkPaint paint;
+ paint.setShader(bitmap_shader);
+ paint.setAntiAlias(true);
+ bitmap_shader->unref();
+
+ SkRect rc;
+ rc.fLeft = 0;
+ rc.fTop = 0;
+ rc.fRight = SkIntToScalar(ps.width());
+ rc.fBottom = SkIntToScalar(ps.height());
+ gfx::Canvas canvas(ps.width(), ps.height(), false);
+ canvas.drawRect(rc, paint);
+
+ return canvas.ExtractBitmap();
+}
+
+void DraggedTabGtk::PaintScreenshotIntoCanvas(gfx::Canvas* canvas,
+ const gfx::Rect& target_bounds) {
+ gfx::Rect rect(0, 0,
+ contents_->allocation.width, contents_->allocation.height);
+ SkBitmap* bitmap = backing_store_->PaintRectToBitmap(rect);
+ if (bitmap) {
+ canvas->DrawBitmapInt(*bitmap, 0, renderer_->bounds().height());
+ delete bitmap;
+ }
+}
+
// static
gboolean DraggedTabGtk::OnExposeEvent(GtkWidget* widget,
GdkEventExpose* event,
DraggedTabGtk* dragged_tab) {
+ SkBitmap bmp;
+ if (dragged_tab->attached_) {
+ bmp = dragged_tab->PaintAttachedTab();
+ } else {
+ bmp = dragged_tab->PaintDetachedView();
+ }
+
if (gtk_util::IsScreenComposited()) {
dragged_tab->SetContainerTransparency();
} else {
- dragged_tab->SetContainerShapeMask();
+ dragged_tab->SetContainerShapeMask(bmp);
}
- return FALSE;
+ gfx::CanvasPaint canvas(event, false);
+ canvas.DrawBitmapInt(bmp, 0, 0);
+
+ // We've already drawn the tab, so don't propagate the expose-event signal.
+ return TRUE;
}
diff --git a/chrome/browser/gtk/tabs/dragged_tab_gtk.h b/chrome/browser/gtk/tabs/dragged_tab_gtk.h
index d942db9..fb5a303 100644
--- a/chrome/browser/gtk/tabs/dragged_tab_gtk.h
+++ b/chrome/browser/gtk/tabs/dragged_tab_gtk.h
@@ -7,14 +7,15 @@
#include <gtk/gtk.h>
+#include "app/gfx/canvas.h"
#include "app/slide_animation.h"
#include "base/gfx/point.h"
#include "base/gfx/rect.h"
#include "base/gfx/size.h"
#include "base/scoped_ptr.h"
#include "base/task.h"
+#include "chrome/browser/renderer_host/backing_store.h"
-class ChromeCanvas;
class TabContents;
class TabRendererGtk;
@@ -33,7 +34,10 @@ class DraggedTabGtk : public AnimationDelegate {
void Attach(int selected_width);
// Notifies the dragged tab that it has been detached from a tabstrip.
- void Detach();
+ // |contents| is the widget that contains the dragged tab contents, while
+ // |backing_store| is the backing store that holds a server-side bitmap of the
+ // visual representation of |contents|.
+ void Detach(GtkWidget* contents, BackingStore* backing_store);
// Notifies the dragged tab that it should update itself.
void Update();
@@ -56,8 +60,11 @@ class DraggedTabGtk : public AnimationDelegate {
virtual void AnimationEnded(const Animation* animation);
virtual void AnimationCanceled(const Animation* animation);
+ // Arranges the contents of the dragged tab.
+ void Layout();
+
// Gets the preferred size of the dragged tab.
- virtual gfx::Size GetPreferredSize();
+ gfx::Size GetPreferredSize();
// Resizes the container to fit the content for the current attachment mode.
void ResizeContainer();
@@ -79,7 +86,18 @@ class DraggedTabGtk : public AnimationDelegate {
// Sets the shape mask for the container window to emulate a transparent
// container window. This is used if compositing is not available for the
// screen.
- void SetContainerShapeMask();
+ void SetContainerShapeMask(const SkBitmap& dragged_contents);
+
+ // Paints the tab when it's attached to a tabstrip.
+ SkBitmap PaintAttachedTab();
+
+ // Paints the tab when it's not attached to any tabstrip.
+ SkBitmap PaintDetachedView();
+
+ // Paints a screenshot of the dragged contents from the backing store into
+ // |canvas|.
+ void PaintScreenshotIntoCanvas(gfx::Canvas* canvas,
+ const gfx::Rect& target_bounds);
// expose-event handler that notifies when the tab needs to be redrawn.
static gboolean OnExposeEvent(GtkWidget* widget, GdkEventExpose* event,
@@ -88,6 +106,13 @@ class DraggedTabGtk : public AnimationDelegate {
// The window that contains the dragged tab or tab contents.
GtkWidget* container_;
+ // The native view of the tab contents.
+ GtkWidget* contents_;
+
+ // The backing store used to create a screenshot of the dragged contents.
+ // Owned by the RWH.
+ BackingStore* backing_store_;
+
// The renderer that paints the dragged tab.
scoped_ptr<TabRendererGtk> renderer_;
diff --git a/chrome/browser/renderer_host/backing_store.h b/chrome/browser/renderer_host/backing_store.h
index fd2d13b..2214518 100644
--- a/chrome/browser/renderer_host/backing_store.h
+++ b/chrome/browser/renderer_host/backing_store.h
@@ -64,6 +64,9 @@ class BackingStore {
// damage: the area to copy
// target: the X id of the target window
void ShowRect(const gfx::Rect& damage, XID target);
+
+ // Paints the server-side backing store data to a SkBitmap.
+ SkBitmap* PaintRectToBitmap(const gfx::Rect& rect);
#endif
// Paints the bitmap from the renderer onto the backing store.
diff --git a/chrome/browser/renderer_host/backing_store_x.cc b/chrome/browser/renderer_host/backing_store_x.cc
index 52fd7dc..b5c3284 100644
--- a/chrome/browser/renderer_host/backing_store_x.cc
+++ b/chrome/browser/renderer_host/backing_store_x.cc
@@ -12,6 +12,7 @@
#include "chrome/common/transport_dib.h"
#include "chrome/common/x11_util.h"
#include "chrome/common/x11_util_internal.h"
+#include "third_party/skia/include/core/SkBitmap.h"
// X Backing Stores:
//
@@ -311,3 +312,28 @@ void BackingStore::ShowRect(const gfx::Rect& rect, XID target) {
rect.x(), rect.y(), rect.width(), rect.height(),
rect.x(), rect.y());
}
+
+SkBitmap* BackingStore::PaintRectToBitmap(const gfx::Rect& rect) {
+ static const int kBytesPerPixel = 4;
+
+ const int width = rect.width();
+ const int height = rect.height();
+ XImage* image = XGetImage(display_, pixmap_,
+ rect.x(), rect.y(),
+ width, height,
+ AllPlanes, ZPixmap);
+ // TODO(jhawkins): Need to convert the image data if the image bits per pixel
+ // is not 32.
+ if (image->bits_per_pixel != 32)
+ return NULL;
+
+ SkBitmap* bitmap = new SkBitmap();
+ bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ bitmap->allocPixels();
+ unsigned char* bitmap_data =
+ reinterpret_cast<unsigned char*>(bitmap->getAddr32(0, 0));
+ memcpy(bitmap_data, image->data, width * height * kBytesPerPixel);
+
+ XFree(image);
+ return bitmap;
+}