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 |