tab_icon_view.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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 "grit/ui_resources.h"
18#include "ui/base/resource/resource_bundle.h"
19#include "ui/base/theme_provider.h"
20#include "ui/gfx/canvas.h"
21#include "ui/gfx/favicon_size.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
28static bool g_initialized = false;
29static gfx::ImageSkia* g_default_favicon = NULL;
30
31// static
32void 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
51TabIconView::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
61TabIconView::~TabIconView() {
62}
63
64void 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
95void 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
103void TabIconView::PaintFavicon(gfx::Canvas* canvas,
104                               const gfx::ImageSkia& image) {
105  PaintIcon(canvas, image, 0, 0, image.width(), image.height(), true);
106}
107
108void 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
140void 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
158gfx::Size TabIconView::GetPreferredSize() const {
159  return gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize);
160}
161