summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/browser_theme_provider.h8
-rw-r--r--chrome/browser/gtk/bookmark_bar_gtk.cc8
-rw-r--r--chrome/browser/gtk/browser_toolbar_gtk.cc8
-rw-r--r--chrome/browser/gtk/browser_window_gtk.cc87
-rw-r--r--chrome/browser/gtk/cairo_cached_surface.cc68
-rw-r--r--chrome/browser/gtk/cairo_cached_surface.h57
-rw-r--r--chrome/browser/gtk/custom_button.cc89
-rw-r--r--chrome/browser/gtk/custom_button.h11
-rw-r--r--chrome/browser/gtk/find_bar_gtk.cc10
-rw-r--r--chrome/browser/gtk/go_button_gtk.cc8
-rw-r--r--chrome/browser/gtk/gtk_theme_provider.cc33
-rw-r--r--chrome/browser/gtk/gtk_theme_provider.h16
-rw-r--r--chrome/browser/gtk/toolbar_star_toggle_gtk.cc10
-rw-r--r--chrome/chrome.gyp2
14 files changed, 298 insertions, 117 deletions
diff --git a/chrome/browser/browser_theme_provider.h b/chrome/browser/browser_theme_provider.h
index 0053ef2..7532f97 100644
--- a/chrome/browser/browser_theme_provider.h
+++ b/chrome/browser/browser_theme_provider.h
@@ -242,6 +242,10 @@ class BrowserThemeProvider : public base::RefCounted<BrowserThemeProvider>,
// Save the modified bitmap at image_cache_[id].
virtual void SaveThemeBitmap(const std::string resource_name, int id);
+ // Clears the platform-specific caches. Do not call directly; it's called
+ // from ClearCaches().
+ virtual void FreePlatformCaches();
+
Profile* profile() { return profile_; }
// Subclasses may need us to not use the on-disk image cache. The GTK
@@ -312,10 +316,6 @@ class BrowserThemeProvider : public base::RefCounted<BrowserThemeProvider>,
// Frees generated images and clears the image cache.
void ClearCaches();
- // Clears the platform-specific caches. Do not call directly; it's called
- // from ClearCaches().
- void FreePlatformCaches();
-
// Encode image at image_cache_[id] as PNG and write to disk.
bool WriteImagesToDisk();
diff --git a/chrome/browser/gtk/bookmark_bar_gtk.cc b/chrome/browser/gtk/bookmark_bar_gtk.cc
index 0504349..3caac71 100644
--- a/chrome/browser/gtk/bookmark_bar_gtk.cc
+++ b/chrome/browser/gtk/bookmark_bar_gtk.cc
@@ -21,6 +21,7 @@
#include "chrome/browser/gtk/bookmark_tree_model.h"
#include "chrome/browser/gtk/bookmark_utils_gtk.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
+#include "chrome/browser/gtk/cairo_cached_surface.h"
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
@@ -905,10 +906,9 @@ gboolean BookmarkBarGtk::OnEventBoxExpose(GtkWidget* widget,
bar->window_->tabstrip()->GetTabStripOriginForWidget(widget);
GtkThemeProvider* theme_provider = bar->theme_provider_;
- GdkPixbuf* toolbar_background = theme_provider->GetPixbufNamed(
- IDR_THEME_TOOLBAR);
- gdk_cairo_set_source_pixbuf(cr, toolbar_background, tabstrip_origin.x(),
- tabstrip_origin.y());
+ CairoCachedSurface* background = theme_provider->GetSurfaceNamed(
+ IDR_THEME_TOOLBAR, widget);
+ background->SetSource(cr, tabstrip_origin.x(), tabstrip_origin.y());
// We tile the toolbar background in both directions.
cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cr,
diff --git a/chrome/browser/gtk/browser_toolbar_gtk.cc b/chrome/browser/gtk/browser_toolbar_gtk.cc
index 3bced3d..24fbf7a 100644
--- a/chrome/browser/gtk/browser_toolbar_gtk.cc
+++ b/chrome/browser/gtk/browser_toolbar_gtk.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/encoding_menu_controller.h"
#include "chrome/browser/gtk/back_forward_button_gtk.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
+#include "chrome/browser/gtk/cairo_cached_surface.h"
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/go_button_gtk.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"
@@ -541,10 +542,9 @@ gboolean BrowserToolbarGtk::OnAlignmentExpose(GtkWidget* widget,
gfx::Point tabstrip_origin =
toolbar->window_->tabstrip()->GetTabStripOriginForWidget(widget);
GtkThemeProvider* theme_provider = toolbar->theme_provider_;
- GdkPixbuf* toolbar_background = theme_provider->GetPixbufNamed(
- IDR_THEME_TOOLBAR);
- gdk_cairo_set_source_pixbuf(cr, toolbar_background, tabstrip_origin.x(),
- tabstrip_origin.y());
+ CairoCachedSurface* background = theme_provider->GetSurfaceNamed(
+ IDR_THEME_TOOLBAR, widget);
+ background->SetSource(cr, tabstrip_origin.x(), tabstrip_origin.y());
// We tile the toolbar background in both directions.
cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cr,
diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc
index a7e4d44..52f0887 100644
--- a/chrome/browser/gtk/browser_window_gtk.cc
+++ b/chrome/browser/gtk/browser_window_gtk.cc
@@ -41,6 +41,7 @@
#include "chrome/browser/gtk/bookmark_manager_gtk.h"
#include "chrome/browser/gtk/browser_titlebar.h"
#include "chrome/browser/gtk/browser_toolbar_gtk.h"
+#include "chrome/browser/gtk/cairo_cached_surface.h"
#include "chrome/browser/gtk/clear_browsing_data_dialog_gtk.h"
#include "chrome/browser/gtk/download_shelf_gtk.h"
#include "chrome/browser/gtk/edit_search_engine_dialog.h"
@@ -339,12 +340,11 @@ gboolean OnCompactNavSpacerExpose(GtkWidget* widget,
// tab strip.
gfx::Point tabstrip_origin =
window->tabstrip()->GetTabStripOriginForWidget(widget);
- ThemeProvider* theme_provider =
- window->browser()->profile()->GetThemeProvider();
- GdkPixbuf* toolbar_background = theme_provider->GetPixbufNamed(
- IDR_THEME_TOOLBAR);
- gdk_cairo_set_source_pixbuf(cr, toolbar_background, tabstrip_origin.x(),
- tabstrip_origin.y());
+ GtkThemeProvider* theme_provider = GtkThemeProvider::GetFrom(
+ window->browser()->profile());
+ CairoCachedSurface* background = theme_provider->GetSurfaceNamed(
+ IDR_THEME_TOOLBAR, widget);
+ background->SetSource(cr, tabstrip_origin.x(), tabstrip_origin.y());
// We tile the toolbar background in both directions.
cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cr,
@@ -596,8 +596,8 @@ void BrowserWindowGtk::HandleKeyboardEvent(GdkEventKey* event) {
gboolean BrowserWindowGtk::OnCustomFrameExpose(GtkWidget* widget,
GdkEventExpose* event,
BrowserWindowGtk* window) {
- ThemeProvider* theme_provider =
- window->browser()->profile()->GetThemeProvider();
+ GtkThemeProvider* theme_provider = GtkThemeProvider::GetFrom(
+ window->browser()->profile());
// Draw the default background.
cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(widget->window));
@@ -613,18 +613,19 @@ gboolean BrowserWindowGtk::OnCustomFrameExpose(GtkWidget* widget,
image_name = window->browser()->profile()->IsOffTheRecord() ?
IDR_THEME_FRAME_INCOGNITO_INACTIVE : IDR_THEME_FRAME_INACTIVE;
}
- GdkPixbuf* pixbuf = theme_provider->GetPixbufNamed(image_name);
- gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
+ CairoCachedSurface* surface = theme_provider->GetSurfaceNamed(
+ image_name, widget);
+ surface->SetSource(cr, 0, 0);
cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cr, event->area.x, event->area.y,
event->area.width, event->area.height);
cairo_fill(cr);
if (theme_provider->HasCustomImage(IDR_THEME_FRAME_OVERLAY)) {
- GdkPixbuf* theme_overlay = theme_provider->GetPixbufNamed(
+ CairoCachedSurface* theme_overlay = theme_provider->GetSurfaceNamed(
window->IsActive() ? IDR_THEME_FRAME_OVERLAY
- : IDR_THEME_FRAME_OVERLAY_INACTIVE);
- gdk_cairo_set_source_pixbuf(cr, theme_overlay, 0, 0);
+ : IDR_THEME_FRAME_OVERLAY_INACTIVE, widget);
+ theme_overlay->SetSource(cr, 0, 0);
cairo_paint(cr);
}
@@ -654,21 +655,20 @@ gboolean BrowserWindowGtk::OnCustomFrameExpose(GtkWidget* widget,
void BrowserWindowGtk::DrawContentShadow(cairo_t* cr,
BrowserWindowGtk* window) {
// Draw the shadow above the toolbar. Tabs on the tabstrip will draw over us.
- ThemeProvider* theme_provider =
- window->browser()->profile()->GetThemeProvider();
+ GtkThemeProvider* theme_provider = GtkThemeProvider::GetFrom(
+ window->browser()->profile());
int left_x, top_y;
gtk_widget_translate_coordinates(window->content_vbox_,
GTK_WIDGET(window->window_), 0, 0, &left_x,
&top_y);
int width = window->content_vbox_->allocation.width;
- GdkPixbuf* top_center =
- theme_provider->GetPixbufNamed(IDR_CONTENT_TOP_CENTER);
- gdk_cairo_set_source_pixbuf(cr, top_center,
- left_x, top_y - kContentShadowThickness);
+ CairoCachedSurface* top_center = theme_provider->GetSurfaceNamed(
+ IDR_CONTENT_TOP_CENTER, window->content_vbox_);
+ top_center->SetSource(cr, left_x, top_y - kContentShadowThickness);
cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cr, left_x, top_y - kContentShadowThickness, width,
- gdk_pixbuf_get_height(top_center));
+ top_center->Height());
cairo_fill(cr);
// Only draw the rest of the shadow if the user has the custom frame enabled.
@@ -680,10 +680,10 @@ void BrowserWindowGtk::DrawContentShadow(cairo_t* cr,
// corners extend to the base of the toolbar (one pixel above the dividing
// line).
int right_x = left_x + width;
- GdkPixbuf* top_left =
- theme_provider->GetPixbufNamed(IDR_CONTENT_TOP_LEFT_CORNER);
- gdk_cairo_set_source_pixbuf(cr, top_left,
- left_x - kContentShadowThickness, top_y - kContentShadowThickness);
+ CairoCachedSurface* top_left = theme_provider->GetSurfaceNamed(
+ IDR_CONTENT_TOP_LEFT_CORNER, window->content_vbox_);
+ top_left->SetSource(
+ cr, left_x - kContentShadowThickness, top_y - kContentShadowThickness);
// The toolbar is shorter in location bar only mode so clip the image to the
// height of the toolbar + the amount of shadow above the toolbar.
int top_corner_height =
@@ -696,10 +696,9 @@ void BrowserWindowGtk::DrawContentShadow(cairo_t* cr,
cairo_fill(cr);
// Likewise, we crop off the left column of pixels for the top right corner.
- GdkPixbuf* top_right =
- theme_provider->GetPixbufNamed(IDR_CONTENT_TOP_RIGHT_CORNER);
- gdk_cairo_set_source_pixbuf(cr, top_right,
- right_x - 1, top_y - kContentShadowThickness);
+ CairoCachedSurface* top_right = theme_provider->GetSurfaceNamed(
+ IDR_CONTENT_TOP_RIGHT_CORNER, window->content_vbox_);
+ top_right->SetSource(cr, right_x - 1, top_y - kContentShadowThickness);
cairo_rectangle(cr,
right_x,
top_y - kContentShadowThickness,
@@ -718,9 +717,9 @@ void BrowserWindowGtk::DrawContentShadow(cairo_t* cr,
// drawn by the bottom corners.
int side_height = bottom_y - side_y - 1;
if (side_height > 0) {
- GdkPixbuf* left = theme_provider->GetPixbufNamed(IDR_CONTENT_LEFT_SIDE);
- gdk_cairo_set_source_pixbuf(cr, left,
- left_x - kContentShadowThickness, side_y);
+ CairoCachedSurface* left = theme_provider->GetSurfaceNamed(
+ IDR_CONTENT_LEFT_SIDE, window->content_vbox_);
+ left->SetSource(cr, left_x - kContentShadowThickness, side_y);
cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cr,
left_x - kContentShadowThickness,
@@ -729,8 +728,9 @@ void BrowserWindowGtk::DrawContentShadow(cairo_t* cr,
side_height);
cairo_fill(cr);
- GdkPixbuf* right = theme_provider->GetPixbufNamed(IDR_CONTENT_RIGHT_SIDE);
- gdk_cairo_set_source_pixbuf(cr, right, right_x - 1, side_y);
+ CairoCachedSurface* right = theme_provider->GetSurfaceNamed(
+ IDR_CONTENT_RIGHT_SIDE, window->content_vbox_);
+ right->SetSource(cr, right_x - 1, side_y);
cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cr,
right_x,
@@ -742,24 +742,21 @@ void BrowserWindowGtk::DrawContentShadow(cairo_t* cr,
// Draw the bottom corners. The bottom corners also draw the bottom row of
// pixels of the side shadows.
- GdkPixbuf* bottom_left =
- theme_provider->GetPixbufNamed(IDR_CONTENT_BOTTOM_LEFT_CORNER);
- gdk_cairo_set_source_pixbuf(cr, bottom_left,
- left_x - kContentShadowThickness, bottom_y - 1);
+ CairoCachedSurface* bottom_left = theme_provider->GetSurfaceNamed(
+ IDR_CONTENT_BOTTOM_LEFT_CORNER, window->content_vbox_);
+ bottom_left->SetSource(cr, left_x - kContentShadowThickness, bottom_y - 1);
cairo_paint(cr);
- GdkPixbuf* bottom_right =
- theme_provider->GetPixbufNamed(IDR_CONTENT_BOTTOM_RIGHT_CORNER);
- gdk_cairo_set_source_pixbuf(cr, bottom_right,
- right_x - 1, bottom_y - 1);
+ CairoCachedSurface* bottom_right = theme_provider->GetSurfaceNamed(
+ IDR_CONTENT_BOTTOM_RIGHT_CORNER, window->content_vbox_);
+ bottom_right->SetSource(cr, right_x - 1, bottom_y - 1);
cairo_paint(cr);
// Finally, draw the bottom row. Since we don't overlap the contents, we clip
// the top row of pixels.
- GdkPixbuf* bottom =
- theme_provider->GetPixbufNamed(IDR_CONTENT_BOTTOM_CENTER);
- gdk_cairo_set_source_pixbuf(cr, bottom,
- left_x + 1, bottom_y - 1);
+ CairoCachedSurface* bottom = theme_provider->GetSurfaceNamed(
+ IDR_CONTENT_BOTTOM_CENTER, window->content_vbox_);
+ bottom->SetSource(cr, left_x + 1, bottom_y - 1);
cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cr,
left_x + 1,
diff --git a/chrome/browser/gtk/cairo_cached_surface.cc b/chrome/browser/gtk/cairo_cached_surface.cc
new file mode 100644
index 0000000..90e0ae4
--- /dev/null
+++ b/chrome/browser/gtk/cairo_cached_surface.cc
@@ -0,0 +1,68 @@
+// 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.
+
+#include "chrome/browser/gtk/cairo_cached_surface.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+CairoCachedSurface::CairoCachedSurface() : pixbuf_(NULL), surface_(NULL) {
+}
+
+CairoCachedSurface::~CairoCachedSurface() {
+ if (surface_)
+ cairo_surface_destroy(surface_);
+
+ if (pixbuf_)
+ g_object_unref(pixbuf_);
+}
+
+int CairoCachedSurface::Width() const {
+ return pixbuf_ ? gdk_pixbuf_get_width(pixbuf_) : -1;
+}
+
+int CairoCachedSurface::Height() const {
+ return pixbuf_ ? gdk_pixbuf_get_height(pixbuf_) : -1;
+}
+
+void CairoCachedSurface::UsePixbuf(GdkPixbuf* pixbuf) {
+ if (surface_) {
+ cairo_surface_destroy(surface_);
+ surface_ = NULL;
+ }
+
+ if (pixbuf)
+ g_object_ref(pixbuf);
+
+ if (pixbuf_)
+ g_object_unref(pixbuf_);
+
+ pixbuf_ = pixbuf;
+}
+
+void CairoCachedSurface::SetSource(cairo_t* cr, int x, int y) {
+ DCHECK(pixbuf_);
+ DCHECK(cr);
+
+ if (!surface_) {
+ // First time here since last UsePixbuf call. Generate the surface.
+ cairo_surface_t* target = cairo_get_target(cr);
+ surface_ = cairo_surface_create_similar(
+ target,
+ CAIRO_CONTENT_COLOR_ALPHA,
+ gdk_pixbuf_get_width(pixbuf_),
+ gdk_pixbuf_get_height(pixbuf_));
+
+ DCHECK(surface_);
+ DCHECK(cairo_surface_get_type(surface_) == CAIRO_SURFACE_TYPE_XLIB ||
+ cairo_surface_get_type(surface_) == CAIRO_SURFACE_TYPE_XCB);
+
+ cairo_t* copy_cr = cairo_create(surface_);
+ gdk_cairo_set_source_pixbuf(copy_cr, pixbuf_, 0, 0);
+ cairo_paint(copy_cr);
+ cairo_destroy(copy_cr);
+ }
+
+ cairo_set_source_surface(cr, surface_, x, y);
+}
diff --git a/chrome/browser/gtk/cairo_cached_surface.h b/chrome/browser/gtk/cairo_cached_surface.h
new file mode 100644
index 0000000..2c0b4d3
--- /dev/null
+++ b/chrome/browser/gtk/cairo_cached_surface.h
@@ -0,0 +1,57 @@
+// 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_BROWSER_GTK_CAIRO_CACHED_SURFACE_H_
+#define CHROME_BROWSER_GTK_CAIRO_CACHED_SURFACE_H_
+
+#include <gtk/gtk.h>
+
+// A helper class that takes a GdkPixbuf* and renders it to the screen. Unlike
+// gdk_cairo_set_source_pixbuf(), CairoCachedSurface assumes that the pixbuf is
+// immutable after UsePixbuf() is called and can be sent to the X server
+// once. From then on, that cached version is used so we don't upload the same
+// image each and every time we expose.
+//
+// Most cached surfaces are owned by the GtkThemeProvider, which associates
+// them with a certain XDisplay. Some users of surfaces (CustomDrawButtonBase,
+// for example) own their surfaces instead since they interact with the
+// ResourceBundle instead of the GtkThemeProvider.
+class CairoCachedSurface {
+ public:
+ CairoCachedSurface();
+ ~CairoCachedSurface();
+
+ // Whether this CairoCachedSurface owns a GdkPixbuf.
+ bool valid() const {
+ return pixbuf_;
+ }
+
+ // The dimensions of the underlying pixbuf/surface. (or -1 if invalid.)
+ int Width() const;
+ int Height() const;
+
+ // Sets the pixbuf that we pass to cairo. Calling UsePixbuf() only derefs the
+ // current pixbuf and surface (if they exist). Actually transfering data to
+ // the X server occurs at SetSource() time. Calling UsePixbuf() should only
+ // be done once as it clears cached data from the X server.
+ void UsePixbuf(GdkPixbuf* pixbuf);
+
+ // Sets our pixbuf as the active surface starting at (x, y), uploading it in
+ // case we don't have an X backed surface cached.
+ void SetSource(cairo_t* cr, int x, int y);
+
+ // Raw access to the pixbuf. May be NULL. Used for a few gdk operations
+ // regarding window shaping.
+ GdkPixbuf* pixbuf() { return pixbuf_; }
+
+ private:
+ // The source pixbuf.
+ GdkPixbuf* pixbuf_;
+
+ // Our cached surface. This should be a xlib surface so the data lives on the
+ // server instead of on the client.
+ cairo_surface_t* surface_;
+};
+
+#endif // CHROME_BROWSER_GTK_CAIRO_CACHED_SURFACE_H_
diff --git a/chrome/browser/gtk/custom_button.cc b/chrome/browser/gtk/custom_button.cc
index 276393a..745f495 100644
--- a/chrome/browser/gtk/custom_button.cc
+++ b/chrome/browser/gtk/custom_button.cc
@@ -9,6 +9,7 @@
#include "app/theme_provider.h"
#include "base/basictypes.h"
#include "base/gfx/gtk_util.h"
+#include "chrome/browser/gtk/cairo_cached_surface.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/common/gtk_util.h"
@@ -25,6 +26,10 @@ CustomDrawButtonBase::CustomDrawButtonBase(GtkThemeProvider* theme_provider,
highlight_id_(highlight_id),
depressed_id_(depressed_id),
theme_provider_(theme_provider) {
+ for (int i = 0; i < (GTK_STATE_INSENSITIVE + 1); ++i)
+ surfaces_[i].reset(new CairoCachedSurface);
+ background_image_.reset(new CairoCachedSurface);
+
if (theme_provider) {
// Load images by pretending that we got a BROWSER_THEME_CHANGED
// notification.
@@ -36,34 +41,39 @@ CustomDrawButtonBase::CustomDrawButtonBase(GtkThemeProvider* theme_provider,
} else {
// Load the button images from the resource bundle.
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- pixbufs_[GTK_STATE_NORMAL] =
- normal_id ? rb.GetRTLEnabledPixbufNamed(normal_id) : NULL;
- pixbufs_[GTK_STATE_ACTIVE] =
- active_id ? rb.GetRTLEnabledPixbufNamed(active_id) : NULL;
- pixbufs_[GTK_STATE_PRELIGHT] =
- highlight_id ? rb.GetRTLEnabledPixbufNamed(highlight_id) : NULL;
- pixbufs_[GTK_STATE_SELECTED] = NULL;
- pixbufs_[GTK_STATE_INSENSITIVE] =
- depressed_id ? rb.GetRTLEnabledPixbufNamed(depressed_id) : NULL;
+ surfaces_[GTK_STATE_NORMAL]->UsePixbuf(
+ normal_id ? rb.GetRTLEnabledPixbufNamed(normal_id) : NULL);
+ surfaces_[GTK_STATE_ACTIVE]->UsePixbuf(
+ active_id ? rb.GetRTLEnabledPixbufNamed(active_id) : NULL);
+ surfaces_[GTK_STATE_PRELIGHT]->UsePixbuf(
+ highlight_id ? rb.GetRTLEnabledPixbufNamed(highlight_id) : NULL);
+ surfaces_[GTK_STATE_SELECTED]->UsePixbuf(NULL);
+ surfaces_[GTK_STATE_INSENSITIVE]->UsePixbuf(
+ depressed_id ? rb.GetRTLEnabledPixbufNamed(depressed_id) : NULL);
}
}
CustomDrawButtonBase::~CustomDrawButtonBase() {
- if (background_image_) {
- g_object_unref(background_image_);
- background_image_ = NULL;
- }
+}
+
+int CustomDrawButtonBase::Width() const {
+ return surfaces_[0]->Width();
+}
+
+int CustomDrawButtonBase::Height() const {
+ return surfaces_[0]->Height();
}
gboolean CustomDrawButtonBase::OnExpose(GtkWidget* widget, GdkEventExpose* e) {
- GdkPixbuf* pixbuf = pixbufs_[paint_override_ >= 0 ?
- paint_override_ : GTK_WIDGET_STATE(widget)];
+ CairoCachedSurface* pixbuf =
+ surfaces_[paint_override_ >= 0 ?
+ paint_override_ : GTK_WIDGET_STATE(widget)].get();
// Fall back to the default image if we don't have one for this state.
- if (!pixbuf)
- pixbuf = pixbufs_[GTK_STATE_NORMAL];
+ if (!pixbuf || !pixbuf->valid())
+ pixbuf = surfaces_[GTK_STATE_NORMAL].get();
- if (!pixbuf)
+ if (!pixbuf || !pixbuf->valid())
return FALSE;
cairo_t* cairo_context = gdk_cairo_create(GDK_DRAWABLE(widget->window));
@@ -71,16 +81,16 @@ gboolean CustomDrawButtonBase::OnExpose(GtkWidget* widget, GdkEventExpose* e) {
// The widget might be larger than the pixbuf. Paint the pixbuf flush with the
// start of the widget (left for LTR, right for RTL) and its bottom.
- gfx::Rect bounds = gfx::Rect(0, 0, gdk_pixbuf_get_width(pixbuf), 0);
+ gfx::Rect bounds = gfx::Rect(0, 0, pixbuf->Width(), 0);
int x = gtk_util::MirroredLeftPointForRect(widget, bounds);
- int y = widget->allocation.height - gdk_pixbuf_get_height(pixbuf);
+ int y = widget->allocation.height - pixbuf->Height();
- if (background_image_) {
- gdk_cairo_set_source_pixbuf(cairo_context, background_image_, x, y);
+ if (background_image_->valid()) {
+ background_image_->SetSource(cairo_context, x, y);
cairo_paint(cairo_context);
}
- gdk_cairo_set_source_pixbuf(cairo_context, pixbuf, x, y);
+ pixbuf->SetSource(cairo_context, x, y);
cairo_paint(cairo_context);
cairo_destroy(cairo_context);
@@ -90,14 +100,16 @@ gboolean CustomDrawButtonBase::OnExpose(GtkWidget* widget, GdkEventExpose* e) {
void CustomDrawButtonBase::SetBackground(SkColor color,
SkBitmap* image, SkBitmap* mask) {
if (!image || !mask) {
- if (background_image_) {
- g_object_unref(background_image_);
- background_image_ = NULL;
+ if (background_image_->valid()) {
+ background_image_->UsePixbuf(NULL);
}
} else {
SkBitmap img = skia::ImageOperations::CreateButtonBackground(color,
*image, *mask);
- background_image_ = gfx::GdkPixbufFromSkBitmap(&img);
+
+ GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(&img);
+ background_image_->UsePixbuf(pixbuf);
+ g_object_unref(pixbuf);
}
}
@@ -106,15 +118,15 @@ void CustomDrawButtonBase::Observe(NotificationType type,
DCHECK(theme_provider_);
DCHECK(NotificationType::BROWSER_THEME_CHANGED == type);
- pixbufs_[GTK_STATE_NORMAL] = normal_id_ ?
- theme_provider_->GetRTLEnabledPixbufNamed(normal_id_) : NULL;
- pixbufs_[GTK_STATE_ACTIVE] = active_id_ ?
- theme_provider_->GetRTLEnabledPixbufNamed(active_id_) : NULL;
- pixbufs_[GTK_STATE_PRELIGHT] = highlight_id_ ?
- theme_provider_->GetRTLEnabledPixbufNamed(highlight_id_) : NULL;
- pixbufs_[GTK_STATE_SELECTED] = NULL;
- pixbufs_[GTK_STATE_INSENSITIVE] = depressed_id_ ?
- theme_provider_->GetRTLEnabledPixbufNamed(depressed_id_) : NULL;
+ surfaces_[GTK_STATE_NORMAL]->UsePixbuf(normal_id_ ?
+ theme_provider_->GetRTLEnabledPixbufNamed(normal_id_) : NULL);
+ surfaces_[GTK_STATE_ACTIVE]->UsePixbuf(active_id_ ?
+ theme_provider_->GetRTLEnabledPixbufNamed(active_id_) : NULL);
+ surfaces_[GTK_STATE_PRELIGHT]->UsePixbuf(highlight_id_ ?
+ theme_provider_->GetRTLEnabledPixbufNamed(highlight_id_) : NULL);
+ surfaces_[GTK_STATE_SELECTED]->UsePixbuf(NULL);
+ surfaces_[GTK_STATE_INSENSITIVE]->UsePixbuf(depressed_id_ ?
+ theme_provider_->GetRTLEnabledPixbufNamed(depressed_id_) : NULL);
}
CustomDrawButton::CustomDrawButton(int normal_id, int active_id,
@@ -211,9 +223,8 @@ void CustomDrawButton::SetBrowserTheme() {
gtk_widget_set_app_paintable(widget_.get(), FALSE);
gtk_widget_set_double_buffered(widget_.get(), TRUE);
} else {
- gtk_widget_set_size_request(widget_.get(),
- gdk_pixbuf_get_width(button_base_.pixbufs(0)),
- gdk_pixbuf_get_height(button_base_.pixbufs(0)));
+ gtk_widget_set_size_request(widget_.get(), button_base_.Width(),
+ button_base_.Height());
gtk_widget_set_app_paintable(widget_.get(), TRUE);
// We effectively double-buffer by virtue of having only one image...
diff --git a/chrome/browser/gtk/custom_button.h b/chrome/browser/gtk/custom_button.h
index 768b4ca..27dc275 100644
--- a/chrome/browser/gtk/custom_button.h
+++ b/chrome/browser/gtk/custom_button.h
@@ -16,6 +16,7 @@
#include "chrome/common/owned_widget_gtk.h"
#include "third_party/skia/include/core/SkBitmap.h"
+class CairoCachedSurface;
class GtkThemeProvider;
// These classes implement two kinds of custom-drawn buttons. They're
@@ -36,7 +37,9 @@ class CustomDrawButtonBase : public NotificationObserver {
~CustomDrawButtonBase();
- GdkPixbuf* pixbufs(int i) const { return pixbufs_[i]; }
+ // Returns the dimensions of the first surface.
+ int Width() const;
+ int Height() const;
gboolean OnExpose(GtkWidget* widget, GdkEventExpose* e);
@@ -52,12 +55,12 @@ class CustomDrawButtonBase : public NotificationObserver {
const NotificationDetails& details);
private:
- // We store one GdkPixbuf* for each possible state of the button;
+ // We store one surface for each possible state of the button;
// INSENSITIVE is the last available state;
- GdkPixbuf* pixbufs_[GTK_STATE_INSENSITIVE + 1];
+ scoped_ptr<CairoCachedSurface> surfaces_[GTK_STATE_INSENSITIVE + 1];
// The background image.
- GdkPixbuf* background_image_;
+ scoped_ptr<CairoCachedSurface> background_image_;
// If non-negative, the state to paint the button.
int paint_override_;
diff --git a/chrome/browser/gtk/find_bar_gtk.cc b/chrome/browser/gtk/find_bar_gtk.cc
index 503e1b8..94301d2 100644
--- a/chrome/browser/gtk/find_bar_gtk.cc
+++ b/chrome/browser/gtk/find_bar_gtk.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/profile.h"
#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/gtk/browser_window_gtk.h"
+#include "chrome/browser/gtk/cairo_cached_surface.h"
#include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/nine_box.h"
@@ -762,14 +763,13 @@ gboolean FindBarGtk::OnExpose(GtkWidget* widget, GdkEventExpose* e,
cairo_clip(cr);
gfx::Point tabstrip_origin =
bar->window_->tabstrip()->GetTabStripOriginForWidget(widget);
- GdkPixbuf* background = bar->browser_->profile()->GetThemeProvider()->
- GetPixbufNamed(IDR_THEME_TOOLBAR);
- gdk_cairo_set_source_pixbuf(cr, background,
- tabstrip_origin.x(), tabstrip_origin.y());
+ CairoCachedSurface* background = bar->theme_provider_->GetSurfaceNamed(
+ IDR_THEME_TOOLBAR, widget);
+ background->SetSource(cr, tabstrip_origin.x(), tabstrip_origin.y());
cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cr, tabstrip_origin.x(), tabstrip_origin.y(),
e->area.x + e->area.width - tabstrip_origin.x(),
- gdk_pixbuf_get_height(background));
+ background->Height());
cairo_fill(cr);
cairo_destroy(cr);
diff --git a/chrome/browser/gtk/go_button_gtk.cc b/chrome/browser/gtk/go_button_gtk.cc
index e4606bb..bd3bc23 100644
--- a/chrome/browser/gtk/go_button_gtk.cc
+++ b/chrome/browser/gtk/go_button_gtk.cc
@@ -36,9 +36,7 @@ GoButtonGtk::GoButtonGtk(LocationBarViewGtk* location_bar, Browser* browser)
go_(theme_provider_, IDR_GO, IDR_GO_P, IDR_GO_H, 0),
stop_(theme_provider_, IDR_STOP, IDR_STOP_P, IDR_STOP_H, 0),
widget_(gtk_chrome_button_new()) {
- gtk_widget_set_size_request(widget_.get(),
- gdk_pixbuf_get_width(go_.pixbufs(0)),
- gdk_pixbuf_get_height(go_.pixbufs(0)));
+ gtk_widget_set_size_request(widget_.get(), go_.Width(), go_.Height());
gtk_widget_set_app_paintable(widget_.get(), TRUE);
// We effectively double-buffer by virtue of having only one image...
@@ -245,9 +243,7 @@ void GoButtonGtk::UpdateThemeButtons() {
gtk_widget_set_app_paintable(widget_.get(), FALSE);
gtk_widget_set_double_buffered(widget_.get(), TRUE);
} else {
- gtk_widget_set_size_request(widget_.get(),
- gdk_pixbuf_get_width(go_.pixbufs(0)),
- gdk_pixbuf_get_height(go_.pixbufs(0)));
+ gtk_widget_set_size_request(widget_.get(), go_.Width(), go_.Height());
gtk_widget_set_app_paintable(widget_.get(), TRUE);
// We effectively double-buffer by virtue of having only one image...
diff --git a/chrome/browser/gtk/gtk_theme_provider.cc b/chrome/browser/gtk/gtk_theme_provider.cc
index 6b37ed5..e705eb0 100644
--- a/chrome/browser/gtk/gtk_theme_provider.cc
+++ b/chrome/browser/gtk/gtk_theme_provider.cc
@@ -9,6 +9,7 @@
#include "base/gfx/gtk_util.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/profile.h"
+#include "chrome/browser/gtk/cairo_cached_surface.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/notification_details.h"
@@ -163,6 +164,25 @@ GdkColor GtkThemeProvider::GetBorderColor() {
return color;
}
+CairoCachedSurface* GtkThemeProvider::GetSurfaceNamed(
+ int id, GtkWidget* widget_on_display) {
+ GdkDisplay* display = gtk_widget_get_display(widget_on_display);
+ CairoCachedSurfaceMap& surface_map = per_display_surfaces_[display];
+
+ // Check to see if we already have the pixbuf in the cache.
+ CairoCachedSurfaceMap::const_iterator found = surface_map.find(id);
+ if (found != surface_map.end())
+ return found->second;
+
+ GdkPixbuf* pixbuf = GetPixbufNamed(id);
+ CairoCachedSurface* surface = new CairoCachedSurface;
+ surface->UsePixbuf(pixbuf);
+
+ surface_map[id] = surface;
+
+ return surface;
+}
+
void GtkThemeProvider::LoadThemePrefs() {
if (use_gtk_) {
LoadGtkValues();
@@ -208,6 +228,19 @@ void GtkThemeProvider::SaveThemeBitmap(const std::string resource_name,
}
}
+void GtkThemeProvider::FreePlatformCaches() {
+ BrowserThemeProvider::FreePlatformCaches();
+
+ for (PerDisplaySurfaceMap::iterator it = per_display_surfaces_.begin();
+ it != per_display_surfaces_.end(); ++it) {
+ for (CairoCachedSurfaceMap::iterator jt = it->second.begin();
+ jt != it->second.end(); ++jt) {
+ delete jt->second;
+ }
+ }
+ per_display_surfaces_.clear();
+}
+
// static
void GtkThemeProvider::OnStyleSet(GtkWidget* widget,
GtkStyle* previous_style,
diff --git a/chrome/browser/gtk/gtk_theme_provider.h b/chrome/browser/gtk/gtk_theme_provider.h
index e914d89..526d245 100644
--- a/chrome/browser/gtk/gtk_theme_provider.h
+++ b/chrome/browser/gtk/gtk_theme_provider.h
@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_GTK_GTK_THEME_PROVIDER_H_
#define CHROME_BROWSER_GTK_GTK_THEME_PROVIDER_H_
+#include <map>
#include <string>
#include <vector>
@@ -14,8 +15,10 @@
#include "skia/ext/skia_utils.h"
+class CairoCachedSurface;
class Profile;
+typedef struct _GdkDisplay GdkDisplay;
typedef struct _GtkStyle GtkStyle;
typedef struct _GtkWidget GtkWidget;
@@ -67,6 +70,11 @@ class GtkThemeProvider : public BrowserThemeProvider,
GtkWidget* fake_window() { return fake_window_; }
GtkWidget* fake_label() { return fake_label_.get(); }
+ // Returns a CairoCachedSurface for a particular Display. CairoCachedSurfaces
+ // (hopefully) live on the X server, instead of the client so we don't have
+ // to send the image to the server on each expose.
+ CairoCachedSurface* GetSurfaceNamed(int id, GtkWidget* widget_on_display);
+
protected:
// Possibly creates a theme specific version of theme_toolbar_default.
// (minimally acceptable version right now, which is just a fill of the bg
@@ -85,6 +93,9 @@ class GtkThemeProvider : public BrowserThemeProvider,
// the superclass.
virtual void SaveThemeBitmap(const std::string resource_name, int id);
+ // Additionally frees the CairoCachedSurfaces.
+ virtual void FreePlatformCaches();
+
// Handles signal from GTK that our theme has been changed.
static void OnStyleSet(GtkWidget* widget,
GtkStyle* previous_style,
@@ -113,6 +124,11 @@ class GtkThemeProvider : public BrowserThemeProvider,
// A list of all GtkChromeButton instances. We hold on to these to notify
// them of theme changes.
std::vector<GtkWidget*> chrome_buttons_;
+
+ // Cairo surfaces for each GdkDisplay.
+ typedef std::map<int, CairoCachedSurface*> CairoCachedSurfaceMap;
+ typedef std::map<GdkDisplay*, CairoCachedSurfaceMap> PerDisplaySurfaceMap;
+ PerDisplaySurfaceMap per_display_surfaces_;
};
#endif // CHROME_BROWSER_GTK_GTK_THEME_PROVIDER_H_
diff --git a/chrome/browser/gtk/toolbar_star_toggle_gtk.cc b/chrome/browser/gtk/toolbar_star_toggle_gtk.cc
index 8723a48..c122a9e 100644
--- a/chrome/browser/gtk/toolbar_star_toggle_gtk.cc
+++ b/chrome/browser/gtk/toolbar_star_toggle_gtk.cc
@@ -24,9 +24,8 @@ ToolbarStarToggleGtk::ToolbarStarToggleGtk(BrowserToolbarGtk* host)
theme_provider_(GtkThemeProvider::GetFrom(host->profile())),
unstarred_(theme_provider_, IDR_STAR, IDR_STAR_P, IDR_STAR_H, IDR_STAR_D),
starred_(theme_provider_, IDR_STARRED, IDR_STARRED_P, IDR_STARRED_H, 0) {
- gtk_widget_set_size_request(widget_.get(),
- gdk_pixbuf_get_width(unstarred_.pixbufs(0)),
- gdk_pixbuf_get_height(unstarred_.pixbufs(0)));
+ gtk_widget_set_size_request(widget_.get(), unstarred_.Width(),
+ unstarred_.Height());
gtk_widget_set_app_paintable(widget_.get(), TRUE);
// We effectively double-buffer by virtue of having only one image...
@@ -131,9 +130,8 @@ void ToolbarStarToggleGtk::UpdateGTKButton() {
gtk_widget_set_app_paintable(widget_.get(), FALSE);
gtk_widget_set_double_buffered(widget_.get(), TRUE);
} else {
- gtk_widget_set_size_request(widget_.get(),
- gdk_pixbuf_get_width(unstarred_.pixbufs(0)),
- gdk_pixbuf_get_height(unstarred_.pixbufs(0)));
+ gtk_widget_set_size_request(widget_.get(), unstarred_.Width(),
+ unstarred_.Height());
gtk_widget_set_app_paintable(widget_.get(), TRUE);
// We effectively double-buffer by virtue of having only one image...
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 8f592ac..f1298d6 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -1250,6 +1250,8 @@
'browser/gtk/browser_window_factory_gtk.cc',
'browser/gtk/browser_window_gtk.cc',
'browser/gtk/browser_window_gtk.h',
+ 'browser/gtk/cairo_cached_surface.cc',
+ 'browser/gtk/cairo_cached_surface.h',
'browser/gtk/clear_browsing_data_dialog_gtk.cc',
'browser/gtk/clear_browsing_data_dialog_gtk.h',
'browser/gtk/constrained_window_gtk.cc',