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. 4 5#ifndef CHROME_BROWSER_UI_GTK_TABS_TAB_RENDERER_GTK_H_ 6#define CHROME_BROWSER_UI_GTK_TABS_TAB_RENDERER_GTK_H_ 7 8#include <gtk/gtk.h> 9#include <map> 10 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 "content/public/browser/notification_observer.h" 16#include "content/public/browser/notification_registrar.h" 17#include "third_party/skia/include/core/SkBitmap.h" 18#include "ui/base/animation/animation_delegate.h" 19#include "ui/base/gtk/gtk_signal.h" 20#include "ui/base/gtk/owned_widget_gtk.h" 21#include "ui/gfx/canvas.h" 22#include "ui/gfx/font.h" 23#include "ui/gfx/image/cairo_cached_surface.h" 24#include "ui/gfx/rect.h" 25 26namespace gfx { 27class CairoCachedSurface; 28class Image; 29class Size; 30} // namespace gfx 31 32class CustomDrawButton; 33class GtkThemeService; 34 35namespace content { 36class WebContents; 37} 38 39namespace ui { 40class SlideAnimation; 41class ThrobAnimation; 42} 43 44class TabRendererGtk : public ui::AnimationDelegate, 45 public content::NotificationObserver { 46 public: 47 // Possible animation states. 48 enum AnimationState { 49 ANIMATION_NONE, 50 ANIMATION_WAITING, 51 ANIMATION_LOADING 52 }; 53 54 class LoadingAnimation : public content::NotificationObserver { 55 public: 56 struct Data { 57 explicit Data(GtkThemeService* theme_service); 58 Data(int loading, int waiting, int waiting_to_loading); 59 60 int loading_animation_frame_count; 61 int waiting_animation_frame_count; 62 int waiting_to_loading_frame_count_ratio; 63 }; 64 65 explicit LoadingAnimation(GtkThemeService* theme_service); 66 67 // Used in unit tests to inject specific data. 68 explicit LoadingAnimation(const LoadingAnimation::Data& data); 69 70 virtual ~LoadingAnimation(); 71 72 // Advance the loading animation to the next frame, or hide the animation if 73 // the tab isn't loading. Returns |true| if the icon area needs to be 74 // repainted. 75 bool ValidateLoadingAnimation(AnimationState animation_state); 76 77 AnimationState animation_state() const { return animation_state_; } 78 int animation_frame() const { return animation_frame_; } 79 80 // Provide content::NotificationObserver implementation. 81 virtual void Observe(int type, 82 const content::NotificationSource& source, 83 const content::NotificationDetails& details) OVERRIDE; 84 85 private: 86 scoped_ptr<Data> data_; 87 88 // Used to listen for theme change notifications. 89 content::NotificationRegistrar registrar_; 90 91 // Gives us our throbber images. 92 GtkThemeService* theme_service_; 93 94 // Current state of the animation. 95 AnimationState animation_state_; 96 97 // The current index into the Animation image strip. 98 int animation_frame_; 99 100 DISALLOW_COPY_AND_ASSIGN(LoadingAnimation); 101 }; 102 103 explicit TabRendererGtk(GtkThemeService* theme_service); 104 virtual ~TabRendererGtk(); 105 106 // Provide content::NotificationObserver implementation. 107 virtual void Observe(int type, 108 const content::NotificationSource& source, 109 const content::NotificationDetails& details) OVERRIDE; 110 111 // WebContents. If only the loading state was updated, the loading_only flag 112 // should be specified. If other things change, set this flag to false to 113 // update everything. 114 virtual void UpdateData(content::WebContents* contents, 115 bool app, 116 bool loading_only); 117 118 // Sets the blocked state of the tab. 119 void SetBlocked(bool pinned); 120 bool is_blocked() const; 121 122 // Sets the mini-state of the tab. 123 void set_mini(bool mini) { data_.mini = mini; } 124 bool mini() const { return data_.mini; } 125 126 // Sets the app state of the tab. 127 void set_app(bool app) { data_.app = app; } 128 bool app() const { return data_.app; } 129 130 // Are we in the process of animating a mini tab state change on this tab? 131 void set_animating_mini_change(bool value) { 132 data_.animating_mini_change = value; 133 } 134 135 // Updates the display to reflect the contents of this TabRenderer's model. 136 void UpdateFromModel(); 137 138 // Returns true if the Tab is active, false otherwise. 139 virtual bool IsActive() const; 140 141 // Set |is_active_| property of this tab. 142 void set_is_active(bool is_active) { is_active_ = is_active; } 143 144 // Returns true if the Tab is selected, false otherwise. 145 virtual bool IsSelected() const; 146 147 // Returns true if the Tab is visible, false otherwise. 148 virtual bool IsVisible() const; 149 150 // Sets the visibility of the Tab. 151 virtual void SetVisible(bool visible) const; 152 153 // Paints the tab using resources from the display that |widget| is on, 154 // drawing into |cr|. 155 void Paint(GtkWidget* widget, cairo_t* cr); 156 157 // Paints the tab, and keeps the result server-side. The returned surface must 158 // be freed with cairo_surface_destroy(). 159 cairo_surface_t* PaintToSurface(GtkWidget* widget, cairo_t* cr); 160 161 // There is no PaintNow available, so the fastest we can do is schedule a 162 // paint with the windowing system. 163 void SchedulePaint(); 164 165 // Notifies the Tab that the close button has been clicked. 166 virtual void CloseButtonClicked(); 167 168 // Sets the bounds of the tab. 169 virtual void SetBounds(const gfx::Rect& bounds); 170 171 // Advance the loading animation to the next frame, or hide the animation if 172 // the tab isn't loading. Returns |true| if the icon area needs to be 173 // repainted. 174 bool ValidateLoadingAnimation(AnimationState animation_state); 175 176 // Repaint only the area of the tab that contains the favicon. 177 void PaintFaviconArea(GtkWidget* widget, cairo_t* cr); 178 179 // Returns whether the Tab should display a favicon. 180 bool ShouldShowIcon() const; 181 182 // Returns the minimum possible size of a single unselected Tab. 183 static gfx::Size GetMinimumUnselectedSize(); 184 // Returns the minimum possible size of a selected Tab. Selected tabs must 185 // always show a close button and have a larger minimum size than unselected 186 // tabs. 187 static gfx::Size GetMinimumSelectedSize(); 188 // Returns the preferred size of a single Tab, assuming space is 189 // available. 190 static gfx::Size GetStandardSize(); 191 192 // Returns the width for mini-tabs. Mini-tabs always have this width. 193 static int GetMiniWidth(); 194 195 static gfx::Font* title_font() { return title_font_; } 196 197 // Returns the bounds of the Tab. 198 int x() const { return bounds_.x(); } 199 int y() const { return bounds_.y(); } 200 int width() const { return bounds_.width(); } 201 int height() const { return bounds_.height(); } 202 203 gfx::Rect bounds() const { return bounds_; } 204 205 gfx::Rect favicon_bounds() const { return favicon_bounds_; } 206 207 // Returns the non-mirrored (LTR) bounds of this tab. 208 gfx::Rect GetNonMirroredBounds(GtkWidget* parent) const; 209 210 // Returns the requested bounds of the tab. 211 gfx::Rect GetRequisition() const; 212 213 GtkWidget* widget() const { return tab_.get(); } 214 215 // Start/stop the mini-tab title animation. 216 void StartMiniTabTitleAnimation(); 217 void StopMiniTabTitleAnimation(); 218 219 void set_vertical_offset(int offset) { background_offset_y_ = offset; } 220 221 protected: 222 const gfx::Rect& title_bounds() const { return title_bounds_; } 223 const gfx::Rect& close_button_bounds() const { return close_button_bounds_; } 224 225 // Raise button to top of Z-order. 226 void Raise() const; 227 228 // Returns the title of the Tab. 229 string16 GetTitle() const; 230 231 // enter-notify-event handler that signals when the mouse enters the tab. 232 CHROMEGTK_CALLBACK_1(TabRendererGtk, gboolean, OnEnterNotifyEvent, 233 GdkEventCrossing*); 234 235 // leave-notify-event handler that signals when the mouse enters the tab. 236 CHROMEGTK_CALLBACK_1(TabRendererGtk, gboolean, OnLeaveNotifyEvent, 237 GdkEventCrossing*); 238 239 private: 240 class FaviconCrashAnimation; 241 242 enum CaptureState { 243 NONE, 244 RECORDING, 245 PROJECTING 246 }; 247 248 // Model data. We store this here so that we don't need to ask the underlying 249 // model, which is tricky since instances of this object can outlive the 250 // corresponding objects in the underlying model. 251 struct TabData { 252 TabData(); 253 ~TabData(); 254 255 SkBitmap favicon; 256 gfx::CairoCachedSurface cairo_favicon; 257 gfx::CairoCachedSurface cairo_overlay; 258 bool is_default_favicon; 259 string16 title; 260 bool loading; 261 bool crashed; 262 bool incognito; 263 bool show_icon; 264 bool mini; 265 bool blocked; 266 bool animating_mini_change; 267 bool app; 268 CaptureState capture_state; 269 }; 270 271 // Overridden from ui::AnimationDelegate: 272 virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE; 273 virtual void AnimationCanceled(const ui::Animation* animation) OVERRIDE; 274 virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE; 275 276 // Starts/Stops the crash animation. 277 void StartCrashAnimation(); 278 void StopCrashAnimation(); 279 280 // Return true if the crash animation is currently running. 281 bool IsPerformingCrashAnimation() const; 282 283 // Set the temporary offset for the favicon. This is used during animation. 284 void SetFaviconHidingOffset(int offset); 285 286 void DisplayCrashedFavicon(); 287 void ResetCrashedFavicon(); 288 289 // Sets up an overlay for the favicon and starts a throbbing animation 290 // if this tab is currently capturing media. 291 void UpdateFaviconOverlay(content::WebContents* contents); 292 293 // Generates the bounds for the interior items of the tab. 294 void Layout(); 295 296 // Returns the local bounds of the tab. This returns the rect 297 // {0, 0, width(), height()} for now, as we don't yet support borders. 298 gfx::Rect GetLocalBounds(); 299 300 // Moves the close button widget within the GtkFixed container. 301 void MoveCloseButtonWidget(); 302 303 // Returns the largest of the favicon, title text, and the close button. 304 static int GetContentHeight(); 305 306 void PaintTab(GtkWidget* widget, GdkEventExpose* event); 307 308 // Paint various portions of the Tab 309 void PaintTitle(GtkWidget* widget, cairo_t* cr); 310 void PaintIcon(GtkWidget* widget, cairo_t* cr); 311 void PaintTabBackground(GtkWidget* widget, cairo_t* cr); 312 void PaintInactiveTabBackground(GtkWidget* widget, cairo_t* cr); 313 void PaintActiveTabBackground(GtkWidget* widget, cairo_t* cr); 314 void PaintLoadingAnimation(GtkWidget* widget, cairo_t* cairo); 315 316 // Draws the given |tab_bg| onto |cr| using the tab shape masks along the 317 // sides for the rounded tab shape. 318 void DrawTabBackground(cairo_t* cr, 319 GtkWidget* widget, 320 const gfx::Image& tab_bg, 321 int offset_x, 322 int offset_y); 323 324 // Draws the tab shadow using the given idr resources onto |cr|. 325 void DrawTabShadow(cairo_t* cr, 326 GtkWidget* widget, 327 int left_idr, 328 int center_idr, 329 int right_idr); 330 331 // Returns the number of favicon-size elements that can fit in the tab's 332 // current size. 333 int IconCapacity() const; 334 335 // Returns whether the Tab should display a close button. 336 bool ShouldShowCloseBox() const; 337 338 CustomDrawButton* MakeCloseButton(); 339 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(); 344 345 // Handles the clicked signal for the close button. 346 CHROMEGTK_CALLBACK_0(TabRendererGtk, void, OnCloseButtonClicked); 347 348 // Handles middle clicking the close button. 349 CHROMEGTK_CALLBACK_1(TabRendererGtk, gboolean, OnCloseButtonMouseRelease, 350 GdkEventButton*); 351 352 // expose-event handler that redraws the tab. 353 CHROMEGTK_CALLBACK_1(TabRendererGtk, gboolean, OnExposeEvent, 354 GdkEventExpose*); 355 356 // size-allocate handler used to update the current bounds of the tab. 357 CHROMEGTK_CALLBACK_1(TabRendererGtk, void, OnSizeAllocate, GtkAllocation*); 358 359 // TODO(jhawkins): Move to TabResources. 360 static void InitResources(); 361 static bool initialized_; 362 363 // The bounds of various sections of the display. 364 gfx::Rect favicon_bounds_; 365 gfx::Rect title_bounds_; 366 gfx::Rect close_button_bounds_; 367 368 TabData data_; 369 370 static int tab_active_l_width_; 371 static int tab_active_l_height_; 372 static int tab_inactive_l_width_; 373 static int tab_inactive_l_height_; 374 375 static gfx::Font* title_font_; 376 static int title_font_height_; 377 378 static int close_button_width_; 379 static int close_button_height_; 380 381 content::NotificationRegistrar registrar_; 382 383 // The GtkDrawingArea we draw the tab on. 384 ui::OwnedWidgetGtk tab_; 385 386 // Whether we're showing the icon. It is cached so that we can detect when it 387 // changes and layout appropriately. 388 bool showing_icon_; 389 390 // Whether we are showing the close button. It is cached so that we can 391 // detect when it changes and layout appropriately. 392 bool showing_close_button_; 393 394 // The offset used to animate the favicon location. 395 int favicon_hiding_offset_; 396 397 // The animation object used to swap the favicon with the sad tab icon. 398 scoped_ptr<FaviconCrashAnimation> crash_animation_; 399 400 // Set when the crashed favicon should be displayed. 401 bool should_display_crashed_favicon_; 402 403 // The bounds of this Tab. 404 gfx::Rect bounds_; 405 406 // The requested bounds of this tab. These bounds are relative to the 407 // tabstrip. 408 gfx::Rect requisition_; 409 410 // Hover animation. 411 scoped_ptr<ui::SlideAnimation> hover_animation_; 412 413 // Animation used when the title of an inactive mini-tab changes. 414 scoped_ptr<ui::ThrobAnimation> mini_title_animation_; 415 416 // Animation used when the favicon has an overlay (e.g. for recording). 417 scoped_ptr<ui::ThrobAnimation> favicon_overlay_animation_; 418 419 // Contains the loading animation state. 420 LoadingAnimation loading_animation_; 421 422 // The offset used to paint the tab theme images. 423 int background_offset_x_; 424 425 // The vertical offset used to paint the tab theme images. Controlled by the 426 // tabstrip and plumbed here to offset the theme image by the size of the 427 // alignment in the BrowserTitlebar. 428 int background_offset_y_; 429 430 GtkThemeService* theme_service_; 431 432 // The close button. 433 scoped_ptr<CustomDrawButton> close_button_; 434 435 // The current color of the close button. 436 SkColor close_button_color_; 437 438 // Indicates whether this tab is the active one. 439 bool is_active_; 440 441 // Color of the title text on the selected tab. 442 SkColor selected_title_color_; 443 444 // Color of the title text on an unselected tab. 445 SkColor unselected_title_color_; 446 447 DISALLOW_COPY_AND_ASSIGN(TabRendererGtk); 448}; 449 450#endif // CHROME_BROWSER_UI_GTK_TABS_TAB_RENDERER_GTK_H_ 451