summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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();