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 |