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_VIEWS_TABS_TAB_H_ 6 #define CHROME_BROWSER_UI_VIEWS_TABS_TAB_H_ 7 8 #include <list> 9 #include <string> 10 11 #include "base/memory/ref_counted.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "chrome/browser/ui/views/tabs/tab_renderer_data.h" 14 #include "ui/base/layout.h" 15 #include "ui/gfx/animation/animation_delegate.h" 16 #include "ui/gfx/point.h" 17 #include "ui/views/context_menu_controller.h" 18 #include "ui/views/controls/button/button.h" 19 #include "ui/views/controls/glow_hover_controller.h" 20 #include "ui/views/view.h" 21 22 class TabController; 23 24 namespace gfx { 25 class Animation; 26 class AnimationContainer; 27 class LinearAnimation; 28 class MultiAnimation; 29 class ThrobAnimation; 30 } 31 namespace views { 32 class ImageButton; 33 class Label; 34 } 35 36 /////////////////////////////////////////////////////////////////////////////// 37 // 38 // A View that renders a Tab in a TabStrip. 39 // 40 /////////////////////////////////////////////////////////////////////////////// 41 class Tab : public gfx::AnimationDelegate, 42 public views::ButtonListener, 43 public views::ContextMenuController, 44 public views::View { 45 public: 46 // The menu button's class name. 47 static const char kViewClassName[]; 48 49 explicit Tab(TabController* controller); 50 virtual ~Tab(); 51 52 // Used to set/check whether this Tab is being animated closed. 53 void set_closing(bool closing) { closing_ = closing; } 54 bool closing() const { return closing_; } 55 56 // See description above field. 57 void set_dragging(bool dragging) { dragging_ = dragging; } 58 bool dragging() const { return dragging_; } 59 60 // Used to mark the tab as having been detached. Once this has happened, the 61 // tab should be invisibly closed. This is irreversible. 62 void set_detached() { detached_ = true; } 63 bool detached() const { return detached_; } 64 65 // Sets the container all animations run from. 66 void set_animation_container(gfx::AnimationContainer* container); 67 68 // Returns true if this tab is the active tab. 69 bool IsActive() const; 70 71 // Returns true if the tab is selected. 72 bool IsSelected() const; 73 74 // Sets the data this tabs displays. Invokes DataChanged. 75 void SetData(const TabRendererData& data); 76 const TabRendererData& data() const { return data_; } 77 78 // Sets the network state. If the network state changes NetworkStateChanged is 79 // invoked. 80 void UpdateLoadingAnimation(TabRendererData::NetworkState state); 81 82 // Starts/Stops a pulse animation. 83 void StartPulse(); 84 void StopPulse(); 85 86 // Start/stop the mini-tab title animation. 87 void StartMiniTabTitleAnimation(); 88 void StopMiniTabTitleAnimation(); 89 90 // Set the background offset used to match the image in the inactive tab 91 // to the frame image. 92 void set_background_offset(const gfx::Point& offset) { 93 background_offset_ = offset; 94 } 95 96 // Returns true if this tab became the active tab selected in 97 // response to the last ui::ET_GESTURE_BEGIN gesture dispatched to 98 // this tab. Only used for collecting UMA metrics. 99 // See ash/touch/touch_uma.cc. 100 bool tab_activated_with_last_gesture_begin() const { 101 return tab_activated_with_last_gesture_begin_; 102 } 103 104 views::GlowHoverController* hover_controller() { 105 return &hover_controller_; 106 } 107 108 // Returns the inset within the first dragged tab to use when calculating the 109 // "drag insertion point". If we simply used the x-coordinate of the tab, 110 // we'd be calculating based on a point well before where the user considers 111 // the tab to "be". The value here is chosen to "feel good" based on the 112 // widths of the tab images and the tab overlap. 113 // 114 // Note that this must return a value smaller than the midpoint of any tab's 115 // width, or else the user won't be able to drag a tab to the left of the 116 // first tab in the strip. 117 static int leading_width_for_drag() { return 16; } 118 119 // Returns the minimum possible size of a single unselected Tab. 120 static gfx::Size GetMinimumUnselectedSize(); 121 // Returns the minimum possible size of a selected Tab. Selected tabs must 122 // always show a close button and have a larger minimum size than unselected 123 // tabs. 124 static gfx::Size GetMinimumSelectedSize(); 125 // Returns the preferred size of a single Tab, assuming space is 126 // available. 127 static gfx::Size GetStandardSize(); 128 129 // Returns the width for touch tabs. 130 static int GetTouchWidth(); 131 132 // Returns the width for mini-tabs. Mini-tabs always have this width. 133 static int GetMiniWidth(); 134 135 // Returns the height for immersive mode tabs. 136 static int GetImmersiveHeight(); 137 138 private: 139 friend class TabTest; 140 FRIEND_TEST_ALL_PREFIXES(TabTest, CloseButtonLayout); 141 142 friend class TabStripTest; 143 FRIEND_TEST_ALL_PREFIXES(TabStripTest, TabHitTestMaskWhenStacked); 144 FRIEND_TEST_ALL_PREFIXES(TabStripTest, ClippedTabCloseButton); 145 146 // The animation object used to swap the favicon with the sad tab icon. 147 class FaviconCrashAnimation; 148 class TabCloseButton; 149 150 // Contains a cached image and the values used to generate it. 151 struct ImageCacheEntry { 152 ImageCacheEntry(); 153 ~ImageCacheEntry(); 154 155 // ID of the resource used. 156 int resource_id; 157 158 // Scale factor we're drawing it. 159 ui::ScaleFactor scale_factor; 160 161 // The image. 162 gfx::ImageSkia image; 163 }; 164 165 typedef std::list<ImageCacheEntry> ImageCache; 166 167 // Overridden from gfx::AnimationDelegate: 168 virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE; 169 virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE; 170 virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE; 171 172 // Overridden from views::ButtonListener: 173 virtual void ButtonPressed(views::Button* sender, 174 const ui::Event& event) OVERRIDE; 175 176 // Overridden from views::ContextMenuController: 177 virtual void ShowContextMenuForView(views::View* source, 178 const gfx::Point& point, 179 ui::MenuSourceType source_type) OVERRIDE; 180 181 // Overridden from views::View: 182 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; 183 virtual void Layout() OVERRIDE; 184 virtual void OnThemeChanged() OVERRIDE; 185 virtual const char* GetClassName() const OVERRIDE; 186 virtual bool HasHitTestMask() const OVERRIDE; 187 virtual void GetHitTestMask(HitTestSource source, 188 gfx::Path* path) const OVERRIDE; 189 virtual bool GetTooltipText(const gfx::Point& p, 190 base::string16* tooltip) const OVERRIDE; 191 virtual bool GetTooltipTextOrigin(const gfx::Point& p, 192 gfx::Point* origin) const OVERRIDE; 193 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE; 194 virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE; 195 virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE; 196 virtual void OnMouseCaptureLost() OVERRIDE; 197 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE; 198 virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE; 199 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE; 200 virtual void GetAccessibleState(ui::AXViewState* state) OVERRIDE; 201 202 // Overridden from ui::EventHandler: 203 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; 204 205 // Invoked from Layout to adjust the position of the favicon or media 206 // indicator for mini tabs. 207 void MaybeAdjustLeftForMiniTab(gfx::Rect* bounds) const; 208 209 // Invoked from SetData after |data_| has been updated to the new data. 210 void DataChanged(const TabRendererData& old); 211 212 // Paint with the normal tab style. 213 void PaintTab(gfx::Canvas* canvas); 214 215 // Paint with the "immersive mode" light-bar style. 216 void PaintImmersiveTab(gfx::Canvas* canvas); 217 218 // Paint various portions of the Tab 219 void PaintTabBackground(gfx::Canvas* canvas); 220 void PaintInactiveTabBackgroundWithTitleChange(gfx::Canvas* canvas); 221 void PaintInactiveTabBackground(gfx::Canvas* canvas); 222 void PaintInactiveTabBackgroundUsingResourceId(gfx::Canvas* canvas, 223 int tab_id); 224 void PaintActiveTabBackground(gfx::Canvas* canvas); 225 226 // Paints the favicon and media indicator icon, mirrored for RTL if needed. 227 void PaintIcon(gfx::Canvas* canvas); 228 void PaintMediaIndicator(gfx::Canvas* canvas); 229 230 // Invoked if data_.network_state changes, or the network_state is not none. 231 void AdvanceLoadingAnimation(TabRendererData::NetworkState old_state, 232 TabRendererData::NetworkState state); 233 234 // Returns the number of favicon-size elements that can fit in the tab's 235 // current size. 236 int IconCapacity() const; 237 238 // Returns whether the Tab should display a favicon. 239 bool ShouldShowIcon() const; 240 241 // Returns whether the Tab should display the media indicator. 242 bool ShouldShowMediaIndicator() const; 243 244 // Returns whether the Tab should display a close button. 245 bool ShouldShowCloseBox() const; 246 247 // Gets the throb value for the tab. When a tab is not selected the 248 // active background is drawn at |GetThrobValue()|%. This is used for hover, 249 // mini tab title change and pulsing. 250 double GetThrobValue(); 251 252 // Set the temporary offset for the favicon. This is used during the crash 253 // animation. 254 void SetFaviconHidingOffset(int offset); 255 256 void DisplayCrashedFavicon(); 257 void ResetCrashedFavicon(); 258 259 void StopCrashAnimation(); 260 void StartCrashAnimation(); 261 262 // Returns true if the crash animation is currently running. 263 bool IsPerformingCrashAnimation() const; 264 265 // Starts the media indicator fade-in/out animation. There's no stop method 266 // because this is not a continuous animation. 267 void StartMediaIndicatorAnimation(); 268 269 // Schedules repaint task for icon. 270 void ScheduleIconPaint(); 271 272 // Returns the rectangle for the light bar in immersive mode. 273 gfx::Rect GetImmersiveBarRect() const; 274 275 // Gets the tab id and frame id. 276 void GetTabIdAndFrameId(views::Widget* widget, 277 int* tab_id, 278 int* frame_id) const; 279 280 // Performs a one-time initialization of static resources such as tab images. 281 static void InitTabResources(); 282 283 // Returns the minimum possible size of a single unselected Tab, not 284 // including considering touch mode. 285 static gfx::Size GetBasicMinimumUnselectedSize(); 286 287 // Loads the images to be used for the tab background. 288 static void LoadTabImages(); 289 290 // Returns the cached image for the specified arguments, or an empty image if 291 // there isn't one cached. 292 static gfx::ImageSkia GetCachedImage(int resource_id, 293 const gfx::Size& size, 294 ui::ScaleFactor scale_factor); 295 296 // Caches the specified image. 297 static void SetCachedImage(int resource_id, 298 ui::ScaleFactor scale_factor, 299 const gfx::ImageSkia& image); 300 301 // The controller, never NULL. 302 TabController* controller_; 303 304 TabRendererData data_; 305 306 // True if the tab is being animated closed. 307 bool closing_; 308 309 // True if the tab is being dragged. 310 bool dragging_; 311 312 // True if the tab has been detached. 313 bool detached_; 314 315 // The offset used to animate the favicon location. This is used when the tab 316 // crashes. 317 int favicon_hiding_offset_; 318 319 // The current index of the loading animation. The range varies depending on 320 // whether the tab is loading or waiting, see AdvanceLoadingAnimation(). 321 int loading_animation_frame_; 322 323 // Step in the immersive loading progress indicator. 324 int immersive_loading_step_; 325 326 bool should_display_crashed_favicon_; 327 328 // Whole-tab throbbing "pulse" animation. 329 scoped_ptr<gfx::ThrobAnimation> pulse_animation_; 330 331 scoped_ptr<gfx::MultiAnimation> mini_title_change_animation_; 332 333 // Crash icon animation (in place of favicon). 334 scoped_ptr<gfx::LinearAnimation> crash_icon_animation_; 335 336 // Media indicator fade-in/out animation (i.e., only on show/hide, not a 337 // continuous animation). 338 scoped_ptr<gfx::Animation> media_indicator_animation_; 339 TabMediaState animating_media_state_; 340 341 scoped_refptr<gfx::AnimationContainer> animation_container_; 342 343 views::ImageButton* close_button_; 344 views::Label* title_; 345 346 bool tab_activated_with_last_gesture_begin_; 347 348 views::GlowHoverController hover_controller_; 349 350 // The bounds of various sections of the display. 351 gfx::Rect favicon_bounds_; 352 gfx::Rect media_indicator_bounds_; 353 354 // The offset used to paint the inactive background image. 355 gfx::Point background_offset_; 356 357 struct TabImage { 358 gfx::ImageSkia* image_l; 359 gfx::ImageSkia* image_c; 360 gfx::ImageSkia* image_r; 361 int l_width; 362 int r_width; 363 }; 364 static TabImage tab_active_; 365 static TabImage tab_inactive_; 366 static TabImage tab_alpha_; 367 368 // Whether we're showing the icon. It is cached so that we can detect when it 369 // changes and layout appropriately. 370 bool showing_icon_; 371 372 // Whether we're showing the media indicator. It is cached so that we can 373 // detect when it changes and layout appropriately. 374 bool showing_media_indicator_; 375 376 // Whether we are showing the close button. It is cached so that we can 377 // detect when it changes and layout appropriately. 378 bool showing_close_button_; 379 380 // The current color of the close button. 381 SkColor close_button_color_; 382 383 // As the majority of the tabs are inactive, and painting tabs is slowish, 384 // we cache a handful of the inactive tab backgrounds here. 385 static ImageCache* image_cache_; 386 387 DISALLOW_COPY_AND_ASSIGN(Tab); 388 }; 389 390 #endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_H_ 391