| Index: chrome/browser/ui/gtk/tabs/tab_renderer_gtk.cc
|
| diff --git a/chrome/browser/ui/gtk/tabs/tab_renderer_gtk.cc b/chrome/browser/ui/gtk/tabs/tab_renderer_gtk.cc
|
| deleted file mode 100644
|
| index 2381ac889ea7a87172d3e246e355f20167da4a63..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/ui/gtk/tabs/tab_renderer_gtk.cc
|
| +++ /dev/null
|
| @@ -1,1206 +0,0 @@
|
| -// Copyright (c) 2012 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/ui/gtk/tabs/tab_renderer_gtk.h"
|
| -
|
| -#include <algorithm>
|
| -#include <utility>
|
| -
|
| -#include "base/debug/trace_event.h"
|
| -#include "base/strings/utf_string_conversions.h"
|
| -#include "chrome/browser/chrome_notification_types.h"
|
| -#include "chrome/browser/defaults.h"
|
| -#include "chrome/browser/extensions/tab_helper.h"
|
| -#include "chrome/browser/favicon/favicon_tab_helper.h"
|
| -#include "chrome/browser/profiles/profile.h"
|
| -#include "chrome/browser/themes/theme_properties.h"
|
| -#include "chrome/browser/ui/browser.h"
|
| -#include "chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h"
|
| -#include "chrome/browser/ui/gtk/custom_button.h"
|
| -#include "chrome/browser/ui/gtk/gtk_theme_service.h"
|
| -#include "chrome/browser/ui/gtk/gtk_util.h"
|
| -#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
|
| -#include "chrome/browser/ui/tabs/tab_utils.h"
|
| -#include "content/public/browser/notification_source.h"
|
| -#include "content/public/browser/web_contents.h"
|
| -#include "grit/generated_resources.h"
|
| -#include "grit/theme_resources.h"
|
| -#include "grit/ui_resources.h"
|
| -#include "skia/ext/image_operations.h"
|
| -#include "ui/base/gtk/gtk_screen_util.h"
|
| -#include "ui/base/l10n/l10n_util.h"
|
| -#include "ui/base/resource/resource_bundle.h"
|
| -#include "ui/gfx/animation/slide_animation.h"
|
| -#include "ui/gfx/animation/throb_animation.h"
|
| -#include "ui/gfx/canvas_skia_paint.h"
|
| -#include "ui/gfx/favicon_size.h"
|
| -#include "ui/gfx/gtk_compat.h"
|
| -#include "ui/gfx/gtk_util.h"
|
| -#include "ui/gfx/image/cairo_cached_surface.h"
|
| -#include "ui/gfx/image/image.h"
|
| -#include "ui/gfx/pango_util.h"
|
| -#include "ui/gfx/platform_font_pango.h"
|
| -#include "ui/gfx/skbitmap_operations.h"
|
| -
|
| -using content::WebContents;
|
| -
|
| -namespace {
|
| -
|
| -const int kFontPixelSize = 12;
|
| -const int kLeftPadding = 16;
|
| -const int kTopPadding = 6;
|
| -const int kRightPadding = 15;
|
| -const int kBottomPadding = 5;
|
| -const int kFaviconTitleSpacing = 4;
|
| -const int kTitleCloseButtonSpacing = 5;
|
| -const int kStandardTitleWidth = 175;
|
| -const int kDropShadowOffset = 2;
|
| -const int kInactiveTabBackgroundOffsetY = 15;
|
| -
|
| -// When a non-mini-tab becomes a mini-tab the width of the tab animates. If
|
| -// the width of a mini-tab is >= kMiniTabRendererAsNormalTabWidth then the tab
|
| -// is rendered as a normal tab. This is done to avoid having the title
|
| -// immediately disappear when transitioning a tab from normal to mini-tab.
|
| -const int kMiniTabRendererAsNormalTabWidth =
|
| - browser_defaults::kMiniTabWidth + 30;
|
| -
|
| -// The tab images are designed to overlap the toolbar by 1 pixel. For now we
|
| -// don't actually overlap the toolbar, so this is used to know how many pixels
|
| -// at the bottom of the tab images are to be ignored.
|
| -const int kToolbarOverlap = 1;
|
| -
|
| -// How long the hover state takes.
|
| -const int kHoverDurationMs = 90;
|
| -
|
| -// How opaque to make the hover state (out of 1).
|
| -const double kHoverOpacity = 0.33;
|
| -
|
| -// Opacity for non-active selected tabs.
|
| -const double kSelectedTabOpacity = 0.45;
|
| -
|
| -// Selected (but not active) tabs have their throb value scaled down by this.
|
| -const double kSelectedTabThrobScale = 0.5;
|
| -
|
| -// Max opacity for the mini-tab title change animation.
|
| -const double kMiniTitleChangeThrobOpacity = 0.75;
|
| -
|
| -// Duration for when the title of an inactive mini-tab changes.
|
| -const int kMiniTitleChangeThrobDuration = 1000;
|
| -
|
| -// The horizontal offset used to position the close button in the tab.
|
| -const int kCloseButtonHorzFuzz = 4;
|
| -
|
| -// Gets the bounds of |widget| relative to |parent|.
|
| -gfx::Rect GetWidgetBoundsRelativeToParent(GtkWidget* parent,
|
| - GtkWidget* widget) {
|
| - gfx::Rect bounds = ui::GetWidgetScreenBounds(widget);
|
| - bounds.Offset(-ui::GetWidgetScreenOffset(parent));
|
| - return bounds;
|
| -}
|
| -
|
| -// Returns a GdkPixbuf after resizing the SkBitmap as necessary to the
|
| -// specified desired width and height. Caller must g_object_unref the returned
|
| -// pixbuf when no longer used.
|
| -GdkPixbuf* GetResizedGdkPixbufFromSkBitmap(const SkBitmap& bitmap,
|
| - int dest_w,
|
| - int dest_h) {
|
| - float float_dest_w = static_cast<float>(dest_w);
|
| - float float_dest_h = static_cast<float>(dest_h);
|
| - int bitmap_w = bitmap.width();
|
| - int bitmap_h = bitmap.height();
|
| -
|
| - // Scale proportionately.
|
| - float scale = std::min(float_dest_w / bitmap_w,
|
| - float_dest_h / bitmap_h);
|
| - int final_dest_w = static_cast<int>(bitmap_w * scale);
|
| - int final_dest_h = static_cast<int>(bitmap_h * scale);
|
| -
|
| - GdkPixbuf* pixbuf;
|
| - if (final_dest_w == bitmap_w && final_dest_h == bitmap_h) {
|
| - pixbuf = gfx::GdkPixbufFromSkBitmap(bitmap);
|
| - } else {
|
| - SkBitmap resized_icon = skia::ImageOperations::Resize(
|
| - bitmap,
|
| - skia::ImageOperations::RESIZE_BETTER,
|
| - final_dest_w, final_dest_h);
|
| - pixbuf = gfx::GdkPixbufFromSkBitmap(resized_icon);
|
| - }
|
| - return pixbuf;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -TabRendererGtk::LoadingAnimation::Data::Data(
|
| - GtkThemeService* theme_service) {
|
| - // The loading animation image is a strip of states. Each state must be
|
| - // square, so the height must divide the width evenly.
|
| - SkBitmap loading_animation_frames =
|
| - theme_service->GetImageNamed(IDR_THROBBER).AsBitmap();
|
| - DCHECK(!loading_animation_frames.isNull());
|
| - DCHECK_EQ(loading_animation_frames.width() %
|
| - loading_animation_frames.height(), 0);
|
| - loading_animation_frame_count =
|
| - loading_animation_frames.width() /
|
| - loading_animation_frames.height();
|
| -
|
| - SkBitmap waiting_animation_frames =
|
| - theme_service->GetImageNamed(IDR_THROBBER_WAITING).AsBitmap();
|
| - DCHECK(!waiting_animation_frames.isNull());
|
| - DCHECK_EQ(waiting_animation_frames.width() %
|
| - waiting_animation_frames.height(), 0);
|
| - waiting_animation_frame_count =
|
| - waiting_animation_frames.width() /
|
| - waiting_animation_frames.height();
|
| -
|
| - waiting_to_loading_frame_count_ratio =
|
| - waiting_animation_frame_count /
|
| - loading_animation_frame_count;
|
| - // TODO(beng): eventually remove this when we have a proper themeing system.
|
| - // themes not supporting IDR_THROBBER_WAITING are causing this
|
| - // value to be 0 which causes DIV0 crashes. The value of 5
|
| - // matches the current bitmaps in our source.
|
| - if (waiting_to_loading_frame_count_ratio == 0)
|
| - waiting_to_loading_frame_count_ratio = 5;
|
| -}
|
| -
|
| -TabRendererGtk::LoadingAnimation::Data::Data(
|
| - int loading, int waiting, int waiting_to_loading)
|
| - : loading_animation_frame_count(loading),
|
| - waiting_animation_frame_count(waiting),
|
| - waiting_to_loading_frame_count_ratio(waiting_to_loading) {
|
| -}
|
| -
|
| -bool TabRendererGtk::initialized_ = false;
|
| -int TabRendererGtk::tab_active_l_width_ = 0;
|
| -int TabRendererGtk::tab_active_l_height_ = 0;
|
| -int TabRendererGtk::tab_inactive_l_height_ = 0;
|
| -gfx::Font* TabRendererGtk::title_font_ = NULL;
|
| -int TabRendererGtk::title_font_height_ = 0;
|
| -int TabRendererGtk::close_button_width_ = 0;
|
| -int TabRendererGtk::close_button_height_ = 0;
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// TabRendererGtk::LoadingAnimation, public:
|
| -//
|
| -TabRendererGtk::LoadingAnimation::LoadingAnimation(
|
| - GtkThemeService* theme_service)
|
| - : data_(new Data(theme_service)),
|
| - theme_service_(theme_service),
|
| - animation_state_(ANIMATION_NONE),
|
| - animation_frame_(0) {
|
| - registrar_.Add(this,
|
| - chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
|
| - content::Source<ThemeService>(theme_service_));
|
| -}
|
| -
|
| -TabRendererGtk::LoadingAnimation::LoadingAnimation(
|
| - const LoadingAnimation::Data& data)
|
| - : data_(new Data(data)),
|
| - theme_service_(NULL),
|
| - animation_state_(ANIMATION_NONE),
|
| - animation_frame_(0) {
|
| -}
|
| -
|
| -TabRendererGtk::LoadingAnimation::~LoadingAnimation() {}
|
| -
|
| -bool TabRendererGtk::LoadingAnimation::ValidateLoadingAnimation(
|
| - AnimationState animation_state) {
|
| - bool has_changed = false;
|
| - if (animation_state_ != animation_state) {
|
| - // The waiting animation is the reverse of the loading animation, but at a
|
| - // different rate - the following reverses and scales the animation_frame_
|
| - // so that the frame is at an equivalent position when going from one
|
| - // animation to the other.
|
| - if (animation_state_ == ANIMATION_WAITING &&
|
| - animation_state == ANIMATION_LOADING) {
|
| - animation_frame_ = data_->loading_animation_frame_count -
|
| - (animation_frame_ / data_->waiting_to_loading_frame_count_ratio);
|
| - }
|
| - animation_state_ = animation_state;
|
| - has_changed = true;
|
| - }
|
| -
|
| - if (animation_state_ != ANIMATION_NONE) {
|
| - animation_frame_ = (animation_frame_ + 1) %
|
| - ((animation_state_ == ANIMATION_WAITING) ?
|
| - data_->waiting_animation_frame_count :
|
| - data_->loading_animation_frame_count);
|
| - has_changed = true;
|
| - } else {
|
| - animation_frame_ = 0;
|
| - }
|
| - return has_changed;
|
| -}
|
| -
|
| -void TabRendererGtk::LoadingAnimation::Observe(
|
| - int type,
|
| - const content::NotificationSource& source,
|
| - const content::NotificationDetails& details) {
|
| - DCHECK(type == chrome::NOTIFICATION_BROWSER_THEME_CHANGED);
|
| - data_.reset(new Data(theme_service_));
|
| -}
|
| -
|
| -TabRendererGtk::TabData::TabData()
|
| - : is_default_favicon(false),
|
| - loading(false),
|
| - crashed(false),
|
| - incognito(false),
|
| - show_icon(true),
|
| - mini(false),
|
| - blocked(false),
|
| - animating_mini_change(false),
|
| - app(false),
|
| - media_state(TAB_MEDIA_STATE_NONE),
|
| - previous_media_state(TAB_MEDIA_STATE_NONE) {
|
| -}
|
| -
|
| -TabRendererGtk::TabData::~TabData() {}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// FaviconCrashAnimation
|
| -//
|
| -// A custom animation subclass to manage the favicon crash animation.
|
| -class TabRendererGtk::FaviconCrashAnimation : public gfx::LinearAnimation,
|
| - public gfx::AnimationDelegate {
|
| - public:
|
| - explicit FaviconCrashAnimation(TabRendererGtk* target)
|
| - : gfx::LinearAnimation(1000, 25, this),
|
| - target_(target) {
|
| - }
|
| - virtual ~FaviconCrashAnimation() {}
|
| -
|
| - // gfx::Animation overrides:
|
| - virtual void AnimateToState(double state) OVERRIDE {
|
| - const double kHidingOffset = 27;
|
| -
|
| - if (state < .5) {
|
| - target_->SetFaviconHidingOffset(
|
| - static_cast<int>(floor(kHidingOffset * 2.0 * state)));
|
| - } else {
|
| - target_->DisplayCrashedFavicon();
|
| - target_->SetFaviconHidingOffset(
|
| - static_cast<int>(
|
| - floor(kHidingOffset - ((state - .5) * 2.0 * kHidingOffset))));
|
| - }
|
| - }
|
| -
|
| - // gfx::AnimationDelegate overrides:
|
| - virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE {
|
| - target_->SetFaviconHidingOffset(0);
|
| - }
|
| -
|
| - private:
|
| - TabRendererGtk* target_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(FaviconCrashAnimation);
|
| -};
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// TabRendererGtk, public:
|
| -
|
| -TabRendererGtk::TabRendererGtk(GtkThemeService* theme_service)
|
| - : showing_icon_(false),
|
| - showing_media_indicator_(false),
|
| - showing_close_button_(false),
|
| - favicon_hiding_offset_(0),
|
| - should_display_crashed_favicon_(false),
|
| - animating_media_state_(TAB_MEDIA_STATE_NONE),
|
| - loading_animation_(theme_service),
|
| - background_offset_x_(0),
|
| - background_offset_y_(kInactiveTabBackgroundOffsetY),
|
| - theme_service_(theme_service),
|
| - close_button_color_(0),
|
| - is_active_(false),
|
| - selected_title_color_(SK_ColorBLACK),
|
| - unselected_title_color_(SkColorSetRGB(64, 64, 64)) {
|
| - InitResources();
|
| -
|
| - theme_service_->InitThemesFor(this);
|
| - registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
|
| - content::Source<ThemeService>(theme_service_));
|
| -
|
| - tab_.Own(gtk_fixed_new());
|
| - gtk_widget_set_app_paintable(tab_.get(), TRUE);
|
| - g_signal_connect(tab_.get(), "expose-event",
|
| - G_CALLBACK(OnExposeEventThunk), this);
|
| - g_signal_connect(tab_.get(), "size-allocate",
|
| - G_CALLBACK(OnSizeAllocateThunk), this);
|
| - close_button_.reset(MakeCloseButton());
|
| - gtk_widget_show(tab_.get());
|
| -
|
| - hover_animation_.reset(new gfx::SlideAnimation(this));
|
| - hover_animation_->SetSlideDuration(kHoverDurationMs);
|
| -}
|
| -
|
| -TabRendererGtk::~TabRendererGtk() {
|
| - tab_.Destroy();
|
| -}
|
| -
|
| -void TabRendererGtk::Observe(int type,
|
| - const content::NotificationSource& source,
|
| - const content::NotificationDetails& details) {
|
| - DCHECK(chrome::NOTIFICATION_BROWSER_THEME_CHANGED);
|
| - selected_title_color_ =
|
| - theme_service_->GetColor(ThemeProperties::COLOR_TAB_TEXT);
|
| - unselected_title_color_ =
|
| - theme_service_->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB_TEXT);
|
| -}
|
| -
|
| -void TabRendererGtk::UpdateData(WebContents* contents,
|
| - bool app,
|
| - bool loading_only) {
|
| - DCHECK(contents);
|
| - FaviconTabHelper* favicon_tab_helper =
|
| - FaviconTabHelper::FromWebContents(contents);
|
| -
|
| - if (!loading_only) {
|
| - data_.title = contents->GetTitle();
|
| - data_.incognito = contents->GetBrowserContext()->IsOffTheRecord();
|
| -
|
| - TabMediaState next_media_state;
|
| - if (contents->IsCrashed()) {
|
| - data_.crashed = true;
|
| - next_media_state = TAB_MEDIA_STATE_NONE;
|
| - } else {
|
| - data_.crashed = false;
|
| - next_media_state = chrome::GetTabMediaStateForContents(contents);
|
| - }
|
| - if (data_.media_state != next_media_state) {
|
| - data_.previous_media_state = data_.media_state;
|
| - data_.media_state = next_media_state;
|
| - }
|
| -
|
| - data_.favicon = favicon_tab_helper->GetFavicon().AsBitmap();
|
| - data_.app = app;
|
| -
|
| - // Make a cairo cached version of the favicon.
|
| - if (!data_.favicon.isNull()) {
|
| - // Instead of resizing the icon during each frame, create our resized
|
| - // icon resource now, send it to the xserver and use that each frame
|
| - // instead.
|
| -
|
| - // For source images smaller than the favicon square, scale them as if
|
| - // they were padded to fit the favicon square, so we don't blow up tiny
|
| - // favicons into larger or nonproportional results.
|
| - GdkPixbuf* pixbuf = GetResizedGdkPixbufFromSkBitmap(data_.favicon,
|
| - gfx::kFaviconSize, gfx::kFaviconSize);
|
| - data_.cairo_favicon.UsePixbuf(pixbuf);
|
| - g_object_unref(pixbuf);
|
| - } else {
|
| - data_.cairo_favicon.Reset();
|
| - }
|
| -
|
| - // This is kind of a hacky way to determine whether our icon is the default
|
| - // favicon. But the plumbing that would be necessary to do it right would
|
| - // be a good bit of work and would sully code for other platforms which
|
| - // don't care to custom-theme the favicon. Hopefully the default favicon
|
| - // will eventually be chromium-themable and this code will go away.
|
| - data_.is_default_favicon =
|
| - (data_.favicon.pixelRef() ==
|
| - ui::ResourceBundle::GetSharedInstance().GetImageNamed(
|
| - IDR_DEFAULT_FAVICON).AsBitmap().pixelRef());
|
| - }
|
| -
|
| - // Loading state also involves whether we show the favicon, since that's where
|
| - // we display the throbber.
|
| - data_.loading = contents->IsLoading();
|
| - data_.show_icon = favicon_tab_helper->ShouldDisplayFavicon();
|
| -}
|
| -
|
| -void TabRendererGtk::UpdateFromModel() {
|
| - // Force a layout, since the tab may have grown a favicon.
|
| - Layout();
|
| - SchedulePaint();
|
| -
|
| - if (data_.crashed) {
|
| - if (!should_display_crashed_favicon_ && !IsPerformingCrashAnimation())
|
| - StartCrashAnimation();
|
| - } else {
|
| - if (IsPerformingCrashAnimation())
|
| - StopCrashAnimation();
|
| - ResetCrashedFavicon();
|
| - }
|
| -
|
| - if (data_.media_state != data_.previous_media_state) {
|
| - data_.previous_media_state = data_.media_state;
|
| - if (data_.media_state != TAB_MEDIA_STATE_NONE)
|
| - animating_media_state_ = data_.media_state;
|
| - StartMediaIndicatorAnimation();
|
| - }
|
| -}
|
| -
|
| -void TabRendererGtk::SetBlocked(bool blocked) {
|
| - if (data_.blocked == blocked)
|
| - return;
|
| - data_.blocked = blocked;
|
| - // TODO(zelidrag) bug 32399: Make tabs pulse on Linux as well.
|
| -}
|
| -
|
| -bool TabRendererGtk::is_blocked() const {
|
| - return data_.blocked;
|
| -}
|
| -
|
| -bool TabRendererGtk::IsActive() const {
|
| - return is_active_;
|
| -}
|
| -
|
| -bool TabRendererGtk::IsSelected() const {
|
| - return true;
|
| -}
|
| -
|
| -bool TabRendererGtk::IsVisible() const {
|
| - return gtk_widget_get_visible(tab_.get());
|
| -}
|
| -
|
| -void TabRendererGtk::SetVisible(bool visible) const {
|
| - if (visible) {
|
| - gtk_widget_show(tab_.get());
|
| - if (data_.mini)
|
| - gtk_widget_show(close_button_->widget());
|
| - } else {
|
| - gtk_widget_hide_all(tab_.get());
|
| - }
|
| -}
|
| -
|
| -bool TabRendererGtk::ValidateLoadingAnimation(AnimationState animation_state) {
|
| - return loading_animation_.ValidateLoadingAnimation(animation_state);
|
| -}
|
| -
|
| -void TabRendererGtk::PaintFaviconArea(GtkWidget* widget, cairo_t* cr) {
|
| - DCHECK(ShouldShowIcon());
|
| -
|
| - cairo_rectangle(cr,
|
| - x() + favicon_bounds_.x(),
|
| - y() + favicon_bounds_.y(),
|
| - favicon_bounds_.width(),
|
| - favicon_bounds_.height());
|
| - cairo_clip(cr);
|
| -
|
| - // The tab is rendered into a windowless widget whose offset is at the
|
| - // coordinate event->area. Translate by these offsets so we can render at
|
| - // (0,0) to match Windows' rendering metrics.
|
| - cairo_matrix_t cairo_matrix;
|
| - cairo_matrix_init_translate(&cairo_matrix, x(), y());
|
| - cairo_set_matrix(cr, &cairo_matrix);
|
| -
|
| - // Which background should we be painting?
|
| - int theme_id;
|
| - int offset_y = 0;
|
| - if (IsActive()) {
|
| - theme_id = IDR_THEME_TOOLBAR;
|
| - } else {
|
| - theme_id = data_.incognito ? IDR_THEME_TAB_BACKGROUND_INCOGNITO :
|
| - IDR_THEME_TAB_BACKGROUND;
|
| -
|
| - if (!theme_service_->HasCustomImage(theme_id))
|
| - offset_y = background_offset_y_;
|
| - }
|
| -
|
| - // Paint the background behind the favicon.
|
| - const gfx::Image tab_bg = theme_service_->GetImageNamed(theme_id);
|
| - tab_bg.ToCairo()->SetSource(cr, widget, -x(), -offset_y);
|
| - cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
|
| - cairo_rectangle(cr,
|
| - favicon_bounds_.x(), favicon_bounds_.y(),
|
| - favicon_bounds_.width(), favicon_bounds_.height());
|
| - cairo_fill(cr);
|
| -
|
| - if (!IsActive()) {
|
| - double throb_value = GetThrobValue();
|
| - if (throb_value > 0) {
|
| - cairo_push_group(cr);
|
| - gfx::Image active_bg =
|
| - theme_service_->GetImageNamed(IDR_THEME_TOOLBAR);
|
| - active_bg.ToCairo()->SetSource(cr, widget, -x(), 0);
|
| - cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
|
| -
|
| - cairo_rectangle(cr,
|
| - favicon_bounds_.x(), favicon_bounds_.y(),
|
| - favicon_bounds_.width(), favicon_bounds_.height());
|
| - cairo_fill(cr);
|
| -
|
| - cairo_pop_group_to_source(cr);
|
| - cairo_paint_with_alpha(cr, throb_value);
|
| - }
|
| - }
|
| -
|
| - PaintIcon(widget, cr);
|
| -}
|
| -
|
| -void TabRendererGtk::MaybeAdjustLeftForMiniTab(gfx::Rect* icon_bounds) const {
|
| - if (!(mini() || data_.animating_mini_change) ||
|
| - bounds_.width() >= kMiniTabRendererAsNormalTabWidth)
|
| - return;
|
| - const int mini_delta = kMiniTabRendererAsNormalTabWidth - GetMiniWidth();
|
| - const int ideal_delta = bounds_.width() - GetMiniWidth();
|
| - const int ideal_x = (GetMiniWidth() - icon_bounds->width()) / 2;
|
| - icon_bounds->set_x(icon_bounds->x() + static_cast<int>(
|
| - (1 - static_cast<float>(ideal_delta) / static_cast<float>(mini_delta)) *
|
| - (ideal_x - icon_bounds->x())));
|
| -}
|
| -
|
| -// static
|
| -gfx::Size TabRendererGtk::GetMinimumUnselectedSize() {
|
| - InitResources();
|
| -
|
| - gfx::Size minimum_size;
|
| - minimum_size.set_width(kLeftPadding + kRightPadding);
|
| - // Since we use bitmap images, the real minimum height of the image is
|
| - // defined most accurately by the height of the end cap images.
|
| - minimum_size.set_height(tab_active_l_height_ - kToolbarOverlap);
|
| - return minimum_size;
|
| -}
|
| -
|
| -// static
|
| -gfx::Size TabRendererGtk::GetMinimumSelectedSize() {
|
| - gfx::Size minimum_size = GetMinimumUnselectedSize();
|
| - minimum_size.set_width(kLeftPadding + gfx::kFaviconSize + kRightPadding);
|
| - return minimum_size;
|
| -}
|
| -
|
| -// static
|
| -gfx::Size TabRendererGtk::GetStandardSize() {
|
| - gfx::Size standard_size = GetMinimumUnselectedSize();
|
| - standard_size.Enlarge(kFaviconTitleSpacing + kStandardTitleWidth, 0);
|
| - return standard_size;
|
| -}
|
| -
|
| -// static
|
| -int TabRendererGtk::GetMiniWidth() {
|
| - return browser_defaults::kMiniTabWidth;
|
| -}
|
| -
|
| -// static
|
| -int TabRendererGtk::GetContentHeight() {
|
| - // The height of the content of the Tab is the largest of the favicon,
|
| - // the title text and the close button graphic.
|
| - int content_height = std::max(gfx::kFaviconSize, title_font_height_);
|
| - return std::max(content_height, close_button_height_);
|
| -}
|
| -
|
| -gfx::Rect TabRendererGtk::GetNonMirroredBounds(GtkWidget* parent) const {
|
| - // The tabstrip widget is a windowless widget so the tab widget's allocation
|
| - // is relative to the browser titlebar. We need the bounds relative to the
|
| - // tabstrip.
|
| - gfx::Rect bounds = GetWidgetBoundsRelativeToParent(parent, widget());
|
| - bounds.set_x(gtk_util::MirroredLeftPointForRect(parent, bounds));
|
| - return bounds;
|
| -}
|
| -
|
| -gfx::Rect TabRendererGtk::GetRequisition() const {
|
| - return gfx::Rect(requisition_.x(), requisition_.y(),
|
| - requisition_.width(), requisition_.height());
|
| -}
|
| -
|
| -void TabRendererGtk::StartMiniTabTitleAnimation() {
|
| - if (!mini_title_animation_.get()) {
|
| - mini_title_animation_.reset(new gfx::ThrobAnimation(this));
|
| - mini_title_animation_->SetThrobDuration(kMiniTitleChangeThrobDuration);
|
| - }
|
| -
|
| - if (!mini_title_animation_->is_animating())
|
| - mini_title_animation_->StartThrobbing(-1);
|
| -}
|
| -
|
| -void TabRendererGtk::StopMiniTabTitleAnimation() {
|
| - if (mini_title_animation_.get())
|
| - mini_title_animation_->Stop();
|
| -}
|
| -
|
| -void TabRendererGtk::SetBounds(const gfx::Rect& bounds) {
|
| - requisition_ = bounds;
|
| - gtk_widget_set_size_request(tab_.get(), bounds.width(), bounds.height());
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// TabRendererGtk, protected:
|
| -
|
| -void TabRendererGtk::Raise() const {
|
| - if (gtk_button_get_event_window(GTK_BUTTON(close_button_->widget())))
|
| - gdk_window_raise(gtk_button_get_event_window(
|
| - GTK_BUTTON(close_button_->widget())));
|
| -}
|
| -
|
| -base::string16 TabRendererGtk::GetTitle() const {
|
| - return data_.title;
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -// TabRendererGtk, gfx::AnimationDelegate implementation:
|
| -
|
| -void TabRendererGtk::AnimationProgressed(const gfx::Animation* animation) {
|
| - gtk_widget_queue_draw(tab_.get());
|
| -}
|
| -
|
| -void TabRendererGtk::AnimationCanceled(const gfx::Animation* animation) {
|
| - if (media_indicator_animation_ == animation)
|
| - animating_media_state_ = data_.media_state;
|
| - AnimationEnded(animation);
|
| -}
|
| -
|
| -void TabRendererGtk::AnimationEnded(const gfx::Animation* animation) {
|
| - if (media_indicator_animation_ == animation)
|
| - animating_media_state_ = data_.media_state;
|
| - gtk_widget_queue_draw(tab_.get());
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// TabRendererGtk, private:
|
| -
|
| -void TabRendererGtk::StartCrashAnimation() {
|
| - if (!crash_animation_.get())
|
| - crash_animation_.reset(new FaviconCrashAnimation(this));
|
| - crash_animation_->Stop();
|
| - crash_animation_->Start();
|
| -}
|
| -
|
| -void TabRendererGtk::StopCrashAnimation() {
|
| - if (!crash_animation_.get())
|
| - return;
|
| - crash_animation_->Stop();
|
| -}
|
| -
|
| -bool TabRendererGtk::IsPerformingCrashAnimation() const {
|
| - return crash_animation_.get() && crash_animation_->is_animating();
|
| -}
|
| -
|
| -void TabRendererGtk::StartMediaIndicatorAnimation() {
|
| - media_indicator_animation_ =
|
| - chrome::CreateTabMediaIndicatorFadeAnimation(data_.media_state);
|
| - media_indicator_animation_->set_delegate(this);
|
| - media_indicator_animation_->Start();
|
| -}
|
| -
|
| -void TabRendererGtk::SetFaviconHidingOffset(int offset) {
|
| - favicon_hiding_offset_ = offset;
|
| - SchedulePaint();
|
| -}
|
| -
|
| -void TabRendererGtk::DisplayCrashedFavicon() {
|
| - should_display_crashed_favicon_ = true;
|
| -}
|
| -
|
| -void TabRendererGtk::ResetCrashedFavicon() {
|
| - should_display_crashed_favicon_ = false;
|
| -}
|
| -
|
| -void TabRendererGtk::Paint(GtkWidget* widget, cairo_t* cr) {
|
| - // Don't paint if we're narrower than we can render correctly. (This should
|
| - // only happen during animations).
|
| - if (width() < GetMinimumUnselectedSize().width() && !mini())
|
| - return;
|
| -
|
| - // See if the model changes whether the icons should be painted.
|
| - const bool show_icon = ShouldShowIcon();
|
| - const bool show_media_indicator = ShouldShowMediaIndicator();
|
| - const bool show_close_button = ShouldShowCloseBox();
|
| - if (show_icon != showing_icon_ ||
|
| - show_media_indicator != showing_media_indicator_ ||
|
| - show_close_button != showing_close_button_)
|
| - Layout();
|
| -
|
| - PaintTabBackground(widget, cr);
|
| -
|
| - if (!mini() || width() > kMiniTabRendererAsNormalTabWidth)
|
| - PaintTitle(widget, cr);
|
| -
|
| - if (show_icon)
|
| - PaintIcon(widget, cr);
|
| -
|
| - if (show_media_indicator)
|
| - PaintMediaIndicator(widget, cr);
|
| -}
|
| -
|
| -cairo_surface_t* TabRendererGtk::PaintToSurface(GtkWidget* widget,
|
| - cairo_t* cr) {
|
| - cairo_surface_t* target = cairo_get_target(cr);
|
| - cairo_surface_t* out_surface = cairo_surface_create_similar(
|
| - target,
|
| - CAIRO_CONTENT_COLOR_ALPHA,
|
| - width(), height());
|
| -
|
| - cairo_t* out_cr = cairo_create(out_surface);
|
| - Paint(widget, out_cr);
|
| - cairo_destroy(out_cr);
|
| -
|
| - return out_surface;
|
| -}
|
| -
|
| -void TabRendererGtk::SchedulePaint() {
|
| - gtk_widget_queue_draw(tab_.get());
|
| -}
|
| -
|
| -gfx::Rect TabRendererGtk::GetLocalBounds() {
|
| - return gfx::Rect(0, 0, bounds_.width(), bounds_.height());
|
| -}
|
| -
|
| -void TabRendererGtk::Layout() {
|
| - gfx::Rect local_bounds = GetLocalBounds();
|
| - if (local_bounds.IsEmpty())
|
| - return;
|
| - local_bounds.Inset(kLeftPadding, kTopPadding, kRightPadding, kBottomPadding);
|
| -
|
| - // Figure out who is tallest.
|
| - int content_height = GetContentHeight();
|
| -
|
| - // Size the Favicon.
|
| - showing_icon_ = ShouldShowIcon();
|
| - if (showing_icon_) {
|
| - int favicon_top = kTopPadding + (content_height - gfx::kFaviconSize) / 2;
|
| - favicon_bounds_.SetRect(local_bounds.x(), favicon_top,
|
| - gfx::kFaviconSize, gfx::kFaviconSize);
|
| - MaybeAdjustLeftForMiniTab(&favicon_bounds_);
|
| - } else {
|
| - favicon_bounds_.SetRect(local_bounds.x(), local_bounds.y(), 0, 0);
|
| - }
|
| -
|
| - // Size the Close button.
|
| - showing_close_button_ = ShouldShowCloseBox();
|
| - if (showing_close_button_) {
|
| - int close_button_top = kTopPadding +
|
| - (content_height - close_button_height_) / 2;
|
| - int close_button_left =
|
| - local_bounds.right() - close_button_width_ + kCloseButtonHorzFuzz;
|
| - close_button_bounds_.SetRect(close_button_left,
|
| - close_button_top,
|
| - close_button_width_,
|
| - close_button_height_);
|
| -
|
| - // If the close button color has changed, generate a new one.
|
| - if (theme_service_) {
|
| - SkColor tab_text_color =
|
| - theme_service_->GetColor(ThemeProperties::COLOR_TAB_TEXT);
|
| - if (!close_button_color_ || tab_text_color != close_button_color_) {
|
| - close_button_color_ = tab_text_color;
|
| - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
|
| - close_button_->SetBackground(close_button_color_,
|
| - rb.GetImageNamed(IDR_CLOSE_1).AsBitmap(),
|
| - rb.GetImageNamed(IDR_CLOSE_1_MASK).AsBitmap());
|
| - }
|
| - }
|
| - } else {
|
| - close_button_bounds_.SetRect(0, 0, 0, 0);
|
| - }
|
| -
|
| - showing_media_indicator_ = ShouldShowMediaIndicator();
|
| - if (showing_media_indicator_) {
|
| - const gfx::Image& media_indicator_image =
|
| - chrome::GetTabMediaIndicatorImage(animating_media_state_);
|
| - media_indicator_bounds_.set_width(media_indicator_image.Width());
|
| - media_indicator_bounds_.set_height(media_indicator_image.Height());
|
| - media_indicator_bounds_.set_y(
|
| - kTopPadding + (content_height - media_indicator_bounds_.height()) / 2);
|
| - const int right = showing_close_button_ ?
|
| - close_button_bounds_.x() : local_bounds.right();
|
| - media_indicator_bounds_.set_x(std::max(
|
| - local_bounds.x(), right - media_indicator_bounds_.width()));
|
| - MaybeAdjustLeftForMiniTab(&media_indicator_bounds_);
|
| - } else {
|
| - media_indicator_bounds_.SetRect(local_bounds.x(), local_bounds.y(), 0, 0);
|
| - }
|
| -
|
| - if (!mini() || width() >= kMiniTabRendererAsNormalTabWidth) {
|
| - // Size the Title text to fill the remaining space.
|
| - int title_left = favicon_bounds_.right() + kFaviconTitleSpacing;
|
| - int title_top = kTopPadding;
|
| -
|
| - // If the user has big fonts, the title will appear rendered too far down
|
| - // on the y-axis if we use the regular top padding, so we need to adjust it
|
| - // so that the text appears centered.
|
| - gfx::Size minimum_size = GetMinimumUnselectedSize();
|
| - int text_height = title_top + title_font_height_ + kBottomPadding;
|
| - if (text_height > minimum_size.height())
|
| - title_top -= (text_height - minimum_size.height()) / 2;
|
| -
|
| - int title_width;
|
| - if (showing_media_indicator_) {
|
| - title_width = media_indicator_bounds_.x() - kTitleCloseButtonSpacing -
|
| - title_left;
|
| - } else if (close_button_bounds_.width() && close_button_bounds_.height()) {
|
| - title_width = close_button_bounds_.x() - kTitleCloseButtonSpacing -
|
| - title_left;
|
| - } else {
|
| - title_width = local_bounds.width() - title_left;
|
| - }
|
| - title_width = std::max(title_width, 0);
|
| - title_bounds_.SetRect(title_left, title_top, title_width, content_height);
|
| - }
|
| -
|
| - favicon_bounds_.set_x(
|
| - gtk_util::MirroredLeftPointForRect(tab_.get(), favicon_bounds_));
|
| - media_indicator_bounds_.set_x(
|
| - gtk_util::MirroredLeftPointForRect(tab_.get(), media_indicator_bounds_));
|
| - close_button_bounds_.set_x(
|
| - gtk_util::MirroredLeftPointForRect(tab_.get(), close_button_bounds_));
|
| - title_bounds_.set_x(
|
| - gtk_util::MirroredLeftPointForRect(tab_.get(), title_bounds_));
|
| -
|
| - MoveCloseButtonWidget();
|
| -}
|
| -
|
| -void TabRendererGtk::MoveCloseButtonWidget() {
|
| - if (!close_button_bounds_.IsEmpty()) {
|
| - gtk_fixed_move(GTK_FIXED(tab_.get()), close_button_->widget(),
|
| - close_button_bounds_.x(), close_button_bounds_.y());
|
| - gtk_widget_show(close_button_->widget());
|
| - } else {
|
| - gtk_widget_hide(close_button_->widget());
|
| - }
|
| -}
|
| -
|
| -void TabRendererGtk::PaintTab(GtkWidget* widget, GdkEventExpose* event) {
|
| - cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(widget));
|
| - gdk_cairo_rectangle(cr, &event->area);
|
| - cairo_clip(cr);
|
| -
|
| - // The tab is rendered into a windowless widget whose offset is at the
|
| - // coordinate event->area. Translate by these offsets so we can render at
|
| - // (0,0) to match Windows' rendering metrics.
|
| - cairo_matrix_t cairo_matrix;
|
| - cairo_matrix_init_translate(&cairo_matrix, event->area.x, event->area.y);
|
| - cairo_set_matrix(cr, &cairo_matrix);
|
| -
|
| - // Save the original x offset so we can position background images properly.
|
| - background_offset_x_ = event->area.x;
|
| -
|
| - Paint(widget, cr);
|
| - cairo_destroy(cr);
|
| -}
|
| -
|
| -void TabRendererGtk::PaintTitle(GtkWidget* widget, cairo_t* cr) {
|
| - if (title_bounds_.IsEmpty())
|
| - return;
|
| -
|
| - // Paint the Title.
|
| - base::string16 title = data_.title;
|
| - if (title.empty()) {
|
| - title = data_.loading ?
|
| - l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE) :
|
| - CoreTabHelper::GetDefaultTitle();
|
| - } else {
|
| - Browser::FormatTitleForDisplay(&title);
|
| - }
|
| -
|
| - GtkAllocation allocation;
|
| - gtk_widget_get_allocation(widget, &allocation);
|
| - gfx::Rect bounds(allocation);
|
| -
|
| - // Draw the text directly onto the Cairo context. This is necessary for
|
| - // getting the draw order correct, and automatically applying transformations
|
| - // such as scaling when a tab is detached.
|
| - gfx::CanvasSkiaPaintCairo canvas(cr, bounds.size(), true);
|
| -
|
| - SkColor title_color = IsSelected() ? selected_title_color_
|
| - : unselected_title_color_;
|
| -
|
| - // Disable subpixel rendering. This does not work because the canvas has a
|
| - // transparent background.
|
| - int flags = gfx::Canvas::NO_ELLIPSIS | gfx::Canvas::NO_SUBPIXEL_RENDERING;
|
| - canvas.DrawFadeTruncatingStringRectWithFlags(
|
| - title, gfx::Canvas::TruncateFadeTail, gfx::FontList(*title_font_),
|
| - title_color, title_bounds_, flags);
|
| -}
|
| -
|
| -void TabRendererGtk::PaintIcon(GtkWidget* widget, cairo_t* cr) {
|
| - if (loading_animation_.animation_state() != ANIMATION_NONE) {
|
| - PaintLoadingAnimation(widget, cr);
|
| - return;
|
| - }
|
| -
|
| - gfx::CairoCachedSurface* to_display = NULL;
|
| - if (should_display_crashed_favicon_) {
|
| - to_display = theme_service_->GetImageNamed(IDR_SAD_FAVICON).ToCairo();
|
| - } else if (!data_.favicon.isNull()) {
|
| - if (data_.is_default_favicon && theme_service_->UsingNativeTheme()) {
|
| - to_display = GtkThemeService::GetDefaultFavicon(true).ToCairo();
|
| - } else if (data_.cairo_favicon.valid()) {
|
| - to_display = &data_.cairo_favicon;
|
| - }
|
| - }
|
| -
|
| - if (to_display) {
|
| - to_display->SetSource(cr, widget, favicon_bounds_.x(),
|
| - favicon_bounds_.y() + favicon_hiding_offset_);
|
| - cairo_paint(cr);
|
| - }
|
| -}
|
| -
|
| -void TabRendererGtk::PaintMediaIndicator(GtkWidget* widget, cairo_t* cr) {
|
| - if (media_indicator_bounds_.IsEmpty() || !media_indicator_animation_)
|
| - return;
|
| -
|
| - double opaqueness = media_indicator_animation_->GetCurrentValue();
|
| - if (data_.media_state == TAB_MEDIA_STATE_NONE)
|
| - opaqueness = 1.0 - opaqueness; // Fading out, not in.
|
| -
|
| - const gfx::Image& media_indicator_image =
|
| - chrome::GetTabMediaIndicatorImage(animating_media_state_);
|
| - media_indicator_image.ToCairo()->SetSource(
|
| - cr, widget, media_indicator_bounds_.x(), media_indicator_bounds_.y());
|
| - cairo_paint_with_alpha(cr, opaqueness);
|
| -}
|
| -
|
| -void TabRendererGtk::PaintTabBackground(GtkWidget* widget, cairo_t* cr) {
|
| - if (IsActive()) {
|
| - PaintActiveTabBackground(widget, cr);
|
| - } else {
|
| - PaintInactiveTabBackground(widget, cr);
|
| -
|
| - double throb_value = GetThrobValue();
|
| - if (throb_value > 0) {
|
| - cairo_push_group(cr);
|
| - PaintActiveTabBackground(widget, cr);
|
| - cairo_pop_group_to_source(cr);
|
| - cairo_paint_with_alpha(cr, throb_value);
|
| - }
|
| - }
|
| -}
|
| -
|
| -void TabRendererGtk::DrawTabBackground(
|
| - cairo_t* cr,
|
| - GtkWidget* widget,
|
| - const gfx::Image& tab_bg,
|
| - int offset_x,
|
| - int offset_y) {
|
| - tab_bg.ToCairo()->SetSource(cr, widget, -offset_x, -offset_y);
|
| - cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
|
| -
|
| - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
|
| -
|
| - // Draw left edge
|
| - gfx::Image& tab_l_mask = rb.GetNativeImageNamed(IDR_TAB_ALPHA_LEFT);
|
| - tab_l_mask.ToCairo()->MaskSource(cr, widget, 0, 0);
|
| -
|
| - // Draw center
|
| - cairo_rectangle(cr,
|
| - tab_active_l_width_, kDropShadowOffset,
|
| - width() - (2 * tab_active_l_width_),
|
| - tab_inactive_l_height_);
|
| - cairo_fill(cr);
|
| -
|
| - // Draw right edge
|
| - gfx::Image& tab_r_mask = rb.GetNativeImageNamed(IDR_TAB_ALPHA_RIGHT);
|
| - tab_r_mask.ToCairo()->MaskSource(cr, widget,
|
| - width() - tab_active_l_width_, 0);
|
| -}
|
| -
|
| -void TabRendererGtk::DrawTabShadow(cairo_t* cr,
|
| - GtkWidget* widget,
|
| - int left_idr,
|
| - int center_idr,
|
| - int right_idr) {
|
| - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
|
| - gfx::Image& active_image_l = rb.GetNativeImageNamed(left_idr);
|
| - gfx::Image& active_image_c = rb.GetNativeImageNamed(center_idr);
|
| - gfx::Image& active_image_r = rb.GetNativeImageNamed(right_idr);
|
| -
|
| - // Draw left drop shadow
|
| - active_image_l.ToCairo()->SetSource(cr, widget, 0, 0);
|
| - cairo_paint(cr);
|
| -
|
| - // Draw the center shadow
|
| - active_image_c.ToCairo()->SetSource(cr, widget, 0, 0);
|
| - cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
|
| - cairo_rectangle(cr, tab_active_l_width_, 0,
|
| - width() - (2 * tab_active_l_width_),
|
| - height());
|
| - cairo_fill(cr);
|
| -
|
| - // Draw right drop shadow
|
| - active_image_r.ToCairo()->SetSource(
|
| - cr, widget, width() - active_image_r.ToCairo()->Width(), 0);
|
| - cairo_paint(cr);
|
| -}
|
| -
|
| -void TabRendererGtk::PaintInactiveTabBackground(GtkWidget* widget,
|
| - cairo_t* cr) {
|
| - int theme_id = data_.incognito ?
|
| - IDR_THEME_TAB_BACKGROUND_INCOGNITO : IDR_THEME_TAB_BACKGROUND;
|
| -
|
| - gfx::Image tab_bg = theme_service_->GetImageNamed(theme_id);
|
| -
|
| - // 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_service_->HasCustomImage(theme_id) ?
|
| - 0 : background_offset_y_;
|
| -
|
| - DrawTabBackground(cr, widget, tab_bg, background_offset_x_, offset_y);
|
| -
|
| - DrawTabShadow(cr, widget, IDR_TAB_INACTIVE_LEFT, IDR_TAB_INACTIVE_CENTER,
|
| - IDR_TAB_INACTIVE_RIGHT);
|
| -}
|
| -
|
| -void TabRendererGtk::PaintActiveTabBackground(GtkWidget* widget,
|
| - cairo_t* cr) {
|
| - gfx::Image tab_bg = theme_service_->GetImageNamed(IDR_THEME_TOOLBAR);
|
| -
|
| - DrawTabBackground(cr, widget, tab_bg, background_offset_x_, 0);
|
| - DrawTabShadow(cr, widget, IDR_TAB_ACTIVE_LEFT, IDR_TAB_ACTIVE_CENTER,
|
| - IDR_TAB_ACTIVE_RIGHT);
|
| -}
|
| -
|
| -void TabRendererGtk::PaintLoadingAnimation(GtkWidget* widget,
|
| - cairo_t* cr) {
|
| - int id = loading_animation_.animation_state() == ANIMATION_WAITING ?
|
| - IDR_THROBBER_WAITING : IDR_THROBBER;
|
| - gfx::Image throbber = theme_service_->GetImageNamed(id);
|
| -
|
| - const int image_size = throbber.ToCairo()->Height();
|
| - const int image_offset = loading_animation_.animation_frame() * image_size;
|
| - DCHECK(image_size == favicon_bounds_.height());
|
| - DCHECK(image_size == favicon_bounds_.width());
|
| -
|
| - throbber.ToCairo()->SetSource(cr, widget, favicon_bounds_.x() - image_offset,
|
| - favicon_bounds_.y());
|
| - cairo_rectangle(cr, favicon_bounds_.x(), favicon_bounds_.y(),
|
| - image_size, image_size);
|
| - cairo_fill(cr);
|
| -}
|
| -
|
| -int TabRendererGtk::IconCapacity() const {
|
| - if (height() < GetMinimumUnselectedSize().height())
|
| - return 0;
|
| - const int available_width =
|
| - std::max(0, width() - kLeftPadding - kRightPadding);
|
| - const int kPaddingBetweenIcons = 2;
|
| - if (available_width >= gfx::kFaviconSize &&
|
| - available_width < (gfx::kFaviconSize + kPaddingBetweenIcons)) {
|
| - return 1;
|
| - }
|
| - return available_width / (gfx::kFaviconSize + kPaddingBetweenIcons);
|
| -}
|
| -
|
| -bool TabRendererGtk::ShouldShowIcon() const {
|
| - return chrome::ShouldTabShowFavicon(
|
| - IconCapacity(), mini(), IsActive(), data_.show_icon,
|
| - animating_media_state_);
|
| -}
|
| -
|
| -bool TabRendererGtk::ShouldShowMediaIndicator() const {
|
| - return chrome::ShouldTabShowMediaIndicator(
|
| - IconCapacity(), mini(), IsActive(), data_.show_icon,
|
| - animating_media_state_);
|
| -}
|
| -
|
| -bool TabRendererGtk::ShouldShowCloseBox() const {
|
| - return chrome::ShouldTabShowCloseButton(IconCapacity(), mini(), IsActive());
|
| -}
|
| -
|
| -CustomDrawButton* TabRendererGtk::MakeCloseButton() {
|
| - CustomDrawButton* button = CustomDrawButton::CloseButtonBar(theme_service_);
|
| - button->ForceChromeTheme();
|
| -
|
| - g_signal_connect(button->widget(), "clicked",
|
| - G_CALLBACK(OnCloseButtonClickedThunk), this);
|
| - g_signal_connect(button->widget(), "button-release-event",
|
| - G_CALLBACK(OnCloseButtonMouseReleaseThunk), this);
|
| - g_signal_connect(button->widget(), "enter-notify-event",
|
| - G_CALLBACK(OnEnterNotifyEventThunk), this);
|
| - g_signal_connect(button->widget(), "leave-notify-event",
|
| - G_CALLBACK(OnLeaveNotifyEventThunk), this);
|
| - gtk_widget_set_can_focus(button->widget(), FALSE);
|
| - gtk_fixed_put(GTK_FIXED(tab_.get()), button->widget(), 0, 0);
|
| -
|
| - return button;
|
| -}
|
| -
|
| -double TabRendererGtk::GetThrobValue() {
|
| - bool is_selected = IsSelected();
|
| - double min = is_selected ? kSelectedTabOpacity : 0;
|
| - double scale = is_selected ? kSelectedTabThrobScale : 1;
|
| -
|
| - if (mini_title_animation_.get() && mini_title_animation_->is_animating()) {
|
| - return mini_title_animation_->GetCurrentValue() *
|
| - kMiniTitleChangeThrobOpacity * scale + min;
|
| - }
|
| -
|
| - if (hover_animation_.get())
|
| - return kHoverOpacity * hover_animation_->GetCurrentValue() * scale + min;
|
| -
|
| - return is_selected ? kSelectedTabOpacity : 0;
|
| -}
|
| -
|
| -void TabRendererGtk::CloseButtonClicked() {
|
| - // Nothing to do.
|
| -}
|
| -
|
| -void TabRendererGtk::OnCloseButtonClicked(GtkWidget* widget) {
|
| - CloseButtonClicked();
|
| -}
|
| -
|
| -gboolean TabRendererGtk::OnCloseButtonMouseRelease(GtkWidget* widget,
|
| - GdkEventButton* event) {
|
| - if (event->button == 2) {
|
| - CloseButtonClicked();
|
| - return TRUE;
|
| - }
|
| -
|
| - return FALSE;
|
| -}
|
| -
|
| -gboolean TabRendererGtk::OnExposeEvent(GtkWidget* widget,
|
| - GdkEventExpose* event) {
|
| - TRACE_EVENT0("ui::gtk", "TabRendererGtk::OnExposeEvent");
|
| -
|
| - PaintTab(widget, event);
|
| - gtk_container_propagate_expose(GTK_CONTAINER(tab_.get()),
|
| - close_button_->widget(), event);
|
| - return TRUE;
|
| -}
|
| -
|
| -void TabRendererGtk::OnSizeAllocate(GtkWidget* widget,
|
| - GtkAllocation* allocation) {
|
| - gfx::Rect bounds = gfx::Rect(allocation->x, allocation->y,
|
| - allocation->width, allocation->height);
|
| -
|
| - // Nothing to do if the bounds are the same. If we don't catch this, we'll
|
| - // get an infinite loop of size-allocate signals.
|
| - if (bounds_ == bounds)
|
| - return;
|
| -
|
| - bounds_ = bounds;
|
| - Layout();
|
| -}
|
| -
|
| -gboolean TabRendererGtk::OnEnterNotifyEvent(GtkWidget* widget,
|
| - GdkEventCrossing* event) {
|
| - hover_animation_->SetTweenType(gfx::Tween::EASE_OUT);
|
| - hover_animation_->Show();
|
| - return FALSE;
|
| -}
|
| -
|
| -gboolean TabRendererGtk::OnLeaveNotifyEvent(GtkWidget* widget,
|
| - GdkEventCrossing* event) {
|
| - hover_animation_->SetTweenType(gfx::Tween::EASE_IN);
|
| - hover_animation_->Hide();
|
| - return FALSE;
|
| -}
|
| -
|
| -// static
|
| -void TabRendererGtk::InitResources() {
|
| - if (initialized_)
|
| - return;
|
| -
|
| - // Grab the pixel sizes of our masking images.
|
| - ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
|
| - GdkPixbuf* tab_active_l = rb.GetNativeImageNamed(
|
| - IDR_TAB_ACTIVE_LEFT).ToGdkPixbuf();
|
| - tab_active_l_width_ = gdk_pixbuf_get_width(tab_active_l);
|
| - tab_active_l_height_ = gdk_pixbuf_get_height(tab_active_l);
|
| -
|
| - GdkPixbuf* tab_inactive_l = rb.GetNativeImageNamed(
|
| - IDR_TAB_INACTIVE_LEFT).ToGdkPixbuf();
|
| - tab_inactive_l_height_ = gdk_pixbuf_get_height(tab_inactive_l);
|
| -
|
| - GdkPixbuf* tab_close = rb.GetNativeImageNamed(IDR_CLOSE_1).ToGdkPixbuf();
|
| - close_button_width_ = gdk_pixbuf_get_width(tab_close);
|
| - close_button_height_ = gdk_pixbuf_get_height(tab_close);
|
| -
|
| - const gfx::Font& base_font = rb.GetFont(ui::ResourceBundle::BaseFont);
|
| - title_font_ = new gfx::Font(base_font.GetFontName(), kFontPixelSize);
|
| - title_font_height_ = title_font_->GetHeight();
|
| -
|
| - initialized_ = true;
|
| -}
|
|
|