1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef CHROME_BROWSER_UI_GTK_TABS_TAB_RENDERER_GTK_H_
6 #define CHROME_BROWSER_UI_GTK_TABS_TAB_RENDERER_GTK_H_
11 #include "base/basictypes.h"
12 #include "base/compiler_specific.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/strings/string16.h"
15 #include "chrome/browser/ui/tabs/tab_utils.h"
16 #include "content/public/browser/notification_observer.h"
17 #include "content/public/browser/notification_registrar.h"
18 #include "third_party/skia/include/core/SkBitmap.h"
19 #include "ui/base/gtk/gtk_signal.h"
20 #include "ui/base/gtk/owned_widget_gtk.h"
21 #include "ui/gfx/animation/animation_delegate.h"
22 #include "ui/gfx/canvas.h"
23 #include "ui/gfx/font.h"
24 #include "ui/gfx/image/cairo_cached_surface.h"
25 #include "ui/gfx/rect.h"
28 class CairoCachedSurface
;
35 class CustomDrawButton
;
36 class GtkThemeService
;
42 class TabRendererGtk
: public gfx::AnimationDelegate
,
43 public content::NotificationObserver
{
45 // Possible animation states.
52 class LoadingAnimation
: public content::NotificationObserver
{
55 explicit Data(GtkThemeService
* theme_service
);
56 Data(int loading
, int waiting
, int waiting_to_loading
);
58 int loading_animation_frame_count
;
59 int waiting_animation_frame_count
;
60 int waiting_to_loading_frame_count_ratio
;
63 explicit LoadingAnimation(GtkThemeService
* theme_service
);
65 // Used in unit tests to inject specific data.
66 explicit LoadingAnimation(const LoadingAnimation::Data
& data
);
68 virtual ~LoadingAnimation();
70 // Advance the loading animation to the next frame, or hide the animation if
71 // the tab isn't loading. Returns |true| if the icon area needs to be
73 bool ValidateLoadingAnimation(AnimationState animation_state
);
75 AnimationState
animation_state() const { return animation_state_
; }
76 int animation_frame() const { return animation_frame_
; }
78 // Provide content::NotificationObserver implementation.
79 virtual void Observe(int type
,
80 const content::NotificationSource
& source
,
81 const content::NotificationDetails
& details
) OVERRIDE
;
84 scoped_ptr
<Data
> data_
;
86 // Used to listen for theme change notifications.
87 content::NotificationRegistrar registrar_
;
89 // Gives us our throbber images.
90 GtkThemeService
* theme_service_
;
92 // Current state of the animation.
93 AnimationState animation_state_
;
95 // The current index into the Animation image strip.
98 DISALLOW_COPY_AND_ASSIGN(LoadingAnimation
);
101 explicit TabRendererGtk(GtkThemeService
* theme_service
);
102 virtual ~TabRendererGtk();
104 // Provide content::NotificationObserver implementation.
105 virtual void Observe(int type
,
106 const content::NotificationSource
& source
,
107 const content::NotificationDetails
& details
) OVERRIDE
;
109 // WebContents. If only the loading state was updated, the loading_only flag
110 // should be specified. If other things change, set this flag to false to
111 // update everything.
112 virtual void UpdateData(content::WebContents
* contents
,
116 // Sets the blocked state of the tab.
117 void SetBlocked(bool pinned
);
118 bool is_blocked() const;
120 // Sets the mini-state of the tab.
121 void set_mini(bool mini
) { data_
.mini
= mini
; }
122 bool mini() const { return data_
.mini
; }
124 // Sets the app state of the tab.
125 void set_app(bool app
) { data_
.app
= app
; }
126 bool app() const { return data_
.app
; }
128 // Are we in the process of animating a mini tab state change on this tab?
129 void set_animating_mini_change(bool value
) {
130 data_
.animating_mini_change
= value
;
133 // Updates the display to reflect the contents of this TabRenderer's model.
134 void UpdateFromModel();
136 // Returns true if the Tab is active, false otherwise.
137 virtual bool IsActive() const;
139 // Set |is_active_| property of this tab.
140 void set_is_active(bool is_active
) { is_active_
= is_active
; }
142 // Returns true if the Tab is selected, false otherwise.
143 virtual bool IsSelected() const;
145 // Returns true if the Tab is visible, false otherwise.
146 virtual bool IsVisible() const;
148 // Sets the visibility of the Tab.
149 virtual void SetVisible(bool visible
) const;
151 // Paints the tab using resources from the display that |widget| is on,
152 // drawing into |cr|.
153 void Paint(GtkWidget
* widget
, cairo_t
* cr
);
155 // Paints the tab, and keeps the result server-side. The returned surface must
156 // be freed with cairo_surface_destroy().
157 cairo_surface_t
* PaintToSurface(GtkWidget
* widget
, cairo_t
* cr
);
159 // There is no PaintNow available, so the fastest we can do is schedule a
160 // paint with the windowing system.
161 void SchedulePaint();
163 // Notifies the Tab that the close button has been clicked.
164 virtual void CloseButtonClicked();
166 // Sets the bounds of the tab.
167 virtual void SetBounds(const gfx::Rect
& bounds
);
169 // Advance the loading animation to the next frame, or hide the animation if
170 // the tab isn't loading. Returns |true| if the icon area needs to be
172 bool ValidateLoadingAnimation(AnimationState animation_state
);
174 // Repaint only the area of the tab that contains the favicon.
175 void PaintFaviconArea(GtkWidget
* widget
, cairo_t
* cr
);
177 // Returns whether the Tab should display a favicon.
178 bool ShouldShowIcon() const;
180 // Invoked from Layout() to adjust the position of the favicon or media
181 // indicator for mini tabs.
182 void MaybeAdjustLeftForMiniTab(gfx::Rect
* bounds
) const;
184 // Returns the minimum possible size of a single unselected Tab.
185 static gfx::Size
GetMinimumUnselectedSize();
186 // Returns the minimum possible size of a selected Tab. Selected tabs must
187 // always show a close button and have a larger minimum size than unselected
189 static gfx::Size
GetMinimumSelectedSize();
190 // Returns the preferred size of a single Tab, assuming space is
192 static gfx::Size
GetStandardSize();
194 // Returns the width for mini-tabs. Mini-tabs always have this width.
195 static int GetMiniWidth();
197 static gfx::Font
* title_font() { return title_font_
; }
199 // Returns the bounds of the Tab.
200 int x() const { return bounds_
.x(); }
201 int y() const { return bounds_
.y(); }
202 int width() const { return bounds_
.width(); }
203 int height() const { return bounds_
.height(); }
205 gfx::Rect
bounds() const { return bounds_
; }
207 gfx::Rect
favicon_bounds() const { return favicon_bounds_
; }
209 // Returns the non-mirrored (LTR) bounds of this tab.
210 gfx::Rect
GetNonMirroredBounds(GtkWidget
* parent
) const;
212 // Returns the requested bounds of the tab.
213 gfx::Rect
GetRequisition() const;
215 GtkWidget
* widget() const { return tab_
.get(); }
217 // Start/stop the mini-tab title animation.
218 void StartMiniTabTitleAnimation();
219 void StopMiniTabTitleAnimation();
221 void set_vertical_offset(int offset
) { background_offset_y_
= offset
; }
224 const gfx::Rect
& title_bounds() const { return title_bounds_
; }
225 const gfx::Rect
& close_button_bounds() const { return close_button_bounds_
; }
227 // Raise button to top of Z-order.
230 // Returns the title of the Tab.
231 base::string16
GetTitle() const;
233 // enter-notify-event handler that signals when the mouse enters the tab.
234 CHROMEGTK_CALLBACK_1(TabRendererGtk
, gboolean
, OnEnterNotifyEvent
,
237 // leave-notify-event handler that signals when the mouse enters the tab.
238 CHROMEGTK_CALLBACK_1(TabRendererGtk
, gboolean
, OnLeaveNotifyEvent
,
242 class FaviconCrashAnimation
;
244 // Model data. We store this here so that we don't need to ask the underlying
245 // model, which is tricky since instances of this object can outlive the
246 // corresponding objects in the underlying model.
252 gfx::CairoCachedSurface cairo_favicon
;
253 bool is_default_favicon
;
254 base::string16 title
;
261 bool animating_mini_change
;
263 TabMediaState media_state
;
264 TabMediaState previous_media_state
;
267 // Overridden from gfx::AnimationDelegate:
268 virtual void AnimationProgressed(const gfx::Animation
* animation
) OVERRIDE
;
269 virtual void AnimationCanceled(const gfx::Animation
* animation
) OVERRIDE
;
270 virtual void AnimationEnded(const gfx::Animation
* animation
) OVERRIDE
;
272 // Starts/Stops the crash animation.
273 void StartCrashAnimation();
274 void StopCrashAnimation();
276 // Return true if the crash animation is currently running.
277 bool IsPerformingCrashAnimation() const;
279 // Starts the media indicator fade-in/out animation. There's no stop method
280 // because this is not a continuous animation.
281 void StartMediaIndicatorAnimation();
283 // Set the temporary offset for the favicon. This is used during animation.
284 void SetFaviconHidingOffset(int offset
);
286 void DisplayCrashedFavicon();
287 void ResetCrashedFavicon();
289 // Generates the bounds for the interior items of the tab.
292 // Returns the local bounds of the tab. This returns the rect
293 // {0, 0, width(), height()} for now, as we don't yet support borders.
294 gfx::Rect
GetLocalBounds();
296 // Moves the close button widget within the GtkFixed container.
297 void MoveCloseButtonWidget();
299 // Returns the largest of the favicon, title text, and the close button.
300 static int GetContentHeight();
302 void PaintTab(GtkWidget
* widget
, GdkEventExpose
* event
);
304 // Paint various portions of the Tab
305 void PaintTitle(GtkWidget
* widget
, cairo_t
* cr
);
306 void PaintIcon(GtkWidget
* widget
, cairo_t
* cr
);
307 void PaintMediaIndicator(GtkWidget
* widget
, cairo_t
* cr
);
308 void PaintTabBackground(GtkWidget
* widget
, cairo_t
* cr
);
309 void PaintInactiveTabBackground(GtkWidget
* widget
, cairo_t
* cr
);
310 void PaintActiveTabBackground(GtkWidget
* widget
, cairo_t
* cr
);
311 void PaintLoadingAnimation(GtkWidget
* widget
, cairo_t
* cairo
);
313 // Draws the given |tab_bg| onto |cr| using the tab shape masks along the
314 // sides for the rounded tab shape.
315 void DrawTabBackground(cairo_t
* cr
,
317 const gfx::Image
& tab_bg
,
321 // Draws the tab shadow using the given idr resources onto |cr|.
322 void DrawTabShadow(cairo_t
* cr
,
328 // Returns the number of favicon-size elements that can fit in the tab's
330 int IconCapacity() const;
332 // Returns whether the Tab should display the media indicator.
333 bool ShouldShowMediaIndicator() const;
335 // Returns whether the Tab should display a close button.
336 bool ShouldShowCloseBox() const;
338 CustomDrawButton
* MakeCloseButton();
340 // Gets the throb value for the tab. When a tab is not selected the
341 // active background is drawn at |GetThrobValue()|%. This is used for hover
342 // and mini-tab title change effects.
343 double GetThrobValue();
345 // Handles the clicked signal for the close button.
346 CHROMEGTK_CALLBACK_0(TabRendererGtk
, void, OnCloseButtonClicked
);
348 // Handles middle clicking the close button.
349 CHROMEGTK_CALLBACK_1(TabRendererGtk
, gboolean
, OnCloseButtonMouseRelease
,
352 // expose-event handler that redraws the tab.
353 CHROMEGTK_CALLBACK_1(TabRendererGtk
, gboolean
, OnExposeEvent
,
356 // size-allocate handler used to update the current bounds of the tab.
357 CHROMEGTK_CALLBACK_1(TabRendererGtk
, void, OnSizeAllocate
, GtkAllocation
*);
359 // TODO(jhawkins): Move to TabResources.
360 static void InitResources();
361 static bool initialized_
;
363 // The bounds of various sections of the display.
364 gfx::Rect favicon_bounds_
;
365 gfx::Rect title_bounds_
;
366 gfx::Rect media_indicator_bounds_
;
367 gfx::Rect close_button_bounds_
;
371 static int tab_active_l_width_
;
372 static int tab_active_l_height_
;
373 static int tab_inactive_l_width_
;
374 static int tab_inactive_l_height_
;
376 static gfx::Font
* title_font_
;
377 static int title_font_height_
;
379 static int close_button_width_
;
380 static int close_button_height_
;
382 content::NotificationRegistrar registrar_
;
384 // The GtkDrawingArea we draw the tab on.
385 ui::OwnedWidgetGtk tab_
;
387 // Whether we're showing the icon. It is cached so that we can detect when it
388 // changes and layout appropriately.
391 // Whether we're showing the media indicator. It is cached so that we can
392 // detect when it changes and layout appropriately.
393 bool showing_media_indicator_
;
395 // Whether we are showing the close button. It is cached so that we can
396 // detect when it changes and layout appropriately.
397 bool showing_close_button_
;
399 // The offset used to animate the favicon location.
400 int favicon_hiding_offset_
;
402 // The animation object used to swap the favicon with the sad tab icon.
403 scoped_ptr
<FaviconCrashAnimation
> crash_animation_
;
405 // Set when the crashed favicon should be displayed.
406 bool should_display_crashed_favicon_
;
408 // The bounds of this Tab.
411 // The requested bounds of this tab. These bounds are relative to the
413 gfx::Rect requisition_
;
416 scoped_ptr
<gfx::SlideAnimation
> hover_animation_
;
418 // Animation used when the title of an inactive mini-tab changes.
419 scoped_ptr
<gfx::ThrobAnimation
> mini_title_animation_
;
421 // Media indicator fade-in/out animation (i.e., only on show/hide, not a
422 // continuous animation).
423 scoped_ptr
<gfx::Animation
> media_indicator_animation_
;
424 TabMediaState animating_media_state_
;
426 // Contains the loading animation state.
427 LoadingAnimation loading_animation_
;
429 // The offset used to paint the tab theme images.
430 int background_offset_x_
;
432 // The vertical offset used to paint the tab theme images. Controlled by the
433 // tabstrip and plumbed here to offset the theme image by the size of the
434 // alignment in the BrowserTitlebar.
435 int background_offset_y_
;
437 GtkThemeService
* theme_service_
;
440 scoped_ptr
<CustomDrawButton
> close_button_
;
442 // The current color of the close button.
443 SkColor close_button_color_
;
445 // Indicates whether this tab is the active one.
448 // Color of the title text on the selected tab.
449 SkColor selected_title_color_
;
451 // Color of the title text on an unselected tab.
452 SkColor unselected_title_color_
;
454 DISALLOW_COPY_AND_ASSIGN(TabRendererGtk
);
457 #endif // CHROME_BROWSER_UI_GTK_TABS_TAB_RENDERER_GTK_H_