1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/views/tab_icon_view.h" 6 7 #if defined(OS_WIN) 8 #include <windows.h> 9 #include <shellapi.h> 10 #endif 11 12 #include "base/logging.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "chrome/app/chrome_command_ids.h" 15 #include "chrome/browser/ui/views/tab_icon_view_model.h" 16 #include "grit/theme_resources.h" 17 #include "ui/base/resource/resource_bundle.h" 18 #include "ui/base/theme_provider.h" 19 #include "ui/gfx/canvas.h" 20 #include "ui/gfx/favicon_size.h" 21 #include "ui/resources/grit/ui_resources.h" 22 23 #if defined(OS_WIN) 24 #include "chrome/browser/app_icon_win.h" 25 #include "ui/gfx/icon_util.h" 26 #endif 27 28 static bool g_initialized = false; 29 static gfx::ImageSkia* g_default_favicon = NULL; 30 31 // static 32 void TabIconView::InitializeIfNeeded() { 33 if (!g_initialized) { 34 g_initialized = true; 35 36 #if defined(OS_WIN) 37 // The default window icon is the application icon, not the default 38 // favicon. 39 HICON app_icon = GetAppIcon(); 40 scoped_ptr<SkBitmap> bitmap( 41 IconUtil::CreateSkBitmapFromHICON(app_icon, gfx::Size(16, 16))); 42 g_default_favicon = new gfx::ImageSkia(gfx::ImageSkiaRep(*bitmap, 1.0f)); 43 DestroyIcon(app_icon); 44 #else 45 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 46 g_default_favicon = rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_16); 47 #endif 48 } 49 } 50 51 TabIconView::TabIconView(chrome::TabIconViewModel* model, 52 views::MenuButtonListener* listener) 53 : views::MenuButton(NULL, base::string16(), listener, false), 54 model_(model), 55 throbber_running_(false), 56 is_light_(false), 57 throbber_frame_(0) { 58 InitializeIfNeeded(); 59 } 60 61 TabIconView::~TabIconView() { 62 } 63 64 void TabIconView::Update() { 65 static bool initialized = false; 66 static int throbber_frame_count = 0; 67 if (!initialized) { 68 initialized = true; 69 gfx::ImageSkia throbber(*ui::ResourceBundle::GetSharedInstance(). 70 GetImageSkiaNamed(IDR_THROBBER)); 71 throbber_frame_count = throbber.width() / throbber.height(); 72 } 73 74 if (throbber_running_) { 75 // We think the tab is loading. 76 if (!model_->ShouldTabIconViewAnimate()) { 77 // Woops, tab is invalid or not loading, reset our status and schedule 78 // a paint. 79 throbber_running_ = false; 80 SchedulePaint(); 81 } else { 82 // The tab is still loading, increment the frame. 83 throbber_frame_ = (throbber_frame_ + 1) % throbber_frame_count; 84 SchedulePaint(); 85 } 86 } else if (model_->ShouldTabIconViewAnimate()) { 87 // We didn't think we were loading, but the tab is loading. Reset the 88 // frame and status and schedule a paint. 89 throbber_running_ = true; 90 throbber_frame_ = 0; 91 SchedulePaint(); 92 } 93 } 94 95 void TabIconView::PaintThrobber(gfx::Canvas* canvas) { 96 gfx::ImageSkia throbber(*GetThemeProvider()->GetImageSkiaNamed( 97 is_light_ ? IDR_THROBBER_LIGHT : IDR_THROBBER)); 98 int image_size = throbber.height(); 99 PaintIcon(canvas, throbber, throbber_frame_ * image_size, 0, image_size, 100 image_size, false); 101 } 102 103 void TabIconView::PaintFavicon(gfx::Canvas* canvas, 104 const gfx::ImageSkia& image) { 105 PaintIcon(canvas, image, 0, 0, image.width(), image.height(), true); 106 } 107 108 void TabIconView::PaintIcon(gfx::Canvas* canvas, 109 const gfx::ImageSkia& image, 110 int src_x, 111 int src_y, 112 int src_w, 113 int src_h, 114 bool filter) { 115 // For source images smaller than the favicon square, scale them as if they 116 // were padded to fit the favicon square, so we don't blow up tiny favicons 117 // into larger or nonproportional results. 118 float float_src_w = static_cast<float>(src_w); 119 float float_src_h = static_cast<float>(src_h); 120 float scalable_w, scalable_h; 121 if (src_w <= gfx::kFaviconSize && src_h <= gfx::kFaviconSize) { 122 scalable_w = scalable_h = gfx::kFaviconSize; 123 } else { 124 scalable_w = float_src_w; 125 scalable_h = float_src_h; 126 } 127 128 // Scale proportionately. 129 float scale = std::min(static_cast<float>(width()) / scalable_w, 130 static_cast<float>(height()) / scalable_h); 131 int dest_w = static_cast<int>(float_src_w * scale); 132 int dest_h = static_cast<int>(float_src_h * scale); 133 134 // Center the scaled image. 135 canvas->DrawImageInt(image, src_x, src_y, src_w, src_h, 136 (width() - dest_w) / 2, (height() - dest_h) / 2, dest_w, 137 dest_h, filter); 138 } 139 140 void TabIconView::OnPaint(gfx::Canvas* canvas) { 141 bool rendered = false; 142 143 if (throbber_running_) { 144 rendered = true; 145 PaintThrobber(canvas); 146 } else { 147 gfx::ImageSkia favicon = model_->GetFaviconForTabIconView(); 148 if (!favicon.isNull()) { 149 rendered = true; 150 PaintFavicon(canvas, favicon); 151 } 152 } 153 154 if (!rendered) 155 PaintFavicon(canvas, *g_default_favicon); 156 } 157 158 gfx::Size TabIconView::GetPreferredSize() const { 159 return gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize); 160 } 161