summaryrefslogtreecommitdiffstats
path: root/chrome/browser/gtk/tabs
diff options
context:
space:
mode:
authortony@chromium.org <tony@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-27 22:20:17 +0000
committertony@chromium.org <tony@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-27 22:20:17 +0000
commit0f91a9cfbb86373de5c60ae2bd471aa02354252d (patch)
tree7242957dd54c568b467d737036a36f0d252d92c6 /chrome/browser/gtk/tabs
parent264e0e30718f768de69aa1c7429d42123a791d18 (diff)
downloadchromium_src-0f91a9cfbb86373de5c60ae2bd471aa02354252d.zip
chromium_src-0f91a9cfbb86373de5c60ae2bd471aa02354252d.tar.gz
chromium_src-0f91a9cfbb86373de5c60ae2bd471aa02354252d.tar.bz2
Add a fast path for tab strip expose.
This optimizes the common case of just needing to update favicons. If the expose area consists of just favicons, only paint the favicons (i.e., don't bother with the complex tab edges that overlap). This doesn't help when tabs are resizing or moving, but does reduce CPU usage quite a bit. BUG=15872 Review URL: http://codereview.chromium.org/179003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@24675 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/gtk/tabs')
-rw-r--r--chrome/browser/gtk/tabs/tab_renderer_gtk.cc44
-rw-r--r--chrome/browser/gtk/tabs/tab_renderer_gtk.h3
-rw-r--r--chrome/browser/gtk/tabs/tab_strip_gtk.cc60
-rw-r--r--chrome/browser/gtk/tabs/tab_strip_gtk.h11
4 files changed, 116 insertions, 2 deletions
diff --git a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc
index 3034738..f90974d 100644
--- a/chrome/browser/gtk/tabs/tab_renderer_gtk.cc
+++ b/chrome/browser/gtk/tabs/tab_renderer_gtk.cc
@@ -35,6 +35,7 @@ const int kFavIconTitleSpacing = 4;
const int kTitleCloseButtonSpacing = 5;
const int kStandardTitleWidth = 175;
const int kDropShadowOffset = 2;
+const int kInactiveTabBackgroundOffsetY = 20;
// Preferred width of pinned tabs.
const int kPinnedTabWidth = 56;
// When a non-pinned tab is pinned the width of the tab animates. If the width
@@ -333,6 +334,46 @@ bool TabRendererGtk::ValidateLoadingAnimation(AnimationState animation_state) {
return loading_animation_.ValidateLoadingAnimation(animation_state);
}
+void TabRendererGtk::PaintFavIconArea(GdkEventExpose* event) {
+ DCHECK(ShouldShowIcon());
+
+ // The paint area is the favicon bounds, but we're painting into the gdk
+ // window belonging to the tabstrip. So the coordinates are relative to the
+ // top left of the tab strip.
+ event->area.x = x() + favicon_bounds_.x();
+ event->area.y = y() + favicon_bounds_.y();
+ event->area.width = favicon_bounds_.width();
+ event->area.height = favicon_bounds_.height();
+ gfx::CanvasPaint canvas(event, false);
+
+ // The actual paint methods expect 0, 0 to be the tab top left (see
+ // PaintTab).
+ canvas.TranslateInt(x(), y());
+
+ // Paint the background behind the favicon.
+ int theme_id;
+ int offset_y = 0;
+ if (IsSelected()) {
+ theme_id = IDR_THEME_TOOLBAR;
+ } else {
+ if (!data_.off_the_record) {
+ theme_id = IDR_THEME_TAB_BACKGROUND;
+ } else {
+ theme_id = IDR_THEME_TAB_BACKGROUND_INCOGNITO;
+ }
+ if (!theme_provider_->HasCustomImage(theme_id))
+ offset_y = kInactiveTabBackgroundOffsetY;
+ }
+ SkBitmap* tab_bg = theme_provider_->GetBitmapNamed(theme_id);
+ canvas.TileImageInt(*tab_bg,
+ x() + favicon_bounds_.x(), offset_y + favicon_bounds_.y(),
+ favicon_bounds_.x(), favicon_bounds_.y(),
+ favicon_bounds_.width(), favicon_bounds_.height());
+
+ // Now paint the icon.
+ PaintIcon(&canvas);
+}
+
// static
gfx::Size TabRendererGtk::GetMinimumUnselectedSize() {
InitResources();
@@ -752,7 +793,8 @@ void TabRendererGtk::PaintInactiveTabBackground(gfx::Canvas* canvas) {
// If the theme is providing a custom background image, then its top edge
// should be at the top of the tab. Otherwise, we assume that the background
// image is a composited foreground + frame image.
- int offset_y = theme_provider_->HasCustomImage(tab_id) ? 0 : 20;
+ int offset_y = theme_provider_->HasCustomImage(tab_id) ?
+ 0 : kInactiveTabBackgroundOffsetY;
// Draw left edge.
SkBitmap* theme_l = GetMaskedBitmap(tab_alpha_.image_l, tab_bg, offset_x,
diff --git a/chrome/browser/gtk/tabs/tab_renderer_gtk.h b/chrome/browser/gtk/tabs/tab_renderer_gtk.h
index 35d13b5..ff85410 100644
--- a/chrome/browser/gtk/tabs/tab_renderer_gtk.h
+++ b/chrome/browser/gtk/tabs/tab_renderer_gtk.h
@@ -139,6 +139,9 @@ class TabRendererGtk : public AnimationDelegate {
// repainted.
bool ValidateLoadingAnimation(AnimationState animation_state);
+ // Repaint only the area of the tab that contains the favicon.
+ void PaintFavIconArea(GdkEventExpose* event);
+
// Returns the minimum possible size of a single unselected Tab.
static gfx::Size GetMinimumUnselectedSize();
// Returns the minimum possible size of a selected Tab. Selected tabs must
diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.cc b/chrome/browser/gtk/tabs/tab_strip_gtk.cc
index 8db5a3f..590aa07 100644
--- a/chrome/browser/gtk/tabs/tab_strip_gtk.cc
+++ b/chrome/browser/gtk/tabs/tab_strip_gtk.cc
@@ -71,6 +71,26 @@ gfx::Rect GetInitialWidgetBounds(GtkWidget* widget) {
return gfx::Rect(0, 0, request.width, request.height);
}
+// Sort rectangles based on their x position. We don't care about y position
+// so we don't bother breaking ties.
+int CompareGdkRectangles(const void* p1, const void* p2) {
+ int p1_x = static_cast<const GdkRectangle*>(p1)->x;
+ int p2_x = static_cast<const GdkRectangle*>(p2)->x;
+ if (p1_x < p2_x)
+ return -1;
+ else if (p1_x == p2_x)
+ return 0;
+ return 1;
+}
+
+bool GdkRectMatchesTabFavIconBounds(const GdkRectangle& gdk_rect, TabGtk* tab) {
+ gfx::Rect favicon_bounds = tab->favicon_bounds();
+ return gdk_rect.x == favicon_bounds.x() + tab->x() &&
+ gdk_rect.y == favicon_bounds.y() + tab->y() &&
+ gdk_rect.width == favicon_bounds.width() &&
+ gdk_rect.height == favicon_bounds.height();
+}
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -994,7 +1014,6 @@ void TabStripGtk::TabChangedAt(TabContents* contents, int index,
TabGtk* tab = GetTabAt(index);
tab->UpdateData(contents, loading_only);
tab->UpdateFromModel();
- gtk_widget_queue_draw(tabstrip_.get());
}
void TabStripGtk::TabPinnedStateChanged(TabContents* contents, int index) {
@@ -1760,6 +1779,20 @@ gboolean TabStripGtk::OnExpose(GtkWidget* widget, GdkEventExpose* event,
if (gdk_region_empty(event->region))
return TRUE;
+ // If we're only repainting favicons, optimize the paint path and only draw
+ // the favicons.
+ GdkRectangle* rects;
+ gint num_rects;
+ gdk_region_get_rectangles(event->region, &rects, &num_rects);
+ qsort(rects, num_rects, sizeof(GdkRectangle), CompareGdkRectangles);
+ std::vector<int> tabs_to_repaint;
+ if (tabstrip->CanPaintOnlyFavIcons(rects, num_rects, &tabs_to_repaint)) {
+ tabstrip->PaintOnlyFavIcons(event, tabs_to_repaint);
+ g_free(rects);
+ return TRUE;
+ }
+ g_free(rects);
+
// TODO(jhawkins): Ideally we'd like to only draw what's needed in the damage
// rect, but the tab widgets overlap each other, and painting on one widget
// will cause an expose-event to be sent to the widgets underneath. The
@@ -1947,6 +1980,31 @@ void TabStripGtk::SetTabBounds(TabGtk* tab, const gfx::Rect& bounds) {
bds.x(), bds.y());
}
+bool TabStripGtk::CanPaintOnlyFavIcons(const GdkRectangle* rects,
+ int num_rects, std::vector<int>* tabs_to_paint) {
+ // |rects| are sorted so we just need to scan from left to right and compare
+ // it to the tab favicon positions from left to right.
+ int t = 0;
+ for (int r = 0; r < num_rects; ++r) {
+ while (t < GetTabCount()) {
+ TabGtk* tab = GetTabAt(t);
+ if (GdkRectMatchesTabFavIconBounds(rects[r], tab)) {
+ tabs_to_paint->push_back(t);
+ ++t;
+ break;
+ }
+ ++t;
+ }
+ }
+ return static_cast<int>(tabs_to_paint->size()) == num_rects;
+}
+
+void TabStripGtk::PaintOnlyFavIcons(GdkEventExpose* event,
+ const std::vector<int>& tabs_to_paint) {
+ for (size_t i = 0; i < tabs_to_paint.size(); ++i)
+ GetTabAt(tabs_to_paint[i])->PaintFavIconArea(event);
+}
+
CustomDrawButton* TabStripGtk::MakeNewTabButton() {
CustomDrawButton* button = new CustomDrawButton(IDR_NEWTAB_BUTTON,
IDR_NEWTAB_BUTTON_P, IDR_NEWTAB_BUTTON_H, 0);
diff --git a/chrome/browser/gtk/tabs/tab_strip_gtk.h b/chrome/browser/gtk/tabs/tab_strip_gtk.h
index 5445654..6ba5793 100644
--- a/chrome/browser/gtk/tabs/tab_strip_gtk.h
+++ b/chrome/browser/gtk/tabs/tab_strip_gtk.h
@@ -251,6 +251,17 @@ class TabStripGtk : public TabStripModelObserver,
// Sets the bounds of the tab and moves the tab widget to those bounds.
void SetTabBounds(TabGtk* tab, const gfx::Rect& bounds);
+ // Returns true if |rects| are all areas that match up with tab favicons.
+ // |rects| must be sorted from left to right. |tabs_to_paint| are the tab
+ // positions that match the rects.
+ bool CanPaintOnlyFavIcons(const GdkRectangle* rects,
+ int num_rects,
+ std::vector<int>* tabs_to_paint);
+
+ // Paints the tab favicon areas for tabs in |tabs_to_paint|.
+ void PaintOnlyFavIcons(GdkEventExpose* event,
+ const std::vector<int>& tabs_to_paint);
+
// Initializes the new tab button.
CustomDrawButton* MakeNewTabButton();