| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/metro_pin_tab_helper_win.h" | 5 #include "chrome/browser/ui/metro_pin_tab_helper_win.h" |
| 6 | 6 |
| 7 #include <set> |
| 8 |
| 7 #include "base/base_paths.h" | 9 #include "base/base_paths.h" |
| 8 #include "base/bind.h" | 10 #include "base/bind.h" |
| 9 #include "base/file_path.h" | 11 #include "base/file_path.h" |
| 10 #include "base/file_util.h" | 12 #include "base/file_util.h" |
| 11 #include "base/logging.h" | 13 #include "base/logging.h" |
| 12 #include "base/memory/ref_counted.h" | 14 #include "base/memory/ref_counted.h" |
| 13 #include "base/memory/ref_counted_memory.h" | 15 #include "base/memory/ref_counted_memory.h" |
| 14 #include "base/path_service.h" | 16 #include "base/path_service.h" |
| 15 #include "base/string_number_conversions.h" | 17 #include "base/string_number_conversions.h" |
| 16 #include "base/utf_string_conversions.h" | 18 #include "base/utf_string_conversions.h" |
| 17 #include "base/win/metro.h" | 19 #include "base/win/metro.h" |
| 18 #include "chrome/browser/favicon/favicon_tab_helper.h" | 20 #include "chrome/browser/favicon/favicon_tab_helper.h" |
| 21 #include "chrome/browser/favicon/favicon_util.h" |
| 19 #include "chrome/browser/ui/tab_contents/tab_contents.h" | 22 #include "chrome/browser/ui/tab_contents/tab_contents.h" |
| 20 #include "chrome/common/chrome_paths.h" | 23 #include "chrome/common/chrome_paths.h" |
| 24 #include "chrome/common/icon_messages.h" |
| 21 #include "content/public/browser/browser_thread.h" | 25 #include "content/public/browser/browser_thread.h" |
| 22 #include "content/public/browser/web_contents.h" | 26 #include "content/public/browser/web_contents.h" |
| 23 #include "crypto/sha2.h" | 27 #include "crypto/sha2.h" |
| 28 #include "third_party/skia/include/core/SkCanvas.h" |
| 29 #include "third_party/skia/include/core/SkColor.h" |
| 24 #include "ui/gfx/canvas.h" | 30 #include "ui/gfx/canvas.h" |
| 25 #include "ui/gfx/codec/png_codec.h" | 31 #include "ui/gfx/codec/png_codec.h" |
| 26 #include "ui/gfx/color_analysis.h" | 32 #include "ui/gfx/color_analysis.h" |
| 27 #include "ui/gfx/color_utils.h" | 33 #include "ui/gfx/color_utils.h" |
| 28 #include "ui/gfx/image/image.h" | 34 #include "ui/gfx/image/image.h" |
| 29 #include "ui/gfx/rect.h" | 35 #include "ui/gfx/rect.h" |
| 30 #include "ui/gfx/size.h" | 36 #include "ui/gfx/size.h" |
| 31 | 37 |
| 32 DEFINE_WEB_CONTENTS_USER_DATA_KEY(MetroPinTabHelper) | 38 DEFINE_WEB_CONTENTS_USER_DATA_KEY(MetroPinTabHelper) |
| 33 | 39 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 const int kBoxWidth = 40; | 74 const int kBoxWidth = 40; |
| 69 const int kBoxHeight = 40; | 75 const int kBoxHeight = 40; |
| 70 const int kCaptionHeight = 20; | 76 const int kCaptionHeight = 20; |
| 71 const double kBoxFade = 0.75; | 77 const double kBoxFade = 0.75; |
| 72 const int kColorMeanDarknessLimit = 100; | 78 const int kColorMeanDarknessLimit = 100; |
| 73 const int kColorMeanLightnessLimit = 650; | 79 const int kColorMeanLightnessLimit = 650; |
| 74 | 80 |
| 75 if (image.isNull()) | 81 if (image.isNull()) |
| 76 return false; | 82 return false; |
| 77 | 83 |
| 78 *logo_path = logo_dir.Append(tile_id).ReplaceExtension(L".png"); | 84 // First paint the image onto an opaque background to get rid of transparency. |
| 79 | 85 // White is used as it will be disregarded in the mean calculation because of |
| 80 // Use a canvas to paint the tile logo. | 86 // lightness limit. |
| 81 gfx::Canvas canvas(gfx::Size(kLogoWidth, kLogoHeight), ui::SCALE_FACTOR_100P, | 87 SkPaint paint; |
| 82 true); | 88 paint.setColor(SK_ColorWHITE); |
| 89 gfx::Canvas favicon_canvas(gfx::Size(image.width(), image.height()), |
| 90 ui::SCALE_FACTOR_100P, true); |
| 91 favicon_canvas.DrawRect(gfx::Rect(0, 0, image.width(), image.height()), |
| 92 paint); |
| 93 favicon_canvas.DrawImageInt(image, 0, 0); |
| 83 | 94 |
| 84 // Fill the tile logo with the average color from bitmap. To do this we need | 95 // Fill the tile logo with the average color from bitmap. To do this we need |
| 85 // to work out the 'average color' which is calculated using PNG encoded data | 96 // to work out the 'average color' which is calculated using PNG encoded data |
| 86 // of the bitmap. | 97 // of the bitmap. |
| 87 SkPaint paint; | |
| 88 std::vector<unsigned char> icon_png; | 98 std::vector<unsigned char> icon_png; |
| 89 if (!gfx::PNGCodec::EncodeBGRASkBitmap(*image.bitmap(), true, &icon_png)) | 99 if (!gfx::PNGCodec::EncodeBGRASkBitmap( |
| 100 favicon_canvas.ExtractImageRep().sk_bitmap(), false, &icon_png)) { |
| 90 return false; | 101 return false; |
| 102 } |
| 91 | 103 |
| 92 scoped_refptr<base::RefCountedStaticMemory> icon_mem( | 104 scoped_refptr<base::RefCountedStaticMemory> icon_mem( |
| 93 new base::RefCountedStaticMemory(&icon_png.front(), icon_png.size())); | 105 new base::RefCountedStaticMemory(&icon_png.front(), icon_png.size())); |
| 94 color_utils::GridSampler sampler; | 106 color_utils::GridSampler sampler; |
| 95 SkColor mean_color = color_utils::CalculateKMeanColorOfPNG( | 107 SkColor mean_color = color_utils::CalculateKMeanColorOfPNG( |
| 96 icon_mem, kColorMeanDarknessLimit, kColorMeanLightnessLimit, sampler); | 108 icon_mem, kColorMeanDarknessLimit, kColorMeanLightnessLimit, sampler); |
| 97 paint.setColor(mean_color); | 109 paint.setColor(mean_color); |
| 110 gfx::Canvas canvas(gfx::Size(kLogoWidth, kLogoHeight), ui::SCALE_FACTOR_100P, |
| 111 true); |
| 98 canvas.DrawRect(gfx::Rect(0, 0, kLogoWidth, kLogoHeight), paint); | 112 canvas.DrawRect(gfx::Rect(0, 0, kLogoWidth, kLogoHeight), paint); |
| 99 | 113 |
| 100 // Now paint a faded square for the favicon to go in. | 114 // Now paint a faded square for the favicon to go in. |
| 101 color_utils::HSL shift = {-1, -1, kBoxFade}; | 115 color_utils::HSL shift = {-1, -1, kBoxFade}; |
| 102 paint.setColor(color_utils::HSLShift(mean_color, shift)); | 116 paint.setColor(color_utils::HSLShift(mean_color, shift)); |
| 103 int box_left = (kLogoWidth - kBoxWidth) / 2; | 117 int box_left = (kLogoWidth - kBoxWidth) / 2; |
| 104 int box_top = (kLogoHeight - kCaptionHeight - kBoxHeight) / 2; | 118 int box_top = (kLogoHeight - kCaptionHeight - kBoxHeight) / 2; |
| 105 canvas.DrawRect(gfx::Rect(box_left, box_top, kBoxWidth, kBoxHeight), paint); | 119 canvas.DrawRect(gfx::Rect(box_left, box_top, kBoxWidth, kBoxHeight), paint); |
| 106 | 120 |
| 107 // Now paint the favicon into the tile, leaving some room at the bottom for | 121 // Now paint the favicon into the tile, leaving some room at the bottom for |
| 108 // the caption. | 122 // the caption. |
| 109 int left = (kLogoWidth - image.width()) / 2; | 123 int left = (kLogoWidth - image.width()) / 2; |
| 110 int top = (kLogoHeight - kCaptionHeight - image.height()) / 2; | 124 int top = (kLogoHeight - kCaptionHeight - image.height()) / 2; |
| 111 canvas.DrawImageInt(image, left, top); | 125 canvas.DrawImageInt(image, left, top); |
| 112 | 126 |
| 113 SkBitmap logo_bitmap = canvas.ExtractImageRep().sk_bitmap(); | 127 SkBitmap logo_bitmap = canvas.ExtractImageRep().sk_bitmap(); |
| 114 std::vector<unsigned char> logo_png; | 128 std::vector<unsigned char> logo_png; |
| 115 if (!gfx::PNGCodec::EncodeBGRASkBitmap(logo_bitmap, true, &logo_png)) | 129 if (!gfx::PNGCodec::EncodeBGRASkBitmap(logo_bitmap, true, &logo_png)) |
| 116 return false; | 130 return false; |
| 117 | 131 |
| 132 *logo_path = logo_dir.Append(tile_id).ReplaceExtension(L".png"); |
| 118 return file_util::WriteFile(*logo_path, | 133 return file_util::WriteFile(*logo_path, |
| 119 reinterpret_cast<char*>(&logo_png[0]), | 134 reinterpret_cast<char*>(&logo_png[0]), |
| 120 logo_png.size()) > 0; | 135 logo_png.size()) > 0; |
| 121 } | 136 } |
| 122 | 137 |
| 123 // Get the path to the backup logo. If the backup logo already exists in | 138 // Get the path to the backup logo. If the backup logo already exists in |
| 124 // |logo_dir|, it will be used, otherwise it will be copied out of the install | 139 // |logo_dir|, it will be used, otherwise it will be copied out of the install |
| 125 // folder. (The version in the install folder is not used as it may disappear | 140 // folder. (The version in the install folder is not used as it may disappear |
| 126 // after an upgrade, causing tiles to lose their images if Windows rebuilds | 141 // after an upgrade, causing tiles to lose their images if Windows rebuilds |
| 127 // its tile image cache.) | 142 // its tile image cache.) |
| 128 // The path to the logo is returned in |logo_path|, with the return value | 143 // The path to the logo is returned in |logo_path|, with the return value |
| 129 // indicating success. | 144 // indicating success. |
| 130 bool GetPathToBackupLogo(const FilePath& logo_dir, | 145 bool GetPathToBackupLogo(const FilePath& logo_dir, |
| 131 FilePath* logo_path) { | 146 FilePath* logo_path) { |
| 132 const wchar_t kDefaultLogoFileName[] = L"SecondaryTile.png"; | 147 const wchar_t kDefaultLogoFileName[] = L"SecondaryTile.png"; |
| 133 *logo_path = logo_dir.Append(kDefaultLogoFileName); | 148 *logo_path = logo_dir.Append(kDefaultLogoFileName); |
| 134 if (file_util::PathExists(*logo_path)) | 149 if (file_util::PathExists(*logo_path)) |
| 135 return true; | 150 return true; |
| 136 | 151 |
| 137 FilePath default_logo_path; | 152 FilePath default_logo_path; |
| 138 if (!PathService::Get(base::DIR_MODULE, &default_logo_path)) | 153 if (!PathService::Get(base::DIR_MODULE, &default_logo_path)) |
| 139 return false; | 154 return false; |
| 140 | 155 |
| 141 default_logo_path = default_logo_path.Append(kDefaultLogoFileName); | 156 default_logo_path = default_logo_path.Append(kDefaultLogoFileName); |
| 142 return file_util::CopyFile(default_logo_path, *logo_path); | 157 return file_util::CopyFile(default_logo_path, *logo_path); |
| 143 } | 158 } |
| 144 | 159 |
| 145 } // namespace | 160 // The PinPageTaskRunner class performs the necessary FILE thread actions to |
| 161 // pin a page, such as generating or copying the tile image file. When it |
| 162 // has performed these actions it will send the tile creation request to the |
| 163 // metro driver. |
| 164 class PinPageTaskRunner : public base::RefCountedThreadSafe<PinPageTaskRunner> { |
| 165 public: |
| 166 // Creates a task runner for the pinning operation with the given details. |
| 167 // |favicon| can be a null image (i.e. favicon.isNull() can be true), in |
| 168 // which case the backup tile image will be used. |
| 169 PinPageTaskRunner(const string16& title, |
| 170 const string16& url, |
| 171 const gfx::ImageSkia& favicon); |
| 146 | 172 |
| 147 class MetroPinTabHelper::TaskRunner | 173 void Run(); |
| 148 : public base::RefCountedThreadSafe<TaskRunner> { | 174 void RunOnFileThread(); |
| 149 public: | |
| 150 TaskRunner() {} | |
| 151 | |
| 152 void PinPageToStartScreen(const string16& title, | |
| 153 const string16& url, | |
| 154 const gfx::ImageSkia& image); | |
| 155 | 175 |
| 156 private: | 176 private: |
| 157 ~TaskRunner() {} | 177 ~PinPageTaskRunner() {} |
| 158 | 178 |
| 159 friend class base::RefCountedThreadSafe<TaskRunner>; | 179 // Details of the page being pinned. |
| 160 DISALLOW_COPY_AND_ASSIGN(TaskRunner); | 180 const string16 title_; |
| 181 const string16 url_; |
| 182 gfx::ImageSkia favicon_; |
| 183 |
| 184 friend class base::RefCountedThreadSafe<PinPageTaskRunner>; |
| 185 DISALLOW_COPY_AND_ASSIGN(PinPageTaskRunner); |
| 161 }; | 186 }; |
| 162 | 187 |
| 163 void MetroPinTabHelper::TaskRunner::PinPageToStartScreen( | 188 PinPageTaskRunner::PinPageTaskRunner(const string16& title, |
| 164 const string16& title, | 189 const string16& url, |
| 165 const string16& url, | 190 const gfx::ImageSkia& favicon) |
| 166 const gfx::ImageSkia& image) { | 191 : title_(title), |
| 192 url_(url), |
| 193 favicon_(favicon) {} |
| 194 |
| 195 void PinPageTaskRunner::Run() { |
| 196 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 197 |
| 198 content::BrowserThread::PostTask( |
| 199 content::BrowserThread::FILE, |
| 200 FROM_HERE, |
| 201 base::Bind(&PinPageTaskRunner::RunOnFileThread, this)); |
| 202 } |
| 203 |
| 204 void PinPageTaskRunner::RunOnFileThread() { |
| 167 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 205 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
| 168 | 206 |
| 169 string16 tile_id = GenerateTileId(url); | 207 string16 tile_id = GenerateTileId(url_); |
| 170 FilePath logo_dir = GetTileImagesDir(); | 208 FilePath logo_dir = GetTileImagesDir(); |
| 171 if (logo_dir.empty()) { | 209 if (logo_dir.empty()) { |
| 172 LOG(ERROR) << "Could not create directory to store tile image."; | 210 LOG(ERROR) << "Could not create directory to store tile image."; |
| 173 return; | 211 return; |
| 174 } | 212 } |
| 175 | 213 |
| 176 FilePath logo_path; | 214 FilePath logo_path; |
| 177 if (!CreateSiteSpecificLogo(image, tile_id, logo_dir, &logo_path) && | 215 if (!CreateSiteSpecificLogo(favicon_, tile_id, logo_dir, &logo_path) && |
| 178 !GetPathToBackupLogo(logo_dir, &logo_path)) { | 216 !GetPathToBackupLogo(logo_dir, &logo_path)) { |
| 179 LOG(ERROR) << "Count not get path to logo tile."; | 217 LOG(ERROR) << "Count not get path to logo tile."; |
| 180 return; | 218 return; |
| 181 } | 219 } |
| 182 | 220 |
| 183 HMODULE metro_module = base::win::GetMetroModule(); | 221 HMODULE metro_module = base::win::GetMetroModule(); |
| 184 if (!metro_module) | 222 if (!metro_module) |
| 185 return; | 223 return; |
| 186 | 224 |
| 187 typedef void (*MetroPinToStartScreen)(const string16&, const string16&, | 225 typedef void (*MetroPinToStartScreen)(const string16&, const string16&, |
| 188 const string16&, const FilePath&); | 226 const string16&, const FilePath&); |
| 189 MetroPinToStartScreen metro_pin_to_start_screen = | 227 MetroPinToStartScreen metro_pin_to_start_screen = |
| 190 reinterpret_cast<MetroPinToStartScreen>( | 228 reinterpret_cast<MetroPinToStartScreen>( |
| 191 ::GetProcAddress(metro_module, "MetroPinToStartScreen")); | 229 ::GetProcAddress(metro_module, "MetroPinToStartScreen")); |
| 192 if (!metro_pin_to_start_screen) { | 230 if (!metro_pin_to_start_screen) { |
| 193 NOTREACHED(); | 231 NOTREACHED(); |
| 194 return; | 232 return; |
| 195 } | 233 } |
| 196 | 234 |
| 197 VLOG(1) << __FUNCTION__ << " calling pin with title: " << title | 235 metro_pin_to_start_screen(tile_id, title_, url_, logo_path); |
| 198 << " and url: " << url; | 236 } |
| 199 metro_pin_to_start_screen(tile_id, title, url, logo_path); | 237 |
| 238 } // namespace |
| 239 |
| 240 class MetroPinTabHelper::FaviconDownloader { |
| 241 public: |
| 242 FaviconDownloader(MetroPinTabHelper* helper, |
| 243 const string16& title, |
| 244 const string16& url, |
| 245 const gfx::ImageSkia& history_image); |
| 246 ~FaviconDownloader() {} |
| 247 |
| 248 void Start(content::RenderViewHost* host, |
| 249 const std::vector<FaviconURL>& candidates); |
| 250 |
| 251 // Callback for when a favicon has been downloaded. The best bitmap so far |
| 252 // will be stored in |best_candidate_|. If this is the last URL that was being |
| 253 // downloaded, the page is pinned by calling PinPageToStartScreen on the FILE |
| 254 // thread. |
| 255 void OnDidDownloadFavicon(int id, |
| 256 const GURL& image_url, |
| 257 bool errored, |
| 258 int requested_size, |
| 259 const std::vector<SkBitmap>& bitmaps); |
| 260 |
| 261 private: |
| 262 // The tab helper that this downloader is operating for. |
| 263 MetroPinTabHelper* helper_; |
| 264 |
| 265 // Title and URL of the page being pinned. |
| 266 const string16 title_; |
| 267 const string16 url_; |
| 268 |
| 269 // The best candidate we have so far for the current pin operation. |
| 270 gfx::ImageSkia best_candidate_; |
| 271 |
| 272 // Outstanding favicon download requests. |
| 273 std::set<int> in_progress_requests_; |
| 274 |
| 275 DISALLOW_COPY_AND_ASSIGN(FaviconDownloader); |
| 276 }; |
| 277 |
| 278 MetroPinTabHelper::FaviconDownloader::FaviconDownloader( |
| 279 MetroPinTabHelper* helper, |
| 280 const string16& title, |
| 281 const string16& url, |
| 282 const gfx::ImageSkia& history_image) |
| 283 : helper_(helper), |
| 284 title_(title), |
| 285 url_(url), |
| 286 best_candidate_(history_image) {} |
| 287 |
| 288 void MetroPinTabHelper::FaviconDownloader::Start( |
| 289 content::RenderViewHost* host, |
| 290 const std::vector<FaviconURL>& candidates) { |
| 291 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 292 |
| 293 // If there are no candidate URLs, progress straight to pinning. |
| 294 if (candidates.empty()) { |
| 295 scoped_refptr<PinPageTaskRunner> runner( |
| 296 new PinPageTaskRunner(title_, url_, best_candidate_)); |
| 297 runner->Run(); |
| 298 helper_->FaviconDownloaderFinished(); |
| 299 return; |
| 300 } |
| 301 |
| 302 // Request all the candidates. |
| 303 int image_size = 0; // Request the full sized image. |
| 304 for (std::vector<FaviconURL>::const_iterator iter = candidates.begin(); |
| 305 iter != candidates.end(); |
| 306 ++iter) { |
| 307 in_progress_requests_.insert( |
| 308 FaviconUtil::DownloadFavicon(host, iter->icon_url, image_size)); |
| 309 } |
| 310 } |
| 311 |
| 312 void MetroPinTabHelper::FaviconDownloader::OnDidDownloadFavicon( |
| 313 int id, |
| 314 const GURL& image_url, |
| 315 bool errored, |
| 316 int requested_size, |
| 317 const std::vector<SkBitmap>& bitmaps) { |
| 318 const int kMaxIconSize = 32; |
| 319 |
| 320 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 321 std::set<int>::iterator iter = in_progress_requests_.find(id); |
| 322 // Check that this request is one of ours. |
| 323 if (iter == in_progress_requests_.end()) |
| 324 return; |
| 325 |
| 326 in_progress_requests_.erase(iter); |
| 327 |
| 328 // Process the bitmaps, keeping the one that is best so far. |
| 329 if (!errored) { |
| 330 for (std::vector<SkBitmap>::const_iterator iter = bitmaps.begin(); |
| 331 iter != bitmaps.end(); |
| 332 ++iter) { |
| 333 |
| 334 // If the new bitmap is too big, ignore it. |
| 335 if (iter->height() > kMaxIconSize || iter->width() > kMaxIconSize) |
| 336 continue; |
| 337 |
| 338 // If we don't have a best candidate yet, this is better so just grab it. |
| 339 if (best_candidate_.isNull()) { |
| 340 best_candidate_ = gfx::ImageSkia(*iter).DeepCopy(); |
| 341 continue; |
| 342 } |
| 343 |
| 344 // If it is smaller than our best one so far, ignore it. |
| 345 if (iter->height() <= best_candidate_.height() || |
| 346 iter->width() <= best_candidate_.width()) { |
| 347 continue; |
| 348 } |
| 349 |
| 350 // Othewise it is our new best candidate. |
| 351 best_candidate_ = gfx::ImageSkia(*iter).DeepCopy(); |
| 352 } |
| 353 } |
| 354 |
| 355 // If there are no more outstanding requests, pin the page on the FILE thread. |
| 356 // Once this happens this downloader has done its job, so delete it. |
| 357 if (in_progress_requests_.empty()) { |
| 358 scoped_refptr<PinPageTaskRunner> runner( |
| 359 new PinPageTaskRunner(title_, url_, best_candidate_)); |
| 360 runner->Run(); |
| 361 helper_->FaviconDownloaderFinished(); |
| 362 } |
| 200 } | 363 } |
| 201 | 364 |
| 202 MetroPinTabHelper::MetroPinTabHelper(content::WebContents* web_contents) | 365 MetroPinTabHelper::MetroPinTabHelper(content::WebContents* web_contents) |
| 203 : content::WebContentsObserver(web_contents), | 366 : content::WebContentsObserver(web_contents), |
| 204 is_pinned_(false), | 367 is_pinned_(false) {} |
| 205 task_runner_(new TaskRunner) {} | |
| 206 | 368 |
| 207 MetroPinTabHelper::~MetroPinTabHelper() {} | 369 MetroPinTabHelper::~MetroPinTabHelper() {} |
| 208 | 370 |
| 209 void MetroPinTabHelper::TogglePinnedToStartScreen() { | 371 void MetroPinTabHelper::TogglePinnedToStartScreen() { |
| 210 UpdatePinnedStateForCurrentURL(); | 372 UpdatePinnedStateForCurrentURL(); |
| 211 bool was_pinned = is_pinned_; | 373 bool was_pinned = is_pinned_; |
| 212 | 374 |
| 213 // TODO(benwells): This will update the state incorrectly if the user | 375 // TODO(benwells): This will update the state incorrectly if the user |
| 214 // cancels. To fix this some sort of callback needs to be introduced as | 376 // cancels. To fix this some sort of callback needs to be introduced as |
| 215 // the pinning happens on another thread. | 377 // the pinning happens on another thread. |
| 216 is_pinned_ = !is_pinned_; | 378 is_pinned_ = !is_pinned_; |
| 217 | 379 |
| 218 if (was_pinned) { | 380 if (was_pinned) { |
| 219 UnPinPageFromStartScreen(); | 381 UnPinPageFromStartScreen(); |
| 220 return; | 382 return; |
| 221 } | 383 } |
| 222 | 384 |
| 223 // TODO(benwells): Handle downloading a larger favicon if there is one. | |
| 224 GURL url = web_contents()->GetURL(); | 385 GURL url = web_contents()->GetURL(); |
| 225 string16 url_str = UTF8ToUTF16(url.spec()); | 386 string16 url_str = UTF8ToUTF16(url.spec()); |
| 226 string16 title = web_contents()->GetTitle(); | 387 string16 title = web_contents()->GetTitle(); |
| 227 TabContents* tab_contents = TabContents::FromWebContents(web_contents()); | 388 gfx::ImageSkia favicon; |
| 228 DCHECK(tab_contents); | |
| 229 FaviconTabHelper* favicon_tab_helper = FaviconTabHelper::FromWebContents( | 389 FaviconTabHelper* favicon_tab_helper = FaviconTabHelper::FromWebContents( |
| 230 tab_contents->web_contents()); | 390 web_contents()); |
| 231 if (favicon_tab_helper->FaviconIsValid()) { | 391 if (favicon_tab_helper->FaviconIsValid()) |
| 232 gfx::Image favicon = favicon_tab_helper->GetFavicon(); | 392 favicon = favicon_tab_helper->GetFavicon().AsImageSkia().DeepCopy(); |
| 233 gfx::ImageSkia favicon_skia = favicon.AsImageSkia().DeepCopy(); | |
| 234 content::BrowserThread::PostTask( | |
| 235 content::BrowserThread::FILE, | |
| 236 FROM_HERE, | |
| 237 base::Bind(&TaskRunner::PinPageToStartScreen, | |
| 238 task_runner_, | |
| 239 title, | |
| 240 url_str, | |
| 241 favicon_skia)); | |
| 242 return; | |
| 243 } | |
| 244 | 393 |
| 245 content::BrowserThread::PostTask( | 394 favicon_downloader_.reset(new FaviconDownloader(this, title, url_str, |
| 246 content::BrowserThread::FILE, | 395 favicon)); |
| 247 FROM_HERE, | 396 favicon_downloader_->Start(web_contents()->GetRenderViewHost(), |
| 248 base::Bind(&TaskRunner::PinPageToStartScreen, | 397 favicon_url_candidates_); |
| 249 task_runner_, | |
| 250 title, | |
| 251 url_str, | |
| 252 gfx::ImageSkia())); | |
| 253 } | 398 } |
| 254 | 399 |
| 255 void MetroPinTabHelper::DidNavigateMainFrame( | 400 void MetroPinTabHelper::DidNavigateMainFrame( |
| 256 const content::LoadCommittedDetails& /*details*/, | 401 const content::LoadCommittedDetails& /*details*/, |
| 257 const content::FrameNavigateParams& /*params*/) { | 402 const content::FrameNavigateParams& /*params*/) { |
| 258 UpdatePinnedStateForCurrentURL(); | 403 UpdatePinnedStateForCurrentURL(); |
| 404 // Cancel any outstanding pin operations once the user navigates away from |
| 405 // the page. |
| 406 if (favicon_downloader_.get()) |
| 407 favicon_downloader_.reset(); |
| 408 // Any candidate favicons we have are now out of date so clear them. |
| 409 favicon_url_candidates_.clear(); |
| 410 } |
| 411 |
| 412 bool MetroPinTabHelper::OnMessageReceived(const IPC::Message& message) { |
| 413 bool message_handled = false; // Allow other handlers to receive these. |
| 414 IPC_BEGIN_MESSAGE_MAP(MetroPinTabHelper, message) |
| 415 IPC_MESSAGE_HANDLER(IconHostMsg_UpdateFaviconURL, OnUpdateFaviconURL) |
| 416 IPC_MESSAGE_HANDLER(IconHostMsg_DidDownloadFavicon, OnDidDownloadFavicon) |
| 417 IPC_MESSAGE_UNHANDLED(message_handled = false) |
| 418 IPC_END_MESSAGE_MAP() |
| 419 return message_handled; |
| 420 } |
| 421 |
| 422 void MetroPinTabHelper::OnUpdateFaviconURL( |
| 423 int32 page_id, |
| 424 const std::vector<FaviconURL>& candidates) { |
| 425 favicon_url_candidates_ = candidates; |
| 426 } |
| 427 |
| 428 void MetroPinTabHelper::OnDidDownloadFavicon( |
| 429 int id, |
| 430 const GURL& image_url, |
| 431 bool errored, |
| 432 int requested_size, |
| 433 const std::vector<SkBitmap>& bitmaps) { |
| 434 if (favicon_downloader_.get()) |
| 435 favicon_downloader_->OnDidDownloadFavicon(id, image_url, errored, |
| 436 requested_size, bitmaps); |
| 259 } | 437 } |
| 260 | 438 |
| 261 void MetroPinTabHelper::UpdatePinnedStateForCurrentURL() { | 439 void MetroPinTabHelper::UpdatePinnedStateForCurrentURL() { |
| 262 HMODULE metro_module = base::win::GetMetroModule(); | 440 HMODULE metro_module = base::win::GetMetroModule(); |
| 263 if (!metro_module) | 441 if (!metro_module) |
| 264 return; | 442 return; |
| 265 | 443 |
| 266 typedef BOOL (*MetroIsPinnedToStartScreen)(const string16&); | 444 typedef BOOL (*MetroIsPinnedToStartScreen)(const string16&); |
| 267 MetroIsPinnedToStartScreen metro_is_pinned_to_start_screen = | 445 MetroIsPinnedToStartScreen metro_is_pinned_to_start_screen = |
| 268 reinterpret_cast<MetroIsPinnedToStartScreen>( | 446 reinterpret_cast<MetroIsPinnedToStartScreen>( |
| 269 ::GetProcAddress(metro_module, "MetroIsPinnedToStartScreen")); | 447 ::GetProcAddress(metro_module, "MetroIsPinnedToStartScreen")); |
| 270 if (!metro_is_pinned_to_start_screen) { | 448 if (!metro_is_pinned_to_start_screen) { |
| 271 NOTREACHED(); | 449 NOTREACHED(); |
| 272 return; | 450 return; |
| 273 } | 451 } |
| 274 | 452 |
| 275 GURL url = web_contents()->GetURL(); | 453 GURL url = web_contents()->GetURL(); |
| 276 string16 tile_id = GenerateTileId(UTF8ToUTF16(url.spec())); | 454 string16 tile_id = GenerateTileId(UTF8ToUTF16(url.spec())); |
| 277 is_pinned_ = metro_is_pinned_to_start_screen(tile_id) != 0; | 455 is_pinned_ = metro_is_pinned_to_start_screen(tile_id) != 0; |
| 278 VLOG(1) << __FUNCTION__ << " with url " << UTF8ToUTF16(url.spec()) | |
| 279 << " result: " << is_pinned_; | |
| 280 } | 456 } |
| 281 | 457 |
| 282 void MetroPinTabHelper::UnPinPageFromStartScreen() { | 458 void MetroPinTabHelper::UnPinPageFromStartScreen() { |
| 283 HMODULE metro_module = base::win::GetMetroModule(); | 459 HMODULE metro_module = base::win::GetMetroModule(); |
| 284 if (!metro_module) | 460 if (!metro_module) |
| 285 return; | 461 return; |
| 286 | 462 |
| 287 typedef void (*MetroUnPinFromStartScreen)(const string16&); | 463 typedef void (*MetroUnPinFromStartScreen)(const string16&); |
| 288 MetroUnPinFromStartScreen metro_un_pin_from_start_screen = | 464 MetroUnPinFromStartScreen metro_un_pin_from_start_screen = |
| 289 reinterpret_cast<MetroUnPinFromStartScreen>( | 465 reinterpret_cast<MetroUnPinFromStartScreen>( |
| 290 ::GetProcAddress(metro_module, "MetroUnPinFromStartScreen")); | 466 ::GetProcAddress(metro_module, "MetroUnPinFromStartScreen")); |
| 291 if (!metro_un_pin_from_start_screen) { | 467 if (!metro_un_pin_from_start_screen) { |
| 292 NOTREACHED(); | 468 NOTREACHED(); |
| 293 return; | 469 return; |
| 294 } | 470 } |
| 295 | 471 |
| 296 GURL url = web_contents()->GetURL(); | 472 GURL url = web_contents()->GetURL(); |
| 297 VLOG(1) << __FUNCTION__ << " calling unpin with url: " | |
| 298 << UTF8ToUTF16(url.spec()); | |
| 299 string16 tile_id = GenerateTileId(UTF8ToUTF16(url.spec())); | 473 string16 tile_id = GenerateTileId(UTF8ToUTF16(url.spec())); |
| 300 metro_un_pin_from_start_screen(tile_id); | 474 metro_un_pin_from_start_screen(tile_id); |
| 301 } | 475 } |
| 476 |
| 477 void MetroPinTabHelper::FaviconDownloaderFinished() { |
| 478 favicon_downloader_.reset(); |
| 479 } |
| OLD | NEW |