| OLD | NEW |
| (Empty) |
| 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 "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" | |
| 26 | |
| 27 namespace gfx { | |
| 28 class CairoCachedSurface; | |
| 29 class Image; | |
| 30 class Size; | |
| 31 class SlideAnimation; | |
| 32 class ThrobAnimation; | |
| 33 } // namespace gfx | |
| 34 | |
| 35 class CustomDrawButton; | |
| 36 class GtkThemeService; | |
| 37 | |
| 38 namespace content { | |
| 39 class WebContents; | |
| 40 } | |
| 41 | |
| 42 class TabRendererGtk : public gfx::AnimationDelegate, | |
| 43 public content::NotificationObserver { | |
| 44 public: | |
| 45 // Possible animation states. | |
| 46 enum AnimationState { | |
| 47 ANIMATION_NONE, | |
| 48 ANIMATION_WAITING, | |
| 49 ANIMATION_LOADING | |
| 50 }; | |
| 51 | |
| 52 class LoadingAnimation : public content::NotificationObserver { | |
| 53 public: | |
| 54 struct Data { | |
| 55 explicit Data(GtkThemeService* theme_service); | |
| 56 Data(int loading, int waiting, int waiting_to_loading); | |
| 57 | |
| 58 int loading_animation_frame_count; | |
| 59 int waiting_animation_frame_count; | |
| 60 int waiting_to_loading_frame_count_ratio; | |
| 61 }; | |
| 62 | |
| 63 explicit LoadingAnimation(GtkThemeService* theme_service); | |
| 64 | |
| 65 // Used in unit tests to inject specific data. | |
| 66 explicit LoadingAnimation(const LoadingAnimation::Data& data); | |
| 67 | |
| 68 virtual ~LoadingAnimation(); | |
| 69 | |
| 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 | |
| 72 // repainted. | |
| 73 bool ValidateLoadingAnimation(AnimationState animation_state); | |
| 74 | |
| 75 AnimationState animation_state() const { return animation_state_; } | |
| 76 int animation_frame() const { return animation_frame_; } | |
| 77 | |
| 78 // Provide content::NotificationObserver implementation. | |
| 79 virtual void Observe(int type, | |
| 80 const content::NotificationSource& source, | |
| 81 const content::NotificationDetails& details) OVERRIDE; | |
| 82 | |
| 83 private: | |
| 84 scoped_ptr<Data> data_; | |
| 85 | |
| 86 // Used to listen for theme change notifications. | |
| 87 content::NotificationRegistrar registrar_; | |
| 88 | |
| 89 // Gives us our throbber images. | |
| 90 GtkThemeService* theme_service_; | |
| 91 | |
| 92 // Current state of the animation. | |
| 93 AnimationState animation_state_; | |
| 94 | |
| 95 // The current index into the Animation image strip. | |
| 96 int animation_frame_; | |
| 97 | |
| 98 DISALLOW_COPY_AND_ASSIGN(LoadingAnimation); | |
| 99 }; | |
| 100 | |
| 101 explicit TabRendererGtk(GtkThemeService* theme_service); | |
| 102 virtual ~TabRendererGtk(); | |
| 103 | |
| 104 // Provide content::NotificationObserver implementation. | |
| 105 virtual void Observe(int type, | |
| 106 const content::NotificationSource& source, | |
| 107 const content::NotificationDetails& details) OVERRIDE; | |
| 108 | |
| 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, | |
| 113 bool app, | |
| 114 bool loading_only); | |
| 115 | |
| 116 // Sets the blocked state of the tab. | |
| 117 void SetBlocked(bool pinned); | |
| 118 bool is_blocked() const; | |
| 119 | |
| 120 // Sets the mini-state of the tab. | |
| 121 void set_mini(bool mini) { data_.mini = mini; } | |
| 122 bool mini() const { return data_.mini; } | |
| 123 | |
| 124 // Sets the app state of the tab. | |
| 125 void set_app(bool app) { data_.app = app; } | |
| 126 bool app() const { return data_.app; } | |
| 127 | |
| 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; | |
| 131 } | |
| 132 | |
| 133 // Updates the display to reflect the contents of this TabRenderer's model. | |
| 134 void UpdateFromModel(); | |
| 135 | |
| 136 // Returns true if the Tab is active, false otherwise. | |
| 137 virtual bool IsActive() const; | |
| 138 | |
| 139 // Set |is_active_| property of this tab. | |
| 140 void set_is_active(bool is_active) { is_active_ = is_active; } | |
| 141 | |
| 142 // Returns true if the Tab is selected, false otherwise. | |
| 143 virtual bool IsSelected() const; | |
| 144 | |
| 145 // Returns true if the Tab is visible, false otherwise. | |
| 146 virtual bool IsVisible() const; | |
| 147 | |
| 148 // Sets the visibility of the Tab. | |
| 149 virtual void SetVisible(bool visible) const; | |
| 150 | |
| 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); | |
| 154 | |
| 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); | |
| 158 | |
| 159 // There is no PaintNow available, so the fastest we can do is schedule a | |
| 160 // paint with the windowing system. | |
| 161 void SchedulePaint(); | |
| 162 | |
| 163 // Notifies the Tab that the close button has been clicked. | |
| 164 virtual void CloseButtonClicked(); | |
| 165 | |
| 166 // Sets the bounds of the tab. | |
| 167 virtual void SetBounds(const gfx::Rect& bounds); | |
| 168 | |
| 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 | |
| 171 // repainted. | |
| 172 bool ValidateLoadingAnimation(AnimationState animation_state); | |
| 173 | |
| 174 // Repaint only the area of the tab that contains the favicon. | |
| 175 void PaintFaviconArea(GtkWidget* widget, cairo_t* cr); | |
| 176 | |
| 177 // Returns whether the Tab should display a favicon. | |
| 178 bool ShouldShowIcon() const; | |
| 179 | |
| 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; | |
| 183 | |
| 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 | |
| 188 // tabs. | |
| 189 static gfx::Size GetMinimumSelectedSize(); | |
| 190 // Returns the preferred size of a single Tab, assuming space is | |
| 191 // available. | |
| 192 static gfx::Size GetStandardSize(); | |
| 193 | |
| 194 // Returns the width for mini-tabs. Mini-tabs always have this width. | |
| 195 static int GetMiniWidth(); | |
| 196 | |
| 197 static gfx::Font* title_font() { return title_font_; } | |
| 198 | |
| 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(); } | |
| 204 | |
| 205 gfx::Rect bounds() const { return bounds_; } | |
| 206 | |
| 207 gfx::Rect favicon_bounds() const { return favicon_bounds_; } | |
| 208 | |
| 209 // Returns the non-mirrored (LTR) bounds of this tab. | |
| 210 gfx::Rect GetNonMirroredBounds(GtkWidget* parent) const; | |
| 211 | |
| 212 // Returns the requested bounds of the tab. | |
| 213 gfx::Rect GetRequisition() const; | |
| 214 | |
| 215 GtkWidget* widget() const { return tab_.get(); } | |
| 216 | |
| 217 // Start/stop the mini-tab title animation. | |
| 218 void StartMiniTabTitleAnimation(); | |
| 219 void StopMiniTabTitleAnimation(); | |
| 220 | |
| 221 void set_vertical_offset(int offset) { background_offset_y_ = offset; } | |
| 222 | |
| 223 protected: | |
| 224 const gfx::Rect& title_bounds() const { return title_bounds_; } | |
| 225 const gfx::Rect& close_button_bounds() const { return close_button_bounds_; } | |
| 226 | |
| 227 // Raise button to top of Z-order. | |
| 228 void Raise() const; | |
| 229 | |
| 230 // Returns the title of the Tab. | |
| 231 base::string16 GetTitle() const; | |
| 232 | |
| 233 // enter-notify-event handler that signals when the mouse enters the tab. | |
| 234 CHROMEGTK_CALLBACK_1(TabRendererGtk, gboolean, OnEnterNotifyEvent, | |
| 235 GdkEventCrossing*); | |
| 236 | |
| 237 // leave-notify-event handler that signals when the mouse enters the tab. | |
| 238 CHROMEGTK_CALLBACK_1(TabRendererGtk, gboolean, OnLeaveNotifyEvent, | |
| 239 GdkEventCrossing*); | |
| 240 | |
| 241 private: | |
| 242 class FaviconCrashAnimation; | |
| 243 | |
| 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. | |
| 247 struct TabData { | |
| 248 TabData(); | |
| 249 ~TabData(); | |
| 250 | |
| 251 SkBitmap favicon; | |
| 252 gfx::CairoCachedSurface cairo_favicon; | |
| 253 bool is_default_favicon; | |
| 254 base::string16 title; | |
| 255 bool loading; | |
| 256 bool crashed; | |
| 257 bool incognito; | |
| 258 bool show_icon; | |
| 259 bool mini; | |
| 260 bool blocked; | |
| 261 bool animating_mini_change; | |
| 262 bool app; | |
| 263 TabMediaState media_state; | |
| 264 TabMediaState previous_media_state; | |
| 265 }; | |
| 266 | |
| 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; | |
| 271 | |
| 272 // Starts/Stops the crash animation. | |
| 273 void StartCrashAnimation(); | |
| 274 void StopCrashAnimation(); | |
| 275 | |
| 276 // Return true if the crash animation is currently running. | |
| 277 bool IsPerformingCrashAnimation() const; | |
| 278 | |
| 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(); | |
| 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 // Generates the bounds for the interior items of the tab. | |
| 290 void Layout(); | |
| 291 | |
| 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(); | |
| 295 | |
| 296 // Moves the close button widget within the GtkFixed container. | |
| 297 void MoveCloseButtonWidget(); | |
| 298 | |
| 299 // Returns the largest of the favicon, title text, and the close button. | |
| 300 static int GetContentHeight(); | |
| 301 | |
| 302 void PaintTab(GtkWidget* widget, GdkEventExpose* event); | |
| 303 | |
| 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); | |
| 312 | |
| 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, | |
| 316 GtkWidget* widget, | |
| 317 const gfx::Image& tab_bg, | |
| 318 int offset_x, | |
| 319 int offset_y); | |
| 320 | |
| 321 // Draws the tab shadow using the given idr resources onto |cr|. | |
| 322 void DrawTabShadow(cairo_t* cr, | |
| 323 GtkWidget* widget, | |
| 324 int left_idr, | |
| 325 int center_idr, | |
| 326 int right_idr); | |
| 327 | |
| 328 // Returns the number of favicon-size elements that can fit in the tab's | |
| 329 // current size. | |
| 330 int IconCapacity() const; | |
| 331 | |
| 332 // Returns whether the Tab should display the media indicator. | |
| 333 bool ShouldShowMediaIndicator() 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 media_indicator_bounds_; | |
| 367 gfx::Rect close_button_bounds_; | |
| 368 | |
| 369 TabData data_; | |
| 370 | |
| 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_; | |
| 375 | |
| 376 static gfx::Font* title_font_; | |
| 377 static int title_font_height_; | |
| 378 | |
| 379 static int close_button_width_; | |
| 380 static int close_button_height_; | |
| 381 | |
| 382 content::NotificationRegistrar registrar_; | |
| 383 | |
| 384 // The GtkDrawingArea we draw the tab on. | |
| 385 ui::OwnedWidgetGtk tab_; | |
| 386 | |
| 387 // Whether we're showing the icon. It is cached so that we can detect when it | |
| 388 // changes and layout appropriately. | |
| 389 bool showing_icon_; | |
| 390 | |
| 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_; | |
| 394 | |
| 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_; | |
| 398 | |
| 399 // The offset used to animate the favicon location. | |
| 400 int favicon_hiding_offset_; | |
| 401 | |
| 402 // The animation object used to swap the favicon with the sad tab icon. | |
| 403 scoped_ptr<FaviconCrashAnimation> crash_animation_; | |
| 404 | |
| 405 // Set when the crashed favicon should be displayed. | |
| 406 bool should_display_crashed_favicon_; | |
| 407 | |
| 408 // The bounds of this Tab. | |
| 409 gfx::Rect bounds_; | |
| 410 | |
| 411 // The requested bounds of this tab. These bounds are relative to the | |
| 412 // tabstrip. | |
| 413 gfx::Rect requisition_; | |
| 414 | |
| 415 // Hover animation. | |
| 416 scoped_ptr<gfx::SlideAnimation> hover_animation_; | |
| 417 | |
| 418 // Animation used when the title of an inactive mini-tab changes. | |
| 419 scoped_ptr<gfx::ThrobAnimation> mini_title_animation_; | |
| 420 | |
| 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_; | |
| 425 | |
| 426 // Contains the loading animation state. | |
| 427 LoadingAnimation loading_animation_; | |
| 428 | |
| 429 // The offset used to paint the tab theme images. | |
| 430 int background_offset_x_; | |
| 431 | |
| 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_; | |
| 436 | |
| 437 GtkThemeService* theme_service_; | |
| 438 | |
| 439 // The close button. | |
| 440 scoped_ptr<CustomDrawButton> close_button_; | |
| 441 | |
| 442 // The current color of the close button. | |
| 443 SkColor close_button_color_; | |
| 444 | |
| 445 // Indicates whether this tab is the active one. | |
| 446 bool is_active_; | |
| 447 | |
| 448 // Color of the title text on the selected tab. | |
| 449 SkColor selected_title_color_; | |
| 450 | |
| 451 // Color of the title text on an unselected tab. | |
| 452 SkColor unselected_title_color_; | |
| 453 | |
| 454 DISALLOW_COPY_AND_ASSIGN(TabRendererGtk); | |
| 455 }; | |
| 456 | |
| 457 #endif // CHROME_BROWSER_UI_GTK_TABS_TAB_RENDERER_GTK_H_ | |
| OLD | NEW |