summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-09 22:58:58 +0000
committerestade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-09 22:58:58 +0000
commit013a4d61cc1d89a24690dfead3e6b22377d5993a (patch)
tree92ec9c5df500ded546d2ba2730896b33db48b0ac /chrome
parent5420bc1e4fa6d861107a5c847843ac7bd25fb3c4 (diff)
downloadchromium_src-013a4d61cc1d89a24690dfead3e6b22377d5993a.zip
chromium_src-013a4d61cc1d89a24690dfead3e6b22377d5993a.tar.gz
chromium_src-013a4d61cc1d89a24690dfead3e6b22377d5993a.tar.bz2
Improve performance of dragged tab renderering.
Do as much as possible server side. I suspect the main factors that made our previous implementation slow were blitting from client to server, several unnecessary copies of the entire image, and doing an in-memory rgba->bgra swap. Now, even in debug mode with a 30" chrome window, the performance is very fast. BUG=16257,15869 TEST=drag a tab out of the tabstrip, with and without compositing Review URL: http://codereview.chromium.org/155321 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20333 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/gtk/tabs/dragged_tab_gtk.cc158
-rw-r--r--chrome/browser/gtk/tabs/dragged_tab_gtk.h15
-rw-r--r--chrome/browser/renderer_host/backing_store.h6
-rw-r--r--chrome/browser/renderer_host/backing_store_x.cc29
4 files changed, 117 insertions, 91 deletions
diff --git a/chrome/browser/gtk/tabs/dragged_tab_gtk.cc b/chrome/browser/gtk/tabs/dragged_tab_gtk.cc
index 8e829ec..aab4b8c 100644
--- a/chrome/browser/gtk/tabs/dragged_tab_gtk.cc
+++ b/chrome/browser/gtk/tabs/dragged_tab_gtk.cc
@@ -14,12 +14,13 @@
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/gtk/tabs/tab_renderer_gtk.h"
#include "chrome/common/gtk_util.h"
+#include "chrome/common/x11_util.h"
#include "third_party/skia/include/core/SkShader.h"
namespace {
// The size of the dragged window frame.
-const int kDragFrameBorderSize = 2;
+const int kDragFrameBorderSize = 1;
const int kTwiceDragFrameBorderSize = 2 * kDragFrameBorderSize;
// Used to scale the dragged window sizes.
@@ -29,7 +30,9 @@ const int kAnimateToBoundsDurationMs = 150;
const gdouble kTransparentAlpha = (200.0f / 255.0f);
const gdouble kOpaqueAlpha = 1.0f;
-const SkColor kDraggedTabBorderColor = SkColorSetRGB(103, 129, 162);
+const double kDraggedTabBorderColor[] = { 103.0 / 0xff,
+ 129.0 / 0xff,
+ 162.0 / 0xff };
} // namespace
@@ -196,7 +199,7 @@ void DraggedTabGtk::SetContainerColorMap() {
void DraggedTabGtk::SetContainerTransparency() {
cairo_t* cairo_context = gdk_cairo_create(container_->window);
if (!cairo_context)
- return;
+ return;
// Make the background of the dragged tab window fully transparent. All of
// the content of the window (child widgets) will be completely opaque.
@@ -209,9 +212,7 @@ void DraggedTabGtk::SetContainerTransparency() {
cairo_destroy(cairo_context);
}
-void DraggedTabGtk::SetContainerShapeMask(const SkBitmap& dragged_contents) {
- GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&dragged_contents);
-
+void DraggedTabGtk::SetContainerShapeMask(GdkPixbuf* pixbuf) {
// Create a 1bpp bitmap the size of |container_|.
gfx::Size size = bounds().size();
GdkPixmap* pixmap = gdk_pixmap_new(NULL, size.width(), size.height(), 1);
@@ -223,100 +224,97 @@ void DraggedTabGtk::SetContainerShapeMask(const SkBitmap& dragged_contents) {
// Blit the rendered bitmap into a pixmap. Any pixel set in the pixmap will
// be opaque in the container window.
cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE);
+ if (!attached_)
+ cairo_scale(cairo_context, kScalingFactor, kScalingFactor);
gdk_cairo_set_source_pixbuf(cairo_context, pixbuf, 0, 0);
cairo_paint(cairo_context);
+
+ if (!attached_) {
+ // Make the render area depiction opaque (leaving enough room for the
+ // border).
+ cairo_identity_matrix(cairo_context);
+ cairo_set_source_rgba(cairo_context, 1.0f, 1.0f, 1.0f, 1.0f);
+ int tab_height = kScalingFactor * gdk_pixbuf_get_height(pixbuf) -
+ kDragFrameBorderSize;
+ cairo_rectangle(cairo_context,
+ 0, tab_height,
+ size.width(), size.height() - tab_height);
+ cairo_fill(cairo_context);
+ }
+
cairo_destroy(cairo_context);
// Set the shape mask.
gdk_window_shape_combine_mask(container_->window, pixmap, 0, 0);
- g_object_unref(pixbuf);
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) {
- // A drag could be initiated before the backing store is created.
- if (!backing_store_)
- return;
-
- gfx::Rect rect(0, 0, target_bounds.width(), target_bounds.height());
- SkBitmap bitmap = backing_store_->PaintRectToBitmap(rect);
- if (!bitmap.isNull())
- canvas->DrawBitmapInt(bitmap, target_bounds.x(), target_bounds.y());
+GdkPixbuf* DraggedTabGtk::PaintTab() {
+ SkBitmap bitmap = renderer_->PaintBitmap();
+ return gfx::GdkPixbufFromSkBitmap(&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();
- }
-
+ GdkPixbuf* pixbuf = dragged_tab->PaintTab();
if (gtk_util::IsScreenComposited()) {
dragged_tab->SetContainerTransparency();
} else {
- dragged_tab->SetContainerShapeMask(bmp);
+ dragged_tab->SetContainerShapeMask(pixbuf);
+ }
+
+ // Only used when not attached.
+ int tab_height = kScalingFactor * gdk_pixbuf_get_height(pixbuf);
+ int tab_width = kScalingFactor * gdk_pixbuf_get_width(pixbuf);
+
+ // Draw the render area.
+ if (dragged_tab->backing_store_ && !dragged_tab->attached_) {
+ // This leaves room for the border.
+ dragged_tab->backing_store_->PaintToRect(
+ gfx::Rect(kDragFrameBorderSize, tab_height,
+ widget->allocation.width - kTwiceDragFrameBorderSize,
+ widget->allocation.height - tab_height -
+ kDragFrameBorderSize),
+ GDK_DRAWABLE(widget->window));
}
- gfx::CanvasPaint canvas(event, false);
- canvas.DrawBitmapInt(bmp, 0, 0);
+ cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(widget->window));
+ // Draw the border.
+ if (!dragged_tab->attached_) {
+ cairo_set_line_width(cr, kDragFrameBorderSize);
+ cairo_set_source_rgb(cr, kDraggedTabBorderColor[0],
+ kDraggedTabBorderColor[1],
+ kDraggedTabBorderColor[2]);
+ // |offset| is the distance from the edge of the image to the middle of
+ // the border line.
+ double offset = kDragFrameBorderSize / 2.0 - 0.5;
+ double left_x = offset;
+ double top_y = tab_height - kDragFrameBorderSize + offset;
+ double right_x = widget->allocation.width - offset;
+ double bottom_y = widget->allocation.height - offset;
+ double middle_x = tab_width + offset;
+
+ // We don't use cairo_rectangle() because we don't want to draw the border
+ // under the tab itself.
+ cairo_move_to(cr, left_x, top_y);
+ cairo_line_to(cr, left_x, bottom_y);
+ cairo_line_to(cr, right_x, bottom_y);
+ cairo_line_to(cr, right_x, top_y);
+ cairo_line_to(cr, middle_x, top_y);
+ cairo_stroke(cr);
+ }
+
+ // Draw the tab.
+ if (!dragged_tab->attached_)
+ cairo_scale(cr, kScalingFactor, kScalingFactor);
+ gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
+ cairo_paint(cr);
+
+ cairo_destroy(cr);
+
+ g_object_unref(pixbuf);
// 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 fb5a303..0732a12 100644
--- a/chrome/browser/gtk/tabs/dragged_tab_gtk.h
+++ b/chrome/browser/gtk/tabs/dragged_tab_gtk.h
@@ -86,18 +86,11 @@ 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(const SkBitmap& dragged_contents);
+ // |pixbuf| is the pixbuf for the tab only (not the render view).
+ void SetContainerShapeMask(GdkPixbuf* pixbuf);
- // 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);
+ // Paints the tab. The returned pixbuf belongs to the caller.
+ GdkPixbuf* PaintTab();
// expose-event handler that notifies when the tab needs to be redrawn.
static gboolean OnExposeEvent(GtkWidget* widget, GdkEventExpose* event,
diff --git a/chrome/browser/renderer_host/backing_store.h b/chrome/browser/renderer_host/backing_store.h
index 1114a18..49922e78 100644
--- a/chrome/browser/renderer_host/backing_store.h
+++ b/chrome/browser/renderer_host/backing_store.h
@@ -23,6 +23,7 @@
class RenderWidgetHost;
class SkBitmap;
class TransportDIB;
+typedef struct _GdkDrawable GdkDrawable;
// BackingStore ----------------------------------------------------------------
@@ -75,6 +76,11 @@ class BackingStore {
SkBitmap PaintRectToBitmap(const gfx::Rect& rect);
#endif
+#if defined(TOOLKIT_GTK)
+ // Paint the backing store into the target's |dest_rect|.
+ void PaintToRect(const gfx::Rect& dest_rect, GdkDrawable* target);
+#endif
+
// Paints the bitmap from the renderer onto the backing store.
void PaintRect(base::ProcessHandle process,
TransportDIB* bitmap,
diff --git a/chrome/browser/renderer_host/backing_store_x.cc b/chrome/browser/renderer_host/backing_store_x.cc
index 8a8d23f..c1ddad9 100644
--- a/chrome/browser/renderer_host/backing_store_x.cc
+++ b/chrome/browser/renderer_host/backing_store_x.cc
@@ -7,6 +7,10 @@
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
+#if defined(TOOLKIT_GTK)
+#include <cairo-xlib.h>
+#include <gtk/gtk.h>
+#endif
#include <algorithm>
#include <utility>
@@ -336,6 +340,31 @@ void BackingStore::ShowRect(const gfx::Rect& rect, XID target) {
rect.x(), rect.y());
}
+#if defined(TOOLKIT_GTK)
+void BackingStore::PaintToRect(const gfx::Rect& rect, GdkDrawable* target) {
+ cairo_surface_t* surface = cairo_xlib_surface_create(
+ display_, pixmap_, static_cast<Visual*>(visual_),
+ size_.width(), size_.height());
+ cairo_t* cr = gdk_cairo_create(target);
+
+ cairo_translate(cr, rect.x(), rect.y());
+ double x_scale = static_cast<double>(rect.width()) / size_.width();
+ double y_scale = static_cast<double>(rect.height()) / size_.height();
+ cairo_scale(cr, x_scale, y_scale);
+
+ cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface);
+ cairo_pattern_set_filter(pattern, CAIRO_FILTER_BEST);
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+
+ cairo_identity_matrix(cr);
+
+ cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height());
+ cairo_fill(cr);
+ cairo_destroy(cr);
+}
+#endif
+
SkBitmap BackingStore::PaintRectToBitmap(const gfx::Rect& rect) {
base::TimeTicks begin_time = base::TimeTicks::Now();
const int width = std::min(size_.width(), rect.width());