OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/renderer/image_downloader/image_downloader_impl.h" | 5 #include "content/renderer/image_downloader/image_downloader_impl.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/location.h" | |
11 #include "base/logging.h" | 10 #include "base/logging.h" |
12 #include "base/single_thread_task_runner.h" | |
13 #include "base/threading/thread_task_runner_handle.h" | |
14 #include "content/child/image_decoder.h" | |
15 #include "content/public/renderer/render_frame.h" | 11 #include "content/public/renderer/render_frame.h" |
16 #include "content/public/renderer/render_thread.h" | |
17 #include "content/renderer/fetchers/multi_resolution_image_resource_fetcher.h" | |
18 #include "net/base/data_url.h" | |
19 #include "skia/ext/image_operations.h" | 12 #include "skia/ext/image_operations.h" |
20 #include "third_party/WebKit/public/platform/WebCachePolicy.h" | |
21 #include "third_party/WebKit/public/platform/WebURLRequest.h" | |
22 #include "third_party/WebKit/public/platform/WebVector.h" | |
23 #include "third_party/WebKit/public/web/WebLocalFrame.h" | |
24 #include "third_party/WebKit/public/web/WebView.h" | |
25 #include "ui/gfx/favicon_size.h" | |
26 #include "ui/gfx/geometry/size.h" | 13 #include "ui/gfx/geometry/size.h" |
27 #include "ui/gfx/skbitmap_operations.h" | 14 #include "ui/gfx/skbitmap_operations.h" |
28 #include "url/url_constants.h" | |
29 | |
30 using blink::WebCachePolicy; | |
31 using blink::WebFrame; | |
32 using blink::WebVector; | |
33 using blink::WebURL; | |
34 using blink::WebURLRequest; | |
35 | 15 |
36 namespace { | 16 namespace { |
37 | 17 |
38 // Decodes a data: URL image or returns an empty image in case of failure. | |
39 SkBitmap ImageFromDataUrl(const GURL& url) { | |
40 std::string mime_type, char_set, data; | |
41 if (net::DataURL::Parse(url, &mime_type, &char_set, &data) && !data.empty()) { | |
42 // Decode the image using Blink's image decoder. | |
43 content::ImageDecoder decoder( | |
44 gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize)); | |
45 const unsigned char* src_data = | |
46 reinterpret_cast<const unsigned char*>(data.data()); | |
47 | |
48 return decoder.Decode(src_data, data.size()); | |
49 } | |
50 return SkBitmap(); | |
51 } | |
52 | |
53 // Proportionally resizes the |image| to fit in a box of size | 18 // Proportionally resizes the |image| to fit in a box of size |
54 // |max_image_size|. | 19 // |max_image_size|. |
55 SkBitmap ResizeImage(const SkBitmap& image, uint32_t max_image_size) { | 20 SkBitmap ResizeImage(const SkBitmap& image, uint32_t max_image_size) { |
56 if (max_image_size == 0) | 21 if (max_image_size == 0) |
57 return image; | 22 return image; |
58 uint32_t max_dimension = std::max(image.width(), image.height()); | 23 uint32_t max_dimension = std::max(image.width(), image.height()); |
59 if (max_dimension <= max_image_size) | 24 if (max_dimension <= max_image_size) |
60 return image; | 25 return image; |
61 // Proportionally resize the minimal image to fit in a box of size | 26 // Proportionally resize the minimal image to fit in a box of size |
62 // max_image_size. | 27 // max_image_size. |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 return; | 79 return; |
115 images->push_back(resized); | 80 images->push_back(resized); |
116 original_image_sizes->push_back( | 81 original_image_sizes->push_back( |
117 gfx::Size(min_image->width(), min_image->height())); | 82 gfx::Size(min_image->width(), min_image->height())); |
118 } | 83 } |
119 | 84 |
120 } // namespace | 85 } // namespace |
121 | 86 |
122 namespace content { | 87 namespace content { |
123 | 88 |
124 ImageDownloaderImpl::ImageDownloaderImpl( | 89 ImageDownloaderImpl::ImageDownloaderImpl(RenderFrame* render_frame, |
125 RenderFrame* render_frame, | 90 mojom::ImageDownloaderRequest request) |
126 mojom::ImageDownloaderRequest request) | 91 : ImageDownloaderBase(render_frame), binding_(this, std::move(request)) { |
127 : RenderFrameObserver(render_frame), | |
128 binding_(this, std::move(request)) { | |
129 DCHECK(render_frame); | 92 DCHECK(render_frame); |
130 RenderThread::Get()->AddObserver(this); | |
131 binding_.set_connection_error_handler( | 93 binding_.set_connection_error_handler( |
132 base::Bind(&ImageDownloaderImpl::OnDestruct, base::Unretained(this))); | 94 base::Bind(&ImageDownloaderImpl::OnDestruct, base::Unretained(this))); |
133 } | 95 } |
134 | 96 |
135 ImageDownloaderImpl::~ImageDownloaderImpl() { | 97 ImageDownloaderImpl::~ImageDownloaderImpl() {} |
136 RenderThread* thread = RenderThread::Get(); | |
137 // As ImageDownloaderImpl is a strong binding with message pipe, the | |
138 // destructor may run after message loop shutdown, so we need to check whether | |
139 // RenderThread is null. | |
140 if (thread) | |
141 thread->RemoveObserver(this); | |
142 } | |
143 | 98 |
144 // static | 99 // static |
145 void ImageDownloaderImpl::CreateMojoService( | 100 void ImageDownloaderImpl::CreateMojoService( |
146 RenderFrame* render_frame, | 101 RenderFrame* render_frame, |
147 mojom::ImageDownloaderRequest request) { | 102 mojom::ImageDownloaderRequest request) { |
148 DVLOG(1) << "ImageDownloaderImpl::CreateMojoService"; | 103 DVLOG(1) << "ImageDownloaderImpl::CreateMojoService"; |
149 DCHECK(render_frame); | 104 DCHECK(render_frame); |
150 | 105 |
151 // Owns itself. | 106 // Owns itself. Will be deleted when message pipe is destroyed or RenderFrame |
| 107 // is destructed. |
152 new ImageDownloaderImpl(render_frame, std::move(request)); | 108 new ImageDownloaderImpl(render_frame, std::move(request)); |
153 } | 109 } |
154 | 110 |
155 // Ensure all loaders cleared before calling blink::shutdown. | |
156 void ImageDownloaderImpl::OnRenderProcessShutdown() { | |
157 image_fetchers_.clear(); | |
158 } | |
159 | |
160 // ImageDownloader methods: | 111 // ImageDownloader methods: |
161 void ImageDownloaderImpl::DownloadImage(const GURL& image_url, | 112 void ImageDownloaderImpl::DownloadImage(const GURL& image_url, |
162 bool is_favicon, | 113 bool is_favicon, |
163 uint32_t max_bitmap_size, | 114 uint32_t max_bitmap_size, |
164 bool bypass_cache, | 115 bool bypass_cache, |
165 const DownloadImageCallback& callback) { | 116 const DownloadImageCallback& callback) { |
166 std::vector<SkBitmap> result_images; | 117 std::vector<SkBitmap> result_images; |
167 std::vector<gfx::Size> result_original_image_sizes; | 118 std::vector<gfx::Size> result_original_image_sizes; |
168 | 119 |
169 if (image_url.SchemeIs(url::kDataScheme)) { | 120 ImageDownloaderBase::DownloadImage( |
170 SkBitmap data_image = ImageFromDataUrl(image_url); | 121 image_url, is_favicon, bypass_cache, |
171 SkBitmap resized = ResizeImage(data_image, max_bitmap_size); | 122 base::Bind(&ImageDownloaderImpl::DidDownloadImage, base::Unretained(this), |
172 // Drop null or empty SkBitmap. | 123 max_bitmap_size, callback)); |
173 if (!resized.drawsNothing()) { | |
174 result_images.push_back(resized); | |
175 result_original_image_sizes.push_back( | |
176 gfx::Size(data_image.width(), data_image.height())); | |
177 } | |
178 } else { | |
179 if (FetchImage(image_url, is_favicon, max_bitmap_size, bypass_cache, | |
180 callback)) { | |
181 // Will complete asynchronously via ImageDownloaderImpl::DidFetchImage | |
182 return; | |
183 } | |
184 } | |
185 | |
186 ReplyDownloadResult(0, result_images, result_original_image_sizes, callback); | |
187 } | 124 } |
188 | 125 |
189 bool ImageDownloaderImpl::FetchImage(const GURL& image_url, | 126 void ImageDownloaderImpl::DidDownloadImage( |
190 bool is_favicon, | |
191 uint32_t max_image_size, | |
192 bool bypass_cache, | |
193 const DownloadImageCallback& callback) { | |
194 blink::WebLocalFrame* frame = render_frame()->GetWebFrame(); | |
195 DCHECK(frame); | |
196 | |
197 // Create an image resource fetcher and assign it with a call back object. | |
198 image_fetchers_.push_back(new MultiResolutionImageResourceFetcher( | |
199 image_url, frame, 0, is_favicon ? WebURLRequest::RequestContextFavicon | |
200 : WebURLRequest::RequestContextImage, | |
201 bypass_cache ? WebCachePolicy::BypassingCache | |
202 : WebCachePolicy::UseProtocolCachePolicy, | |
203 base::Bind(&ImageDownloaderImpl::DidFetchImage, base::Unretained(this), | |
204 max_image_size, callback))); | |
205 return true; | |
206 } | |
207 | |
208 void ImageDownloaderImpl::DidFetchImage( | |
209 uint32_t max_image_size, | 127 uint32_t max_image_size, |
210 const DownloadImageCallback& callback, | 128 const DownloadImageCallback& callback, |
211 MultiResolutionImageResourceFetcher* fetcher, | 129 int32_t http_status_code, |
212 const std::vector<SkBitmap>& images) { | 130 const std::vector<SkBitmap>& images) { |
213 std::vector<SkBitmap> result_images; | 131 std::vector<SkBitmap> result_images; |
214 std::vector<gfx::Size> result_original_image_sizes; | 132 std::vector<gfx::Size> result_original_image_sizes; |
215 FilterAndResizeImagesForMaximalSize(images, max_image_size, &result_images, | 133 FilterAndResizeImagesForMaximalSize(images, max_image_size, &result_images, |
216 &result_original_image_sizes); | 134 &result_original_image_sizes); |
217 | 135 |
218 ReplyDownloadResult(fetcher->http_status_code(), result_images, | |
219 result_original_image_sizes, callback); | |
220 | |
221 // Remove the image fetcher from our pending list. We're in the callback from | |
222 // MultiResolutionImageResourceFetcher, best to delay deletion. | |
223 ImageResourceFetcherList::iterator iter = | |
224 std::find(image_fetchers_.begin(), image_fetchers_.end(), fetcher); | |
225 if (iter != image_fetchers_.end()) { | |
226 image_fetchers_.weak_erase(iter); | |
227 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, fetcher); | |
228 } | |
229 } | |
230 | |
231 void ImageDownloaderImpl::ReplyDownloadResult( | |
232 int32_t http_status_code, | |
233 const std::vector<SkBitmap>& result_images, | |
234 const std::vector<gfx::Size>& result_original_image_sizes, | |
235 const DownloadImageCallback& callback) { | |
236 callback.Run(http_status_code, result_images, result_original_image_sizes); | 136 callback.Run(http_status_code, result_images, result_original_image_sizes); |
237 } | 137 } |
238 | 138 |
239 void ImageDownloaderImpl::OnDestruct() { | 139 void ImageDownloaderImpl::OnDestruct() { |
240 delete this; | 140 delete this; |
241 } | 141 } |
242 | 142 |
243 } // namespace content | 143 } // namespace content |
OLD | NEW |