172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/tabs/tab_renderer_gtk.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <utility>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/defaults.h"
12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/extensions/extension_tab_helper.h"
1321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h"
15dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h"
1672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/custom_button.h"
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/gtk/gtk_theme_service.h"
1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/gtk/gtk_util.h"
19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
20dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h"
21dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/common/notification_service.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/app_resources.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h"
253f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "ui/base/animation/slide_animation.h"
263f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "ui/base/animation/throb_animation.h"
2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h"
2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h"
2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas_skia_paint.h"
3072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/favicon_size.h"
3172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/platform_font_gtk.h"
3272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/skbitmap_operations.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst int kFontPixelSize = 12;
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kLeftPadding = 16;
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kTopPadding = 6;
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kRightPadding = 15;
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kBottomPadding = 5;
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kDropShadowHeight = 2;
42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst int kFaviconTitleSpacing = 4;
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kTitleCloseButtonSpacing = 5;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kStandardTitleWidth = 175;
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kDropShadowOffset = 2;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kInactiveTabBackgroundOffsetY = 15;
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// When a non-mini-tab becomes a mini-tab the width of the tab animates. If
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the width of a mini-tab is >= kMiniTabRendererAsNormalTabWidth then the tab
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// is rendered as a normal tab. This is done to avoid having the title
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// immediately disappear when transitioning a tab from normal to mini-tab.
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kMiniTabRendererAsNormalTabWidth =
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    browser_defaults::kMiniTabWidth + 30;
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The tab images are designed to overlap the toolbar by 1 pixel. For now we
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// don't actually overlap the toolbar, so this is used to know how many pixels
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// at the bottom of the tab images are to be ignored.
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kToolbarOverlap = 1;
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// How long the hover state takes.
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kHoverDurationMs = 90;
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// How opaque to make the hover state (out of 1).
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst double kHoverOpacity = 0.33;
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Max opacity for the mini-tab title change animation.
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst double kMiniTitleChangeThrobOpacity = 0.75;
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Duration for when the title of an inactive mini-tab changes.
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kMiniTitleChangeThrobDuration = 1000;
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkScalar kTabCapWidth = 15;
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkScalar kTabTopCurveWidth = 4;
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkScalar kTabBottomCurveWidth = 3;
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The vertical and horizontal offset used to position the close button
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// in the tab. TODO(jhawkins): Ask pkasting what the Fuzz is about.
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kCloseButtonVertFuzz = 0;
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kCloseButtonHorzFuzz = 5;
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenSkBitmap* crashed_favicon = NULL;
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Gets the bounds of |widget| relative to |parent|.
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect GetWidgetBoundsRelativeToParent(GtkWidget* parent,
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          GtkWidget* widget) {
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Point parent_pos = gtk_util::GetWidgetScreenPosition(parent);
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Point widget_pos = gtk_util::GetWidgetScreenPosition(widget);
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return gfx::Rect(widget_pos.x() - parent_pos.x(),
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   widget_pos.y() - parent_pos.y(),
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   widget->allocation.width, widget->allocation.height);
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenTabRendererGtk::LoadingAnimation::Data::Data(
9672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ui::ThemeProvider* theme_provider) {
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The loading animation image is a strip of states. Each state must be
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // square, so the height must divide the width evenly.
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  loading_animation_frames = theme_provider->GetBitmapNamed(IDR_THROBBER);
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(loading_animation_frames);
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(loading_animation_frames->width() %
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            loading_animation_frames->height(), 0);
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  loading_animation_frame_count =
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      loading_animation_frames->width() /
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      loading_animation_frames->height();
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  waiting_animation_frames =
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      theme_provider->GetBitmapNamed(IDR_THROBBER_WAITING);
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(waiting_animation_frames);
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(waiting_animation_frames->width() %
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            waiting_animation_frames->height(), 0);
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  waiting_animation_frame_count =
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      waiting_animation_frames->width() /
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      waiting_animation_frames->height();
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  waiting_to_loading_frame_count_ratio =
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      waiting_animation_frame_count /
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      loading_animation_frame_count;
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(beng): eventually remove this when we have a proper themeing system.
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //             themes not supporting IDR_THROBBER_WAITING are causing this
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //             value to be 0 which causes DIV0 crashes. The value of 5
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //             matches the current bitmaps in our source.
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (waiting_to_loading_frame_count_ratio == 0)
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    waiting_to_loading_frame_count_ratio = 5;
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRendererGtk::LoadingAnimation::Data::Data(
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int loading, int waiting, int waiting_to_loading)
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : waiting_animation_frames(NULL),
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      loading_animation_frames(NULL),
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      loading_animation_frame_count(loading),
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      waiting_animation_frame_count(waiting),
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      waiting_to_loading_frame_count_ratio(waiting_to_loading) {
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabRendererGtk::initialized_ = false;
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRendererGtk::TabImage TabRendererGtk::tab_active_ = {0};
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRendererGtk::TabImage TabRendererGtk::tab_inactive_ = {0};
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRendererGtk::TabImage TabRendererGtk::tab_alpha_ = {0};
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Font* TabRendererGtk::title_font_ = NULL;
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint TabRendererGtk::title_font_height_ = 0;
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint TabRendererGtk::close_button_width_ = 0;
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint TabRendererGtk::close_button_height_ = 0;
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSkColor TabRendererGtk::selected_title_color_ = SK_ColorBLACK;
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSkColor TabRendererGtk::unselected_title_color_ = SkColorSetRGB(64, 64, 64);
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabRendererGtk::LoadingAnimation, public:
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRendererGtk::LoadingAnimation::LoadingAnimation(
15172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ui::ThemeProvider* theme_provider)
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : data_(new Data(theme_provider)),
153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      theme_service_(theme_provider),
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      animation_state_(ANIMATION_NONE),
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      animation_frame_(0) {
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this,
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationType::BROWSER_THEME_CHANGED,
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationService::AllSources());
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRendererGtk::LoadingAnimation::LoadingAnimation(
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const LoadingAnimation::Data& data)
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : data_(new Data(data)),
164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      theme_service_(NULL),
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      animation_state_(ANIMATION_NONE),
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      animation_frame_(0) {
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
169731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickTabRendererGtk::LoadingAnimation::~LoadingAnimation() {}
170731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabRendererGtk::LoadingAnimation::ValidateLoadingAnimation(
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AnimationState animation_state) {
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool has_changed = false;
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (animation_state_ != animation_state) {
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The waiting animation is the reverse of the loading animation, but at a
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // different rate - the following reverses and scales the animation_frame_
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // so that the frame is at an equivalent position when going from one
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // animation to the other.
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (animation_state_ == ANIMATION_WAITING &&
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        animation_state == ANIMATION_LOADING) {
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      animation_frame_ = data_->loading_animation_frame_count -
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          (animation_frame_ / data_->waiting_to_loading_frame_count_ratio);
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    animation_state_ = animation_state;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    has_changed = true;
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (animation_state_ != ANIMATION_NONE) {
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    animation_frame_ = (animation_frame_ + 1) %
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       ((animation_state_ == ANIMATION_WAITING) ?
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         data_->waiting_animation_frame_count :
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         data_->loading_animation_frame_count);
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    has_changed = true;
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    animation_frame_ = 0;
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return has_changed;
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::LoadingAnimation::Observe(
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NotificationType type,
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const NotificationSource& source,
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const NotificationDetails& details) {
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(type == NotificationType::BROWSER_THEME_CHANGED);
205ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  data_.reset(new Data(theme_service_));
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// FaviconCrashAnimation
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//  A custom animation subclass to manage the favicon crash animation.
212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass TabRendererGtk::FaviconCrashAnimation : public ui::LinearAnimation,
2133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen                                              public ui::AnimationDelegate {
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  explicit FaviconCrashAnimation(TabRendererGtk* target)
2163f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      : ALLOW_THIS_IN_INITIALIZER_LIST(ui::LinearAnimation(1000, 25, this)),
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        target_(target) {
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual ~FaviconCrashAnimation() {}
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2213f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // ui::Animation overrides:
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void AnimateToState(double state) {
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const double kHidingOffset = 27;
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (state < .5) {
226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      target_->SetFaviconHidingOffset(
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          static_cast<int>(floor(kHidingOffset * 2.0 * state)));
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      target_->DisplayCrashedFavicon();
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      target_->SetFaviconHidingOffset(
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          static_cast<int>(
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              floor(kHidingOffset - ((state - .5) * 2.0 * kHidingOffset))));
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2363f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // ui::AnimationDelegate overrides:
2373f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  virtual void AnimationCanceled(const ui::Animation* animation) {
238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    target_->SetFaviconHidingOffset(0);
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabRendererGtk* target_;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DISALLOW_COPY_AND_ASSIGN(FaviconCrashAnimation);
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabRendererGtk, public:
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
25072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenTabRendererGtk::TabRendererGtk(ui::ThemeProvider* theme_provider)
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : showing_icon_(false),
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      showing_close_button_(false),
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      favicon_hiding_offset_(0),
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      should_display_crashed_favicon_(false),
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      loading_animation_(theme_provider),
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      background_offset_x_(0),
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      background_offset_y_(kInactiveTabBackgroundOffsetY),
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      close_button_color_(0) {
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  InitResources();
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_.Own(gtk_fixed_new());
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_set_app_paintable(tab_.get(), TRUE);
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(tab_.get(), "expose-event",
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnExposeEventThunk), this);
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(tab_.get(), "size-allocate",
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnSizeAllocateThunk), this);
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  close_button_.reset(MakeCloseButton());
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_show(tab_.get());
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2703f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  hover_animation_.reset(new ui::SlideAnimation(this));
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  hover_animation_->SetSlideDuration(kHoverDurationMs);
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED,
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 NotificationService::AllSources());
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabRendererGtk::~TabRendererGtk() {
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_.Destroy();
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BitmapCache::iterator it = cached_bitmaps_.begin();
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       it != cached_bitmaps_.end(); ++it) {
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete it->second.bitmap;
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::UpdateData(TabContents* contents,
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                bool app,
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                bool loading_only) {
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(contents);
289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  theme_service_ = GtkThemeService::GetFrom(contents->profile());
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!loading_only) {
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    data_.title = contents->GetTitle();
293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    data_.incognito = contents->profile()->IsOffTheRecord();
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    data_.crashed = contents->is_crashed();
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
296ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SkBitmap* app_icon =
297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        TabContentsWrapper::GetCurrentWrapperForContents(contents)->
298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            extension_tab_helper()->GetExtensionAppIcon();
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (app_icon)
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      data_.favicon = *app_icon;
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      data_.favicon = contents->GetFavicon();
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    data_.app = app;
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // This is kind of a hacky way to determine whether our icon is the default
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // favicon. But the plumbing that would be necessary to do it right would
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // be a good bit of work and would sully code for other platforms which
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // don't care to custom-theme the favicon. Hopefully the default favicon
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // will eventually be chromium-themable and this code will go away.
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    data_.is_default_favicon =
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        (data_.favicon.pixelRef() ==
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ResourceBundle::GetSharedInstance().GetBitmapNamed(
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            IDR_DEFAULT_FAVICON)->pixelRef());
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Loading state also involves whether we show the favicon, since that's where
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we display the throbber.
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data_.loading = contents->is_loading();
319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  data_.show_icon = contents->ShouldDisplayFavicon();
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::UpdateFromModel() {
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Force a layout, since the tab may have grown a favicon.
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Layout();
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SchedulePaint();
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (data_.crashed) {
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!should_display_crashed_favicon_ && !IsPerformingCrashAnimation())
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      StartCrashAnimation();
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (IsPerformingCrashAnimation())
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      StopCrashAnimation();
333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ResetCrashedFavicon();
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::SetBlocked(bool blocked) {
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (data_.blocked == blocked)
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data_.blocked = blocked;
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(zelidrag) bug 32399: Make tabs pulse on Linux as well.
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabRendererGtk::is_blocked() const {
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return data_.blocked;
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabRendererGtk::IsSelected() const {
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabRendererGtk::IsVisible() const {
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return GTK_WIDGET_FLAGS(tab_.get()) & GTK_VISIBLE;
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::SetVisible(bool visible) const {
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (visible) {
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_widget_show(tab_.get());
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (data_.mini)
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gtk_widget_show(close_button_->widget());
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_widget_hide_all(tab_.get());
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabRendererGtk::ValidateLoadingAnimation(AnimationState animation_state) {
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return loading_animation_.ValidateLoadingAnimation(animation_state);
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
370ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid TabRendererGtk::PaintFaviconArea(GdkEventExpose* event) {
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(ShouldShowIcon());
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The paint area is the favicon bounds, but we're painting into the gdk
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // window belonging to the tabstrip.  So the coordinates are relative to the
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // top left of the tab strip.
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  event->area.x = x() + favicon_bounds_.x();
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  event->area.y = y() + favicon_bounds_.y();
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  event->area.width = favicon_bounds_.width();
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  event->area.height = favicon_bounds_.height();
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::CanvasSkiaPaint canvas(event, false);
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The actual paint methods expect 0, 0 to be the tab top left (see
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // PaintTab).
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas.TranslateInt(x(), y());
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Paint the background behind the favicon.
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int theme_id;
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int offset_y = 0;
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (IsSelected()) {
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    theme_id = IDR_THEME_TOOLBAR;
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
392ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!data_.incognito) {
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      theme_id = IDR_THEME_TAB_BACKGROUND;
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      theme_id = IDR_THEME_TAB_BACKGROUND_INCOGNITO;
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
397ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!theme_service_->HasCustomImage(theme_id))
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      offset_y = background_offset_y_;
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
400ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SkBitmap* tab_bg = theme_service_->GetBitmapNamed(theme_id);
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas.TileImageInt(*tab_bg,
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      x() + favicon_bounds_.x(), offset_y + favicon_bounds_.y(),
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      favicon_bounds_.x(), favicon_bounds_.y(),
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      favicon_bounds_.width(), favicon_bounds_.height());
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!IsSelected()) {
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    double throb_value = GetThrobValue();
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (throb_value > 0) {
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SkRect bounds;
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bounds.set(favicon_bounds_.x(), favicon_bounds_.y(),
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          favicon_bounds_.right(), favicon_bounds_.bottom());
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      canvas.saveLayerAlpha(&bounds, static_cast<int>(throb_value * 0xff),
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            SkCanvas::kARGB_ClipLayer_SaveFlag);
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      canvas.drawARGB(0, 255, 255, 255, SkXfermode::kClear_Mode);
415ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SkBitmap* active_bg = theme_service_->GetBitmapNamed(IDR_THEME_TOOLBAR);
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      canvas.TileImageInt(*active_bg,
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          x() + favicon_bounds_.x(), favicon_bounds_.y(),
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          favicon_bounds_.x(), favicon_bounds_.y(),
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          favicon_bounds_.width(), favicon_bounds_.height());
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      canvas.restore();
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now paint the icon.
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PaintIcon(&canvas);
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
428513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool TabRendererGtk::ShouldShowIcon() const {
429513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (mini() && height() >= GetMinimumUnselectedSize().height()) {
430513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return true;
431513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  } else if (!data_.show_icon) {
432513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return false;
433513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  } else if (IsSelected()) {
434513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    // The selected tab clips favicon before close button.
435513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return IconCapacity() >= 2;
436513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
437513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Non-selected tabs clip close button before favicon.
438513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return IconCapacity() >= 1;
439513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
440513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Size TabRendererGtk::GetMinimumUnselectedSize() {
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  InitResources();
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Size minimum_size;
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  minimum_size.set_width(kLeftPadding + kRightPadding);
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Since we use bitmap images, the real minimum height of the image is
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // defined most accurately by the height of the end cap images.
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  minimum_size.set_height(tab_active_.image_l->height() - kToolbarOverlap);
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return minimum_size;
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Size TabRendererGtk::GetMinimumSelectedSize() {
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Size minimum_size = GetMinimumUnselectedSize();
456ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  minimum_size.set_width(kLeftPadding + kFaviconSize + kRightPadding);
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return minimum_size;
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Size TabRendererGtk::GetStandardSize() {
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Size standard_size = GetMinimumUnselectedSize();
463ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  standard_size.Enlarge(kFaviconTitleSpacing + kStandardTitleWidth, 0);
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return standard_size;
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint TabRendererGtk::GetMiniWidth() {
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return browser_defaults::kMiniTabWidth;
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint TabRendererGtk::GetContentHeight() {
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The height of the content of the Tab is the largest of the favicon,
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the title text and the close button graphic.
476ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int content_height = std::max(kFaviconSize, title_font_height_);
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return std::max(content_height, close_button_height_);
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::LoadTabImages() {
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_alpha_.image_l = rb.GetBitmapNamed(IDR_TAB_ALPHA_LEFT);
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_alpha_.image_r = rb.GetBitmapNamed(IDR_TAB_ALPHA_RIGHT);
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_active_.image_l = rb.GetBitmapNamed(IDR_TAB_ACTIVE_LEFT);
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_active_.image_c = rb.GetBitmapNamed(IDR_TAB_ACTIVE_CENTER);
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_active_.image_r = rb.GetBitmapNamed(IDR_TAB_ACTIVE_RIGHT);
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_active_.l_width = tab_active_.image_l->width();
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_active_.r_width = tab_active_.image_r->width();
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_inactive_.image_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT);
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_inactive_.image_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER);
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_inactive_.image_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT);
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_inactive_.l_width = tab_inactive_.image_l->width();
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab_inactive_.r_width = tab_inactive_.image_r->width();
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  close_button_width_ = rb.GetBitmapNamed(IDR_TAB_CLOSE)->width();
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  close_button_height_ = rb.GetBitmapNamed(IDR_TAB_CLOSE)->height();
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::SetSelectedTitleColor(SkColor color) {
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  selected_title_color_ = color;
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::SetUnselectedTitleColor(SkColor color) {
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  unselected_title_color_ = color;
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect TabRendererGtk::GetNonMirroredBounds(GtkWidget* parent) const {
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The tabstrip widget is a windowless widget so the tab widget's allocation
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // is relative to the browser titlebar.  We need the bounds relative to the
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // tabstrip.
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect bounds = GetWidgetBoundsRelativeToParent(parent, widget());
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bounds.set_x(gtk_util::MirroredLeftPointForRect(parent, bounds));
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return bounds;
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect TabRendererGtk::GetRequisition() const {
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return gfx::Rect(requisition_.x(), requisition_.y(),
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   requisition_.width(), requisition_.height());
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::StartMiniTabTitleAnimation() {
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!mini_title_animation_.get()) {
5293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    mini_title_animation_.reset(new ui::ThrobAnimation(this));
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    mini_title_animation_->SetThrobDuration(kMiniTitleChangeThrobDuration);
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!mini_title_animation_->is_animating()) {
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    mini_title_animation_->StartThrobbing(2);
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (mini_title_animation_->cycles_remaining() <= 2) {
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The title changed while we're already animating. Add at most one more
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // cycle. This is done in an attempt to smooth out pages that continuously
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // change the title.
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    mini_title_animation_->set_cycles_remaining(
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        mini_title_animation_->cycles_remaining() + 2);
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::StopMiniTabTitleAnimation() {
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (mini_title_animation_.get())
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    mini_title_animation_->Stop();
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::SetBounds(const gfx::Rect& bounds) {
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  requisition_ = bounds;
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_set_size_request(tab_.get(), bounds.width(), bounds.height());
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::Observe(NotificationType type,
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             const NotificationSource& source,
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             const NotificationDetails& details) {
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(type == NotificationType::BROWSER_THEME_CHANGED);
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Clear our cache when we receive a theme change notification because it
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // contains cached bitmaps based off the previous theme.
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (BitmapCache::iterator it = cached_bitmaps_.begin();
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       it != cached_bitmaps_.end(); ++it) {
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete it->second.bitmap;
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  cached_bitmaps_.clear();
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabRendererGtk, protected:
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5713f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenstring16 TabRendererGtk::GetTitle() const {
5723f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  return data_.title;
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch///////////////////////////////////////////////////////////////////////////////
5763f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// TabRendererGtk, ui::AnimationDelegate implementation:
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5783f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid TabRendererGtk::AnimationProgressed(const ui::Animation* animation) {
579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_queue_draw(tab_.get());
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5823f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid TabRendererGtk::AnimationCanceled(const ui::Animation* animation) {
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AnimationEnded(animation);
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5863f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid TabRendererGtk::AnimationEnded(const ui::Animation* animation) {
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_queue_draw(tab_.get());
588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TabRendererGtk, private:
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::StartCrashAnimation() {
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!crash_animation_.get())
595ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    crash_animation_.reset(new FaviconCrashAnimation(this));
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  crash_animation_->Stop();
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  crash_animation_->Start();
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::StopCrashAnimation() {
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!crash_animation_.get())
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  crash_animation_->Stop();
604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabRendererGtk::IsPerformingCrashAnimation() const {
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return crash_animation_.get() && crash_animation_->is_animating();
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
610ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid TabRendererGtk::SetFaviconHidingOffset(int offset) {
611ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  favicon_hiding_offset_ = offset;
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SchedulePaint();
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
615ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid TabRendererGtk::DisplayCrashedFavicon() {
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  should_display_crashed_favicon_ = true;
617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
619ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid TabRendererGtk::ResetCrashedFavicon() {
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  should_display_crashed_favicon_ = false;
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::Paint(gfx::Canvas* canvas) {
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Don't paint if we're narrower than we can render correctly. (This should
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // only happen during animations).
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (width() < GetMinimumUnselectedSize().width() && !mini())
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // See if the model changes whether the icons should be painted.
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const bool show_icon = ShouldShowIcon();
631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const bool show_close_button = ShouldShowCloseBox();
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (show_icon != showing_icon_ ||
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      show_close_button != showing_close_button_)
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Layout();
635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
636731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  PaintTabBackground(canvas);
637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!mini() || width() > kMiniTabRendererAsNormalTabWidth)
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PaintTitle(canvas);
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (show_icon)
642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PaintIcon(canvas);
643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSkBitmap TabRendererGtk::PaintBitmap() {
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::CanvasSkia canvas(width(), height(), false);
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Paint(&canvas);
648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return canvas.ExtractBitmap();
649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochcairo_surface_t* TabRendererGtk::PaintToSurface() {
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::CanvasSkia canvas(width(), height(), false);
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Paint(&canvas);
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return cairo_surface_reference(cairo_get_target(canvas.beginPlatformPaint()));
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::SchedulePaint() {
658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_queue_draw(tab_.get());
659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Rect TabRendererGtk::GetLocalBounds() {
662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return gfx::Rect(0, 0, bounds_.width(), bounds_.height());
663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::Layout() {
666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect local_bounds = GetLocalBounds();
667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (local_bounds.IsEmpty())
668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  local_bounds.Inset(kLeftPadding, kTopPadding, kRightPadding, kBottomPadding);
670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Figure out who is tallest.
672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int content_height = GetContentHeight();
673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Size the Favicon.
675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  showing_icon_ = ShouldShowIcon();
676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (showing_icon_) {
677ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int favicon_top = kTopPadding + (content_height - kFaviconSize) / 2;
678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    favicon_bounds_.SetRect(local_bounds.x(), favicon_top,
679ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                            kFaviconSize, kFaviconSize);
680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if ((mini() || data_.animating_mini_change) &&
681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        bounds_.width() < kMiniTabRendererAsNormalTabWidth) {
682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int mini_delta = kMiniTabRendererAsNormalTabWidth - GetMiniWidth();
683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int ideal_delta = bounds_.width() - GetMiniWidth();
684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (ideal_delta < mini_delta) {
685ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        int ideal_x = (GetMiniWidth() - kFaviconSize) / 2;
686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        int x = favicon_bounds_.x() + static_cast<int>(
687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            (1 - static_cast<float>(ideal_delta) /
688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch             static_cast<float>(mini_delta)) *
689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            (ideal_x - favicon_bounds_.x()));
690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        favicon_bounds_.set_x(x);
691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    favicon_bounds_.SetRect(local_bounds.x(), local_bounds.y(), 0, 0);
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Size the Close button.
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  showing_close_button_ = ShouldShowCloseBox();
699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (showing_close_button_) {
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int close_button_top =
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        kTopPadding + kCloseButtonVertFuzz +
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        (content_height - close_button_height_) / 2;
703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    close_button_bounds_.SetRect(local_bounds.width() + kCloseButtonHorzFuzz,
704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 close_button_top, close_button_width_,
705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 close_button_height_);
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If the close button color has changed, generate a new one.
708ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (theme_service_) {
709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SkColor tab_text_color =
710ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        theme_service_->GetColor(ThemeService::COLOR_TAB_TEXT);
711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!close_button_color_ || tab_text_color != close_button_color_) {
712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        close_button_color_ = tab_text_color;
713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ResourceBundle& rb = ResourceBundle::GetSharedInstance();
714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        close_button_->SetBackground(close_button_color_,
715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            rb.GetBitmapNamed(IDR_TAB_CLOSE),
716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            rb.GetBitmapNamed(IDR_TAB_CLOSE_MASK));
717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    close_button_bounds_.SetRect(0, 0, 0, 0);
721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!mini() || width() >= kMiniTabRendererAsNormalTabWidth) {
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Size the Title text to fill the remaining space.
725ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int title_left = favicon_bounds_.right() + kFaviconTitleSpacing;
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int title_top = kTopPadding;
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If the user has big fonts, the title will appear rendered too far down
729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // on the y-axis if we use the regular top padding, so we need to adjust it
730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // so that the text appears centered.
731c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gfx::Size minimum_size = GetMinimumUnselectedSize();
732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int text_height = title_top + title_font_height_ + kBottomPadding;
733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (text_height > minimum_size.height())
734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      title_top -= (text_height - minimum_size.height()) / 2;
735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int title_width;
737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (close_button_bounds_.width() && close_button_bounds_.height()) {
738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      title_width = std::max(close_button_bounds_.x() -
739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             kTitleCloseButtonSpacing - title_left, 0);
740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      title_width = std::max(local_bounds.width() - title_left, 0);
742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    title_bounds_.SetRect(title_left, title_top, title_width, content_height);
744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  favicon_bounds_.set_x(
747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gtk_util::MirroredLeftPointForRect(tab_.get(), favicon_bounds_));
748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  close_button_bounds_.set_x(
749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gtk_util::MirroredLeftPointForRect(tab_.get(), close_button_bounds_));
750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  title_bounds_.set_x(
751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gtk_util::MirroredLeftPointForRect(tab_.get(), title_bounds_));
752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MoveCloseButtonWidget();
754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::MoveCloseButtonWidget() {
757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!close_button_bounds_.IsEmpty()) {
758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_fixed_move(GTK_FIXED(tab_.get()), close_button_->widget(),
759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   close_button_bounds_.x(), close_button_bounds_.y());
760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_widget_show(close_button_->widget());
761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    gtk_widget_hide(close_button_->widget());
763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
766c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSkBitmap* TabRendererGtk::GetMaskedBitmap(const SkBitmap* mask,
767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const SkBitmap* background, int bg_offset_x, int bg_offset_y) {
768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We store a bitmap for each mask + background pair (4 total bitmaps).  We
769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // replace the cached image if the tab has moved relative to the background.
770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BitmapCache::iterator it = cached_bitmaps_.find(std::make_pair(mask,
771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                                 background));
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (it != cached_bitmaps_.end()) {
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (it->second.bg_offset_x == bg_offset_x &&
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        it->second.bg_offset_y == bg_offset_y) {
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return it->second.bitmap;
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The background offset changed so we should re-render with the new
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // offsets.
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete it->second.bitmap;
780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkBitmap image = SkBitmapOperations::CreateTiledBitmap(
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      *background, bg_offset_x, bg_offset_y, mask->width(),
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      height() + kToolbarOverlap);
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CachedBitmap bitmap = {
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bg_offset_x,
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bg_offset_y,
787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    new SkBitmap(SkBitmapOperations::CreateMaskedBitmap(image, *mask))
788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  cached_bitmaps_[std::make_pair(mask, background)] = bitmap;
790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return bitmap.bitmap;
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::PaintTab(GdkEventExpose* event) {
794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::CanvasSkiaPaint canvas(event, false);
795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (canvas.is_empty())
796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The tab is rendered into a windowless widget whose offset is at the
799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // coordinate event->area.  Translate by these offsets so we can render at
800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // (0,0) to match Windows' rendering metrics.
801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas.TranslateInt(event->area.x, event->area.y);
802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Save the original x offset so we can position background images properly.
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  background_offset_x_ = event->area.x;
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Paint(&canvas);
807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::PaintTitle(gfx::Canvas* canvas) {
810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Paint the Title.
811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string16 title = data_.title;
812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (title.empty()) {
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    title = data_.loading ?
814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE) :
815dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        TabContentsWrapper::GetDefaultTitle();
816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Browser::FormatTitleForDisplay(&title);
818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkColor title_color = IsSelected() ? selected_title_color_
821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                     : unselected_title_color_;
82272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  canvas->DrawStringInt(title, *title_font_, title_color,
823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        title_bounds_.x(), title_bounds_.y(),
824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        title_bounds_.width(), title_bounds_.height());
825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::PaintIcon(gfx::Canvas* canvas) {
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (loading_animation_.animation_state() != ANIMATION_NONE) {
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PaintLoadingAnimation(canvas);
830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    canvas->Save();
832ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    canvas->ClipRectInt(0, 0, width(), height() - kFaviconTitleSpacing);
833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (should_display_crashed_favicon_) {
834ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      canvas->DrawBitmapInt(*crashed_favicon, 0, 0,
835ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                            crashed_favicon->width(),
836ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                            crashed_favicon->height(),
837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            favicon_bounds_.x(),
838ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                            favicon_bounds_.y() + favicon_hiding_offset_,
839ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                            kFaviconSize, kFaviconSize,
840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            true);
841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!data_.favicon.isNull()) {
843ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (data_.is_default_favicon && theme_service_->UseGtkTheme()) {
844ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          GdkPixbuf* favicon = GtkThemeService::GetDefaultFavicon(true);
845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          canvas->AsCanvasSkia()->DrawGdkPixbuf(
846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              favicon, favicon_bounds_.x(),
847ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              favicon_bounds_.y() + favicon_hiding_offset_);
848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        } else {
849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // If the favicon is an app icon, it is allowed to be drawn slightly
850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // larger than the standard favicon.
851ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          int faviconHeightOffset = data_.app ? -2 : 0;
852ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          int faviconWidthDelta = data_.app ?
853ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              data_.favicon.width() - kFaviconSize : 0;
854ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          int faviconHeightDelta = data_.app ?
855ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen              data_.favicon.height() - kFaviconSize : 0;
856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // TODO(pkasting): Use code in tab_icon_view.cc:PaintIcon() (or switch
858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          // to using that class to render the favicon).
859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          canvas->DrawBitmapInt(data_.favicon, 0, 0,
860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                data_.favicon.width(),
861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                data_.favicon.height(),
862ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                favicon_bounds_.x() - faviconWidthDelta/2,
863ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                favicon_bounds_.y() + faviconHeightOffset
864ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                    - faviconHeightDelta/2
865ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                    + favicon_hiding_offset_,
866ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                kFaviconSize + faviconWidthDelta,
867ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                kFaviconSize + faviconHeightDelta,
868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                true);
869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    canvas->Restore();
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::PaintTabBackground(gfx::Canvas* canvas) {
877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (IsSelected()) {
878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PaintActiveTabBackground(canvas);
879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PaintInactiveTabBackground(canvas);
881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    double throb_value = GetThrobValue();
883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (throb_value > 0) {
884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      canvas->SaveLayerAlpha(static_cast<int>(throb_value * 0xff),
885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             gfx::Rect(width(), height()));
886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      canvas->AsCanvasSkia()->drawARGB(0, 255, 255, 255,
887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       SkXfermode::kClear_Mode);
888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      PaintActiveTabBackground(canvas);
889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      canvas->Restore();
890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
894c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::PaintInactiveTabBackground(gfx::Canvas* canvas) {
895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The tab image needs to be lined up with the background image
897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // so that it feels partially transparent.
898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int offset_x = background_offset_x_;
899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
900ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int tab_id = data_.incognito ?
901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      IDR_THEME_TAB_BACKGROUND_INCOGNITO : IDR_THEME_TAB_BACKGROUND;
902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
903ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SkBitmap* tab_bg = theme_service_->GetBitmapNamed(tab_id);
904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the theme is providing a custom background image, then its top edge
906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // should be at the top of the tab. Otherwise, we assume that the background
907c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // image is a composited foreground + frame image.
908ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int offset_y = theme_service_->HasCustomImage(tab_id) ?
909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0 : background_offset_y_;
910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Draw left edge.
912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkBitmap* theme_l = GetMaskedBitmap(tab_alpha_.image_l, tab_bg, offset_x,
913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      offset_y);
914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->DrawBitmapInt(*theme_l, 0, 0);
915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Draw right edge.
917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkBitmap* theme_r = GetMaskedBitmap(tab_alpha_.image_r, tab_bg,
918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      offset_x + width() - tab_active_.r_width, offset_y);
919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->DrawBitmapInt(*theme_r, width() - theme_r->width(), 0);
921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Draw center.
923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->TileImageInt(*tab_bg,
924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      offset_x + tab_active_.l_width, kDropShadowOffset + offset_y,
925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tab_active_.l_width, 2,
926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      width() - tab_active_.l_width - tab_active_.r_width, height() - 2);
927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->DrawBitmapInt(*tab_inactive_.image_l, 0, 0);
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->TileImageInt(*tab_inactive_.image_c, tab_inactive_.l_width, 0,
930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      width() - tab_inactive_.l_width - tab_inactive_.r_width, height());
931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->DrawBitmapInt(*tab_inactive_.image_r,
932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      width() - tab_inactive_.r_width, 0);
933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::PaintActiveTabBackground(gfx::Canvas* canvas) {
936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int offset_x = background_offset_x_;
937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
938ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SkBitmap* tab_bg = theme_service_->GetBitmapNamed(IDR_THEME_TOOLBAR);
939c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Draw left edge.
941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkBitmap* theme_l = GetMaskedBitmap(tab_alpha_.image_l, tab_bg, offset_x, 0);
942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->DrawBitmapInt(*theme_l, 0, 0);
943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Draw right edge.
945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkBitmap* theme_r = GetMaskedBitmap(tab_alpha_.image_r, tab_bg,
946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      offset_x + width() - tab_active_.r_width, 0);
947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->DrawBitmapInt(*theme_r, width() - tab_active_.r_width, 0);
948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Draw center.
950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->TileImageInt(*tab_bg,
951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      offset_x + tab_active_.l_width, kDropShadowHeight,
952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tab_active_.l_width, kDropShadowHeight,
953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      width() - tab_active_.l_width - tab_active_.r_width,
954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      height() - kDropShadowHeight);
955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->DrawBitmapInt(*tab_active_.image_l, 0, 0);
957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->TileImageInt(*tab_active_.image_c, tab_active_.l_width, 0,
958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      width() - tab_active_.l_width - tab_active_.r_width, height());
959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->DrawBitmapInt(*tab_active_.image_r, width() - tab_active_.r_width, 0);
960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::PaintLoadingAnimation(gfx::Canvas* canvas) {
963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const SkBitmap* frames =
964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (loading_animation_.animation_state() == ANIMATION_WAITING) ?
965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      loading_animation_.waiting_animation_frames() :
966c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      loading_animation_.loading_animation_frames();
967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const int image_size = frames->height();
968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const int image_offset = loading_animation_.animation_frame() * image_size;
969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(image_size == favicon_bounds_.height());
970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(image_size == favicon_bounds_.width());
971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
972dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // NOTE: the clipping is a work around for 69528, it shouldn't be necessary.
973dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  canvas->Save();
974dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  canvas->ClipRectInt(
975dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      favicon_bounds_.x(), favicon_bounds_.y(), image_size, image_size);
976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->DrawBitmapInt(*frames, image_offset, 0, image_size, image_size,
977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      favicon_bounds_.x(), favicon_bounds_.y(), image_size, image_size,
978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      false);
979dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  canvas->Restore();
980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint TabRendererGtk::IconCapacity() const {
983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (height() < GetMinimumUnselectedSize().height())
984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return 0;
985ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return (width() - kLeftPadding - kRightPadding) / kFaviconSize;
986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool TabRendererGtk::ShouldShowCloseBox() const {
989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The selected tab never clips close button.
990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return !mini() && (IsSelected() || IconCapacity() >= 3);
991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
993c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCustomDrawButton* TabRendererGtk::MakeCloseButton() {
994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CustomDrawButton* button = new CustomDrawButton(IDR_TAB_CLOSE,
995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      IDR_TAB_CLOSE_P, IDR_TAB_CLOSE_H, IDR_TAB_CLOSE);
996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_widget_set_tooltip_text(button->widget(),
998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      l10n_util::GetStringUTF8(IDS_TOOLTIP_CLOSE_TAB).c_str());
999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(button->widget(), "clicked",
1001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnCloseButtonClickedThunk), this);
1002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(button->widget(), "button-release-event",
1003c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnCloseButtonMouseReleaseThunk), this);
1004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(button->widget(), "enter-notify-event",
1005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnEnterNotifyEventThunk), this);
1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_signal_connect(button->widget(), "leave-notify-event",
1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   G_CALLBACK(OnLeaveNotifyEventThunk), this);
1008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GTK_WIDGET_UNSET_FLAGS(button->widget(), GTK_CAN_FOCUS);
1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_fixed_put(GTK_FIXED(tab_.get()), button->widget(), 0, 0);
1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return button;
1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochdouble TabRendererGtk::GetThrobValue() {
1015c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (mini_title_animation_.get() && mini_title_animation_->is_animating()) {
1016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return mini_title_animation_->GetCurrentValue() *
1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        kMiniTitleChangeThrobOpacity;
1018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return hover_animation_.get() ?
1020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kHoverOpacity * hover_animation_->GetCurrentValue() : 0;
1021c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::CloseButtonClicked() {
1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Nothing to do.
1025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::OnCloseButtonClicked(GtkWidget* widget) {
1028c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CloseButtonClicked();
1029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean TabRendererGtk::OnCloseButtonMouseRelease(GtkWidget* widget,
1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                   GdkEventButton* event) {
1033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (event->button == 2) {
1034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CloseButtonClicked();
1035c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return TRUE;
1036c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE;
1039c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean TabRendererGtk::OnExposeEvent(GtkWidget* widget,
1042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       GdkEventExpose* event) {
1043c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PaintTab(event);
1044c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gtk_container_propagate_expose(GTK_CONTAINER(tab_.get()),
1045c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                 close_button_->widget(), event);
1046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return TRUE;
1047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::OnSizeAllocate(GtkWidget* widget,
1050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    GtkAllocation* allocation) {
1051c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gfx::Rect bounds = gfx::Rect(allocation->x, allocation->y,
1052c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                               allocation->width, allocation->height);
1053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1054c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Nothing to do if the bounds are the same.  If we don't catch this, we'll
1055c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // get an infinite loop of size-allocate signals.
1056c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (bounds_ == bounds)
1057c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1058c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1059c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bounds_ = bounds;
1060c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Layout();
1061c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1062c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1063c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean TabRendererGtk::OnEnterNotifyEvent(GtkWidget* widget,
1064c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            GdkEventCrossing* event) {
10653f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  hover_animation_->SetTweenType(ui::Tween::EASE_OUT);
1066c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  hover_animation_->Show();
1067c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE;
1068c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1069c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1070c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgboolean TabRendererGtk::OnLeaveNotifyEvent(GtkWidget* widget,
1071c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            GdkEventCrossing* event) {
10723f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  hover_animation_->SetTweenType(ui::Tween::EASE_IN);
1073c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  hover_animation_->Hide();
1074c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FALSE;
1075c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1077c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
1078c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabRendererGtk::InitResources() {
1079c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (initialized_)
1080c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1081c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1082c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  LoadTabImages();
1083c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1084c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
1085c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const gfx::Font& base_font = rb.GetFont(ResourceBundle::BaseFont);
108672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  title_font_ = new gfx::Font(base_font.GetFontName(), kFontPixelSize);
10873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  title_font_height_ = title_font_->GetHeight();
1088c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1089ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  crashed_favicon = rb.GetBitmapNamed(IDR_SAD_FAVICON);
1090c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1091c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  initialized_ = true;
1092c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1093