// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_H_ #define CHROME_BROWSER_UI_VIEWS_TABS_TAB_H_ #include #include #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "chrome/browser/ui/views/tabs/tab_renderer_data.h" #include "ui/base/layout.h" #include "ui/gfx/animation/animation_delegate.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/paint_throbber.h" #include "ui/views/context_menu_controller.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/glow_hover_controller.h" #include "ui/views/masked_targeter_delegate.h" #include "ui/views/view.h" class MediaIndicatorButton; class TabController; namespace gfx { class Animation; class AnimationContainer; class LinearAnimation; class MultiAnimation; class ThrobAnimation; } namespace views { class ImageButton; class Label; } /////////////////////////////////////////////////////////////////////////////// // // A View that renders a Tab in a TabStrip. // /////////////////////////////////////////////////////////////////////////////// class Tab : public gfx::AnimationDelegate, public views::ButtonListener, public views::ContextMenuController, public views::MaskedTargeterDelegate, public views::View { public: // The Tab's class name. static const char kViewClassName[]; Tab(TabController* controller, gfx::AnimationContainer* container); ~Tab() override; TabController* controller() const { return controller_; } // Used to set/check whether this Tab is being animated closed. void set_closing(bool closing) { closing_ = closing; } bool closing() const { return closing_; } // See description above field. void set_dragging(bool dragging) { dragging_ = dragging; } bool dragging() const { return dragging_; } // Used to mark the tab as having been detached. Once this has happened, the // tab should be invisibly closed. This is irreversible. void set_detached() { detached_ = true; } bool detached() const { return detached_; } SkColor button_color() const { return button_color_; } // Returns true if this tab is the active tab. bool IsActive() const; // Notifies the MediaIndicatorButton that the active state of this tab has // changed. void ActiveStateChanged(); // Called when the media indicator has changed states. void MediaStateChanged(); // Returns true if the tab is selected. bool IsSelected() const; // Sets the data this tabs displays. Invokes DataChanged. Should only be // called after Tab is added to widget hierarchy. void SetData(const TabRendererData& data); const TabRendererData& data() const { return data_; } // Sets the network state. void UpdateLoadingAnimation(TabRendererData::NetworkState state); // Starts/Stops a pulse animation. void StartPulse(); void StopPulse(); // Start/stop the pinned tab title animation. void StartPinnedTabTitleAnimation(); void StopPinnedTabTitleAnimation(); // Set the background offset used to match the image in the inactive tab // to the frame image. void set_background_offset(const gfx::Point& offset) { background_offset_ = offset; } // Returns true if this tab became the active tab selected in // response to the last ui::ET_TAP_DOWN gesture dispatched to // this tab. Only used for collecting UMA metrics. // See ash/touch/touch_uma.cc. bool tab_activated_with_last_tap_down() const { return tab_activated_with_last_tap_down_; } views::GlowHoverController* hover_controller() { return &hover_controller_; } // Returns the width of the largest part of the tab that is available for the // user to click to select/activate the tab. int GetWidthOfLargestSelectableRegion() const; // Called when stacked layout changes and the close button may need to // be updated. void HideCloseButtonForInactiveTabsChanged() { Layout(); } // Returns the inset within the first dragged tab to use when calculating the // "drag insertion point". If we simply used the x-coordinate of the tab, // we'd be calculating based on a point well before where the user considers // the tab to "be". The value here is chosen to "feel good" based on the // widths of the tab images and the tab overlap. // // Note that this must return a value smaller than the midpoint of any tab's // width, or else the user won't be able to drag a tab to the left of the // first tab in the strip. static int leading_width_for_drag() { return 16; } // Returns the minimum possible size of a single unselected Tab. static gfx::Size GetMinimumInactiveSize(); // Returns the minimum possible size of a selected Tab. Selected tabs must // always show a close button and have a larger minimum size than unselected // tabs. static gfx::Size GetMinimumActiveSize(); // Returns the preferred size of a single Tab, assuming space is // available. static gfx::Size GetStandardSize(); // Returns the width for touch tabs. static int GetTouchWidth(); // Returns the width for pinned tabs. Pinned tabs always have this width. static int GetPinnedWidth(); // Returns the height for immersive mode tabs. static int GetImmersiveHeight(); // Returns the Y inset within the tab bounds for drawing the background image. // This is necessary for correct vertical alignment of the frame, tab, and // toolbar images with custom themes. static int GetYInsetForActiveTabBackground(); // Returns the inverse of the slope of the diagonal portion of the tab outer // border. (This is a positive value, so it's specifically for the slope of // the leading edge.) // // This returns the inverse (dx/dy instead of dy/dx) because we use exact // values for the vertical distances between points and then compute the // horizontal deltas from those. static float GetInverseDiagonalSlope(); private: friend class MediaIndicatorButtonTest; friend class TabTest; friend class TabStripTest; FRIEND_TEST_ALL_PREFIXES(TabStripTest, TabHitTestMaskWhenStacked); FRIEND_TEST_ALL_PREFIXES(TabStripTest, TabCloseButtonVisibilityWhenStacked); // The animation object used to swap the favicon with the sad tab icon. class FaviconCrashAnimation; class TabCloseButton; class ThrobberView; // All metadata necessary to uniquely identify a cached image. struct ImageCacheEntryMetadata; // A cached image and the metadata used to generate it. struct ImageCacheEntry; typedef std::list ImageCache; // gfx::AnimationDelegate: void AnimationProgressed(const gfx::Animation* animation) override; void AnimationCanceled(const gfx::Animation* animation) override; void AnimationEnded(const gfx::Animation* animation) override; // views::ButtonListener: void ButtonPressed(views::Button* sender, const ui::Event& event) override; // views::ContextMenuController: void ShowContextMenuForView(views::View* source, const gfx::Point& point, ui::MenuSourceType source_type) override; // views::MaskedTargeterDelegate: bool GetHitTestMask(gfx::Path* mask) const override; // views::View: void ViewHierarchyChanged( const ViewHierarchyChangedDetails& details) override; void OnPaint(gfx::Canvas* canvas) override; void Layout() override; void OnThemeChanged() override; const char* GetClassName() const override; bool GetTooltipText(const gfx::Point& p, base::string16* tooltip) const override; bool GetTooltipTextOrigin(const gfx::Point& p, gfx::Point* origin) const override; bool OnMousePressed(const ui::MouseEvent& event) override; bool OnMouseDragged(const ui::MouseEvent& event) override; void OnMouseReleased(const ui::MouseEvent& event) override; void OnMouseCaptureLost() override; void OnMouseEntered(const ui::MouseEvent& event) override; void OnMouseMoved(const ui::MouseEvent& event) override; void OnMouseExited(const ui::MouseEvent& event) override; void GetAccessibleState(ui::AXViewState* state) override; // ui::EventHandler: void OnGestureEvent(ui::GestureEvent* event) override; // Invoked from Layout to adjust the position of the favicon or media // indicator for pinned tabs. void MaybeAdjustLeftForPinnedTab(gfx::Rect* bounds) const; // Invoked from SetData after |data_| has been updated to the new data. void DataChanged(const TabRendererData& old); // Paint with the normal tab style. void PaintTab(gfx::Canvas* canvas); // Paint with the "immersive mode" light-bar style. void PaintImmersiveTab(gfx::Canvas* canvas); // Paint various portions of the Tab. void PaintTabBackground(gfx::Canvas* canvas); void PaintInactiveTabBackgroundWithTitleChange(gfx::Canvas* canvas); void PaintInactiveTabBackground(gfx::Canvas* canvas); void PaintTabBackgroundUsingFillId(gfx::Canvas* canvas, bool is_active, int fill_id, bool has_custom_image, int y_offset); void PaintTabFill(gfx::Canvas* canvas, gfx::ImageSkia* fill_image, int x_offset, int y_offset, bool is_active); // Paints the favicon, mirrored for RTL if needed. void PaintIcon(gfx::Canvas* canvas); // Invoked if data_.network_state changes, or the network_state is not none. void AdvanceLoadingAnimation(); // Returns the number of favicon-size elements that can fit in the tab's // current size. int IconCapacity() const; // Returns whether the Tab should display a favicon. bool ShouldShowIcon() const; // Returns whether the Tab should display the media indicator. bool ShouldShowMediaIndicator() const; // Returns whether the Tab should display a close button. bool ShouldShowCloseBox() const; // Returns whether the tab should be rendered as a normal tab as opposed to a // pinned tab. bool ShouldRenderAsNormalTab() const; // Gets the throb value for the tab. When a tab is not selected the // active background is drawn at |GetThrobValue()|%. This is used for hover, // mini tab title change and pulsing. double GetThrobValue(); // Set the temporary offset for the favicon. This is used during the crash // animation. void SetFaviconHidingOffset(int offset); void set_should_display_crashed_favicon() { should_display_crashed_favicon_ = true; } // Recalculates the correct |button_color_| and resets the title, media // indicator, and close button colors if necessary. This should be called any // time the theme or active state may have changed. void OnButtonColorMaybeChanged(); // Schedules repaint task for icon. void ScheduleIconPaint(); // Computes a path corresponding to the tab's content region inside the outer // stroke. void GetFillPath(float scale, SkPath* path) const; // Computes a path corresponding to the tab's outer border for a given |scale| // and stores it in |path|. If |extend_to_top| is true, the path is extended // vertically to the top of the tab bounds. The caller uses this for Fitts' // Law purposes in maximized/fullscreen mode. void GetBorderPath(float scale, bool extend_to_top, SkPath* path) const; // Returns the rectangle for the light bar in immersive mode. gfx::Rect GetImmersiveBarRect() const; // Performs a one-time initialization of static resources such as tab images. static void InitTabResources(); // Loads the images to be used for the tab background. static void LoadTabImages(); // The controller, never NULL. TabController* const controller_; TabRendererData data_; // True if the tab is being animated closed. bool closing_; // True if the tab is being dragged. bool dragging_; // True if the tab has been detached. bool detached_; // The offset used to animate the favicon location. This is used when the tab // crashes. int favicon_hiding_offset_; // Step in the immersive loading progress indicator. int immersive_loading_step_; bool should_display_crashed_favicon_; // Whole-tab throbbing "pulse" animation. scoped_ptr pulse_animation_; scoped_ptr pinned_title_change_animation_; // Crash icon animation (in place of favicon). scoped_ptr crash_icon_animation_; scoped_refptr animation_container_; ThrobberView* throbber_; MediaIndicatorButton* media_indicator_button_; views::ImageButton* close_button_; views::Label* title_; bool tab_activated_with_last_tap_down_; views::GlowHoverController hover_controller_; // The bounds of various sections of the display. gfx::Rect favicon_bounds_; // The offset used to paint the inactive background image. gfx::Point background_offset_; struct TabImages { gfx::ImageSkia* image_l; gfx::ImageSkia* image_c; gfx::ImageSkia* image_r; int l_width; int r_width; }; static TabImages active_images_; static TabImages inactive_images_; static TabImages mask_images_; // Whether we're showing the icon. It is cached so that we can detect when it // changes and layout appropriately. bool showing_icon_; // Whether we're showing the media indicator. It is cached so that we can // detect when it changes and layout appropriately. bool showing_media_indicator_; // Whether we are showing the close button. It is cached so that we can // detect when it changes and layout appropriately. bool showing_close_button_; // The current color of the media indicator and close button icons. SkColor button_color_; // As the majority of the tabs are inactive, and painting tabs is slowish, // we cache a handful of the inactive tab backgrounds here. static ImageCache* image_cache_; DISALLOW_COPY_AND_ASSIGN(Tab); }; #endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_H_