172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/tab_icon_view.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <windows.h>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <shellapi.h>
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
14513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "chrome/app/chrome_command_ids.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/app_resources.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h"
1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h"
1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/theme_provider.h"
1972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas.h"
2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/favicon_size.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/app_icon_win.h"
2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/icon_util.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic bool g_initialized = false;
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic SkBitmap* g_default_favicon = NULL;
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabIconView::InitializeIfNeeded() {
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!g_initialized) {
333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    g_initialized = true;
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The default window icon is the application icon, not the default
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // favicon.
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    HICON app_icon = GetAppIcon();
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    g_default_favicon =
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        IconUtil::CreateSkBitmapFromHICON(app_icon, gfx::Size(16, 16));
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DestroyIcon(app_icon);
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    g_default_favicon =
443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_PRODUCT_LOGO_16);
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabIconView::TabIconView(TabIconViewModel* model)
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : model_(model),
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      throbber_running_(false),
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      is_light_(false),
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      throbber_frame_(0) {
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  InitializeIfNeeded();
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTabIconView::~TabIconView() {
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabIconView::Update() {
613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  static bool initialized = false;
623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  static int throbber_frame_count = 0;
633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!initialized) {
643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    initialized = true;
653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    SkBitmap throbber(
663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        *ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_THROBBER));
673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    throbber_frame_count = throbber.width() / throbber.height();
683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (throbber_running_) {
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We think the tab is loading.
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!model_->ShouldTabIconViewAnimate()) {
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Woops, tab is invalid or not loading, reset our status and schedule
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // a paint.
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      throbber_running_ = false;
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SchedulePaint();
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // The tab is still loading, increment the frame.
793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      throbber_frame_ = (throbber_frame_ + 1) % throbber_frame_count;
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SchedulePaint();
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (model_->ShouldTabIconViewAnimate()) {
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We didn't think we were loading, but the tab is loading. Reset the
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // frame and status and schedule a paint.
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    throbber_running_ = true;
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    throbber_frame_ = 0;
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SchedulePaint();
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabIconView::PaintThrobber(gfx::Canvas* canvas) {
923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  SkBitmap throbber(*GetThemeProvider()->GetBitmapNamed(
933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      is_light_ ? IDR_THROBBER_LIGHT : IDR_THROBBER));
943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int image_size = throbber.height();
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  PaintIcon(canvas, throbber, throbber_frame_ * image_size, 0, image_size,
963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            image_size, false);
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid TabIconView::PaintFavicon(gfx::Canvas* canvas, const SkBitmap& bitmap) {
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PaintIcon(canvas, bitmap, 0, 0, bitmap.width(), bitmap.height(), true);
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid TabIconView::PaintIcon(gfx::Canvas* canvas,
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            const SkBitmap& bitmap,
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            int src_x,
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            int src_y,
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            int src_w,
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            int src_h,
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            bool filter) {
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // For source images smaller than the favicon square, scale them as if they
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // were padded to fit the favicon square, so we don't blow up tiny favicons
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // into larger or nonproportional results.
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  float float_src_w = static_cast<float>(src_w);
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  float float_src_h = static_cast<float>(src_h);
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  float scalable_w, scalable_h;
116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (src_w <= kFaviconSize && src_h <= kFaviconSize) {
117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    scalable_w = scalable_h = kFaviconSize;
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scalable_w = float_src_w;
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scalable_h = float_src_h;
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Scale proportionately.
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  float scale = std::min(static_cast<float>(width()) / scalable_w,
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         static_cast<float>(height()) / scalable_h);
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int dest_w = static_cast<int>(float_src_w * scale);
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int dest_h = static_cast<int>(float_src_h * scale);
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Center the scaled image.
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  canvas->DrawBitmapInt(bitmap, src_x, src_y, src_w, src_h,
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        (width() - dest_w) / 2, (height() - dest_h) / 2, dest_w,
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        dest_h, filter);
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
135dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid TabIconView::OnPaint(gfx::Canvas* canvas) {
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool rendered = false;
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (throbber_running_) {
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rendered = true;
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    PaintThrobber(canvas);
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SkBitmap favicon = model_->GetFaviconForTabIconView();
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!favicon.isNull()) {
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      rendered = true;
145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      PaintFavicon(canvas, favicon);
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!rendered)
150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    PaintFavicon(canvas, *g_default_favicon);
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Size TabIconView::GetPreferredSize() {
154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return gfx::Size(kFaviconSize, kFaviconSize);
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
156