summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/gtk/tabs/tab_renderer_gtk.h
blob: a670e3f92f9056587a59e86311e909983fa51c34 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
// 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_GTK_TABS_TAB_RENDERER_GTK_H_
#define CHROME_BROWSER_UI_GTK_TABS_TAB_RENDERER_GTK_H_
#pragma once

#include <gtk/gtk.h>
#include <map>

#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/string16.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/animation/animation_delegate.h"
#include "ui/base/gtk/gtk_signal.h"
#include "ui/base/gtk/owned_widget_gtk.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font.h"
#include "ui/gfx/image/cairo_cached_surface.h"
#include "ui/gfx/rect.h"

namespace gfx {
class CairoCachedSurface;
class Image;
class Size;
}  // namespace gfx

class CustomDrawButton;
class GtkThemeService;

namespace content {
class WebContents;
}

namespace ui {
class SlideAnimation;
class ThrobAnimation;
}

class TabRendererGtk : public ui::AnimationDelegate,
                       public content::NotificationObserver {
 public:
  // Possible animation states.
  enum AnimationState {
    ANIMATION_NONE,
    ANIMATION_WAITING,
    ANIMATION_LOADING
  };

  class LoadingAnimation : public content::NotificationObserver {
   public:
    struct Data {
      explicit Data(GtkThemeService* theme_service);
      Data(int loading, int waiting, int waiting_to_loading);

      int loading_animation_frame_count;
      int waiting_animation_frame_count;
      int waiting_to_loading_frame_count_ratio;
    };

    explicit LoadingAnimation(GtkThemeService* theme_service);

    // Used in unit tests to inject specific data.
    explicit LoadingAnimation(const LoadingAnimation::Data& data);

    virtual ~LoadingAnimation();

    // Advance the loading animation to the next frame, or hide the animation if
    // the tab isn't loading. Returns |true| if the icon area needs to be
    // repainted.
    bool ValidateLoadingAnimation(AnimationState animation_state);

    AnimationState animation_state() const { return animation_state_; }
    int animation_frame() const { return animation_frame_; }

    // Provide content::NotificationObserver implementation.
    virtual void Observe(int type,
                         const content::NotificationSource& source,
                         const content::NotificationDetails& details) OVERRIDE;

   private:
    scoped_ptr<Data> data_;

    // Used to listen for theme change notifications.
    content::NotificationRegistrar registrar_;

    // Gives us our throbber images.
    GtkThemeService* theme_service_;

    // Current state of the animation.
    AnimationState animation_state_;

    // The current index into the Animation image strip.
    int animation_frame_;

    DISALLOW_COPY_AND_ASSIGN(LoadingAnimation);
  };

  explicit TabRendererGtk(GtkThemeService* theme_service);
  virtual ~TabRendererGtk();

  // Provide content::NotificationObserver implementation.
  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) OVERRIDE;

  // WebContents. If only the loading state was updated, the loading_only flag
  // should be specified. If other things change, set this flag to false to
  // update everything.
  virtual void UpdateData(content::WebContents* contents,
                          bool app,
                          bool loading_only);

  // Sets the blocked state of the tab.
  void SetBlocked(bool pinned);
  bool is_blocked() const;

  // Sets the mini-state of the tab.
  void set_mini(bool mini) { data_.mini = mini; }
  bool mini() const { return data_.mini; }

  // Sets the app state of the tab.
  void set_app(bool app) { data_.app = app; }
  bool app() const { return data_.app; }

  // Are we in the process of animating a mini tab state change on this tab?
  void set_animating_mini_change(bool value) {
    data_.animating_mini_change = value;
  }

  // Updates the display to reflect the contents of this TabRenderer's model.
  void UpdateFromModel();

  // Returns true if the Tab is active, false otherwise.
  virtual bool IsActive() const;

  // Set |is_active_| property of this tab.
  void set_is_active(bool is_active) { is_active_ = is_active; }

  // Returns true if the Tab is selected, false otherwise.
  virtual bool IsSelected() const;

  // Returns true if the Tab is visible, false otherwise.
  virtual bool IsVisible() const;

  // Sets the visibility of the Tab.
  virtual void SetVisible(bool visible) const;

  // Paints the tab using resources from the display that |widget| is on,
  // drawing into |cr|.
  void Paint(GtkWidget* widget, cairo_t* cr);

  // Paints the tab, and keeps the result server-side. The returned surface must
  // be freed with cairo_surface_destroy().
  cairo_surface_t* PaintToSurface(GtkWidget* widget, cairo_t* cr);

  // There is no PaintNow available, so the fastest we can do is schedule a
  // paint with the windowing system.
  void SchedulePaint();

  // Notifies the Tab that the close button has been clicked.
  virtual void CloseButtonClicked();

  // Sets the bounds of the tab.
  virtual void SetBounds(const gfx::Rect& bounds);

  // Advance the loading animation to the next frame, or hide the animation if
  // the tab isn't loading.  Returns |true| if the icon area needs to be
  // repainted.
  bool ValidateLoadingAnimation(AnimationState animation_state);

  // Repaint only the area of the tab that contains the favicon.
  void PaintFaviconArea(GtkWidget* widget, cairo_t* cr);

  // Returns whether the Tab should display a favicon.
  bool ShouldShowIcon() const;

  // Returns the minimum possible size of a single unselected Tab.
  static gfx::Size GetMinimumUnselectedSize();
  // 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 GetMinimumSelectedSize();
  // Returns the preferred size of a single Tab, assuming space is
  // available.
  static gfx::Size GetStandardSize();

  // Returns the width for mini-tabs. Mini-tabs always have this width.
  static int GetMiniWidth();

  static gfx::Font* title_font() { return title_font_; }

  // Returns the bounds of the Tab.
  int x() const { return bounds_.x(); }
  int y() const { return bounds_.y(); }
  int width() const { return bounds_.width(); }
  int height() const { return bounds_.height(); }

  gfx::Rect bounds() const { return bounds_; }

  gfx::Rect favicon_bounds() const { return favicon_bounds_; }

  // Returns the non-mirrored (LTR) bounds of this tab.
  gfx::Rect GetNonMirroredBounds(GtkWidget* parent) const;

  // Returns the requested bounds of the tab.
  gfx::Rect GetRequisition() const;

  GtkWidget* widget() const { return tab_.get(); }

  // Start/stop the mini-tab title animation.
  void StartMiniTabTitleAnimation();
  void StopMiniTabTitleAnimation();

  void set_vertical_offset(int offset) { background_offset_y_ = offset; }

 protected:
  const gfx::Rect& title_bounds() const { return title_bounds_; }
  const gfx::Rect& close_button_bounds() const { return close_button_bounds_; }

  // Raise button to top of Z-order.
  void Raise() const;

  // Returns the title of the Tab.
  string16 GetTitle() const;

  // enter-notify-event handler that signals when the mouse enters the tab.
  CHROMEGTK_CALLBACK_1(TabRendererGtk, gboolean, OnEnterNotifyEvent,
                       GdkEventCrossing*);

  // leave-notify-event handler that signals when the mouse enters the tab.
  CHROMEGTK_CALLBACK_1(TabRendererGtk, gboolean, OnLeaveNotifyEvent,
                       GdkEventCrossing*);

 private:
  class FaviconCrashAnimation;

  // Model data. We store this here so that we don't need to ask the underlying
  // model, which is tricky since instances of this object can outlive the
  // corresponding objects in the underlying model.
  struct TabData {
    TabData();
    ~TabData();

    SkBitmap favicon;
    gfx::CairoCachedSurface cairo_favicon;
    bool is_default_favicon;
    string16 title;
    bool loading;
    bool crashed;
    bool incognito;
    bool show_icon;
    bool mini;
    bool blocked;
    bool animating_mini_change;
    bool app;
  };

  // Overridden from ui::AnimationDelegate:
  virtual void AnimationProgressed(const ui::Animation* animation) OVERRIDE;
  virtual void AnimationCanceled(const ui::Animation* animation) OVERRIDE;
  virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE;

  // Starts/Stops the crash animation.
  void StartCrashAnimation();
  void StopCrashAnimation();

  // Return true if the crash animation is currently running.
  bool IsPerformingCrashAnimation() const;

  // Set the temporary offset for the favicon. This is used during animation.
  void SetFaviconHidingOffset(int offset);

  void DisplayCrashedFavicon();
  void ResetCrashedFavicon();

  // Generates the bounds for the interior items of the tab.
  void Layout();

  // Returns the local bounds of the tab.  This returns the rect
  // {0, 0, width(), height()} for now, as we don't yet support borders.
  gfx::Rect GetLocalBounds();

  // Moves the close button widget within the GtkFixed container.
  void MoveCloseButtonWidget();

  // Returns the largest of the favicon, title text, and the close button.
  static int GetContentHeight();

  void PaintTab(GtkWidget* widget, GdkEventExpose* event);

  // Paint various portions of the Tab
  void PaintTitle(GtkWidget* widget, cairo_t* cr);
  void PaintIcon(GtkWidget* widget, cairo_t* cr);
  void PaintTabBackground(GtkWidget* widget, cairo_t* cr);
  void PaintInactiveTabBackground(GtkWidget* widget, cairo_t* cr);
  void PaintActiveTabBackground(GtkWidget* widget, cairo_t* cr);
  void PaintLoadingAnimation(GtkWidget* widget, cairo_t* cairo);

  // Draws the given |tab_bg| onto |cr| using the tab shape masks along the
  // sides for the rounded tab shape.
  void DrawTabBackground(cairo_t* cr,
                         GtkWidget* widget,
                         const gfx::Image* tab_bg,
                         int offset_x,
                         int offset_y);

  // Draws the tab shadow using the given idr resources onto |cr|.
  void DrawTabShadow(cairo_t* cr,
                     GtkWidget* widget,
                     int left_idr,
                     int center_idr,
                     int right_idr);

  // 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 close button.
  bool ShouldShowCloseBox() const;

  CustomDrawButton* MakeCloseButton();

  // 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
  // and mini-tab title change effects.
  double GetThrobValue();

  // Handles the clicked signal for the close button.
  CHROMEGTK_CALLBACK_0(TabRendererGtk, void, OnCloseButtonClicked);

  // Handles middle clicking the close button.
  CHROMEGTK_CALLBACK_1(TabRendererGtk, gboolean, OnCloseButtonMouseRelease,
                       GdkEventButton*);

  // expose-event handler that redraws the tab.
  CHROMEGTK_CALLBACK_1(TabRendererGtk, gboolean, OnExposeEvent,
                       GdkEventExpose*);

  // size-allocate handler used to update the current bounds of the tab.
  CHROMEGTK_CALLBACK_1(TabRendererGtk, void, OnSizeAllocate, GtkAllocation*);

  // TODO(jhawkins): Move to TabResources.
  static void InitResources();
  static bool initialized_;

  // The bounds of various sections of the display.
  gfx::Rect favicon_bounds_;
  gfx::Rect title_bounds_;
  gfx::Rect close_button_bounds_;

  TabData data_;

  static int tab_active_l_width_;
  static int tab_active_l_height_;
  static int tab_inactive_l_width_;
  static int tab_inactive_l_height_;

  static gfx::Font* title_font_;
  static int title_font_height_;

  static int close_button_width_;
  static int close_button_height_;

  content::NotificationRegistrar registrar_;

  // The GtkDrawingArea we draw the tab on.
  ui::OwnedWidgetGtk tab_;

  // 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 are showing the close button. It is cached so that we can
  // detect when it changes and layout appropriately.
  bool showing_close_button_;

  // The offset used to animate the favicon location.
  int favicon_hiding_offset_;

  // The animation object used to swap the favicon with the sad tab icon.
  scoped_ptr<FaviconCrashAnimation> crash_animation_;

  // Set when the crashed favicon should be displayed.
  bool should_display_crashed_favicon_;

  // The bounds of this Tab.
  gfx::Rect bounds_;

  // The requested bounds of this tab.  These bounds are relative to the
  // tabstrip.
  gfx::Rect requisition_;

  // Hover animation.
  scoped_ptr<ui::SlideAnimation> hover_animation_;

  // Animation used when the title of an inactive mini-tab changes.
  scoped_ptr<ui::ThrobAnimation> mini_title_animation_;

  // Contains the loading animation state.
  LoadingAnimation loading_animation_;

  // The offset used to paint the tab theme images.
  int background_offset_x_;

  // The vertical offset used to paint the tab theme images. Controlled by the
  // tabstrip and plumbed here to offset the theme image by the size of the
  // alignment in the BrowserTitlebar.
  int background_offset_y_;

  GtkThemeService* theme_service_;

  // The close button.
  scoped_ptr<CustomDrawButton> close_button_;

  // The current color of the close button.
  SkColor close_button_color_;

  // Indicates whether this tab is the active one.
  bool is_active_;

  // Color of the title text on the selected tab.
  SkColor selected_title_color_;

  // Color of the title text on an unselected tab.
  SkColor unselected_title_color_;

  DISALLOW_COPY_AND_ASSIGN(TabRendererGtk);
};

#endif  // CHROME_BROWSER_UI_GTK_TABS_TAB_RENDERER_GTK_H_