Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(672)

Side by Side Diff: chrome/browser/ui/metro_pin_tab_helper_win.cc

Issue 1581473002: Remove base/win/metro.{cc|h} and some associated code (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixes Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/metro_pin_tab_helper_win.h"
6
7 #include <stdint.h>
8
9 #include <set>
10
11 #include "base/base_paths.h"
12 #include "base/bind.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_util.h"
15 #include "base/logging.h"
16 #include "base/macros.h"
17 #include "base/memory/ref_counted.h"
18 #include "base/memory/ref_counted_memory.h"
19 #include "base/metrics/histogram.h"
20 #include "base/path_service.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/win/metro.h"
24 #include "chrome/common/chrome_paths.h"
25 #include "components/favicon/content/content_favicon_driver.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/web_contents.h"
28 #include "crypto/sha2.h"
29 #include "third_party/skia/include/core/SkCanvas.h"
30 #include "third_party/skia/include/core/SkColor.h"
31 #include "ui/gfx/canvas.h"
32 #include "ui/gfx/codec/png_codec.h"
33 #include "ui/gfx/color_analysis.h"
34 #include "ui/gfx/color_utils.h"
35 #include "ui/gfx/geometry/rect.h"
36 #include "ui/gfx/geometry/size.h"
37 #include "ui/gfx/image/image.h"
38
39 DEFINE_WEB_CONTENTS_USER_DATA_KEY(MetroPinTabHelper);
40
41 namespace {
42
43 // Histogram name for site-specific tile pinning metrics.
44 const char kMetroPinMetric[] = "Metro.SecondaryTilePin";
45
46 // Generate an ID for the tile based on |url_str|. The ID is simply a hash of
47 // the URL.
48 base::string16 GenerateTileId(const base::string16& url_str) {
49 uint8_t hash[crypto::kSHA256Length];
50 crypto::SHA256HashString(base::UTF16ToUTF8(url_str), hash, sizeof(hash));
51 std::string hash_str = base::HexEncode(hash, sizeof(hash));
52 return base::UTF8ToUTF16(hash_str);
53 }
54
55 // Get the path of the directory to store the tile logos in.
56 base::FilePath GetTileImagesDir() {
57 base::FilePath tile_images_dir;
58 if (!PathService::Get(chrome::DIR_USER_DATA, &tile_images_dir))
59 return base::FilePath();
60
61 tile_images_dir = tile_images_dir.Append(L"TileImages");
62 if (!base::DirectoryExists(tile_images_dir) &&
63 !base::CreateDirectory(tile_images_dir))
64 return base::FilePath();
65
66 return tile_images_dir;
67 }
68
69 // For the given |image| and |tile_id|, try to create a site specific logo in
70 // |logo_dir|. The path of any created logo is returned in |logo_path|. Return
71 // value indicates whether a site specific logo was created.
72 bool CreateSiteSpecificLogo(const SkBitmap& bitmap,
73 const base::string16& tile_id,
74 const base::FilePath& logo_dir,
75 base::FilePath* logo_path) {
76 const int kLogoWidth = 120;
77 const int kLogoHeight = 120;
78 const int kBoxWidth = 40;
79 const int kBoxHeight = 40;
80 const int kCaptionHeight = 20;
81 const double kBoxFade = 0.75;
82
83 if (bitmap.isNull())
84 return false;
85
86 // Fill the tile logo with the dominant color of the favicon bitmap.
87 SkColor dominant_color = color_utils::CalculateKMeanColorOfBitmap(bitmap);
88 SkPaint paint;
89 paint.setColor(dominant_color);
90 gfx::Canvas canvas(gfx::Size(kLogoWidth, kLogoHeight), 1.0f,
91 true);
92 canvas.DrawRect(gfx::Rect(0, 0, kLogoWidth, kLogoHeight), paint);
93
94 // Now paint a faded square for the favicon to go in.
95 color_utils::HSL shift = {-1, -1, kBoxFade};
96 paint.setColor(color_utils::HSLShift(dominant_color, shift));
97 int box_left = (kLogoWidth - kBoxWidth) / 2;
98 int box_top = (kLogoHeight - kCaptionHeight - kBoxHeight) / 2;
99 canvas.DrawRect(gfx::Rect(box_left, box_top, kBoxWidth, kBoxHeight), paint);
100
101 // Now paint the favicon into the tile, leaving some room at the bottom for
102 // the caption.
103 int left = (kLogoWidth - bitmap.width()) / 2;
104 int top = (kLogoHeight - kCaptionHeight - bitmap.height()) / 2;
105 canvas.DrawImageInt(gfx::ImageSkia::CreateFrom1xBitmap(bitmap), left, top);
106
107 SkBitmap logo_bitmap = canvas.ExtractImageRep().sk_bitmap();
108 std::vector<unsigned char> logo_png;
109 if (!gfx::PNGCodec::EncodeBGRASkBitmap(logo_bitmap, true, &logo_png))
110 return false;
111
112 *logo_path = logo_dir.Append(tile_id).ReplaceExtension(L".png");
113 return base::WriteFile(*logo_path,
114 reinterpret_cast<char*>(&logo_png[0]),
115 logo_png.size()) > 0;
116 }
117
118 // Get the path to the backup logo. If the backup logo already exists in
119 // |logo_dir|, it will be used, otherwise it will be copied out of the install
120 // folder. (The version in the install folder is not used as it may disappear
121 // after an upgrade, causing tiles to lose their images if Windows rebuilds
122 // its tile image cache.)
123 // The path to the logo is returned in |logo_path|, with the return value
124 // indicating success.
125 bool GetPathToBackupLogo(const base::FilePath& logo_dir,
126 base::FilePath* logo_path) {
127 const wchar_t kDefaultLogoFileName[] = L"SecondaryTile.png";
128 *logo_path = logo_dir.Append(kDefaultLogoFileName);
129 if (base::PathExists(*logo_path))
130 return true;
131
132 base::FilePath default_logo_path;
133 if (!PathService::Get(base::DIR_MODULE, &default_logo_path))
134 return false;
135
136 default_logo_path = default_logo_path.Append(kDefaultLogoFileName);
137 return base::CopyFile(default_logo_path, *logo_path);
138 }
139
140 // UMA reporting callback for site-specific secondary tile creation.
141 void PinPageReportUmaCallback(
142 base::win::MetroSecondaryTilePinUmaResult result) {
143 UMA_HISTOGRAM_ENUMERATION(kMetroPinMetric,
144 result,
145 base::win::METRO_PIN_STATE_LIMIT);
146 }
147
148 // The PinPageTaskRunner class performs the necessary FILE thread actions to
149 // pin a page, such as generating or copying the tile image file. When it
150 // has performed these actions it will send the tile creation request to the
151 // metro driver.
152 class PinPageTaskRunner : public base::RefCountedThreadSafe<PinPageTaskRunner> {
153 public:
154 // Creates a task runner for the pinning operation with the given details.
155 // |favicon| can be a null image (i.e. favicon.isNull() can be true), in
156 // which case the backup tile image will be used.
157 PinPageTaskRunner(const base::string16& title,
158 const base::string16& url,
159 const SkBitmap& favicon);
160
161 void Run();
162 void RunOnFileThread();
163
164 private:
165 ~PinPageTaskRunner() {}
166
167 // Details of the page being pinned.
168 const base::string16 title_;
169 const base::string16 url_;
170 SkBitmap favicon_;
171
172 friend class base::RefCountedThreadSafe<PinPageTaskRunner>;
173 DISALLOW_COPY_AND_ASSIGN(PinPageTaskRunner);
174 };
175
176 PinPageTaskRunner::PinPageTaskRunner(const base::string16& title,
177 const base::string16& url,
178 const SkBitmap& favicon)
179 : title_(title),
180 url_(url),
181 favicon_(favicon) {}
182
183 void PinPageTaskRunner::Run() {
184 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
185
186 content::BrowserThread::PostTask(
187 content::BrowserThread::FILE,
188 FROM_HERE,
189 base::Bind(&PinPageTaskRunner::RunOnFileThread, this));
190 }
191
192 void PinPageTaskRunner::RunOnFileThread() {
193 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
194
195 base::string16 tile_id = GenerateTileId(url_);
196 base::FilePath logo_dir = GetTileImagesDir();
197 if (logo_dir.empty()) {
198 LOG(ERROR) << "Could not create directory to store tile image.";
199 return;
200 }
201
202 base::FilePath logo_path;
203 if (!CreateSiteSpecificLogo(favicon_, tile_id, logo_dir, &logo_path) &&
204 !GetPathToBackupLogo(logo_dir, &logo_path)) {
205 LOG(ERROR) << "Count not get path to logo tile.";
206 return;
207 }
208
209 UMA_HISTOGRAM_ENUMERATION(kMetroPinMetric,
210 base::win::METRO_PIN_LOGO_READY,
211 base::win::METRO_PIN_STATE_LIMIT);
212
213 HMODULE metro_module = base::win::GetMetroModule();
214 if (!metro_module)
215 return;
216
217 base::win::MetroPinToStartScreen metro_pin_to_start_screen =
218 reinterpret_cast<base::win::MetroPinToStartScreen>(
219 ::GetProcAddress(metro_module, "MetroPinToStartScreen"));
220 if (!metro_pin_to_start_screen) {
221 NOTREACHED();
222 return;
223 }
224
225 metro_pin_to_start_screen(tile_id,
226 title_,
227 url_,
228 logo_path,
229 base::Bind(&PinPageReportUmaCallback));
230 }
231
232 } // namespace
233
234 class MetroPinTabHelper::FaviconChooser {
235 public:
236 FaviconChooser(MetroPinTabHelper* helper,
237 const base::string16& title,
238 const base::string16& url,
239 const SkBitmap& history_bitmap);
240
241 ~FaviconChooser() {}
242
243 // Pin the page on the FILE thread using the current |best_candidate_| and
244 // delete the FaviconChooser.
245 void UseChosenCandidate();
246
247 // Update the |best_candidate_| with the newly downloaded favicons provided.
248 void UpdateCandidate(int id,
249 const GURL& image_url,
250 const std::vector<SkBitmap>& bitmaps);
251
252 void AddPendingRequest(int request_id);
253
254 private:
255 // The tab helper that this chooser is operating for.
256 MetroPinTabHelper* helper_;
257
258 // Title and URL of the page being pinned.
259 const base::string16 title_;
260 const base::string16 url_;
261
262 // The best candidate we have so far for the current pin operation.
263 SkBitmap best_candidate_;
264
265 // Outstanding favicon download requests.
266 std::set<int> in_progress_requests_;
267
268 DISALLOW_COPY_AND_ASSIGN(FaviconChooser);
269 };
270
271 MetroPinTabHelper::FaviconChooser::FaviconChooser(
272 MetroPinTabHelper* helper,
273 const base::string16& title,
274 const base::string16& url,
275 const SkBitmap& history_bitmap)
276 : helper_(helper),
277 title_(title),
278 url_(url),
279 best_candidate_(history_bitmap) {}
280
281 void MetroPinTabHelper::FaviconChooser::UseChosenCandidate() {
282 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
283 scoped_refptr<PinPageTaskRunner> runner(
284 new PinPageTaskRunner(title_, url_, best_candidate_));
285 runner->Run();
286 helper_->FaviconDownloaderFinished();
287 }
288
289 void MetroPinTabHelper::FaviconChooser::UpdateCandidate(
290 int id,
291 const GURL& image_url,
292 const std::vector<SkBitmap>& bitmaps) {
293 const int kMaxIconSize = 32;
294
295 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
296
297 std::set<int>::iterator iter = in_progress_requests_.find(id);
298 // Check that this request is one of ours.
299 if (iter == in_progress_requests_.end())
300 return;
301
302 in_progress_requests_.erase(iter);
303
304 // Process the bitmaps, keeping the one that is best so far.
305 for (std::vector<SkBitmap>::const_iterator iter = bitmaps.begin();
306 iter != bitmaps.end();
307 ++iter) {
308
309 // If the new bitmap is too big, ignore it.
310 if (iter->height() > kMaxIconSize || iter->width() > kMaxIconSize)
311 continue;
312
313 // If we don't have a best candidate yet, this is better so just grab it.
314 if (best_candidate_.isNull()) {
315 best_candidate_ = *iter;
316 continue;
317 }
318
319 // If it is smaller than our best one so far, ignore it.
320 if (iter->height() <= best_candidate_.height() ||
321 iter->width() <= best_candidate_.width()) {
322 continue;
323 }
324
325 // Othewise it is our new best candidate.
326 best_candidate_ = *iter;
327 }
328
329 // If there are no more outstanding requests, pin the page on the FILE thread.
330 // Once this happens this downloader has done its job, so delete it.
331 if (in_progress_requests_.empty())
332 UseChosenCandidate();
333 }
334
335 void MetroPinTabHelper::FaviconChooser::AddPendingRequest(int request_id) {
336 in_progress_requests_.insert(request_id);
337 }
338
339 MetroPinTabHelper::MetroPinTabHelper(content::WebContents* web_contents)
340 : content::WebContentsObserver(web_contents) {
341 }
342
343 MetroPinTabHelper::~MetroPinTabHelper() {}
344
345 bool MetroPinTabHelper::IsPinned() const {
346 HMODULE metro_module = base::win::GetMetroModule();
347 if (!metro_module)
348 return false;
349
350 typedef BOOL (*MetroIsPinnedToStartScreen)(const base::string16&);
351 MetroIsPinnedToStartScreen metro_is_pinned_to_start_screen =
352 reinterpret_cast<MetroIsPinnedToStartScreen>(
353 ::GetProcAddress(metro_module, "MetroIsPinnedToStartScreen"));
354 if (!metro_is_pinned_to_start_screen) {
355 NOTREACHED();
356 return false;
357 }
358
359 GURL url = web_contents()->GetURL();
360 base::string16 tile_id = GenerateTileId(base::UTF8ToUTF16(url.spec()));
361 return metro_is_pinned_to_start_screen(tile_id) != 0;
362 }
363
364 void MetroPinTabHelper::TogglePinnedToStartScreen() {
365 if (IsPinned()) {
366 UMA_HISTOGRAM_ENUMERATION(kMetroPinMetric,
367 base::win::METRO_UNPIN_INITIATED,
368 base::win::METRO_PIN_STATE_LIMIT);
369 UnPinPageFromStartScreen();
370 return;
371 }
372
373 UMA_HISTOGRAM_ENUMERATION(kMetroPinMetric,
374 base::win::METRO_PIN_INITIATED,
375 base::win::METRO_PIN_STATE_LIMIT);
376 GURL url = web_contents()->GetURL();
377 base::string16 url_str = base::UTF8ToUTF16(url.spec());
378 base::string16 title = web_contents()->GetTitle();
379 // TODO(oshima): Use scoped_ptr::Pass to pass it to other thread.
380 SkBitmap favicon;
381 favicon::FaviconDriver* favicon_driver =
382 favicon::ContentFaviconDriver::FromWebContents(web_contents());
383 if (favicon_driver->FaviconIsValid()) {
384 // Only the 1x bitmap data is needed.
385 favicon = favicon_driver->GetFavicon()
386 .AsImageSkia()
387 .GetRepresentation(1.0f)
388 .sk_bitmap();
389 }
390
391 favicon_chooser_.reset(new FaviconChooser(this, title, url_str, favicon));
392
393 if (favicon_url_candidates_.empty()) {
394 favicon_chooser_->UseChosenCandidate();
395 return;
396 }
397
398 // Request all the candidates.
399 int max_image_size = 0; // Do not resize images.
400 for (std::vector<content::FaviconURL>::const_iterator iter =
401 favicon_url_candidates_.begin();
402 iter != favicon_url_candidates_.end();
403 ++iter) {
404 favicon_chooser_->AddPendingRequest(
405 web_contents()->DownloadImage(iter->icon_url,
406 true,
407 max_image_size,
408 false,
409 base::Bind(&MetroPinTabHelper::DidDownloadFavicon,
410 base::Unretained(this))));
411 }
412
413 }
414
415 void MetroPinTabHelper::DidNavigateMainFrame(
416 const content::LoadCommittedDetails& /*details*/,
417 const content::FrameNavigateParams& /*params*/) {
418 // Cancel any outstanding pin operations once the user navigates away from
419 // the page.
420 if (favicon_chooser_.get())
421 favicon_chooser_.reset();
422 // Any candidate favicons we have are now out of date so clear them.
423 favicon_url_candidates_.clear();
424 }
425
426 void MetroPinTabHelper::DidUpdateFaviconURL(
427 const std::vector<content::FaviconURL>& candidates) {
428 favicon_url_candidates_ = candidates;
429 }
430
431 void MetroPinTabHelper::DidDownloadFavicon(
432 int id,
433 int http_status_code,
434 const GURL& image_url,
435 const std::vector<SkBitmap>& bitmaps,
436 const std::vector<gfx::Size>& original_bitmap_sizes) {
437 if (favicon_chooser_.get()) {
438 favicon_chooser_->UpdateCandidate(id, image_url, bitmaps);
439 }
440 }
441
442 void MetroPinTabHelper::UnPinPageFromStartScreen() {
443 HMODULE metro_module = base::win::GetMetroModule();
444 if (!metro_module)
445 return;
446
447 base::win::MetroUnPinFromStartScreen metro_un_pin_from_start_screen =
448 reinterpret_cast<base::win::MetroUnPinFromStartScreen>(
449 ::GetProcAddress(metro_module, "MetroUnPinFromStartScreen"));
450 if (!metro_un_pin_from_start_screen) {
451 NOTREACHED();
452 return;
453 }
454
455 GURL url = web_contents()->GetURL();
456 base::string16 tile_id = GenerateTileId(base::UTF8ToUTF16(url.spec()));
457 metro_un_pin_from_start_screen(tile_id,
458 base::Bind(&PinPageReportUmaCallback));
459 }
460
461 void MetroPinTabHelper::FaviconDownloaderFinished() {
462 favicon_chooser_.reset();
463 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698