Chromium Code Reviews| 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(string16& title, string16& url, gfx::ImageSkia& favicon); | |
| 146 | 170 |
| 147 class MetroPinTabHelper::TaskRunner | 171 void Run(); |
| 148 : public base::RefCountedThreadSafe<TaskRunner> { | 172 void RunOnFileThread(); |
| 149 public: | |
| 150 TaskRunner() {} | |
| 151 | |
| 152 void PinPageToStartScreen(const string16& title, | |
| 153 const string16& url, | |
| 154 const gfx::ImageSkia& image); | |
| 155 | 173 |
| 156 private: | 174 private: |
| 157 ~TaskRunner() {} | 175 ~PinPageTaskRunner() {} |
| 158 | 176 |
| 159 friend class base::RefCountedThreadSafe<TaskRunner>; | 177 // Details of the page being pinned. |
| 160 DISALLOW_COPY_AND_ASSIGN(TaskRunner); | 178 string16 title_; |
| 179 string16 url_; | |
| 180 gfx::ImageSkia favicon_; | |
| 181 | |
| 182 friend class base::RefCountedThreadSafe<PinPageTaskRunner>; | |
| 183 DISALLOW_COPY_AND_ASSIGN(PinPageTaskRunner); | |
| 161 }; | 184 }; |
| 162 | 185 |
| 163 void MetroPinTabHelper::TaskRunner::PinPageToStartScreen( | 186 PinPageTaskRunner::PinPageTaskRunner(string16& title, |
| 164 const string16& title, | 187 string16& url, |
| 165 const string16& url, | 188 gfx::ImageSkia& favicon) |
| 166 const gfx::ImageSkia& image) { | 189 : title_(title), url_(url), favicon_(favicon) {} |
|
sky
2012/10/29 15:06:41
Since you wrapped the constructor each param on it
benwells
2012/10/29 23:20:44
Done.
| |
| 190 | |
| 191 void PinPageTaskRunner::Run() { | |
| 192 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 193 | |
| 194 content::BrowserThread::PostTask( | |
| 195 content::BrowserThread::FILE, | |
| 196 FROM_HERE, | |
| 197 base::Bind(&PinPageTaskRunner::RunOnFileThread, this)); | |
| 198 } | |
| 199 | |
| 200 void PinPageTaskRunner::RunOnFileThread() { | |
| 167 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 201 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); |
| 168 | 202 |
| 169 string16 tile_id = GenerateTileId(url); | 203 string16 tile_id = GenerateTileId(url_); |
| 170 FilePath logo_dir = GetTileImagesDir(); | 204 FilePath logo_dir = GetTileImagesDir(); |
| 171 if (logo_dir.empty()) { | 205 if (logo_dir.empty()) { |
| 172 LOG(ERROR) << "Could not create directory to store tile image."; | 206 LOG(ERROR) << "Could not create directory to store tile image."; |
| 173 return; | 207 return; |
| 174 } | 208 } |
| 175 | 209 |
| 176 FilePath logo_path; | 210 FilePath logo_path; |
| 177 if (!CreateSiteSpecificLogo(image, tile_id, logo_dir, &logo_path) && | 211 if (!CreateSiteSpecificLogo(favicon_, tile_id, logo_dir, &logo_path) && |
| 178 !GetPathToBackupLogo(logo_dir, &logo_path)) { | 212 !GetPathToBackupLogo(logo_dir, &logo_path)) { |
| 179 LOG(ERROR) << "Count not get path to logo tile."; | 213 LOG(ERROR) << "Count not get path to logo tile."; |
| 180 return; | 214 return; |
| 181 } | 215 } |
| 182 | 216 |
| 183 HMODULE metro_module = base::win::GetMetroModule(); | 217 HMODULE metro_module = base::win::GetMetroModule(); |
|
sky
2012/10/29 15:06:41
I'm not familiar with the metro module, is is thre
benwells
2012/10/29 23:20:44
Yes, this part is. This code just calls a metro fu
| |
| 184 if (!metro_module) | 218 if (!metro_module) |
| 185 return; | 219 return; |
| 186 | 220 |
| 187 typedef void (*MetroPinToStartScreen)(const string16&, const string16&, | 221 typedef void (*MetroPinToStartScreen)(const string16&, const string16&, |
| 188 const string16&, const FilePath&); | 222 const string16&, const FilePath&); |
| 189 MetroPinToStartScreen metro_pin_to_start_screen = | 223 MetroPinToStartScreen metro_pin_to_start_screen = |
| 190 reinterpret_cast<MetroPinToStartScreen>( | 224 reinterpret_cast<MetroPinToStartScreen>( |
| 191 ::GetProcAddress(metro_module, "MetroPinToStartScreen")); | 225 ::GetProcAddress(metro_module, "MetroPinToStartScreen")); |
| 192 if (!metro_pin_to_start_screen) { | 226 if (!metro_pin_to_start_screen) { |
| 193 NOTREACHED(); | 227 NOTREACHED(); |
| 194 return; | 228 return; |
| 195 } | 229 } |
| 196 | 230 |
| 197 VLOG(1) << __FUNCTION__ << " calling pin with title: " << title | 231 metro_pin_to_start_screen(tile_id, title_, url_, logo_path); |
| 198 << " and url: " << url; | 232 } |
| 199 metro_pin_to_start_screen(tile_id, title, url, logo_path); | 233 |
| 234 } // namespace | |
| 235 | |
| 236 class MetroPinTabHelper::FaviconDownloader { | |
| 237 public: | |
| 238 FaviconDownloader(MetroPinTabHelper* helper, | |
| 239 const string16& title, | |
| 240 const string16& url, | |
| 241 const gfx::ImageSkia& history_image); | |
| 242 ~FaviconDownloader() {} | |
| 243 | |
| 244 void Start(content::RenderViewHost* host, | |
| 245 const std::vector<FaviconURL>& candidates); | |
| 246 | |
| 247 // Callback for when a favicon has been downloaded. The best bitmap so far | |
| 248 // will be stored in |best_candidate_|. If this is the last URL that was being | |
| 249 // downloaded, the page is pinned by calling PinPageToStartScreen on the FILE | |
| 250 // thread. | |
| 251 void OnDidDownloadFavicon(int id, | |
| 252 const GURL& image_url, | |
| 253 bool errored, | |
| 254 int requested_size, | |
| 255 const std::vector<SkBitmap>& bitmaps); | |
| 256 | |
| 257 private: | |
| 258 // The tab helper that this downloader is operating for. | |
| 259 MetroPinTabHelper* helper_; | |
| 260 | |
| 261 // Title and URL of the page being pinned. | |
| 262 string16 title_; | |
|
sky
2012/10/29 15:06:41
const title_ and url_
benwells
2012/10/29 23:20:44
Done.
| |
| 263 string16 url_; | |
| 264 | |
| 265 // The best candidate we have so far for the current pin operation. | |
| 266 gfx::ImageSkia best_candidate_; | |
| 267 | |
| 268 // Outstanding favicon download requests. | |
| 269 std::set<int> in_progress_requests_; | |
| 270 | |
| 271 DISALLOW_COPY_AND_ASSIGN(FaviconDownloader); | |
| 272 }; | |
| 273 | |
| 274 MetroPinTabHelper::FaviconDownloader::FaviconDownloader( | |
| 275 MetroPinTabHelper* helper, | |
| 276 const string16& title, | |
| 277 const string16& url, | |
| 278 const gfx::ImageSkia& history_image) | |
| 279 : helper_(helper), | |
| 280 title_(title), | |
| 281 url_(url), | |
| 282 best_candidate_(history_image) {} | |
| 283 | |
| 284 void MetroPinTabHelper::FaviconDownloader::Start( | |
| 285 content::RenderViewHost* host, | |
| 286 const std::vector<FaviconURL>& candidates) { | |
| 287 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 288 | |
| 289 // If there are no candidate URLs, progress straight to pinning. | |
| 290 if (candidates.empty()) { | |
| 291 scoped_refptr<PinPageTaskRunner> runner( | |
| 292 new PinPageTaskRunner(title_, url_, best_candidate_)); | |
| 293 runner->Run(); | |
| 294 helper_->FaviconDownloaderFinished(); | |
| 295 return; | |
| 296 } | |
| 297 | |
| 298 // Request all the candidates. | |
| 299 int image_size = 0; // Request the full sized image. | |
| 300 for (std::vector<FaviconURL>::const_iterator iter = candidates.begin(); | |
| 301 iter != candidates.end(); | |
| 302 ++iter) { | |
| 303 in_progress_requests_.insert( | |
| 304 FaviconUtil::DownloadFavicon(host, iter->icon_url, image_size)); | |
| 305 } | |
| 306 } | |
| 307 | |
| 308 void MetroPinTabHelper::FaviconDownloader::OnDidDownloadFavicon( | |
| 309 int id, | |
| 310 const GURL& image_url, | |
| 311 bool errored, | |
| 312 int requested_size, | |
| 313 const std::vector<SkBitmap>& bitmaps) { | |
| 314 const int kMaxIconSize = 32; | |
| 315 | |
| 316 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 317 std::set<int>::iterator iter = in_progress_requests_.find(id); | |
| 318 // Check that this request is one of ours. | |
| 319 if (iter == in_progress_requests_.end()) | |
| 320 return; | |
| 321 | |
| 322 in_progress_requests_.erase(iter); | |
| 323 | |
| 324 // Process the bitmaps, keeping the one that is best so far. | |
| 325 if (!errored) { | |
| 326 for (std::vector<SkBitmap>::const_iterator iter = bitmaps.begin(); | |
| 327 iter != bitmaps.end(); | |
| 328 ++iter) { | |
| 329 | |
| 330 // If we don't have a best candidate yet, this is better so just grab it. | |
| 331 if (best_candidate_.isNull()) { | |
|
sky
2012/10/29 15:06:41
Might this result in an image bigger than kMaxIcon
benwells
2012/10/29 23:20:44
Oh yes, good catch.
| |
| 332 best_candidate_ = gfx::ImageSkia(*iter).DeepCopy(); | |
| 333 continue; | |
| 334 } | |
| 335 // If the new bitmap is bigger than the best candidate, and not greater | |
| 336 // than the max size, grab it. | |
| 337 if (iter->height() > kMaxIconSize || iter->width() > kMaxIconSize) | |
| 338 continue; | |
| 339 | |
| 340 if (iter->height() <= best_candidate_.height() || | |
| 341 iter->width() <= best_candidate_.width()) { | |
| 342 continue; | |
| 343 } | |
| 344 | |
| 345 best_candidate_ = gfx::ImageSkia(*iter).DeepCopy(); | |
| 346 } | |
| 347 } | |
| 348 | |
| 349 // If there are no more outstanding requests, pin the page on the FILE thread. | |
| 350 // Once this happens this downloader has done its job, so delete it. | |
| 351 if (in_progress_requests_.empty()) { | |
| 352 scoped_refptr<PinPageTaskRunner> runner( | |
| 353 new PinPageTaskRunner(title_, url_, best_candidate_)); | |
| 354 runner->Run(); | |
| 355 helper_->FaviconDownloaderFinished(); | |
| 356 } | |
| 200 } | 357 } |
| 201 | 358 |
| 202 MetroPinTabHelper::MetroPinTabHelper(content::WebContents* web_contents) | 359 MetroPinTabHelper::MetroPinTabHelper(content::WebContents* web_contents) |
| 203 : content::WebContentsObserver(web_contents), | 360 : content::WebContentsObserver(web_contents), |
| 204 is_pinned_(false), | 361 is_pinned_(false) {} |
| 205 task_runner_(new TaskRunner) {} | |
| 206 | 362 |
| 207 MetroPinTabHelper::~MetroPinTabHelper() {} | 363 MetroPinTabHelper::~MetroPinTabHelper() {} |
| 208 | 364 |
| 209 void MetroPinTabHelper::TogglePinnedToStartScreen() { | 365 void MetroPinTabHelper::TogglePinnedToStartScreen() { |
| 210 UpdatePinnedStateForCurrentURL(); | 366 UpdatePinnedStateForCurrentURL(); |
| 211 bool was_pinned = is_pinned_; | 367 bool was_pinned = is_pinned_; |
| 212 | 368 |
| 213 // TODO(benwells): This will update the state incorrectly if the user | 369 // 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 | 370 // cancels. To fix this some sort of callback needs to be introduced as |
| 215 // the pinning happens on another thread. | 371 // the pinning happens on another thread. |
| 216 is_pinned_ = !is_pinned_; | 372 is_pinned_ = !is_pinned_; |
| 217 | 373 |
| 218 if (was_pinned) { | 374 if (was_pinned) { |
| 219 UnPinPageFromStartScreen(); | 375 UnPinPageFromStartScreen(); |
| 220 return; | 376 return; |
| 221 } | 377 } |
| 222 | 378 |
| 223 // TODO(benwells): Handle downloading a larger favicon if there is one. | |
| 224 GURL url = web_contents()->GetURL(); | 379 GURL url = web_contents()->GetURL(); |
| 225 string16 url_str = UTF8ToUTF16(url.spec()); | 380 string16 url_str = UTF8ToUTF16(url.spec()); |
| 226 string16 title = web_contents()->GetTitle(); | 381 string16 title = web_contents()->GetTitle(); |
| 227 TabContents* tab_contents = TabContents::FromWebContents(web_contents()); | 382 gfx::ImageSkia favicon; |
| 228 DCHECK(tab_contents); | |
| 229 FaviconTabHelper* favicon_tab_helper = FaviconTabHelper::FromWebContents( | 383 FaviconTabHelper* favicon_tab_helper = FaviconTabHelper::FromWebContents( |
| 230 tab_contents->web_contents()); | 384 web_contents()); |
| 231 if (favicon_tab_helper->FaviconIsValid()) { | 385 if (favicon_tab_helper->FaviconIsValid()) |
| 232 gfx::Image favicon = favicon_tab_helper->GetFavicon(); | 386 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 | 387 |
| 245 content::BrowserThread::PostTask( | 388 favicon_downloader_.reset(new FaviconDownloader(this, title, url_str, |
| 246 content::BrowserThread::FILE, | 389 favicon)); |
| 247 FROM_HERE, | 390 favicon_downloader_->Start(web_contents()->GetRenderViewHost(), |
| 248 base::Bind(&TaskRunner::PinPageToStartScreen, | 391 favicon_url_candidates_); |
| 249 task_runner_, | |
| 250 title, | |
| 251 url_str, | |
| 252 gfx::ImageSkia())); | |
| 253 } | 392 } |
| 254 | 393 |
| 255 void MetroPinTabHelper::DidNavigateMainFrame( | 394 void MetroPinTabHelper::DidNavigateMainFrame( |
| 256 const content::LoadCommittedDetails& /*details*/, | 395 const content::LoadCommittedDetails& /*details*/, |
| 257 const content::FrameNavigateParams& /*params*/) { | 396 const content::FrameNavigateParams& /*params*/) { |
| 258 UpdatePinnedStateForCurrentURL(); | 397 UpdatePinnedStateForCurrentURL(); |
| 398 // Cancel any outstanding pin operations once the user navigates away from | |
| 399 // the page. | |
| 400 if (favicon_downloader_.get()) | |
| 401 favicon_downloader_.reset(); | |
|
sky
2012/10/29 15:06:41
Does this mean if the user pins something and the
benwells
2012/10/29 23:20:44
I think it makes the most sense. The pin action co
| |
| 402 // Any candidate favicons we have are now out of date so clear them. | |
| 403 favicon_url_candidates_.clear(); | |
| 404 } | |
| 405 | |
| 406 bool MetroPinTabHelper::OnMessageReceived(const IPC::Message& message) { | |
| 407 bool message_handled = false; // Allow other handlers to receive these. | |
| 408 IPC_BEGIN_MESSAGE_MAP(MetroPinTabHelper, message) | |
| 409 IPC_MESSAGE_HANDLER(IconHostMsg_UpdateFaviconURL, OnUpdateFaviconURL) | |
| 410 IPC_MESSAGE_HANDLER(IconHostMsg_DidDownloadFavicon, OnDidDownloadFavicon) | |
| 411 IPC_MESSAGE_UNHANDLED(message_handled = false) | |
| 412 IPC_END_MESSAGE_MAP() | |
| 413 return message_handled; | |
| 414 } | |
| 415 | |
| 416 void MetroPinTabHelper::OnUpdateFaviconURL( | |
| 417 int32 page_id, | |
| 418 const std::vector<FaviconURL>& candidates) { | |
| 419 favicon_url_candidates_ = candidates; | |
| 420 } | |
| 421 | |
| 422 void MetroPinTabHelper::OnDidDownloadFavicon( | |
| 423 int id, | |
| 424 const GURL& image_url, | |
| 425 bool errored, | |
| 426 int requested_size, | |
| 427 const std::vector<SkBitmap>& bitmaps) { | |
| 428 if (favicon_downloader_.get()) | |
| 429 favicon_downloader_->OnDidDownloadFavicon(id, image_url, errored, | |
| 430 requested_size, bitmaps); | |
| 259 } | 431 } |
| 260 | 432 |
| 261 void MetroPinTabHelper::UpdatePinnedStateForCurrentURL() { | 433 void MetroPinTabHelper::UpdatePinnedStateForCurrentURL() { |
| 262 HMODULE metro_module = base::win::GetMetroModule(); | 434 HMODULE metro_module = base::win::GetMetroModule(); |
| 263 if (!metro_module) | 435 if (!metro_module) |
| 264 return; | 436 return; |
| 265 | 437 |
| 266 typedef BOOL (*MetroIsPinnedToStartScreen)(const string16&); | 438 typedef BOOL (*MetroIsPinnedToStartScreen)(const string16&); |
| 267 MetroIsPinnedToStartScreen metro_is_pinned_to_start_screen = | 439 MetroIsPinnedToStartScreen metro_is_pinned_to_start_screen = |
| 268 reinterpret_cast<MetroIsPinnedToStartScreen>( | 440 reinterpret_cast<MetroIsPinnedToStartScreen>( |
| 269 ::GetProcAddress(metro_module, "MetroIsPinnedToStartScreen")); | 441 ::GetProcAddress(metro_module, "MetroIsPinnedToStartScreen")); |
| 270 if (!metro_is_pinned_to_start_screen) { | 442 if (!metro_is_pinned_to_start_screen) { |
| 271 NOTREACHED(); | 443 NOTREACHED(); |
| 272 return; | 444 return; |
| 273 } | 445 } |
| 274 | 446 |
| 275 GURL url = web_contents()->GetURL(); | 447 GURL url = web_contents()->GetURL(); |
| 276 string16 tile_id = GenerateTileId(UTF8ToUTF16(url.spec())); | 448 string16 tile_id = GenerateTileId(UTF8ToUTF16(url.spec())); |
| 277 is_pinned_ = metro_is_pinned_to_start_screen(tile_id) != 0; | 449 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 } | 450 } |
| 281 | 451 |
| 282 void MetroPinTabHelper::UnPinPageFromStartScreen() { | 452 void MetroPinTabHelper::UnPinPageFromStartScreen() { |
| 283 HMODULE metro_module = base::win::GetMetroModule(); | 453 HMODULE metro_module = base::win::GetMetroModule(); |
| 284 if (!metro_module) | 454 if (!metro_module) |
| 285 return; | 455 return; |
| 286 | 456 |
| 287 typedef void (*MetroUnPinFromStartScreen)(const string16&); | 457 typedef void (*MetroUnPinFromStartScreen)(const string16&); |
| 288 MetroUnPinFromStartScreen metro_un_pin_from_start_screen = | 458 MetroUnPinFromStartScreen metro_un_pin_from_start_screen = |
| 289 reinterpret_cast<MetroUnPinFromStartScreen>( | 459 reinterpret_cast<MetroUnPinFromStartScreen>( |
| 290 ::GetProcAddress(metro_module, "MetroUnPinFromStartScreen")); | 460 ::GetProcAddress(metro_module, "MetroUnPinFromStartScreen")); |
| 291 if (!metro_un_pin_from_start_screen) { | 461 if (!metro_un_pin_from_start_screen) { |
| 292 NOTREACHED(); | 462 NOTREACHED(); |
| 293 return; | 463 return; |
| 294 } | 464 } |
| 295 | 465 |
| 296 GURL url = web_contents()->GetURL(); | 466 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())); | 467 string16 tile_id = GenerateTileId(UTF8ToUTF16(url.spec())); |
| 300 metro_un_pin_from_start_screen(tile_id); | 468 metro_un_pin_from_start_screen(tile_id); |
| 301 } | 469 } |
| 470 | |
| 471 void MetroPinTabHelper::FaviconDownloaderFinished() { | |
| 472 favicon_downloader_.reset(); | |
| 473 } | |
| OLD | NEW |