• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "base/basictypes.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/string16.h"
15 #include "chrome/browser/ui/gtk/owned_widget_gtk.h"
16 #include "content/common/notification_observer.h"
17 #include "content/common/notification_registrar.h"
18 #include "third_party/skia/include/core/SkBitmap.h"
19 #include "ui/base/animation/animation_delegate.h"
20 #include "ui/base/gtk/gtk_signal.h"
21 #include "ui/gfx/canvas.h"
22 #include "ui/gfx/font.h"
23 #include "ui/gfx/rect.h"
24 
25 namespace gfx {
26 class Size;
27 }  // namespace gfx
28 
29 class CustomDrawButton;
30 class GtkThemeService;
31 class TabContents;
32 
33 namespace ui {
34 class SlideAnimation;
35 class ThemeProvider;
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(ui::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(ui::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 
animation_state()74     AnimationState animation_state() const { return animation_state_; }
animation_frame()75     int animation_frame() const { return animation_frame_; }
76 
waiting_animation_frames()77     const SkBitmap* waiting_animation_frames() const {
78       return data_->waiting_animation_frames;
79     }
loading_animation_frames()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     ui::ThemeProvider* theme_service_;
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(ui::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.
set_mini(bool mini)120   void set_mini(bool mini) { data_.mini = mini; }
mini()121   bool mini() const { return data_.mini; }
122 
123   // Sets the app state of the tab.
set_app(bool app)124   void set_app(bool app) { data_.app = 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?
set_animating_mini_change(bool value)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 
title_font()200   static gfx::Font* title_font() { return title_font_; }
201 
202   // Returns the bounds of the Tab.
x()203   int x() const { return bounds_.x(); }
y()204   int y() const { return bounds_.y(); }
width()205   int width() const { return bounds_.width(); }
height()206   int height() const { return bounds_.height(); }
207 
bounds()208   gfx::Rect bounds() const { return bounds_; }
209 
favicon_bounds()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 
widget()218   GtkWidget* widget() const { return tab_.get(); }
219 
220   // Start/stop the mini-tab title animation.
221   void StartMiniTabTitleAnimation();
222   void StopMiniTabTitleAnimation();
223 
set_vertical_offset(int offset)224   void set_vertical_offset(int offset) { background_offset_y_ = offset; }
225 
226  protected:
title_bounds()227   const gfx::Rect& title_bounds() const { return title_bounds_; }
close_button_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 {
TabDataTabData259     TabData()
260         : is_default_favicon(false),
261           loading(false),
262           crashed(false),
263           incognito(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 incognito;
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 favicon_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   GtkThemeService* theme_service_;
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_
457