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