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 |