diff options
-rw-r--r-- | chrome/browser/gtk/tabs/tab_renderer_gtk.cc | 44 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_renderer_gtk.h | 3 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_strip_gtk.cc | 60 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_strip_gtk.h | 11 |
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(); |