diff options
author | jhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-19 00:09:23 +0000 |
---|---|---|
committer | jhawkins@chromium.org <jhawkins@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-19 00:09:23 +0000 |
commit | 19132f5e56873a226220d41f01434b2fc52e3a85 (patch) | |
tree | 7713e30369408855ac11c4444d504c989eb68f6b /chrome | |
parent | 0a7800ee17acd0f383fac1a99d664ee6a12a878f (diff) | |
download | chromium_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.cc | 7 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/dragged_tab_gtk.cc | 124 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/dragged_tab_gtk.h | 33 | ||||
-rw-r--r-- | chrome/browser/renderer_host/backing_store.h | 3 | ||||
-rw-r--r-- | chrome/browser/renderer_host/backing_store_x.cc | 26 |
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; +} |