OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |