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) | |
127 : RenderFrameObserver(render_frame), | 91 : RenderFrameObserver(render_frame), |
128 binding_(this, std::move(request)) { | 92 binding_(this, std::move(request)), |
93 image_downloader_(render_frame) { | |
129 DCHECK(render_frame); | 94 DCHECK(render_frame); |
130 RenderThread::Get()->AddObserver(this); | |
131 binding_.set_connection_error_handler( | 95 binding_.set_connection_error_handler( |
132 base::Bind(&ImageDownloaderImpl::OnDestruct, base::Unretained(this))); | 96 base::Bind(&ImageDownloaderImpl::OnDestruct, base::Unretained(this))); |
133 } | 97 } |
134 | 98 |
135 ImageDownloaderImpl::~ImageDownloaderImpl() { | 99 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 | 100 |
144 // static | 101 // static |
145 void ImageDownloaderImpl::CreateMojoService( | 102 void ImageDownloaderImpl::CreateMojoService( |
146 RenderFrame* render_frame, | 103 RenderFrame* render_frame, |
147 mojom::ImageDownloaderRequest request) { | 104 mojom::ImageDownloaderRequest request) { |
148 DVLOG(1) << "ImageDownloaderImpl::CreateMojoService"; | 105 DVLOG(1) << "ImageDownloaderImpl::CreateMojoService"; |
149 DCHECK(render_frame); | 106 DCHECK(render_frame); |
150 | 107 |
151 // Owns itself. | 108 // Owns itself. Will be deleted when message pipe is destroyed or render frame |
miu
2016/12/03 01:05:30
This isn't correct: The class doesn't use mojo::St
xjz
2016/12/06 19:50:55
As chatted face to face, this is correct. When mes
| |
109 // is destructed. | |
152 new ImageDownloaderImpl(render_frame, std::move(request)); | 110 new ImageDownloaderImpl(render_frame, std::move(request)); |
153 } | 111 } |
154 | 112 |
155 // Ensure all loaders cleared before calling blink::shutdown. | |
156 void ImageDownloaderImpl::OnRenderProcessShutdown() { | |
157 image_fetchers_.clear(); | |
158 } | |
159 | |
160 // ImageDownloader methods: | 113 // ImageDownloader methods: |
161 void ImageDownloaderImpl::DownloadImage(const GURL& image_url, | 114 void ImageDownloaderImpl::DownloadImage(const GURL& image_url, |
162 bool is_favicon, | 115 bool is_favicon, |
163 uint32_t max_bitmap_size, | 116 uint32_t max_bitmap_size, |
164 bool bypass_cache, | 117 bool bypass_cache, |
165 const DownloadImageCallback& callback) { | 118 const DownloadImageCallback& callback) { |
166 std::vector<SkBitmap> result_images; | 119 std::vector<SkBitmap> result_images; |
167 std::vector<gfx::Size> result_original_image_sizes; | 120 std::vector<gfx::Size> result_original_image_sizes; |
168 | 121 |
169 if (image_url.SchemeIs(url::kDataScheme)) { | 122 image_downloader_.DownloadImage( |
170 SkBitmap data_image = ImageFromDataUrl(image_url); | 123 image_url, is_favicon, bypass_cache, |
171 SkBitmap resized = ResizeImage(data_image, max_bitmap_size); | 124 base::Bind(&ImageDownloaderImpl::DidDownloadImage, base::Unretained(this), |
172 // Drop null or empty SkBitmap. | 125 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 } | 126 } |
188 | 127 |
189 bool ImageDownloaderImpl::FetchImage(const GURL& image_url, | 128 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, | 129 uint32_t max_image_size, |
210 const DownloadImageCallback& callback, | 130 const DownloadImageCallback& callback, |
211 MultiResolutionImageResourceFetcher* fetcher, | 131 int32_t http_status_code, |
212 const std::vector<SkBitmap>& images) { | 132 const std::vector<SkBitmap>& images) { |
213 std::vector<SkBitmap> result_images; | 133 std::vector<SkBitmap> result_images; |
214 std::vector<gfx::Size> result_original_image_sizes; | 134 std::vector<gfx::Size> result_original_image_sizes; |
215 FilterAndResizeImagesForMaximalSize(images, max_image_size, &result_images, | 135 FilterAndResizeImagesForMaximalSize(images, max_image_size, &result_images, |
216 &result_original_image_sizes); | 136 &result_original_image_sizes); |
217 | 137 |
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); | 138 callback.Run(http_status_code, result_images, result_original_image_sizes); |
237 } | 139 } |
238 | 140 |
239 void ImageDownloaderImpl::OnDestruct() { | 141 void ImageDownloaderImpl::OnDestruct() { |
240 delete this; | 142 delete this; |
241 } | 143 } |
242 | 144 |
243 } // namespace content | 145 } // namespace content |
OLD | NEW |