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 int minimum_icon_size_in_dp
,
20 const ManifestIconDownloader::IconFetchCallback
& callback
) {
21 DCHECK(minimum_icon_size_in_dp
<= ideal_icon_size_in_dp
);
22 if (!web_contents
|| !icon_url
.is_valid())
25 const gfx::Screen
* screen
=
26 gfx::Screen::GetScreenFor(web_contents
->GetNativeView());
28 const float device_scale_factor
=
29 screen
->GetPrimaryDisplay().device_scale_factor();
30 const int ideal_icon_size_in_px
=
31 static_cast<int>(round(ideal_icon_size_in_dp
* device_scale_factor
));
32 const int minimum_icon_size_in_px
=
33 static_cast<int>(round(minimum_icon_size_in_dp
* device_scale_factor
));
35 web_contents
->DownloadImage(
38 0, // max_bitmap_size - 0 means no maximum size.
39 false, // bypass_cache
40 base::Bind(&ManifestIconDownloader::OnIconFetched
,
41 ideal_icon_size_in_px
,
42 minimum_icon_size_in_px
,
47 void ManifestIconDownloader::OnIconFetched(
48 int ideal_icon_size_in_px
,
49 int minimum_icon_size_in_px
,
50 const ManifestIconDownloader::IconFetchCallback
& callback
,
54 const std::vector
<SkBitmap
>& bitmaps
,
55 const std::vector
<gfx::Size
>& sizes
) {
56 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
58 const int closest_index
= FindClosestBitmapIndex(
59 ideal_icon_size_in_px
, minimum_icon_size_in_px
, bitmaps
);
61 if (closest_index
== -1) {
62 callback
.Run(SkBitmap());
66 const SkBitmap
& chosen
= bitmaps
[closest_index
];
68 // Only scale if we need to scale down. For scaling up we will let the system
69 // handle that when it is required to display it. This saves space in the
70 // webapp storage system as well.
71 if (chosen
.height() > ideal_icon_size_in_px
) {
72 content::BrowserThread::PostTask(
73 content::BrowserThread::IO
,
75 base::Bind(&ManifestIconDownloader::ScaleIcon
,
76 ideal_icon_size_in_px
,
85 void ManifestIconDownloader::ScaleIcon(
86 int ideal_icon_size_in_px
,
87 const SkBitmap
& bitmap
,
88 const ManifestIconDownloader::IconFetchCallback
& callback
) {
89 DCHECK_CURRENTLY_ON(content::BrowserThread::IO
);
91 const SkBitmap
& scaled
= skia::ImageOperations::Resize(
93 skia::ImageOperations::RESIZE_BEST
,
94 ideal_icon_size_in_px
,
95 ideal_icon_size_in_px
);
97 content::BrowserThread::PostTask(
98 content::BrowserThread::UI
,
100 base::Bind(callback
, scaled
));
103 int ManifestIconDownloader::FindClosestBitmapIndex(
104 int ideal_icon_size_in_px
,
105 int minimum_icon_size_in_px
,
106 const std::vector
<SkBitmap
>& bitmaps
) {
108 int best_delta
= std::numeric_limits
<int>::min();
109 const int max_negative_delta
=
110 minimum_icon_size_in_px
- ideal_icon_size_in_px
;
112 for (size_t i
= 0; i
< bitmaps
.size(); ++i
) {
113 if (bitmaps
[i
].height() != bitmaps
[i
].width())
116 int delta
= bitmaps
[i
].width() - ideal_icon_size_in_px
;
120 if (best_delta
> 0 && delta
< 0)
123 if ((best_delta
> 0 && delta
< best_delta
) ||
124 (best_delta
< 0 && delta
> best_delta
&& delta
>= max_negative_delta
)) {