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_LOCATION_BAR_ZOOM_BUBBLE_VIEW_H_ 6 #define CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_ZOOM_BUBBLE_VIEW_H_ 7 8 #include "base/gtest_prod_util.h" 9 #include "base/macros.h" 10 #include "base/timer/timer.h" 11 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h" 12 #include "chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h" 13 #include "components/sessions/core/session_id.h" 14 #include "content/public/browser/notification_observer.h" 15 #include "content/public/browser/notification_registrar.h" 16 #include "content/public/browser/web_contents_observer.h" 17 #include "extensions/browser/extension_icon_image.h" 18 #include "ui/views/controls/label.h" 19 20 namespace content { 21 class WebContents; 22 } 23 24 namespace views { 25 class AXVirtualView; 26 class Button; 27 class ImageButton; 28 } // namespace views 29 30 // View used to display the zoom percentage when it has changed. 31 class ZoomBubbleView : public LocationBarBubbleDelegateView, 32 public ImmersiveModeController::Observer, 33 public extensions::IconImage::Observer { 34 public: 35 // Shows the bubble and automatically closes it after a short time period if 36 // |reason| is AUTOMATIC. 37 static void ShowBubble(content::WebContents* web_contents, 38 DisplayReason reason); 39 40 // If the bubble is being shown for the given |web_contents|, refreshes it. 41 static bool RefreshBubbleIfShowing(const content::WebContents* web_contents); 42 43 // Closes the showing bubble (if one exists). 44 static void CloseCurrentBubble(); 45 46 // Returns the zoom bubble if the zoom bubble is showing. Returns NULL 47 // otherwise. 48 static ZoomBubbleView* GetZoomBubble(); 49 50 // Refreshes the bubble by changing the zoom percentage appropriately and 51 // resetting the timer if necessary. 52 void Refresh(); 53 54 private: 55 FRIEND_TEST_ALL_PREFIXES(ZoomBubbleBrowserTest, ImmersiveFullscreen); 56 FRIEND_TEST_ALL_PREFIXES(ZoomBubbleBrowserTest, 57 BubbleSuppressingExtensionRefreshesExistingBubble); 58 FRIEND_TEST_ALL_PREFIXES(ZoomBubbleBrowserTest, FocusPreventsClose); 59 FRIEND_TEST_ALL_PREFIXES(ZoomBubbleBrowserTest, AnchorPositionsInFullscreen); 60 61 // Returns true if we can reuse the existing bubble for the given 62 // |web_contents|. 63 static bool CanRefresh(const content::WebContents* web_contents); 64 65 // Stores information about the extension that initiated the zoom change, if 66 // any. 67 struct ZoomBubbleExtensionInfo { 68 ZoomBubbleExtensionInfo(); 69 ~ZoomBubbleExtensionInfo(); 70 71 // The unique id of the extension, which is used to find the correct 72 // extension after clicking on the image button in the zoom bubble. 73 std::string id; 74 75 // The name of the extension, which appears in the tooltip of the image 76 // button in the zoom bubble. 77 std::string name; 78 79 // An image of the extension's icon, which appears in the zoom bubble as an 80 // image button. 81 std::unique_ptr<const extensions::IconImage> icon_image; 82 }; 83 84 // Constructs ZoomBubbleView. Anchors the bubble to |anchor_view|, which must 85 // not be nullptr. The bubble will auto-close when |reason| is AUTOMATIC. If 86 // |immersive_mode_controller_| is present, the bubble will auto-close when 87 // the top-of-window views are revealed. 88 ZoomBubbleView(views::View* anchor_view, 89 content::WebContents* web_contents, 90 DisplayReason reason, 91 ImmersiveModeController* immersive_mode_controller); 92 ~ZoomBubbleView() override; 93 94 // LocationBarBubbleDelegateView: 95 base::string16 GetAccessibleWindowTitle() const override; 96 void OnFocus() override; 97 void OnBlur() override; 98 void OnGestureEvent(ui::GestureEvent* event) override; 99 void OnKeyEvent(ui::KeyEvent* event) override; 100 void OnMouseEntered(const ui::MouseEvent& event) override; 101 void OnMouseExited(const ui::MouseEvent& event) override; 102 void Init() override; 103 void WindowClosing() override; 104 void CloseBubble() override; 105 106 // ImmersiveModeController::Observer 107 void OnImmersiveRevealStarted() override; 108 void OnImmersiveModeControllerDestroyed() override; 109 110 // extensions::IconImage::Observer 111 void OnExtensionIconImageChanged(extensions::IconImage* /* image */) override; 112 113 // Sets information about the extension that initiated the zoom change. 114 // Calling this method asserts that the extension |extension| did initiate 115 // the zoom change. 116 void SetExtensionInfo(const extensions::Extension* extension); 117 118 // Updates |label_| with the up to date zoom. 119 void UpdateZoomPercent(); 120 121 // Updates visibility of the zoom icon. 122 void UpdateZoomIconVisibility(); 123 124 // Starts a timer which will close the bubble if |auto_close_| is true. 125 void StartTimerIfNecessary(); 126 127 // Stops the auto-close timer. 128 void StopTimer(); 129 130 // Called when any button is pressed; does common logic, then runs |closure|. 131 void ButtonPressed(base::RepeatingClosure closure); 132 133 // Called by ButtonPressed() when |image_button_| is pressed. 134 void ImageButtonPressed(); 135 136 ZoomBubbleExtensionInfo extension_info_; 137 138 // Singleton instance of the zoom bubble. The zoom bubble can only be shown on 139 // the active browser window, so there is no case in which it will be shown 140 // twice at the same time. 141 static ZoomBubbleView* zoom_bubble_; 142 143 // Timer used to auto close the bubble. 144 base::OneShotTimer auto_close_timer_; 145 146 // Timer duration that is made longer if a user presses + or - buttons. 147 base::TimeDelta auto_close_duration_; 148 149 // Image button in the zoom bubble that will show the |extension_icon_| image 150 // if an extension initiated the zoom change, and links to that extension at 151 // "chrome://extensions". 152 views::ImageButton* image_button_ = nullptr; 153 154 // Label displaying the zoom percentage. 155 views::Label* label_ = nullptr; 156 157 // Action buttons that can change zoom. 158 views::Button* zoom_out_button_ = nullptr; 159 views::Button* zoom_in_button_ = nullptr; 160 views::Button* reset_button_ = nullptr; 161 162 // Virtual view used to announce zoom level changes. 163 views::AXVirtualView* zoom_level_alert_ = nullptr; 164 165 // Whether the currently displayed bubble will automatically close. 166 bool auto_close_; 167 168 // Used to ignore close requests generated automatically in response to 169 // button presses, since pressing a button in the bubble should not trigger 170 // closing. 171 bool ignore_close_bubble_ = false; 172 173 // The immersive mode controller for the BrowserView containing 174 // |web_contents_|. 175 // Not owned. 176 ImmersiveModeController* immersive_mode_controller_; 177 178 // The session of the Browser that triggered the bubble. This allows the zoom 179 // icon to be updated even if the WebContents is destroyed. 180 const SessionID session_id_; 181 182 DISALLOW_COPY_AND_ASSIGN(ZoomBubbleView); 183 }; 184 185 #endif // CHROME_BROWSER_UI_VIEWS_LOCATION_BAR_ZOOM_BUBBLE_VIEW_H_ 186