Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(199)

Side by Side Diff: chrome/browser/ui/gtk/tabs/tab_renderer_gtk.cc

Issue 8392011: GTK: Step 1 of tab strip refresh. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: More cleanup Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/gtk/tabs/tab_renderer_gtk.h" 5 #include "chrome/browser/ui/gtk/tabs/tab_renderer_gtk.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/utf_string_conversions.h" 10 #include "base/utf_string_conversions.h"
11 #include "chrome/browser/defaults.h" 11 #include "chrome/browser/defaults.h"
12 #include "chrome/browser/extensions/extension_tab_helper.h" 12 #include "chrome/browser/extensions/extension_tab_helper.h"
13 #include "chrome/browser/favicon/favicon_tab_helper.h" 13 #include "chrome/browser/favicon/favicon_tab_helper.h"
14 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser.h" 15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h" 16 #include "chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h"
17 #include "chrome/browser/ui/gtk/cairo_cached_surface.h"
17 #include "chrome/browser/ui/gtk/custom_button.h" 18 #include "chrome/browser/ui/gtk/custom_button.h"
18 #include "chrome/browser/ui/gtk/gtk_theme_service.h" 19 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
19 #include "chrome/browser/ui/gtk/gtk_util.h" 20 #include "chrome/browser/ui/gtk/gtk_util.h"
20 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" 21 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
21 #include "chrome/common/chrome_notification_types.h" 22 #include "chrome/common/chrome_notification_types.h"
22 #include "content/browser/tab_contents/tab_contents.h" 23 #include "content/browser/tab_contents/tab_contents.h"
23 #include "content/public/browser/notification_source.h" 24 #include "content/public/browser/notification_source.h"
24 #include "grit/generated_resources.h" 25 #include "grit/generated_resources.h"
25 #include "grit/theme_resources.h" 26 #include "grit/theme_resources.h"
26 #include "grit/theme_resources_standard.h" 27 #include "grit/theme_resources_standard.h"
27 #include "grit/ui_resources.h" 28 #include "grit/ui_resources.h"
28 #include "ui/base/animation/slide_animation.h" 29 #include "ui/base/animation/slide_animation.h"
29 #include "ui/base/animation/throb_animation.h" 30 #include "ui/base/animation/throb_animation.h"
30 #include "ui/base/l10n/l10n_util.h" 31 #include "ui/base/l10n/l10n_util.h"
31 #include "ui/base/resource/resource_bundle.h" 32 #include "ui/base/resource/resource_bundle.h"
32 #include "ui/gfx/canvas_skia_paint.h" 33 #include "ui/gfx/canvas_skia_paint.h"
33 #include "ui/gfx/favicon_size.h" 34 #include "ui/gfx/favicon_size.h"
35 #include "ui/gfx/gtk_util.h"
36 #include "ui/gfx/pango_util.h"
34 #include "ui/gfx/platform_font_pango.h" 37 #include "ui/gfx/platform_font_pango.h"
35 #include "ui/gfx/skbitmap_operations.h" 38 #include "ui/gfx/skbitmap_operations.h"
39 #include "skia/ext/image_operations.h"
36 40
37 #if !GTK_CHECK_VERSION(2, 22, 0) 41 #if !GTK_CHECK_VERSION(2, 22, 0)
38 #define gtk_button_get_event_window(button) button->event_window 42 #define gtk_button_get_event_window(button) button->event_window
39 #endif // Gtk+ >= 2.22 43 #endif // Gtk+ >= 2.22
40 44
41 namespace { 45 namespace {
42 46
43 const int kFontPixelSize = 12; 47 const int kFontPixelSize = 12;
44 const int kLeftPadding = 16; 48 const int kLeftPadding = 16;
45 const int kTopPadding = 6; 49 const int kTopPadding = 6;
(...skipping 28 matching lines...) Expand all
74 const double kMiniTitleChangeThrobOpacity = 0.75; 78 const double kMiniTitleChangeThrobOpacity = 0.75;
75 79
76 // Duration for when the title of an inactive mini-tab changes. 80 // Duration for when the title of an inactive mini-tab changes.
77 const int kMiniTitleChangeThrobDuration = 1000; 81 const int kMiniTitleChangeThrobDuration = 1000;
78 82
79 // The vertical and horizontal offset used to position the close button 83 // The vertical and horizontal offset used to position the close button
80 // in the tab. TODO(jhawkins): Ask pkasting what the Fuzz is about. 84 // in the tab. TODO(jhawkins): Ask pkasting what the Fuzz is about.
81 const int kCloseButtonVertFuzz = 0; 85 const int kCloseButtonVertFuzz = 0;
82 const int kCloseButtonHorzFuzz = 5; 86 const int kCloseButtonHorzFuzz = 5;
83 87
84 SkBitmap* crashed_favicon = NULL;
85
86 // Gets the bounds of |widget| relative to |parent|. 88 // Gets the bounds of |widget| relative to |parent|.
87 gfx::Rect GetWidgetBoundsRelativeToParent(GtkWidget* parent, 89 gfx::Rect GetWidgetBoundsRelativeToParent(GtkWidget* parent,
88 GtkWidget* widget) { 90 GtkWidget* widget) {
89 gfx::Point parent_pos = gtk_util::GetWidgetScreenPosition(parent); 91 gfx::Point parent_pos = gtk_util::GetWidgetScreenPosition(parent);
90 gfx::Point widget_pos = gtk_util::GetWidgetScreenPosition(widget); 92 gfx::Point widget_pos = gtk_util::GetWidgetScreenPosition(widget);
91 return gfx::Rect(widget_pos.x() - parent_pos.x(), 93 return gfx::Rect(widget_pos.x() - parent_pos.x(),
92 widget_pos.y() - parent_pos.y(), 94 widget_pos.y() - parent_pos.y(),
93 widget->allocation.width, widget->allocation.height); 95 widget->allocation.width, widget->allocation.height);
94 } 96 }
95 97
96 } // namespace 98 } // namespace
97 99
98 TabRendererGtk::LoadingAnimation::Data::Data( 100 TabRendererGtk::LoadingAnimation::Data::Data(
99 ThemeService* theme_service) { 101 GtkThemeService* theme_service) {
100 // The loading animation image is a strip of states. Each state must be 102 // The loading animation image is a strip of states. Each state must be
101 // square, so the height must divide the width evenly. 103 // square, so the height must divide the width evenly.
102 loading_animation_frames = theme_service->GetBitmapNamed(IDR_THROBBER); 104 SkBitmap* loading_animation_frames =
105 theme_service->GetBitmapNamed(IDR_THROBBER);
103 DCHECK(loading_animation_frames); 106 DCHECK(loading_animation_frames);
104 DCHECK_EQ(loading_animation_frames->width() % 107 DCHECK_EQ(loading_animation_frames->width() %
105 loading_animation_frames->height(), 0); 108 loading_animation_frames->height(), 0);
106 loading_animation_frame_count = 109 loading_animation_frame_count =
107 loading_animation_frames->width() / 110 loading_animation_frames->width() /
108 loading_animation_frames->height(); 111 loading_animation_frames->height();
109 112
110 waiting_animation_frames = 113 SkBitmap* waiting_animation_frames =
111 theme_service->GetBitmapNamed(IDR_THROBBER_WAITING); 114 theme_service->GetBitmapNamed(IDR_THROBBER_WAITING);
112 DCHECK(waiting_animation_frames); 115 DCHECK(waiting_animation_frames);
113 DCHECK_EQ(waiting_animation_frames->width() % 116 DCHECK_EQ(waiting_animation_frames->width() %
114 waiting_animation_frames->height(), 0); 117 waiting_animation_frames->height(), 0);
115 waiting_animation_frame_count = 118 waiting_animation_frame_count =
116 waiting_animation_frames->width() / 119 waiting_animation_frames->width() /
117 waiting_animation_frames->height(); 120 waiting_animation_frames->height();
118 121
119 waiting_to_loading_frame_count_ratio = 122 waiting_to_loading_frame_count_ratio =
120 waiting_animation_frame_count / 123 waiting_animation_frame_count /
121 loading_animation_frame_count; 124 loading_animation_frame_count;
122 // TODO(beng): eventually remove this when we have a proper themeing system. 125 // TODO(beng): eventually remove this when we have a proper themeing system.
123 // themes not supporting IDR_THROBBER_WAITING are causing this 126 // themes not supporting IDR_THROBBER_WAITING are causing this
124 // value to be 0 which causes DIV0 crashes. The value of 5 127 // value to be 0 which causes DIV0 crashes. The value of 5
125 // matches the current bitmaps in our source. 128 // matches the current bitmaps in our source.
126 if (waiting_to_loading_frame_count_ratio == 0) 129 if (waiting_to_loading_frame_count_ratio == 0)
127 waiting_to_loading_frame_count_ratio = 5; 130 waiting_to_loading_frame_count_ratio = 5;
128 } 131 }
129 132
130 TabRendererGtk::LoadingAnimation::Data::Data( 133 TabRendererGtk::LoadingAnimation::Data::Data(
131 int loading, int waiting, int waiting_to_loading) 134 int loading, int waiting, int waiting_to_loading)
132 : waiting_animation_frames(NULL), 135 : loading_animation_frame_count(loading),
133 loading_animation_frames(NULL),
134 loading_animation_frame_count(loading),
135 waiting_animation_frame_count(waiting), 136 waiting_animation_frame_count(waiting),
136 waiting_to_loading_frame_count_ratio(waiting_to_loading) { 137 waiting_to_loading_frame_count_ratio(waiting_to_loading) {
137 } 138 }
138 139
139 bool TabRendererGtk::initialized_ = false; 140 bool TabRendererGtk::initialized_ = false;
140 TabRendererGtk::TabImage TabRendererGtk::tab_active_ = {0}; 141 int TabRendererGtk::tab_active_l_width_ = 0;
141 TabRendererGtk::TabImage TabRendererGtk::tab_inactive_ = {0}; 142 int TabRendererGtk::tab_active_l_height_ = 0;
142 TabRendererGtk::TabImage TabRendererGtk::tab_alpha_ = {0}; 143 int TabRendererGtk::tab_active_r_width_ = 0;
144 int TabRendererGtk::tab_inactive_l_width_ = 0;
145 int TabRendererGtk::tab_inactive_l_height_ = 0;
146 int TabRendererGtk::tab_inactive_r_width_ = 0;
143 gfx::Font* TabRendererGtk::title_font_ = NULL; 147 gfx::Font* TabRendererGtk::title_font_ = NULL;
144 int TabRendererGtk::title_font_height_ = 0; 148 int TabRendererGtk::title_font_height_ = 0;
145 int TabRendererGtk::close_button_width_ = 0; 149 int TabRendererGtk::close_button_width_ = 0;
146 int TabRendererGtk::close_button_height_ = 0; 150 int TabRendererGtk::close_button_height_ = 0;
147 SkColor TabRendererGtk::selected_title_color_ = SK_ColorBLACK; 151 SkColor TabRendererGtk::selected_title_color_ = SK_ColorBLACK;
148 SkColor TabRendererGtk::unselected_title_color_ = SkColorSetRGB(64, 64, 64); 152 SkColor TabRendererGtk::unselected_title_color_ = SkColorSetRGB(64, 64, 64);
149 153
150 //////////////////////////////////////////////////////////////////////////////// 154 ////////////////////////////////////////////////////////////////////////////////
151 // TabRendererGtk::LoadingAnimation, public: 155 // TabRendererGtk::LoadingAnimation, public:
152 // 156 //
153 TabRendererGtk::LoadingAnimation::LoadingAnimation( 157 TabRendererGtk::LoadingAnimation::LoadingAnimation(
154 ThemeService* theme_service) 158 GtkThemeService* theme_service)
155 : data_(new Data(theme_service)), 159 : data_(new Data(theme_service)),
156 theme_service_(theme_service), 160 theme_service_(theme_service),
157 animation_state_(ANIMATION_NONE), 161 animation_state_(ANIMATION_NONE),
158 animation_frame_(0) { 162 animation_frame_(0) {
159 registrar_.Add(this, 163 registrar_.Add(this,
160 chrome::NOTIFICATION_BROWSER_THEME_CHANGED, 164 chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
161 content::Source<ThemeService>(theme_service_)); 165 content::Source<ThemeService>(theme_service_));
162 } 166 }
163 167
164 TabRendererGtk::LoadingAnimation::LoadingAnimation( 168 TabRendererGtk::LoadingAnimation::LoadingAnimation(
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 } 205 }
202 206
203 void TabRendererGtk::LoadingAnimation::Observe( 207 void TabRendererGtk::LoadingAnimation::Observe(
204 int type, 208 int type,
205 const content::NotificationSource& source, 209 const content::NotificationSource& source,
206 const content::NotificationDetails& details) { 210 const content::NotificationDetails& details) {
207 DCHECK(type == chrome::NOTIFICATION_BROWSER_THEME_CHANGED); 211 DCHECK(type == chrome::NOTIFICATION_BROWSER_THEME_CHANGED);
208 data_.reset(new Data(theme_service_)); 212 data_.reset(new Data(theme_service_));
209 } 213 }
210 214
215 TabRendererGtk::TabData::TabData()
216 : is_default_favicon(false),
217 loading(false),
218 crashed(false),
219 incognito(false),
220 show_icon(true),
221 mini(false),
222 blocked(false),
223 animating_mini_change(false),
224 app(false) {
225 }
226
227 TabRendererGtk::TabData::~TabData() {}
228
211 //////////////////////////////////////////////////////////////////////////////// 229 ////////////////////////////////////////////////////////////////////////////////
212 // FaviconCrashAnimation 230 // FaviconCrashAnimation
213 // 231 //
214 // A custom animation subclass to manage the favicon crash animation. 232 // A custom animation subclass to manage the favicon crash animation.
215 class TabRendererGtk::FaviconCrashAnimation : public ui::LinearAnimation, 233 class TabRendererGtk::FaviconCrashAnimation : public ui::LinearAnimation,
216 public ui::AnimationDelegate { 234 public ui::AnimationDelegate {
217 public: 235 public:
218 explicit FaviconCrashAnimation(TabRendererGtk* target) 236 explicit FaviconCrashAnimation(TabRendererGtk* target)
219 : ALLOW_THIS_IN_INITIALIZER_LIST(ui::LinearAnimation(1000, 25, this)), 237 : ALLOW_THIS_IN_INITIALIZER_LIST(ui::LinearAnimation(1000, 25, this)),
220 target_(target) { 238 target_(target) {
(...skipping 22 matching lines...) Expand all
243 261
244 private: 262 private:
245 TabRendererGtk* target_; 263 TabRendererGtk* target_;
246 264
247 DISALLOW_COPY_AND_ASSIGN(FaviconCrashAnimation); 265 DISALLOW_COPY_AND_ASSIGN(FaviconCrashAnimation);
248 }; 266 };
249 267
250 //////////////////////////////////////////////////////////////////////////////// 268 ////////////////////////////////////////////////////////////////////////////////
251 // TabRendererGtk, public: 269 // TabRendererGtk, public:
252 270
253 TabRendererGtk::TabRendererGtk(ThemeService* theme_service) 271 TabRendererGtk::TabRendererGtk(GtkThemeService* theme_service)
254 : showing_icon_(false), 272 : showing_icon_(false),
255 showing_close_button_(false), 273 showing_close_button_(false),
256 favicon_hiding_offset_(0), 274 favicon_hiding_offset_(0),
257 should_display_crashed_favicon_(false), 275 should_display_crashed_favicon_(false),
258 loading_animation_(theme_service), 276 loading_animation_(theme_service),
259 background_offset_x_(0), 277 background_offset_x_(0),
260 background_offset_y_(kInactiveTabBackgroundOffsetY), 278 background_offset_y_(kInactiveTabBackgroundOffsetY),
261 theme_service_(theme_service), 279 theme_service_(theme_service),
262 close_button_color_(0), 280 close_button_color_(0),
263 is_active_(false) { 281 is_active_(false) {
264 InitResources(); 282 InitResources();
265 283
266 tab_.Own(gtk_fixed_new()); 284 tab_.Own(gtk_fixed_new());
267 gtk_widget_set_app_paintable(tab_.get(), TRUE); 285 gtk_widget_set_app_paintable(tab_.get(), TRUE);
268 g_signal_connect(tab_.get(), "expose-event", 286 g_signal_connect(tab_.get(), "expose-event",
269 G_CALLBACK(OnExposeEventThunk), this); 287 G_CALLBACK(OnExposeEventThunk), this);
270 g_signal_connect(tab_.get(), "size-allocate", 288 g_signal_connect(tab_.get(), "size-allocate",
271 G_CALLBACK(OnSizeAllocateThunk), this); 289 G_CALLBACK(OnSizeAllocateThunk), this);
272 close_button_.reset(MakeCloseButton()); 290 close_button_.reset(MakeCloseButton());
273 gtk_widget_show(tab_.get()); 291 gtk_widget_show(tab_.get());
274 292
275 hover_animation_.reset(new ui::SlideAnimation(this)); 293 hover_animation_.reset(new ui::SlideAnimation(this));
276 hover_animation_->SetSlideDuration(kHoverDurationMs); 294 hover_animation_->SetSlideDuration(kHoverDurationMs);
277
278 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
279 content::Source<ThemeService>(theme_service_));
280 } 295 }
281 296
282 TabRendererGtk::~TabRendererGtk() { 297 TabRendererGtk::~TabRendererGtk() {
283 tab_.Destroy(); 298 tab_.Destroy();
284 for (BitmapCache::iterator it = cached_bitmaps_.begin();
285 it != cached_bitmaps_.end(); ++it) {
286 delete it->second.bitmap;
287 }
288 } 299 }
289 300
290 void TabRendererGtk::UpdateData(TabContents* contents, 301 void TabRendererGtk::UpdateData(TabContents* contents,
291 bool app, 302 bool app,
292 bool loading_only) { 303 bool loading_only) {
293 DCHECK(contents); 304 DCHECK(contents);
294 TabContentsWrapper* wrapper = 305 TabContentsWrapper* wrapper =
295 TabContentsWrapper::GetCurrentWrapperForContents(contents); 306 TabContentsWrapper::GetCurrentWrapperForContents(contents);
296 307
297 if (!loading_only) { 308 if (!loading_only) {
298 data_.title = contents->GetTitle(); 309 data_.title = contents->GetTitle();
299 data_.incognito = contents->browser_context()->IsOffTheRecord(); 310 data_.incognito = contents->browser_context()->IsOffTheRecord();
300 data_.crashed = contents->is_crashed(); 311 data_.crashed = contents->is_crashed();
301 312
302 SkBitmap* app_icon = 313 SkBitmap* app_icon =
303 TabContentsWrapper::GetCurrentWrapperForContents(contents)-> 314 TabContentsWrapper::GetCurrentWrapperForContents(contents)->
304 extension_tab_helper()->GetExtensionAppIcon(); 315 extension_tab_helper()->GetExtensionAppIcon();
305 if (app_icon) 316 if (app_icon) {
306 data_.favicon = *app_icon; 317 data_.favicon = *app_icon;
307 else 318 } else {
308 data_.favicon = wrapper->favicon_tab_helper()->GetFavicon(); 319 data_.favicon = wrapper->favicon_tab_helper()->GetFavicon();
320 }
309 321
310 data_.app = app; 322 data_.app = app;
323
324 // Make a cairo cached version of the favicon.
325 if (!data_.favicon.isNull()) {
326 // Instead of resizing the icon during each frame, create our resized
327 // icon resource now, send it to the xserver and use that each frame
328 // instead.
329
330 // For source images smaller than the favicon square, scale them as if
331 // they were padded to fit the favicon square, so we don't blow up tiny
332 // falcons into larger or nonproportional results.
333 int src_w = data_.favicon.width();
334 int src_h = data_.favicon.height();
335 float float_src_w = static_cast<float>(src_w);
336 float float_src_h = static_cast<float>(src_h);
337 float scalable_w, scalable_h;
338 if (src_w <= gfx::kFaviconSize && src_h <= gfx::kFaviconSize) {
339 scalable_w = scalable_h = gfx::kFaviconSize;
340 } else {
341 scalable_w = float_src_w;
342 scalable_h = float_src_h;
343 }
344
345 // Scale proportionately.
346 float float_size = gfx::kFaviconSize;
347 float scale = std::min(float_size / scalable_w,
348 float_size / scalable_h);
349 int dest_w = static_cast<int>(float_src_w * scale);
350 int dest_h = static_cast<int>(float_src_h * scale);
351
352 GdkPixbuf* pixbuf;
353 if (dest_w == src_w && dest_h == src_h) {
354 pixbuf = gfx::GdkPixbufFromSkBitmap(&data_.favicon);
355 } else {
356 SkBitmap resized_icon = skia::ImageOperations::Resize(
357 data_.favicon,
358 skia::ImageOperations::RESIZE_BETTER,
359 dest_w, dest_h);
360 pixbuf = gfx::GdkPixbufFromSkBitmap(&resized_icon);
361 }
362
363 data_.cairo_favicon.UsePixbuf(pixbuf);
364 g_object_unref(pixbuf);
365 } else {
366 data_.cairo_favicon.Reset();
367 }
368
311 // This is kind of a hacky way to determine whether our icon is the default 369 // This is kind of a hacky way to determine whether our icon is the default
312 // favicon. But the plumbing that would be necessary to do it right would 370 // favicon. But the plumbing that would be necessary to do it right would
313 // be a good bit of work and would sully code for other platforms which 371 // be a good bit of work and would sully code for other platforms which
314 // don't care to custom-theme the favicon. Hopefully the default favicon 372 // don't care to custom-theme the favicon. Hopefully the default favicon
315 // will eventually be chromium-themable and this code will go away. 373 // will eventually be chromium-themable and this code will go away.
316 data_.is_default_favicon = 374 data_.is_default_favicon =
317 (data_.favicon.pixelRef() == 375 (data_.favicon.pixelRef() ==
318 ResourceBundle::GetSharedInstance().GetBitmapNamed( 376 ResourceBundle::GetSharedInstance().GetBitmapNamed(
319 IDR_DEFAULT_FAVICON)->pixelRef()); 377 IDR_DEFAULT_FAVICON)->pixelRef());
320 } 378 }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 gtk_widget_show(close_button_->widget()); 428 gtk_widget_show(close_button_->widget());
371 } else { 429 } else {
372 gtk_widget_hide_all(tab_.get()); 430 gtk_widget_hide_all(tab_.get());
373 } 431 }
374 } 432 }
375 433
376 bool TabRendererGtk::ValidateLoadingAnimation(AnimationState animation_state) { 434 bool TabRendererGtk::ValidateLoadingAnimation(AnimationState animation_state) {
377 return loading_animation_.ValidateLoadingAnimation(animation_state); 435 return loading_animation_.ValidateLoadingAnimation(animation_state);
378 } 436 }
379 437
380 void TabRendererGtk::PaintFaviconArea(GdkEventExpose* event) { 438 void TabRendererGtk::PaintFaviconArea(GtkWidget* widget, cairo_t* cr) {
381 DCHECK(ShouldShowIcon()); 439 DCHECK(ShouldShowIcon());
382 440
383 // The paint area is the favicon bounds, but we're painting into the gdk 441 cairo_rectangle(cr,
384 // window belonging to the tabstrip. So the coordinates are relative to the 442 x() + favicon_bounds_.x(),
385 // top left of the tab strip. 443 y() + favicon_bounds_.y(),
386 event->area.x = x() + favicon_bounds_.x(); 444 favicon_bounds_.width(),
387 event->area.y = y() + favicon_bounds_.y(); 445 favicon_bounds_.height());
388 event->area.width = favicon_bounds_.width(); 446 cairo_clip(cr);
389 event->area.height = favicon_bounds_.height();
390 gfx::CanvasSkiaPaint canvas(event, false);
391 447
392 // The actual paint methods expect 0, 0 to be the tab top left (see 448 // The tab is rendered into a windowless widget whose offset is at the
393 // PaintTab). 449 // coordinate event->area. Translate by these offsets so we can render at
394 canvas.TranslateInt(x(), y()); 450 // (0,0) to match Windows' rendering metrics.
451 cairo_matrix_t cairo_matrix;
452 cairo_matrix_init_translate(&cairo_matrix, x(), y());
453 cairo_set_matrix(cr, &cairo_matrix);
395 454
396 // Paint the background behind the favicon. 455 // Which background should we be painting?
397 int theme_id; 456 int theme_id;
398 int offset_y = 0; 457 int offset_y = 0;
399 if (IsActive()) { 458 if (IsActive()) {
400 theme_id = IDR_THEME_TOOLBAR; 459 theme_id = IDR_THEME_TOOLBAR;
401 } else { 460 } else {
402 if (!data_.incognito) { 461 if (!data_.incognito) {
403 theme_id = IDR_THEME_TAB_BACKGROUND; 462 theme_id = IDR_THEME_TAB_BACKGROUND;
Evan Stade 2011/10/25 23:33:30 ternary operator
Elliot Glaysher 2011/10/26 21:06:57 Done.
404 } else { 463 } else {
405 theme_id = IDR_THEME_TAB_BACKGROUND_INCOGNITO; 464 theme_id = IDR_THEME_TAB_BACKGROUND_INCOGNITO;
406 } 465 }
407 if (!theme_service_->HasCustomImage(theme_id)) 466 if (!theme_service_->HasCustomImage(theme_id))
408 offset_y = background_offset_y_; 467 offset_y = background_offset_y_;
409 } 468 }
410 SkBitmap* tab_bg = theme_service_->GetBitmapNamed(theme_id); 469
411 canvas.TileImageInt(*tab_bg, 470 // Paint the background behind the favicon.
412 x() + favicon_bounds_.x(), offset_y + favicon_bounds_.y(), 471 CairoCachedSurface* tab_bg =
413 favicon_bounds_.x(), favicon_bounds_.y(), 472 theme_service_->GetSurfaceNamed(theme_id, widget);
414 favicon_bounds_.width(), favicon_bounds_.height()); 473 tab_bg->SetSource(cr, -x(), -offset_y);
474 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
475 cairo_rectangle(cr,
476 favicon_bounds_.x(), favicon_bounds_.y(),
477 favicon_bounds_.width(), favicon_bounds_.height());
478 cairo_fill(cr);
415 479
416 if (!IsActive()) { 480 if (!IsActive()) {
417 double throb_value = GetThrobValue(); 481 double throb_value = GetThrobValue();
418 if (throb_value > 0) { 482 if (throb_value > 0) {
419 SkRect bounds; 483 cairo_push_group(cr);
420 bounds.set(favicon_bounds_.x(), favicon_bounds_.y(), 484 CairoCachedSurface* active_bg = theme_service_->GetSurfaceNamed(
421 favicon_bounds_.right(), favicon_bounds_.bottom()); 485 IDR_THEME_TOOLBAR, widget);
422 canvas.sk_canvas()->saveLayerAlpha( 486 active_bg->SetSource(cr, -x(), 0);
423 &bounds, static_cast<int>(throb_value * 0xff), 487 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
424 SkCanvas::kARGB_ClipLayer_SaveFlag); 488
425 canvas.sk_canvas()->drawARGB(0, 255, 255, 255, SkXfermode::kClear_Mode); 489 cairo_rectangle(cr,
426 SkBitmap* active_bg = theme_service_->GetBitmapNamed(IDR_THEME_TOOLBAR); 490 favicon_bounds_.x(), favicon_bounds_.y(),
427 canvas.TileImageInt(*active_bg, 491 favicon_bounds_.width(), favicon_bounds_.height());
428 x() + favicon_bounds_.x(), favicon_bounds_.y(), 492 cairo_fill(cr);
429 favicon_bounds_.x(), favicon_bounds_.y(), 493
430 favicon_bounds_.width(), favicon_bounds_.height()); 494 cairo_pop_group_to_source(cr);
431 canvas.sk_canvas()->restore(); 495 cairo_paint_with_alpha(cr, throb_value);
432 } 496 }
433 } 497 }
434 498
435 // Now paint the icon. 499 PaintIcon(widget, cr);
436 PaintIcon(&canvas);
437 } 500 }
438 501
439 bool TabRendererGtk::ShouldShowIcon() const { 502 bool TabRendererGtk::ShouldShowIcon() const {
440 if (mini() && height() >= GetMinimumUnselectedSize().height()) { 503 if (mini() && height() >= GetMinimumUnselectedSize().height()) {
441 return true; 504 return true;
442 } else if (!data_.show_icon) { 505 } else if (!data_.show_icon) {
443 return false; 506 return false;
444 } else if (IsActive()) { 507 } else if (IsActive()) {
445 // The active tab clips favicon before close button. 508 // The active tab clips favicon before close button.
446 return IconCapacity() >= 2; 509 return IconCapacity() >= 2;
447 } 510 }
448 // Non-selected tabs clip close button before favicon. 511 // Non-selected tabs clip close button before favicon.
449 return IconCapacity() >= 1; 512 return IconCapacity() >= 1;
450 } 513 }
451 514
452 // static 515 // static
453 gfx::Size TabRendererGtk::GetMinimumUnselectedSize() { 516 gfx::Size TabRendererGtk::GetMinimumUnselectedSize() {
454 InitResources(); 517 InitResources();
455 518
456 gfx::Size minimum_size; 519 gfx::Size minimum_size;
457 minimum_size.set_width(kLeftPadding + kRightPadding); 520 minimum_size.set_width(kLeftPadding + kRightPadding);
458 // Since we use bitmap images, the real minimum height of the image is 521 // Since we use bitmap images, the real minimum height of the image is
459 // defined most accurately by the height of the end cap images. 522 // defined most accurately by the height of the end cap images.
460 minimum_size.set_height(tab_active_.image_l->height() - kToolbarOverlap); 523 minimum_size.set_height(tab_active_l_height_ - kToolbarOverlap);
461 return minimum_size; 524 return minimum_size;
462 } 525 }
463 526
464 // static 527 // static
465 gfx::Size TabRendererGtk::GetMinimumSelectedSize() { 528 gfx::Size TabRendererGtk::GetMinimumSelectedSize() {
466 gfx::Size minimum_size = GetMinimumUnselectedSize(); 529 gfx::Size minimum_size = GetMinimumUnselectedSize();
467 minimum_size.set_width(kLeftPadding + gfx::kFaviconSize + kRightPadding); 530 minimum_size.set_width(kLeftPadding + gfx::kFaviconSize + kRightPadding);
468 return minimum_size; 531 return minimum_size;
469 } 532 }
470 533
(...skipping 11 matching lines...) Expand all
482 545
483 // static 546 // static
484 int TabRendererGtk::GetContentHeight() { 547 int TabRendererGtk::GetContentHeight() {
485 // The height of the content of the Tab is the largest of the favicon, 548 // The height of the content of the Tab is the largest of the favicon,
486 // the title text and the close button graphic. 549 // the title text and the close button graphic.
487 int content_height = std::max(gfx::kFaviconSize, title_font_height_); 550 int content_height = std::max(gfx::kFaviconSize, title_font_height_);
488 return std::max(content_height, close_button_height_); 551 return std::max(content_height, close_button_height_);
489 } 552 }
490 553
491 // static 554 // static
492 void TabRendererGtk::LoadTabImages() {
493 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
494
495 tab_alpha_.image_l = rb.GetBitmapNamed(IDR_TAB_ALPHA_LEFT);
496 tab_alpha_.image_r = rb.GetBitmapNamed(IDR_TAB_ALPHA_RIGHT);
497
498 tab_active_.image_l = rb.GetBitmapNamed(IDR_TAB_ACTIVE_LEFT);
499 tab_active_.image_c = rb.GetBitmapNamed(IDR_TAB_ACTIVE_CENTER);
500 tab_active_.image_r = rb.GetBitmapNamed(IDR_TAB_ACTIVE_RIGHT);
501 tab_active_.l_width = tab_active_.image_l->width();
502 tab_active_.r_width = tab_active_.image_r->width();
503
504 tab_inactive_.image_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT);
505 tab_inactive_.image_c = rb.GetBitmapNamed(IDR_TAB_INACTIVE_CENTER);
506 tab_inactive_.image_r = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT);
507 tab_inactive_.l_width = tab_inactive_.image_l->width();
508 tab_inactive_.r_width = tab_inactive_.image_r->width();
509
510 close_button_width_ = rb.GetBitmapNamed(IDR_TAB_CLOSE)->width();
511 close_button_height_ = rb.GetBitmapNamed(IDR_TAB_CLOSE)->height();
512 }
513
514 // static
515 void TabRendererGtk::SetSelectedTitleColor(SkColor color) { 555 void TabRendererGtk::SetSelectedTitleColor(SkColor color) {
516 selected_title_color_ = color; 556 selected_title_color_ = color;
517 } 557 }
518 558
519 // static 559 // static
520 void TabRendererGtk::SetUnselectedTitleColor(SkColor color) { 560 void TabRendererGtk::SetUnselectedTitleColor(SkColor color) {
521 unselected_title_color_ = color; 561 unselected_title_color_ = color;
522 } 562 }
523 563
524 gfx::Rect TabRendererGtk::GetNonMirroredBounds(GtkWidget* parent) const { 564 gfx::Rect TabRendererGtk::GetNonMirroredBounds(GtkWidget* parent) const {
(...skipping 23 matching lines...) Expand all
548 void TabRendererGtk::StopMiniTabTitleAnimation() { 588 void TabRendererGtk::StopMiniTabTitleAnimation() {
549 if (mini_title_animation_.get()) 589 if (mini_title_animation_.get())
550 mini_title_animation_->Stop(); 590 mini_title_animation_->Stop();
551 } 591 }
552 592
553 void TabRendererGtk::SetBounds(const gfx::Rect& bounds) { 593 void TabRendererGtk::SetBounds(const gfx::Rect& bounds) {
554 requisition_ = bounds; 594 requisition_ = bounds;
555 gtk_widget_set_size_request(tab_.get(), bounds.width(), bounds.height()); 595 gtk_widget_set_size_request(tab_.get(), bounds.width(), bounds.height());
556 } 596 }
557 597
558 void TabRendererGtk::Observe(int type,
559 const content::NotificationSource& source,
560 const content::NotificationDetails& details) {
561 DCHECK(type == chrome::NOTIFICATION_BROWSER_THEME_CHANGED);
562
563 // Clear our cache when we receive a theme change notification because it
564 // contains cached bitmaps based off the previous theme.
565 for (BitmapCache::iterator it = cached_bitmaps_.begin();
566 it != cached_bitmaps_.end(); ++it) {
567 delete it->second.bitmap;
568 }
569 cached_bitmaps_.clear();
570 }
571
572 //////////////////////////////////////////////////////////////////////////////// 598 ////////////////////////////////////////////////////////////////////////////////
573 // TabRendererGtk, protected: 599 // TabRendererGtk, protected:
574 600
575 void TabRendererGtk::Raise() const { 601 void TabRendererGtk::Raise() const {
576 if (gtk_button_get_event_window(GTK_BUTTON(close_button_->widget()))) 602 if (gtk_button_get_event_window(GTK_BUTTON(close_button_->widget())))
577 gdk_window_raise(gtk_button_get_event_window( 603 gdk_window_raise(gtk_button_get_event_window(
578 GTK_BUTTON(close_button_->widget()))); 604 GTK_BUTTON(close_button_->widget())));
579 } 605 }
580 606
581 string16 TabRendererGtk::GetTitle() const { 607 string16 TabRendererGtk::GetTitle() const {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
623 } 649 }
624 650
625 void TabRendererGtk::DisplayCrashedFavicon() { 651 void TabRendererGtk::DisplayCrashedFavicon() {
626 should_display_crashed_favicon_ = true; 652 should_display_crashed_favicon_ = true;
627 } 653 }
628 654
629 void TabRendererGtk::ResetCrashedFavicon() { 655 void TabRendererGtk::ResetCrashedFavicon() {
630 should_display_crashed_favicon_ = false; 656 should_display_crashed_favicon_ = false;
631 } 657 }
632 658
633 void TabRendererGtk::Paint(gfx::Canvas* canvas) { 659 void TabRendererGtk::Paint(GtkWidget* widget, cairo_t* cr) {
634 // Don't paint if we're narrower than we can render correctly. (This should 660 // Don't paint if we're narrower than we can render correctly. (This should
635 // only happen during animations). 661 // only happen during animations).
636 if (width() < GetMinimumUnselectedSize().width() && !mini()) 662 if (width() < GetMinimumUnselectedSize().width() && !mini())
637 return; 663 return;
638 664
639 // See if the model changes whether the icons should be painted. 665 // See if the model changes whether the icons should be painted.
640 const bool show_icon = ShouldShowIcon(); 666 const bool show_icon = ShouldShowIcon();
641 const bool show_close_button = ShouldShowCloseBox(); 667 const bool show_close_button = ShouldShowCloseBox();
642 if (show_icon != showing_icon_ || 668 if (show_icon != showing_icon_ ||
643 show_close_button != showing_close_button_) 669 show_close_button != showing_close_button_)
644 Layout(); 670 Layout();
645 671
646 PaintTabBackground(canvas); 672 PaintTabBackground(widget, cr);
647 673
648 if (!mini() || width() > kMiniTabRendererAsNormalTabWidth) 674 if (!mini() || width() > kMiniTabRendererAsNormalTabWidth)
649 PaintTitle(canvas); 675 PaintTitle(widget, cr);
650 676
651 if (show_icon) 677 if (show_icon)
652 PaintIcon(canvas); 678 PaintIcon(widget, cr);
653 } 679 }
654 680
655 cairo_surface_t* TabRendererGtk::PaintToSurface() { 681 cairo_surface_t* TabRendererGtk::PaintToSurface(GtkWidget* widget,
656 gfx::CanvasSkia canvas(width(), height(), false); 682 cairo_t* cr) {
657 Paint(&canvas); 683 cairo_surface_t* target = cairo_get_target(cr);
658 return cairo_surface_reference(cairo_get_target( 684 cairo_surface_t* out_surface = cairo_surface_create_similar(
659 skia::BeginPlatformPaint(canvas.sk_canvas()))); 685 target,
686 CAIRO_CONTENT_COLOR_ALPHA,
687 width(), height());
688
689 cairo_t* out_cr = cairo_create(out_surface);
690 Paint(widget, out_cr);
691 cairo_destroy(out_cr);
692
693 return out_surface;
660 } 694 }
661 695
662 void TabRendererGtk::SchedulePaint() { 696 void TabRendererGtk::SchedulePaint() {
663 gtk_widget_queue_draw(tab_.get()); 697 gtk_widget_queue_draw(tab_.get());
664 } 698 }
665 699
666 gfx::Rect TabRendererGtk::GetLocalBounds() { 700 gfx::Rect TabRendererGtk::GetLocalBounds() {
667 return gfx::Rect(0, 0, bounds_.width(), bounds_.height()); 701 return gfx::Rect(0, 0, bounds_.width(), bounds_.height());
668 } 702 }
669 703
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
761 void TabRendererGtk::MoveCloseButtonWidget() { 795 void TabRendererGtk::MoveCloseButtonWidget() {
762 if (!close_button_bounds_.IsEmpty()) { 796 if (!close_button_bounds_.IsEmpty()) {
763 gtk_fixed_move(GTK_FIXED(tab_.get()), close_button_->widget(), 797 gtk_fixed_move(GTK_FIXED(tab_.get()), close_button_->widget(),
764 close_button_bounds_.x(), close_button_bounds_.y()); 798 close_button_bounds_.x(), close_button_bounds_.y());
765 gtk_widget_show(close_button_->widget()); 799 gtk_widget_show(close_button_->widget());
766 } else { 800 } else {
767 gtk_widget_hide(close_button_->widget()); 801 gtk_widget_hide(close_button_->widget());
768 } 802 }
769 } 803 }
770 804
771 SkBitmap* TabRendererGtk::GetMaskedBitmap(const SkBitmap* mask, 805 void TabRendererGtk::PaintTab(GtkWidget* widget, GdkEventExpose* event) {
772 const SkBitmap* background, int bg_offset_x, int bg_offset_y) { 806 cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(widget->window));
773 // We store a bitmap for each mask + background pair (4 total bitmaps). We 807 gdk_cairo_rectangle(cr, &event->area);
774 // replace the cached image if the tab has moved relative to the background. 808 cairo_clip(cr);
775 BitmapCache::iterator it = cached_bitmaps_.find(std::make_pair(mask,
776 background));
777 if (it != cached_bitmaps_.end()) {
778 if (it->second.bg_offset_x == bg_offset_x &&
779 it->second.bg_offset_y == bg_offset_y) {
780 return it->second.bitmap;
781 }
782 // The background offset changed so we should re-render with the new
783 // offsets.
784 delete it->second.bitmap;
785 }
786 SkBitmap image = SkBitmapOperations::CreateTiledBitmap(
787 *background, bg_offset_x, bg_offset_y, mask->width(),
788 height() + kToolbarOverlap);
789 CachedBitmap bitmap = {
790 bg_offset_x,
791 bg_offset_y,
792 new SkBitmap(SkBitmapOperations::CreateMaskedBitmap(image, *mask))
793 };
794 cached_bitmaps_[std::make_pair(mask, background)] = bitmap;
795 return bitmap.bitmap;
796 }
797
798 void TabRendererGtk::PaintTab(GdkEventExpose* event) {
799 gfx::CanvasSkiaPaint canvas(event, false);
800 if (canvas.is_empty())
801 return;
802 809
803 // The tab is rendered into a windowless widget whose offset is at the 810 // The tab is rendered into a windowless widget whose offset is at the
804 // coordinate event->area. Translate by these offsets so we can render at 811 // coordinate event->area. Translate by these offsets so we can render at
805 // (0,0) to match Windows' rendering metrics. 812 // (0,0) to match Windows' rendering metrics.
806 canvas.TranslateInt(event->area.x, event->area.y); 813 cairo_matrix_t cairo_matrix;
814 cairo_matrix_init_translate(&cairo_matrix, event->area.x, event->area.y);
815 cairo_set_matrix(cr, &cairo_matrix);
807 816
808 // Save the original x offset so we can position background images properly. 817 // Save the original x offset so we can position background images properly.
809 background_offset_x_ = event->area.x; 818 background_offset_x_ = event->area.x;
810 819
811 Paint(&canvas); 820 Paint(widget, cr);
821 cairo_destroy(cr);
812 } 822 }
813 823
814 void TabRendererGtk::PaintTitle(gfx::Canvas* canvas) { 824 void TabRendererGtk::PaintTitle(GtkWidget* widget, cairo_t* cr) {
825 if (title_bounds_.IsEmpty())
826 return;
827
815 // Paint the Title. 828 // Paint the Title.
816 string16 title = data_.title; 829 string16 title = data_.title;
817 if (title.empty()) { 830 if (title.empty()) {
818 title = data_.loading ? 831 title = data_.loading ?
819 l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE) : 832 l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE) :
820 TabContentsWrapper::GetDefaultTitle(); 833 TabContentsWrapper::GetDefaultTitle();
821 } else { 834 } else {
822 Browser::FormatTitleForDisplay(&title); 835 Browser::FormatTitleForDisplay(&title);
823 } 836 }
824 837
825 SkColor title_color = IsSelected() ? selected_title_color_ 838 SkColor title_color = IsSelected() ? selected_title_color_
826 : unselected_title_color_; 839 : unselected_title_color_;
827 canvas->DrawStringInt(title, *title_font_, title_color, 840
828 title_bounds_.x(), title_bounds_.y(), 841 gfx::PangoDrawString context(
829 title_bounds_.width(), title_bounds_.height()); 842 cr, title, *title_font_, title_bounds_,
843 title_bounds_,
844 base::i18n::IsRTL() ? gfx::Canvas::TEXT_ALIGN_RIGHT :
845 gfx::Canvas::TEXT_ALIGN_LEFT);
846 context.Draw(title_color);
830 } 847 }
831 848
832 void TabRendererGtk::PaintIcon(gfx::Canvas* canvas) { 849 void TabRendererGtk::PaintIcon(GtkWidget* widget, cairo_t* cr) {
833 if (loading_animation_.animation_state() != ANIMATION_NONE) { 850 if (loading_animation_.animation_state() != ANIMATION_NONE) {
834 PaintLoadingAnimation(canvas); 851 PaintLoadingAnimation(widget, cr);
835 } else { 852 } else {
836 canvas->Save();
837 canvas->ClipRectInt(0, 0, width(), height() - kFaviconTitleSpacing);
838 if (should_display_crashed_favicon_) { 853 if (should_display_crashed_favicon_) {
839 canvas->DrawBitmapInt(*crashed_favicon, 0, 0, 854 theme_service_->GetSurfaceNamed(IDR_SAD_FAVICON, widget)->SetSource(
840 crashed_favicon->width(), 855 cr, favicon_bounds_.x(),
841 crashed_favicon->height(), 856 favicon_bounds_.y() + favicon_hiding_offset_);
842 favicon_bounds_.x(), 857 cairo_paint(cr);
843 favicon_bounds_.y() + favicon_hiding_offset_,
844 gfx::kFaviconSize, gfx::kFaviconSize,
845 true);
846 } else { 858 } else {
847 if (!data_.favicon.isNull()) { 859 if (!data_.favicon.isNull()) {
848 if (data_.is_default_favicon && theme_service_->UsingNativeTheme()) { 860 if (data_.is_default_favicon && theme_service_->UsingNativeTheme()) {
849 GdkPixbuf* favicon = GtkThemeService::GetDefaultFavicon(true); 861 GdkPixbuf* favicon = GtkThemeService::GetDefaultFavicon(true);
850 canvas->AsCanvasSkia()->DrawGdkPixbuf( 862
851 favicon, favicon_bounds_.x(), 863 // TODO(erg): Get GtkThemeService to hand us a
864 // CairoCachedSurface. Then we can simplify all of this.
865 gdk_cairo_set_source_pixbuf(
866 cr, favicon, favicon_bounds_.x(),
852 favicon_bounds_.y() + favicon_hiding_offset_); 867 favicon_bounds_.y() + favicon_hiding_offset_);
853 } else { 868 cairo_paint(cr);
854 // If the favicon is an app icon, it is allowed to be drawn slightly 869 } else if (data_.cairo_favicon.valid()) {
855 // larger than the standard favicon. 870 // TODO(erg): We should research whether we still need to draw app
856 int faviconHeightOffset = data_.app ? -2 : 0; 871 // icons larger. We don't appear to be getting larger icons.
857 int faviconWidthDelta = data_.app ? 872 data_.cairo_favicon.SetSource(
858 data_.favicon.width() - gfx::kFaviconSize : 0; 873 cr,
859 int faviconHeightDelta = data_.app ? 874 favicon_bounds_.x(),
860 data_.favicon.height() - gfx::kFaviconSize : 0; 875 favicon_bounds_.y() + favicon_hiding_offset_);
861 876 cairo_paint(cr);
862 // TODO(pkasting): Use code in tab_icon_view.cc:PaintIcon() (or switch
863 // to using that class to render the favicon).
864 canvas->DrawBitmapInt(data_.favicon, 0, 0,
865 data_.favicon.width(),
866 data_.favicon.height(),
867 favicon_bounds_.x() - faviconWidthDelta/2,
868 favicon_bounds_.y() + faviconHeightOffset
869 - faviconHeightDelta/2
870 + favicon_hiding_offset_,
871 gfx::kFaviconSize + faviconWidthDelta,
872 gfx::kFaviconSize + faviconHeightDelta,
873 true);
874 } 877 }
875 } 878 }
876 } 879 }
877 canvas->Restore();
878 }
879 }
880
881 void TabRendererGtk::PaintTabBackground(gfx::Canvas* canvas) {
882 if (IsActive()) {
883 PaintActiveTabBackground(canvas);
884 } else {
885 PaintInactiveTabBackground(canvas);
886
887 double throb_value = GetThrobValue();
888 if (throb_value > 0) {
889 canvas->SaveLayerAlpha(static_cast<int>(throb_value * 0xff),
890 gfx::Rect(width(), height()));
891 canvas->GetSkCanvas()->drawARGB(0, 255, 255, 255,
892 SkXfermode::kClear_Mode);
893 PaintActiveTabBackground(canvas);
894 canvas->Restore();
895 }
896 } 880 }
897 } 881 }
898 882
899 void TabRendererGtk::PaintInactiveTabBackground(gfx::Canvas* canvas) { 883 void TabRendererGtk::PaintTabBackground(GtkWidget* widget, cairo_t* cr) {
884 if (IsActive()) {
885 PaintActiveTabBackground(widget, cr);
886 } else {
887 PaintInactiveTabBackground(widget, cr);
900 888
901 // The tab image needs to be lined up with the background image 889 double throb_value = GetThrobValue();
902 // so that it feels partially transparent. 890 if (throb_value > 0) {
903 int offset_x = background_offset_x_; 891 cairo_push_group(cr);
892 PaintActiveTabBackground(widget, cr);
893 cairo_pop_group_to_source(cr);
894 cairo_paint_with_alpha(cr, throb_value);
895 }
896 }
897 }
904 898
905 int tab_id = data_.incognito ? 899 void TabRendererGtk::DrawTabBackground(
900 cairo_t* cr,
901 GtkWidget* widget,
902 CairoCachedSurface* tab_bg,
903 int offset_x,
904 int offset_y) {
905 tab_bg->SetSource(cr, -offset_x, -offset_y);
906 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
907
908 // Draw left edge
909 CairoCachedSurface* tab_l_mask =
910 theme_service_->GetSurfaceNamed(IDR_TAB_ALPHA_LEFT, widget);
911 tab_l_mask->MaskSource(cr, 0, 0);
912
913 // Draw center
914 cairo_rectangle(cr,
915 tab_active_l_width_, kDropShadowOffset,
916 width() - tab_active_l_width_ - tab_active_r_width_,
917 tab_inactive_l_height_);
918 cairo_fill(cr);
919
920 // Draw right edge
921 CairoCachedSurface* tab_r_mask =
922 theme_service_->GetSurfaceNamed(IDR_TAB_ALPHA_RIGHT, widget);
923 tab_r_mask->MaskSource(cr, width() - tab_active_r_width_, 0);
924 }
925
926 void TabRendererGtk::DrawTabShadow(
927 cairo_t* cr,
928 GtkWidget* widget,
929 int left_idr,
930 int center_idr,
931 int right_idr) {
932 // Draw left drop shadow
933 CairoCachedSurface* active_image_l =
934 theme_service_->GetSurfaceNamed(left_idr, widget);
935 active_image_l->SetSource(cr, 0, 0);
936 cairo_paint(cr);
937
938 // Draw the center shadow
939 CairoCachedSurface* active_image_c =
940 theme_service_->GetSurfaceNamed(center_idr, widget);
941 active_image_c->SetSource(cr, 0, 0);
942 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
943 cairo_rectangle(cr, tab_active_l_width_, 0,
944 width() - tab_active_l_width_ - tab_active_r_width_,
945 height());
946 cairo_fill(cr);
947
948 // Draw right drop shadow
949 CairoCachedSurface* active_image_r =
950 theme_service_->GetSurfaceNamed(right_idr, widget);
951 active_image_r->SetSource(cr, width() - active_image_r->Width(), 0);
952 cairo_paint(cr);
953 }
954
955 void TabRendererGtk::PaintInactiveTabBackground(GtkWidget* widget,
956 cairo_t* cr) {
957 int theme_id = data_.incognito ?
906 IDR_THEME_TAB_BACKGROUND_INCOGNITO : IDR_THEME_TAB_BACKGROUND; 958 IDR_THEME_TAB_BACKGROUND_INCOGNITO : IDR_THEME_TAB_BACKGROUND;
907 if (IsSelected()) 959 if (IsSelected())
908 tab_id = IDR_THEME_TAB_BACKGROUND_V; 960 theme_id = IDR_THEME_TAB_BACKGROUND_V;
909 961
910 SkBitmap* tab_bg = theme_service_->GetBitmapNamed(tab_id); 962 CairoCachedSurface* tab_bg =
963 theme_service_->GetSurfaceNamed(theme_id, widget);
911 964
912 // If the theme is providing a custom background image, then its top edge 965 // If the theme is providing a custom background image, then its top edge
913 // should be at the top of the tab. Otherwise, we assume that the background 966 // should be at the top of the tab. Otherwise, we assume that the background
914 // image is a composited foreground + frame image. 967 // image is a composited foreground + frame image.
915 int offset_y = theme_service_->HasCustomImage(tab_id) ? 968 int offset_y = theme_service_->HasCustomImage(theme_id) ?
916 0 : background_offset_y_; 969 0 : background_offset_y_;
917 970
918 // Draw left edge. 971 DrawTabBackground(cr, widget, tab_bg, background_offset_x_, offset_y);
919 SkBitmap* theme_l = GetMaskedBitmap(tab_alpha_.image_l, tab_bg, offset_x,
920 offset_y);
921 canvas->DrawBitmapInt(*theme_l, 0, 0);
922 972
923 // Draw right edge. 973 DrawTabShadow(cr, widget, IDR_TAB_INACTIVE_LEFT, IDR_TAB_INACTIVE_CENTER,
924 SkBitmap* theme_r = GetMaskedBitmap(tab_alpha_.image_r, tab_bg, 974 IDR_TAB_INACTIVE_RIGHT);
925 offset_x + width() - tab_active_.r_width, offset_y);
926
927 canvas->DrawBitmapInt(*theme_r, width() - theme_r->width(), 0);
928
929 // Draw center.
930 canvas->TileImageInt(*tab_bg,
931 offset_x + tab_active_.l_width, kDropShadowOffset + offset_y,
932 tab_active_.l_width, 2,
933 width() - tab_active_.l_width - tab_active_.r_width, height() - 2);
934
935 canvas->DrawBitmapInt(*tab_inactive_.image_l, 0, 0);
936 canvas->TileImageInt(*tab_inactive_.image_c, tab_inactive_.l_width, 0,
937 width() - tab_inactive_.l_width - tab_inactive_.r_width, height());
938 canvas->DrawBitmapInt(*tab_inactive_.image_r,
939 width() - tab_inactive_.r_width, 0);
940 } 975 }
941 976
942 void TabRendererGtk::PaintActiveTabBackground(gfx::Canvas* canvas) { 977 void TabRendererGtk::PaintActiveTabBackground(GtkWidget* widget,
943 int offset_x = background_offset_x_; 978 cairo_t* cr) {
979 CairoCachedSurface* tab_bg =
980 theme_service_->GetSurfaceNamed(IDR_THEME_TOOLBAR, widget);
944 981
945 SkBitmap* tab_bg = theme_service_->GetBitmapNamed(IDR_THEME_TOOLBAR); 982 DrawTabBackground(cr, widget, tab_bg, background_offset_x_, 0);
946 983 DrawTabShadow(cr, widget, IDR_TAB_ACTIVE_LEFT, IDR_TAB_ACTIVE_CENTER,
947 // Draw left edge. 984 IDR_TAB_ACTIVE_RIGHT);
948 SkBitmap* theme_l = GetMaskedBitmap(tab_alpha_.image_l, tab_bg, offset_x, 0);
949 canvas->DrawBitmapInt(*theme_l, 0, 0);
950
951 // Draw right edge.
952 SkBitmap* theme_r = GetMaskedBitmap(tab_alpha_.image_r, tab_bg,
953 offset_x + width() - tab_active_.r_width, 0);
954 canvas->DrawBitmapInt(*theme_r, width() - tab_active_.r_width, 0);
955
956 // Draw center.
957 canvas->TileImageInt(*tab_bg,
958 offset_x + tab_active_.l_width, kDropShadowHeight,
959 tab_active_.l_width, kDropShadowHeight,
960 width() - tab_active_.l_width - tab_active_.r_width,
961 height() - kDropShadowHeight);
962
963 canvas->DrawBitmapInt(*tab_active_.image_l, 0, 0);
964 canvas->TileImageInt(*tab_active_.image_c, tab_active_.l_width, 0,
965 width() - tab_active_.l_width - tab_active_.r_width, height());
966 canvas->DrawBitmapInt(*tab_active_.image_r, width() - tab_active_.r_width, 0);
967 } 985 }
968 986
969 void TabRendererGtk::PaintLoadingAnimation(gfx::Canvas* canvas) { 987 void TabRendererGtk::PaintLoadingAnimation(GtkWidget* widget,
970 const SkBitmap* frames = 988 cairo_t* cr) {
971 (loading_animation_.animation_state() == ANIMATION_WAITING) ? 989 int id = loading_animation_.animation_state() == ANIMATION_WAITING ?
972 loading_animation_.waiting_animation_frames() : 990 IDR_THROBBER_WAITING : IDR_THROBBER;
973 loading_animation_.loading_animation_frames(); 991 CairoCachedSurface* throbber = theme_service_->GetSurfaceNamed(id, widget);
974 const int image_size = frames->height(); 992
993 const int image_size = throbber->Height();
975 const int image_offset = loading_animation_.animation_frame() * image_size; 994 const int image_offset = loading_animation_.animation_frame() * image_size;
976 DCHECK(image_size == favicon_bounds_.height()); 995 DCHECK(image_size == favicon_bounds_.height());
977 DCHECK(image_size == favicon_bounds_.width()); 996 DCHECK(image_size == favicon_bounds_.width());
978 997
979 // NOTE: the clipping is a work around for 69528, it shouldn't be necessary. 998 throbber->SetSource(cr, favicon_bounds_.x() - image_offset,
980 canvas->Save(); 999 favicon_bounds_.y());
981 canvas->ClipRectInt( 1000 cairo_rectangle(cr, favicon_bounds_.x(), favicon_bounds_.y(),
982 favicon_bounds_.x(), favicon_bounds_.y(), image_size, image_size); 1001 image_size, image_size);
983 canvas->DrawBitmapInt(*frames, image_offset, 0, image_size, image_size, 1002 cairo_fill(cr);
984 favicon_bounds_.x(), favicon_bounds_.y(), image_size, image_size,
985 false);
986 canvas->Restore();
987 } 1003 }
988 1004
989 int TabRendererGtk::IconCapacity() const { 1005 int TabRendererGtk::IconCapacity() const {
990 if (height() < GetMinimumUnselectedSize().height()) 1006 if (height() < GetMinimumUnselectedSize().height())
991 return 0; 1007 return 0;
992 return (width() - kLeftPadding - kRightPadding) / gfx::kFaviconSize; 1008 return (width() - kLeftPadding - kRightPadding) / gfx::kFaviconSize;
993 } 1009 }
994 1010
995 bool TabRendererGtk::ShouldShowCloseBox() const { 1011 bool TabRendererGtk::ShouldShowCloseBox() const {
996 // The selected tab never clips close button. 1012 // The selected tab never clips close button.
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1040 if (event->button == 2) { 1056 if (event->button == 2) {
1041 CloseButtonClicked(); 1057 CloseButtonClicked();
1042 return TRUE; 1058 return TRUE;
1043 } 1059 }
1044 1060
1045 return FALSE; 1061 return FALSE;
1046 } 1062 }
1047 1063
1048 gboolean TabRendererGtk::OnExposeEvent(GtkWidget* widget, 1064 gboolean TabRendererGtk::OnExposeEvent(GtkWidget* widget,
1049 GdkEventExpose* event) { 1065 GdkEventExpose* event) {
1050 PaintTab(event); 1066 PaintTab(widget, event);
1051 gtk_container_propagate_expose(GTK_CONTAINER(tab_.get()), 1067 gtk_container_propagate_expose(GTK_CONTAINER(tab_.get()),
1052 close_button_->widget(), event); 1068 close_button_->widget(), event);
1053 return TRUE; 1069 return TRUE;
1054 } 1070 }
1055 1071
1056 void TabRendererGtk::OnSizeAllocate(GtkWidget* widget, 1072 void TabRendererGtk::OnSizeAllocate(GtkWidget* widget,
1057 GtkAllocation* allocation) { 1073 GtkAllocation* allocation) {
1058 gfx::Rect bounds = gfx::Rect(allocation->x, allocation->y, 1074 gfx::Rect bounds = gfx::Rect(allocation->x, allocation->y,
1059 allocation->width, allocation->height); 1075 allocation->width, allocation->height);
1060 1076
(...skipping 18 matching lines...) Expand all
1079 hover_animation_->SetTweenType(ui::Tween::EASE_IN); 1095 hover_animation_->SetTweenType(ui::Tween::EASE_IN);
1080 hover_animation_->Hide(); 1096 hover_animation_->Hide();
1081 return FALSE; 1097 return FALSE;
1082 } 1098 }
1083 1099
1084 // static 1100 // static
1085 void TabRendererGtk::InitResources() { 1101 void TabRendererGtk::InitResources() {
1086 if (initialized_) 1102 if (initialized_)
1087 return; 1103 return;
1088 1104
1089 LoadTabImages(); 1105 // Grab the pixel sizes of our masking images.
1106 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
1107 SkBitmap* tab_active_l = rb.GetBitmapNamed(IDR_TAB_ACTIVE_LEFT);
1108 tab_active_l_width_ = tab_active_l->width();
1109 tab_active_l_height_ = tab_active_l->height();
1110 tab_active_r_width_ = rb.GetBitmapNamed(IDR_TAB_ACTIVE_RIGHT)->width();
Evan Stade 2011/10/25 23:33:30 the active and inactive widths are different?
Elliot Glaysher 2011/10/26 21:06:57 Done.
1090 1111
1091 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 1112 SkBitmap* tab_inactive_l = rb.GetBitmapNamed(IDR_TAB_INACTIVE_LEFT);
1113 tab_inactive_l_width_ = tab_inactive_l->width();
1114 tab_inactive_l_height_ = tab_inactive_l->height();
1115 tab_inactive_r_width_ = rb.GetBitmapNamed(IDR_TAB_INACTIVE_RIGHT)->width();
1116 close_button_width_ = rb.GetBitmapNamed(IDR_TAB_CLOSE)->width();
1117 close_button_height_ = rb.GetBitmapNamed(IDR_TAB_CLOSE)->height();
1118
1092 const gfx::Font& base_font = rb.GetFont(ResourceBundle::BaseFont); 1119 const gfx::Font& base_font = rb.GetFont(ResourceBundle::BaseFont);
1093 title_font_ = new gfx::Font(base_font.GetFontName(), kFontPixelSize); 1120 title_font_ = new gfx::Font(base_font.GetFontName(), kFontPixelSize);
1094 title_font_height_ = title_font_->GetHeight(); 1121 title_font_height_ = title_font_->GetHeight();
1095 1122
1096 crashed_favicon = rb.GetBitmapNamed(IDR_SAD_FAVICON);
1097
1098 initialized_ = true; 1123 initialized_ = true;
1099 } 1124 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698