diff options
-rw-r--r-- | chrome/browser/browser_theme_provider.h | 8 | ||||
-rw-r--r-- | chrome/browser/gtk/bookmark_bar_gtk.cc | 8 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_toolbar_gtk.cc | 8 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_window_gtk.cc | 87 | ||||
-rw-r--r-- | chrome/browser/gtk/cairo_cached_surface.cc | 68 | ||||
-rw-r--r-- | chrome/browser/gtk/cairo_cached_surface.h | 57 | ||||
-rw-r--r-- | chrome/browser/gtk/custom_button.cc | 89 | ||||
-rw-r--r-- | chrome/browser/gtk/custom_button.h | 11 | ||||
-rw-r--r-- | chrome/browser/gtk/find_bar_gtk.cc | 10 | ||||
-rw-r--r-- | chrome/browser/gtk/go_button_gtk.cc | 8 | ||||
-rw-r--r-- | chrome/browser/gtk/gtk_theme_provider.cc | 33 | ||||
-rw-r--r-- | chrome/browser/gtk/gtk_theme_provider.h | 16 | ||||
-rw-r--r-- | chrome/browser/gtk/toolbar_star_toggle_gtk.cc | 10 | ||||
-rw-r--r-- | chrome/chrome.gyp | 2 |
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', |