1 // Copyright 2015 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.
5 #include "chrome/browser/manifest/manifest_icon_downloader.h"
9 #include "chrome/browser/manifest/manifest_icon_selector.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/browser/web_contents.h"
12 #include "skia/ext/image_operations.h"
13 #include "ui/gfx/screen.h"
15 bool ManifestIconDownloader::Download(
16 content::WebContents
* web_contents
,
18 int ideal_icon_size_in_dp
,
19 const ManifestIconDownloader::IconFetchCallback
& callback
) {
20 if (!web_contents
|| !icon_url
.is_valid())
23 const gfx::Screen
* screen
=
24 gfx::Screen::GetScreenFor(web_contents
->GetNativeView());
26 const float device_scale_factor
=
27 screen
->GetPrimaryDisplay().device_scale_factor();
28 const float ideal_icon_size_in_px
=
29 ideal_icon_size_in_dp
* device_scale_factor
;
31 const int minimum_scale_factor
= std::max(
32 static_cast<int>(floor(device_scale_factor
- 1)), 1);
33 const float minimum_icon_size_in_px
=
34 ideal_icon_size_in_dp
* minimum_scale_factor
;
36 web_contents
->DownloadImage(
39 0, // max_bitmap_size - 0 means no maximum size.
40 false, // bypass_cache
41 base::Bind(&ManifestIconDownloader::OnIconFetched
,
42 ideal_icon_size_in_px
,
43 minimum_icon_size_in_px
,
48 void ManifestIconDownloader::OnIconFetched(
49 int ideal_icon_size_in_px
,
50 int minimum_icon_size_in_px
,
51 const ManifestIconDownloader::IconFetchCallback
& callback
,
55 const std::vector
<SkBitmap
>& bitmaps
,
56 const std::vector
<gfx::Size
>& sizes
) {
57 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
59 const int closest_index
= FindClosestBitmapIndex(
60 ideal_icon_size_in_px
, minimum_icon_size_in_px
, bitmaps
);
62 if (closest_index
== -1) {
63 callback
.Run(SkBitmap());
67 const SkBitmap
& chosen
= bitmaps
[closest_index
];
69 // Only scale if we need to scale down. For scaling up we will let the system
70 // handle that when it is required to display it. This saves space in the
71 // webapp storage system as well.
72 if (chosen
.height() > ideal_icon_size_in_px
) {
73 content::BrowserThread::PostTask(
74 content::BrowserThread::IO
,
76 base::Bind(&ManifestIconDownloader::ScaleIcon
,
77 ideal_icon_size_in_px
,
86 void ManifestIconDownloader::ScaleIcon(
87 int ideal_icon_size_in_px
,
88 const SkBitmap
& bitmap
,
89 const ManifestIconDownloader::IconFetchCallback
& callback
) {
90 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
92 const SkBitmap
& scaled
= skia::ImageOperations::Resize(
94 skia::ImageOperations::RESIZE_BEST
,
95 ideal_icon_size_in_px
,
96 ideal_icon_size_in_px
);
98 content::BrowserThread::PostTask(
99 content::BrowserThread::UI
,
101 base::Bind(callback
, scaled
));
104 int ManifestIconDownloader::FindClosestBitmapIndex(
105 int ideal_icon_size_in_px
,
106 int minimum_icon_size_in_px
,
107 const std::vector
<SkBitmap
>& bitmaps
) {
109 int best_delta
= std::numeric_limits
<int>::min();
110 const int max_negative_delta
=
111 minimum_icon_size_in_px
- ideal_icon_size_in_px
;
113 for (size_t i
= 0; i
< bitmaps
.size(); ++i
) {
114 if (bitmaps
[i
].height() != bitmaps
[i
].width())
117 int delta
= bitmaps
[i
].width() - ideal_icon_size_in_px
;
121 if (best_delta
> 0 && delta
< 0)
124 if ((best_delta
> 0 && delta
< best_delta
) ||
125 (best_delta
< 0 && delta
> best_delta
&& delta
>= max_negative_delta
)) {