OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 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 #pragma once |
| 8 |
| 9 #include <gtk/gtk.h> |
| 10 #include <map> |
| 11 |
| 12 #include "app/gtk_signal.h" |
| 13 #include "base/basictypes.h" |
| 14 #include "base/scoped_ptr.h" |
| 15 #include "base/string16.h" |
| 16 #include "chrome/browser/gtk/owned_widget_gtk.h" |
| 17 #include "chrome/common/notification_observer.h" |
| 18 #include "chrome/common/notification_registrar.h" |
| 19 #include "gfx/canvas.h" |
| 20 #include "gfx/font.h" |
| 21 #include "gfx/rect.h" |
| 22 #include "third_party/skia/include/core/SkBitmap.h" |
| 23 #include "ui/base/animation/animation_delegate.h" |
| 24 |
| 25 namespace gfx { |
| 26 class Size; |
| 27 } // namespace gfx |
| 28 |
| 29 class CustomDrawButton; |
| 30 class GtkThemeProvider; |
| 31 class TabContents; |
| 32 class ThemeProvider; |
| 33 |
| 34 namespace ui { |
| 35 class SlideAnimation; |
| 36 class ThrobAnimation; |
| 37 } |
| 38 |
| 39 class TabRendererGtk : public ui::AnimationDelegate, |
| 40 public NotificationObserver { |
| 41 public: |
| 42 // Possible animation states. |
| 43 enum AnimationState { |
| 44 ANIMATION_NONE, |
| 45 ANIMATION_WAITING, |
| 46 ANIMATION_LOADING |
| 47 }; |
| 48 |
| 49 class LoadingAnimation : public NotificationObserver { |
| 50 public: |
| 51 struct Data { |
| 52 explicit Data(ThemeProvider* theme_provider); |
| 53 Data(int loading, int waiting, int waiting_to_loading); |
| 54 |
| 55 SkBitmap* waiting_animation_frames; |
| 56 SkBitmap* loading_animation_frames; |
| 57 int loading_animation_frame_count; |
| 58 int waiting_animation_frame_count; |
| 59 int waiting_to_loading_frame_count_ratio; |
| 60 }; |
| 61 |
| 62 explicit LoadingAnimation(ThemeProvider* theme_provider); |
| 63 |
| 64 // Used in unit tests to inject specific data. |
| 65 explicit LoadingAnimation(const LoadingAnimation::Data& data); |
| 66 |
| 67 virtual ~LoadingAnimation(); |
| 68 |
| 69 // Advance the loading animation to the next frame, or hide the animation if |
| 70 // the tab isn't loading. Returns |true| if the icon area needs to be |
| 71 // repainted. |
| 72 bool ValidateLoadingAnimation(AnimationState animation_state); |
| 73 |
| 74 AnimationState animation_state() const { return animation_state_; } |
| 75 int animation_frame() const { return animation_frame_; } |
| 76 |
| 77 const SkBitmap* waiting_animation_frames() const { |
| 78 return data_->waiting_animation_frames; |
| 79 } |
| 80 const SkBitmap* loading_animation_frames() const { |
| 81 return data_->loading_animation_frames; |
| 82 } |
| 83 |
| 84 // Provide NotificationObserver implementation. |
| 85 virtual void Observe(NotificationType type, |
| 86 const NotificationSource& source, |
| 87 const NotificationDetails& details); |
| 88 |
| 89 private: |
| 90 scoped_ptr<Data> data_; |
| 91 |
| 92 // Used to listen for theme change notifications. |
| 93 NotificationRegistrar registrar_; |
| 94 |
| 95 // Gives us our throbber images. |
| 96 ThemeProvider* theme_provider_; |
| 97 |
| 98 // Current state of the animation. |
| 99 AnimationState animation_state_; |
| 100 |
| 101 // The current index into the Animation image strip. |
| 102 int animation_frame_; |
| 103 |
| 104 DISALLOW_COPY_AND_ASSIGN(LoadingAnimation); |
| 105 }; |
| 106 |
| 107 explicit TabRendererGtk(ThemeProvider* theme_provider); |
| 108 virtual ~TabRendererGtk(); |
| 109 |
| 110 // TabContents. If only the loading state was updated, the loading_only flag |
| 111 // should be specified. If other things change, set this flag to false to |
| 112 // update everything. |
| 113 virtual void UpdateData(TabContents* contents, bool app, bool loading_only); |
| 114 |
| 115 // Sets the blocked state of the tab. |
| 116 void SetBlocked(bool pinned); |
| 117 bool is_blocked() const; |
| 118 |
| 119 // Sets the mini-state of the tab. |
| 120 void set_mini(bool mini) { data_.mini = mini; } |
| 121 bool mini() const { return data_.mini; } |
| 122 |
| 123 // Sets the app state of the tab. |
| 124 void set_app(bool app) { data_.app = app; } |
| 125 bool app() const { return data_.app; } |
| 126 |
| 127 // Are we in the process of animating a mini tab state change on this tab? |
| 128 void set_animating_mini_change(bool value) { |
| 129 data_.animating_mini_change = value; |
| 130 } |
| 131 |
| 132 // Updates the display to reflect the contents of this TabRenderer's model. |
| 133 void UpdateFromModel(); |
| 134 |
| 135 // Returns true if the Tab is selected, false otherwise. |
| 136 virtual bool IsSelected() const; |
| 137 |
| 138 // Returns true if the Tab is visible, false otherwise. |
| 139 virtual bool IsVisible() const; |
| 140 |
| 141 // Sets the visibility of the Tab. |
| 142 virtual void SetVisible(bool visible) const; |
| 143 |
| 144 // Paints the tab into |canvas|. |
| 145 virtual void Paint(gfx::Canvas* canvas); |
| 146 |
| 147 // Paints the tab into a SkBitmap. |
| 148 virtual SkBitmap PaintBitmap(); |
| 149 |
| 150 // Paints the tab, and keeps the result server-side. The returned surface must |
| 151 // be freed with cairo_surface_destroy(). |
| 152 virtual cairo_surface_t* PaintToSurface(); |
| 153 |
| 154 // There is no PaintNow available, so the fastest we can do is schedule a |
| 155 // paint with the windowing system. |
| 156 virtual void SchedulePaint(); |
| 157 |
| 158 // Notifies the Tab that the close button has been clicked. |
| 159 virtual void CloseButtonClicked(); |
| 160 |
| 161 // Sets the bounds of the tab. |
| 162 virtual void SetBounds(const gfx::Rect& bounds); |
| 163 |
| 164 // Provide NotificationObserver implementation. |
| 165 virtual void Observe(NotificationType type, |
| 166 const NotificationSource& source, |
| 167 const NotificationDetails& details); |
| 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(GdkEventExpose* event); |
| 176 |
| 177 // Returns whether the Tab should display a favicon. |
| 178 bool ShouldShowIcon() const; |
| 179 |
| 180 // Returns the minimum possible size of a single unselected Tab. |
| 181 static gfx::Size GetMinimumUnselectedSize(); |
| 182 // Returns the minimum possible size of a selected Tab. Selected tabs must |
| 183 // always show a close button and have a larger minimum size than unselected |
| 184 // tabs. |
| 185 static gfx::Size GetMinimumSelectedSize(); |
| 186 // Returns the preferred size of a single Tab, assuming space is |
| 187 // available. |
| 188 static gfx::Size GetStandardSize(); |
| 189 |
| 190 // Returns the width for mini-tabs. Mini-tabs always have this width. |
| 191 static int GetMiniWidth(); |
| 192 |
| 193 // Loads the images to be used for the tab background. |
| 194 static void LoadTabImages(); |
| 195 |
| 196 // Sets the colors used for painting text on the tabs. |
| 197 static void SetSelectedTitleColor(SkColor color); |
| 198 static void SetUnselectedTitleColor(SkColor color); |
| 199 |
| 200 static gfx::Font* title_font() { return title_font_; } |
| 201 |
| 202 // Returns the bounds of the Tab. |
| 203 int x() const { return bounds_.x(); } |
| 204 int y() const { return bounds_.y(); } |
| 205 int width() const { return bounds_.width(); } |
| 206 int height() const { return bounds_.height(); } |
| 207 |
| 208 gfx::Rect bounds() const { return bounds_; } |
| 209 |
| 210 gfx::Rect favicon_bounds() const { return favicon_bounds_; } |
| 211 |
| 212 // Returns the non-mirrored (LTR) bounds of this tab. |
| 213 gfx::Rect GetNonMirroredBounds(GtkWidget* parent) const; |
| 214 |
| 215 // Returns the requested bounds of the tab. |
| 216 gfx::Rect GetRequisition() const; |
| 217 |
| 218 GtkWidget* widget() const { return tab_.get(); } |
| 219 |
| 220 // Start/stop the mini-tab title animation. |
| 221 void StartMiniTabTitleAnimation(); |
| 222 void StopMiniTabTitleAnimation(); |
| 223 |
| 224 void set_vertical_offset(int offset) { background_offset_y_ = offset; } |
| 225 |
| 226 protected: |
| 227 const gfx::Rect& title_bounds() const { return title_bounds_; } |
| 228 const gfx::Rect& close_button_bounds() const { return close_button_bounds_; } |
| 229 |
| 230 // Returns the title of the Tab. |
| 231 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 // The data structure used to hold cached bitmaps. We need to manually free |
| 245 // the bitmap in CachedBitmap when we remove it from |cached_bitmaps_|. We |
| 246 // handle this when we replace images in the map and in the destructor. |
| 247 struct CachedBitmap { |
| 248 int bg_offset_x; |
| 249 int bg_offset_y; |
| 250 SkBitmap* bitmap; |
| 251 }; |
| 252 typedef std::map<std::pair<const SkBitmap*, const SkBitmap*>, CachedBitmap> |
| 253 BitmapCache; |
| 254 |
| 255 // Model data. We store this here so that we don't need to ask the underlying |
| 256 // model, which is tricky since instances of this object can outlive the |
| 257 // corresponding objects in the underlying model. |
| 258 struct TabData { |
| 259 TabData() |
| 260 : is_default_favicon(false), |
| 261 loading(false), |
| 262 crashed(false), |
| 263 off_the_record(false), |
| 264 show_icon(true), |
| 265 mini(false), |
| 266 blocked(false), |
| 267 animating_mini_change(false), |
| 268 app(false) { |
| 269 } |
| 270 |
| 271 SkBitmap favicon; |
| 272 bool is_default_favicon; |
| 273 string16 title; |
| 274 bool loading; |
| 275 bool crashed; |
| 276 bool off_the_record; |
| 277 bool show_icon; |
| 278 bool mini; |
| 279 bool blocked; |
| 280 bool animating_mini_change; |
| 281 bool app; |
| 282 }; |
| 283 |
| 284 // TODO(jhawkins): Move into TabResources class. |
| 285 struct TabImage { |
| 286 SkBitmap* image_l; |
| 287 SkBitmap* image_c; |
| 288 SkBitmap* image_r; |
| 289 int l_width; |
| 290 int r_width; |
| 291 int y_offset; |
| 292 }; |
| 293 |
| 294 // Overridden from ui::AnimationDelegate: |
| 295 virtual void AnimationProgressed(const ui::Animation* animation); |
| 296 virtual void AnimationCanceled(const ui::Animation* animation); |
| 297 virtual void AnimationEnded(const ui::Animation* animation); |
| 298 |
| 299 // Starts/Stops the crash animation. |
| 300 void StartCrashAnimation(); |
| 301 void StopCrashAnimation(); |
| 302 |
| 303 // Return true if the crash animation is currently running. |
| 304 bool IsPerformingCrashAnimation() const; |
| 305 |
| 306 // Set the temporary offset for the favicon. This is used during animation. |
| 307 void SetFavIconHidingOffset(int offset); |
| 308 |
| 309 void DisplayCrashedFavIcon(); |
| 310 void ResetCrashedFavIcon(); |
| 311 |
| 312 // Generates the bounds for the interior items of the tab. |
| 313 void Layout(); |
| 314 |
| 315 // Returns the local bounds of the tab. This returns the rect |
| 316 // {0, 0, width(), height()} for now, as we don't yet support borders. |
| 317 gfx::Rect GetLocalBounds(); |
| 318 |
| 319 // Moves the close button widget within the GtkFixed container. |
| 320 void MoveCloseButtonWidget(); |
| 321 |
| 322 // Returns the largest of the favicon, title text, and the close button. |
| 323 static int GetContentHeight(); |
| 324 |
| 325 // A helper method for generating the masked bitmaps used to draw the curved |
| 326 // edges of tabs. We cache the generated bitmaps because they can take a |
| 327 // long time to compute. |
| 328 SkBitmap* GetMaskedBitmap(const SkBitmap* mask, |
| 329 const SkBitmap* background, |
| 330 int bg_offset_x, |
| 331 int bg_offset_y); |
| 332 BitmapCache cached_bitmaps_; |
| 333 |
| 334 // Paints the tab, minus the close button. |
| 335 void PaintTab(GdkEventExpose* event); |
| 336 |
| 337 // Paint various portions of the Tab |
| 338 void PaintTitle(gfx::Canvas* canvas); |
| 339 void PaintIcon(gfx::Canvas* canvas); |
| 340 void PaintTabBackground(gfx::Canvas* canvas); |
| 341 void PaintInactiveTabBackground(gfx::Canvas* canvas); |
| 342 void PaintActiveTabBackground(gfx::Canvas* canvas); |
| 343 void PaintLoadingAnimation(gfx::Canvas* canvas); |
| 344 |
| 345 // Returns the number of favicon-size elements that can fit in the tab's |
| 346 // current size. |
| 347 int IconCapacity() const; |
| 348 |
| 349 |
| 350 // Returns whether the Tab should display a close button. |
| 351 bool ShouldShowCloseBox() const; |
| 352 |
| 353 CustomDrawButton* MakeCloseButton(); |
| 354 |
| 355 // Gets the throb value for the tab. When a tab is not selected the |
| 356 // active background is drawn at |GetThrobValue()|%. This is used for hover |
| 357 // and mini-tab title change effects. |
| 358 double GetThrobValue(); |
| 359 |
| 360 // Handles the clicked signal for the close button. |
| 361 CHROMEGTK_CALLBACK_0(TabRendererGtk, void, OnCloseButtonClicked); |
| 362 |
| 363 // Handles middle clicking the close button. |
| 364 CHROMEGTK_CALLBACK_1(TabRendererGtk, gboolean, OnCloseButtonMouseRelease, |
| 365 GdkEventButton*); |
| 366 |
| 367 // expose-event handler that redraws the tab. |
| 368 CHROMEGTK_CALLBACK_1(TabRendererGtk, gboolean, OnExposeEvent, |
| 369 GdkEventExpose*); |
| 370 |
| 371 // size-allocate handler used to update the current bounds of the tab. |
| 372 CHROMEGTK_CALLBACK_1(TabRendererGtk, void, OnSizeAllocate, GtkAllocation*); |
| 373 |
| 374 // TODO(jhawkins): Move to TabResources. |
| 375 static void InitResources(); |
| 376 static bool initialized_; |
| 377 |
| 378 // The bounds of various sections of the display. |
| 379 gfx::Rect favicon_bounds_; |
| 380 gfx::Rect title_bounds_; |
| 381 gfx::Rect close_button_bounds_; |
| 382 |
| 383 TabData data_; |
| 384 |
| 385 static TabImage tab_active_; |
| 386 static TabImage tab_inactive_; |
| 387 static TabImage tab_alpha_; |
| 388 |
| 389 static gfx::Font* title_font_; |
| 390 static int title_font_height_; |
| 391 |
| 392 static int close_button_width_; |
| 393 static int close_button_height_; |
| 394 |
| 395 static SkColor selected_title_color_; |
| 396 static SkColor unselected_title_color_; |
| 397 |
| 398 // The GtkDrawingArea we draw the tab on. |
| 399 OwnedWidgetGtk tab_; |
| 400 |
| 401 // Whether we're showing the icon. It is cached so that we can detect when it |
| 402 // changes and layout appropriately. |
| 403 bool showing_icon_; |
| 404 |
| 405 // Whether we are showing the close button. It is cached so that we can |
| 406 // detect when it changes and layout appropriately. |
| 407 bool showing_close_button_; |
| 408 |
| 409 // The offset used to animate the favicon location. |
| 410 int fav_icon_hiding_offset_; |
| 411 |
| 412 // The animation object used to swap the favicon with the sad tab icon. |
| 413 scoped_ptr<FavIconCrashAnimation> crash_animation_; |
| 414 |
| 415 // Set when the crashed favicon should be displayed. |
| 416 bool should_display_crashed_favicon_; |
| 417 |
| 418 // The bounds of this Tab. |
| 419 gfx::Rect bounds_; |
| 420 |
| 421 // The requested bounds of this tab. These bounds are relative to the |
| 422 // tabstrip. |
| 423 gfx::Rect requisition_; |
| 424 |
| 425 // Hover animation. |
| 426 scoped_ptr<ui::SlideAnimation> hover_animation_; |
| 427 |
| 428 // Animation used when the title of an inactive mini-tab changes. |
| 429 scoped_ptr<ui::ThrobAnimation> mini_title_animation_; |
| 430 |
| 431 // Contains the loading animation state. |
| 432 LoadingAnimation loading_animation_; |
| 433 |
| 434 // The offset used to paint the tab theme images. |
| 435 int background_offset_x_; |
| 436 |
| 437 // The vertical offset used to paint the tab theme images. Controlled by the |
| 438 // tabstrip and plumbed here to offset the theme image by the size of the |
| 439 // alignment in the BrowserTitlebar. |
| 440 int background_offset_y_; |
| 441 |
| 442 GtkThemeProvider* theme_provider_; |
| 443 |
| 444 // The close button. |
| 445 scoped_ptr<CustomDrawButton> close_button_; |
| 446 |
| 447 // The current color of the close button. |
| 448 SkColor close_button_color_; |
| 449 |
| 450 // Used to listen for theme change notifications. |
| 451 NotificationRegistrar registrar_; |
| 452 |
| 453 DISALLOW_COPY_AND_ASSIGN(TabRendererGtk); |
| 454 }; |
| 455 |
| 456 #endif // CHROME_BROWSER_UI_GTK_TABS_TAB_RENDERER_GTK_H_ |
OLD | NEW |