- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / image_loading_helper.cc
1 // Copyright (c) 2013 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 "content/renderer/image_loading_helper.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "content/child/image_decoder.h"
10 #include "content/common/image_messages.h"
11 #include "content/public/common/url_constants.h"
12 #include "content/public/renderer/render_view.h"
13 #include "content/renderer/fetchers/multi_resolution_image_resource_fetcher.h"
14 #include "net/base/data_url.h"
15 #include "skia/ext/image_operations.h"
16 #include "third_party/WebKit/public/platform/WebURLRequest.h"
17 #include "third_party/WebKit/public/platform/WebVector.h"
18 #include "third_party/WebKit/public/web/WebFrame.h"
19 #include "third_party/WebKit/public/web/WebView.h"
20 #include "ui/gfx/favicon_size.h"
21 #include "ui/gfx/size.h"
22 #include "ui/gfx/skbitmap_operations.h"
23 #include "webkit/glue/webkit_glue.h"
24
25 using WebKit::WebFrame;
26 using WebKit::WebVector;
27 using WebKit::WebURL;
28 using WebKit::WebURLRequest;
29
30 namespace {
31
32 //  Proportionally resizes the |image| to fit in a box of size
33 // |max_image_size|.
34 SkBitmap ResizeImage(const SkBitmap& image, uint32_t max_image_size) {
35   if (max_image_size == 0)
36     return image;
37   uint32_t max_dimension = std::max(image.width(), image.height());
38   if (max_dimension <= max_image_size)
39     return image;
40   // Proportionally resize the minimal image to fit in a box of size
41   // max_image_size.
42   return skia::ImageOperations::Resize(
43       image,
44       skia::ImageOperations::RESIZE_BEST,
45       static_cast<uint64_t>(image.width()) * max_image_size / max_dimension,
46       static_cast<uint64_t>(image.height()) * max_image_size / max_dimension);
47 }
48
49 // Filters the array of bitmaps, removing all images that do not fit in a box of
50 // size |max_image_size|. Returns the result if it is not empty. Otherwise,
51 // find the smallest image in the array and resize it proportionally to fit
52 // in a box of size |max_image_size|.
53 // Sets |original_image_sizes| to the sizes of |images| before resizing.
54 void FilterAndResizeImagesForMaximalSize(
55     const std::vector<SkBitmap>& unfiltered,
56     uint32_t max_image_size,
57     std::vector<SkBitmap>* images,
58     std::vector<gfx::Size>* original_image_sizes) {
59   images->clear();
60   original_image_sizes->clear();
61
62   if (!unfiltered.size())
63     return;
64
65   if (max_image_size == 0)
66     max_image_size = std::numeric_limits<uint32_t>::max();
67
68   const SkBitmap* min_image = NULL;
69   uint32_t min_image_size = std::numeric_limits<uint32_t>::max();
70   // Filter the images by |max_image_size|, and also identify the smallest image
71   // in case all the images are bigger than |max_image_size|.
72   for (std::vector<SkBitmap>::const_iterator it = unfiltered.begin();
73        it != unfiltered.end();
74        ++it) {
75     const SkBitmap& image = *it;
76     uint32_t current_size = std::max(it->width(), it->height());
77     if (current_size < min_image_size) {
78       min_image = &image;
79       min_image_size = current_size;
80     }
81     if (static_cast<uint32_t>(image.width()) <= max_image_size &&
82         static_cast<uint32_t>(image.height()) <= max_image_size) {
83       images->push_back(image);
84       original_image_sizes->push_back(gfx::Size(image.width(), image.height()));
85     }
86   }
87   DCHECK(min_image);
88   if (images->size())
89     return;
90   // Proportionally resize the minimal image to fit in a box of size
91   // |max_image_size|.
92   images->push_back(ResizeImage(*min_image, max_image_size));
93   original_image_sizes->push_back(
94       gfx::Size(min_image->width(), min_image->height()));
95 }
96
97 }  // namespace
98
99 namespace content {
100
101 ImageLoadingHelper::ImageLoadingHelper(RenderView* render_view)
102     : RenderViewObserver(render_view) {
103 }
104
105 ImageLoadingHelper::~ImageLoadingHelper() {
106 }
107
108 void ImageLoadingHelper::OnDownloadImage(int id,
109                                          const GURL& image_url,
110                                          bool is_favicon,
111                                          uint32_t max_image_size) {
112   std::vector<SkBitmap> result_images;
113   std::vector<gfx::Size> result_original_image_sizes;
114   if (image_url.SchemeIs(chrome::kDataScheme)) {
115     SkBitmap data_image = ImageFromDataUrl(image_url);
116     if (!data_image.empty()) {
117       result_images.push_back(ResizeImage(data_image, max_image_size));
118       result_original_image_sizes.push_back(
119           gfx::Size(data_image.width(), data_image.height()));
120     }
121   } else {
122     if (DownloadImage(id, image_url, is_favicon, max_image_size)) {
123       // Will complete asynchronously via ImageLoadingHelper::DidDownloadImage
124       return;
125     }
126   }
127
128   Send(new ImageHostMsg_DidDownloadImage(routing_id(),
129                                          id,
130                                          0,
131                                          image_url,
132                                          result_images,
133                                          result_original_image_sizes));
134 }
135
136 bool ImageLoadingHelper::DownloadImage(int id,
137                                        const GURL& image_url,
138                                        bool is_favicon,
139                                        uint32_t max_image_size) {
140   // Make sure webview was not shut down.
141   if (!render_view()->GetWebView())
142     return false;
143   // Create an image resource fetcher and assign it with a call back object.
144   image_fetchers_.push_back(new MultiResolutionImageResourceFetcher(
145       image_url,
146       render_view()->GetWebView()->mainFrame(),
147       id,
148       is_favicon ? WebURLRequest::TargetIsFavicon :
149                    WebURLRequest::TargetIsImage,
150       base::Bind(&ImageLoadingHelper::DidDownloadImage,
151                  base::Unretained(this),
152                  max_image_size)));
153   return true;
154 }
155
156 void ImageLoadingHelper::DidDownloadImage(
157     uint32_t max_image_size,
158     MultiResolutionImageResourceFetcher* fetcher,
159     const std::vector<SkBitmap>& images) {
160   std::vector<SkBitmap> result_images;
161   std::vector<gfx::Size> result_original_image_sizes;
162   FilterAndResizeImagesForMaximalSize(images, max_image_size, &result_images,
163       &result_original_image_sizes);
164
165   // Notify requester of image download status.
166   Send(new ImageHostMsg_DidDownloadImage(
167       routing_id(),
168       fetcher->id(),
169       fetcher->http_status_code(),
170       fetcher->image_url(),
171       result_images,
172       result_original_image_sizes));
173
174   // Remove the image fetcher from our pending list. We're in the callback from
175   // MultiResolutionImageResourceFetcher, best to delay deletion.
176   ImageResourceFetcherList::iterator iter =
177       std::find(image_fetchers_.begin(), image_fetchers_.end(), fetcher);
178   if (iter != image_fetchers_.end()) {
179     image_fetchers_.weak_erase(iter);
180     base::MessageLoop::current()->DeleteSoon(FROM_HERE, fetcher);
181   }
182 }
183
184 SkBitmap ImageLoadingHelper::ImageFromDataUrl(const GURL& url) const {
185   std::string mime_type, char_set, data;
186   if (net::DataURL::Parse(url, &mime_type, &char_set, &data) && !data.empty()) {
187     // Decode the image using WebKit's image decoder.
188     ImageDecoder decoder(gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize));
189     const unsigned char* src_data =
190         reinterpret_cast<const unsigned char*>(&data[0]);
191
192     return decoder.Decode(src_data, data.size());
193   }
194   return SkBitmap();
195 }
196
197 bool ImageLoadingHelper::OnMessageReceived(const IPC::Message& message) {
198   bool handled = true;
199   IPC_BEGIN_MESSAGE_MAP(ImageLoadingHelper, message)
200     IPC_MESSAGE_HANDLER(ImageMsg_DownloadImage, OnDownloadImage)
201     IPC_MESSAGE_UNHANDLED(handled = false)
202   IPC_END_MESSAGE_MAP()
203
204   return handled;
205 }
206
207 }  // namespace content