[M73 Dev][EFL] Disable VizDisplayCompositor for EFL port
[platform/framework/web/chromium-efl.git] / components / favicon_base / favicon_util.cc
1 // Copyright 2014 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 "components/favicon_base/favicon_util.h"
6
7 #include <stddef.h>
8
9 #include <algorithm>
10 #include <cmath>
11
12 #include "base/trace_event/trace_event.h"
13 #include "build/build_config.h"
14 #include "components/favicon_base/favicon_types.h"
15 #include "components/favicon_base/select_favicon_frames.h"
16 #include "skia/ext/image_operations.h"
17 #include "third_party/skia/include/core/SkBitmap.h"
18 #include "third_party/skia/include/core/SkCanvas.h"
19 #include "ui/base/layout.h"
20 #include "ui/gfx/codec/png_codec.h"
21 #include "ui/gfx/favicon_size.h"
22 #include "ui/gfx/geometry/size.h"
23 #include "ui/gfx/image/image_png_rep.h"
24 #include "ui/gfx/image/image_skia.h"
25
26 #if defined(OS_MACOSX) && !defined(OS_IOS)
27 #include "base/mac/mac_util.h"
28 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
29
30 namespace favicon_base {
31 namespace {
32
33 // Creates image reps of DIP size |favicon_size| for the subset of
34 // |favicon_scales| for which the image reps can be created without resizing
35 // or decoding the bitmap data.
36 std::vector<gfx::ImagePNGRep> SelectFaviconFramesFromPNGsWithoutResizing(
37     const std::vector<favicon_base::FaviconRawBitmapResult>& png_data,
38     const std::vector<float>& favicon_scales,
39     int favicon_size) {
40   TRACE_EVENT0("browser",
41                "FaviconUtil::SelectFaviconFramesFromPNGsWithoutResizing");
42   std::vector<gfx::ImagePNGRep> png_reps;
43   if (png_data.empty())
44     return png_reps;
45
46   // A |favicon_size| of 0 indicates that the largest frame is desired.
47   if (favicon_size == 0) {
48     int maximum_area = 0;
49     scoped_refptr<base::RefCountedMemory> best_candidate;
50     for (size_t i = 0; i < png_data.size(); ++i) {
51       int area = png_data[i].pixel_size.GetArea();
52       if (area > maximum_area) {
53         maximum_area = area;
54         best_candidate = png_data[i].bitmap_data;
55       }
56     }
57     png_reps.push_back(gfx::ImagePNGRep(best_candidate, 1.0f));
58     return png_reps;
59   }
60
61   // Build a map which will be used to determine the scale used to
62   // create a bitmap with given pixel size.
63   std::map<int, float> desired_pixel_sizes;
64   for (size_t i = 0; i < favicon_scales.size(); ++i) {
65     int pixel_size =
66         static_cast<int>(std::ceil(favicon_size * favicon_scales[i]));
67     desired_pixel_sizes[pixel_size] = favicon_scales[i];
68   }
69
70   for (size_t i = 0; i < png_data.size(); ++i) {
71     if (!png_data[i].is_valid())
72       continue;
73
74     const gfx::Size& pixel_size = png_data[i].pixel_size;
75     if (pixel_size.width() != pixel_size.height())
76       continue;
77
78     auto it = desired_pixel_sizes.find(pixel_size.width());
79     if (it == desired_pixel_sizes.end())
80       continue;
81
82     png_reps.push_back(gfx::ImagePNGRep(png_data[i].bitmap_data, it->second));
83   }
84
85   return png_reps;
86 }
87
88 // Returns a resampled bitmap of |desired_size| x |desired_size| by resampling
89 // the best bitmap out of |input_bitmaps|.
90 // ResizeBitmapByDownsamplingIfPossible() is similar to SelectFaviconFrames()
91 // but it operates on bitmaps which have already been resampled via
92 // SelectFaviconFrames().
93 SkBitmap ResizeBitmapByDownsamplingIfPossible(
94     const std::vector<SkBitmap>& input_bitmaps,
95     int desired_size) {
96   DCHECK(!input_bitmaps.empty());
97   DCHECK_NE(0, desired_size);
98
99   SkBitmap best_bitmap;
100   for (size_t i = 0; i < input_bitmaps.size(); ++i) {
101     const SkBitmap& input_bitmap = input_bitmaps[i];
102     if (input_bitmap.width() == desired_size &&
103         input_bitmap.height() == desired_size) {
104       return input_bitmap;
105     } else if (best_bitmap.isNull()) {
106       best_bitmap = input_bitmap;
107     } else if (input_bitmap.width() >= best_bitmap.width() &&
108                input_bitmap.height() >= best_bitmap.height()) {
109       if (best_bitmap.width() < desired_size ||
110           best_bitmap.height() < desired_size) {
111         best_bitmap = input_bitmap;
112       }
113     } else {
114       if (input_bitmap.width() >= desired_size &&
115           input_bitmap.height() >= desired_size) {
116         best_bitmap = input_bitmap;
117       }
118     }
119   }
120
121   if (desired_size % best_bitmap.width() == 0 &&
122       desired_size % best_bitmap.height() == 0) {
123     // Use nearest neighbour resampling if upsampling by an integer. This
124     // makes the result look similar to the result of SelectFaviconFrames().
125     SkBitmap bitmap;
126     bitmap.allocN32Pixels(desired_size, desired_size);
127     if (!best_bitmap.isOpaque())
128       bitmap.eraseARGB(0, 0, 0, 0);
129
130     SkCanvas canvas(bitmap);
131     canvas.drawBitmapRect(best_bitmap,
132                           SkRect::MakeIWH(desired_size, desired_size), nullptr);
133     return bitmap;
134   }
135   return skia::ImageOperations::Resize(best_bitmap,
136                                        skia::ImageOperations::RESIZE_LANCZOS3,
137                                        desired_size,
138                                        desired_size);
139 }
140
141 }  // namespace
142
143 std::vector<float> GetFaviconScales() {
144   const float kScale1x = 1.0f;
145   std::vector<ui::ScaleFactor> resource_scale_factors =
146       ui::GetSupportedScaleFactors();
147
148   // TODO(ios): 1.0f should not be necessary on iOS retina devices. However
149   // the sync service only supports syncing 100p favicons. Until sync supports
150   // other scales 100p is needed in the list of scales to retrieve and
151   // store the favicons in both 100p for sync and 200p for display. cr/160503.
152   std::vector<float> favicon_scales(1, kScale1x);
153   for (size_t i = 0; i < resource_scale_factors.size(); ++i) {
154     if (resource_scale_factors[i] != ui::SCALE_FACTOR_100P)
155       favicon_scales.push_back(
156           ui::GetScaleForScaleFactor(resource_scale_factors[i]));
157   }
158   return favicon_scales;
159 }
160
161 void SetFaviconColorSpace(gfx::Image* image) {
162 #if defined(OS_MACOSX) && !defined(OS_IOS)
163   image->SetSourceColorSpace(base::mac::GetSystemColorSpace());
164 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
165 }
166
167 gfx::Image SelectFaviconFramesFromPNGs(
168     const std::vector<favicon_base::FaviconRawBitmapResult>& png_data,
169     const std::vector<float>& favicon_scales,
170     int favicon_size) {
171   TRACE_EVENT0("browser", "FaviconUtil::SelectFaviconFramesFromPNGs");
172
173   // Create image reps for as many scales as possible without resizing
174   // the bitmap data or decoding it. FaviconHandler stores already resized
175   // favicons into history so no additional resizing should be needed in the
176   // common case.
177   // Creating the gfx::Image from |png_data| without resizing or decoding if
178   // possible is important because:
179   // - Sync does a byte-to-byte comparison of gfx::Image::As1xPNGBytes() to
180   //   the data it put into the database in order to determine whether any
181   //   updates should be pushed to sync.
182   // - The decoding occurs on the UI thread and the decoding can be a
183   //   significant performance hit if a user has many bookmarks.
184   // TODO(pkotwicz): Move the decoding off the UI thread.
185   std::vector<gfx::ImagePNGRep> png_reps =
186       SelectFaviconFramesFromPNGsWithoutResizing(
187           png_data, favicon_scales, favicon_size);
188
189   // SelectFaviconFramesFromPNGsWithoutResizing() should have selected the
190   // largest favicon if |favicon_size| == 0.
191   if (favicon_size == 0)
192     return gfx::Image(png_reps);
193
194   std::vector<float> favicon_scales_to_generate = favicon_scales;
195   for (size_t i = 0; i < png_reps.size(); ++i) {
196     auto iter = std::find(favicon_scales_to_generate.begin(),
197                           favicon_scales_to_generate.end(), png_reps[i].scale);
198     if (iter != favicon_scales_to_generate.end())
199       favicon_scales_to_generate.erase(iter);
200   }
201
202   if (favicon_scales_to_generate.empty())
203     return gfx::Image(png_reps);
204
205   std::vector<SkBitmap> bitmaps;
206   for (size_t i = 0; i < png_data.size(); ++i) {
207     if (!png_data[i].is_valid())
208       continue;
209
210     SkBitmap bitmap;
211     if (gfx::PNGCodec::Decode(png_data[i].bitmap_data->front(),
212                               png_data[i].bitmap_data->size(),
213                               &bitmap)) {
214       bitmaps.push_back(bitmap);
215     }
216   }
217
218   if (bitmaps.empty())
219     return gfx::Image();
220
221   gfx::ImageSkia resized_image_skia;
222   for (size_t i = 0; i < favicon_scales_to_generate.size(); ++i) {
223     float scale = favicon_scales_to_generate[i];
224     int desired_size_in_pixel =
225         static_cast<int>(std::ceil(favicon_size * scale));
226     SkBitmap bitmap =
227         ResizeBitmapByDownsamplingIfPossible(bitmaps, desired_size_in_pixel);
228     resized_image_skia.AddRepresentation(gfx::ImageSkiaRep(bitmap, scale));
229   }
230
231   if (png_reps.empty())
232     return gfx::Image(resized_image_skia);
233
234   std::vector<gfx::ImageSkiaRep> resized_image_skia_reps =
235       resized_image_skia.image_reps();
236   for (size_t i = 0; i < resized_image_skia_reps.size(); ++i) {
237     scoped_refptr<base::RefCountedBytes> png_bytes(new base::RefCountedBytes());
238     if (gfx::PNGCodec::EncodeBGRASkBitmap(
239             resized_image_skia_reps[i].GetBitmap(), false,
240             &png_bytes->data())) {
241       png_reps.push_back(
242           gfx::ImagePNGRep(png_bytes, resized_image_skia_reps[i].scale()));
243     }
244   }
245
246   return gfx::Image(png_reps);
247 }
248
249 favicon_base::FaviconRawBitmapResult ResizeFaviconBitmapResult(
250     const std::vector<favicon_base::FaviconRawBitmapResult>&
251         favicon_bitmap_results,
252     int desired_size_in_pixel) {
253   TRACE_EVENT0("browser", "FaviconUtil::ResizeFaviconBitmapResult");
254
255   if (favicon_bitmap_results.empty() || !favicon_bitmap_results[0].is_valid())
256     return favicon_base::FaviconRawBitmapResult();
257
258   favicon_base::FaviconRawBitmapResult bitmap_result =
259       favicon_bitmap_results[0];
260
261   // If the desired size is 0, SelectFaviconFrames() will return the largest
262   // bitmap without doing any resizing. As |favicon_bitmap_results| has bitmap
263   // data for a single bitmap, return it and avoid an unnecessary decode.
264   if (desired_size_in_pixel == 0)
265     return bitmap_result;
266
267   // If history bitmap is already desired pixel size, return early.
268   if (bitmap_result.pixel_size.width() == desired_size_in_pixel &&
269       bitmap_result.pixel_size.height() == desired_size_in_pixel)
270     return bitmap_result;
271
272   // Convert raw bytes to SkBitmap, resize via SelectFaviconFrames(), then
273   // convert back.
274   std::vector<float> desired_favicon_scales;
275   desired_favicon_scales.push_back(1.0f);
276
277   gfx::Image resized_image = favicon_base::SelectFaviconFramesFromPNGs(
278       favicon_bitmap_results, desired_favicon_scales, desired_size_in_pixel);
279
280   std::vector<unsigned char> resized_bitmap_data;
281   if (!gfx::PNGCodec::EncodeBGRASkBitmap(resized_image.AsBitmap(), false,
282                                          &resized_bitmap_data)) {
283     return favicon_base::FaviconRawBitmapResult();
284   }
285
286   bitmap_result.bitmap_data = base::RefCountedBytes::TakeVector(
287       &resized_bitmap_data);
288   bitmap_result.pixel_size =
289       gfx::Size(desired_size_in_pixel, desired_size_in_pixel);
290
291   return bitmap_result;
292 }
293
294 }  // namespace favicon_base