OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "chrome/browser/ui/intents/web_intent_icon_loader.h" | |
6 | |
7 #include "chrome/browser/favicon/favicon_service.h" | |
8 #include "chrome/browser/favicon/favicon_service_factory.h" | |
9 #include "chrome/browser/ui/intents/web_intent_picker_model.h" | |
10 #include "content/public/browser/browser_thread.h" | |
11 #include "net/base/load_flags.h" | |
12 #include "net/url_request/url_fetcher.h" | |
13 #include "net/url_request/url_fetcher_delegate.h" | |
14 #include "skia/ext/image_operations.h" | |
15 #include "ui/gfx/codec/png_codec.h" | |
16 #include "ui/gfx/favicon_size.h" | |
17 | |
18 namespace { | |
19 | |
20 typedef base::Callback<void(const gfx::Image&)> | |
21 ExtensionIconAvailableCallback; | |
22 | |
23 // Decodes an |icon_repsonse| as delivered via URLFetcher. The response should | |
24 // be in PNG format, but is not guaranteed to be. Posts the |callback| task | |
25 // when done. | |
26 void DecodeExtensionIconAndResize( | |
27 scoped_ptr<std::string> icon_response, | |
28 const ExtensionIconAvailableCallback& callback) { | |
29 SkBitmap icon_bitmap; | |
30 if (gfx::PNGCodec::Decode( | |
31 reinterpret_cast<const unsigned char*>(icon_response->data()), | |
32 icon_response->length(), | |
33 &icon_bitmap)) { | |
34 SkBitmap resized_icon = skia::ImageOperations::Resize( | |
35 icon_bitmap, | |
36 skia::ImageOperations::RESIZE_BEST, | |
37 gfx::kFaviconSize, gfx::kFaviconSize); | |
38 gfx::Image icon_image = gfx::Image::CreateFrom1xBitmap(resized_icon); | |
39 | |
40 content::BrowserThread::PostTask( | |
41 content::BrowserThread::UI, | |
42 FROM_HERE, | |
43 base::Bind(callback, icon_image)); | |
44 } | |
45 } | |
46 | |
47 // Self-deleting trampoline that forwards A URLFetcher response to a callback. | |
48 class URLFetcherTrampoline : public net::URLFetcherDelegate { | |
49 public: | |
50 typedef base::Callback<void(const net::URLFetcher* source)> | |
51 ForwardingCallback; | |
52 | |
53 explicit URLFetcherTrampoline(const ForwardingCallback& callback) | |
54 : callback_(callback) {} | |
55 virtual ~URLFetcherTrampoline() {} | |
56 | |
57 // net::URLFetcherDelegate implementation. | |
58 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; | |
59 | |
60 private: | |
61 // Fowarding callback from |OnURLFetchComplete|. | |
62 ForwardingCallback callback_; | |
63 }; | |
64 | |
65 void URLFetcherTrampoline::OnURLFetchComplete( | |
66 const net::URLFetcher* source) { | |
67 DCHECK(!callback_.is_null()); | |
68 callback_.Run(source); | |
69 delete source; | |
70 delete this; | |
71 } | |
72 | |
73 } | |
74 | |
75 namespace web_intents { | |
76 | |
77 IconLoader::IconLoader(Profile* profile, | |
78 WebIntentPickerModel* model) | |
79 : profile_(profile), | |
80 model_(model), | |
81 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | |
82 } | |
83 | |
84 IconLoader::~IconLoader() {} | |
85 | |
86 void IconLoader::LoadFavicon(const GURL& url) { | |
87 FaviconService* favicon_service = | |
88 FaviconServiceFactory::GetForProfile(profile_, | |
89 Profile::EXPLICIT_ACCESS); | |
90 | |
91 favicon_service->GetFaviconImageForURL( | |
92 FaviconService::FaviconForURLParams( | |
93 profile_, url, history::FAVICON, gfx::kFaviconSize), | |
94 base::Bind( | |
95 &IconLoader::OnFaviconDataAvailable, | |
96 weak_ptr_factory_.GetWeakPtr(), url), | |
97 &cancelable_task_tracker_); | |
98 } | |
99 | |
100 void IconLoader::LoadExtensionIcon(const GURL& url, | |
101 const std::string& extension_id) { | |
102 | |
103 net::URLFetcher* icon_url_fetcher = net::URLFetcher::Create( | |
104 0, | |
105 url, | |
106 net::URLFetcher::GET, | |
107 new URLFetcherTrampoline( | |
108 base::Bind( | |
109 &IconLoader::OnExtensionIconURLFetchComplete, | |
110 weak_ptr_factory_.GetWeakPtr(), extension_id))); | |
111 | |
112 icon_url_fetcher->SetLoadFlags( | |
113 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); | |
114 icon_url_fetcher->SetRequestContext(profile_->GetRequestContext()); | |
115 icon_url_fetcher->Start(); | |
116 } | |
117 | |
118 void IconLoader::OnFaviconDataAvailable( | |
119 const GURL& url, | |
120 const history::FaviconImageResult& image_result) { | |
121 if (!image_result.image.IsEmpty()) | |
122 model_->UpdateFaviconForServiceWithURL(url, image_result.image); | |
123 } | |
124 | |
125 void IconLoader::OnExtensionIconURLFetchComplete( | |
126 const std::string& extension_id, const net::URLFetcher* source) { | |
127 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
128 if (source->GetResponseCode() != 200) | |
129 return; | |
130 | |
131 scoped_ptr<std::string> response(new std::string); | |
132 if (!source->GetResponseAsString(response.get())) | |
133 return; | |
134 | |
135 // Decoding the extension icon needs to happen on a worker thread, not the | |
136 // UI thread. However, callbacks to IconLoader need to happen on the UI | |
137 // thread, since IconLoader lives on UI thread. (And WeakPtrs must be de- | |
138 // referenced on the thread they were created on). | |
139 ExtensionIconAvailableCallback available_callback = | |
140 base::Bind( | |
141 &IconLoader::OnExtensionIconAvailable, | |
142 weak_ptr_factory_.GetWeakPtr(), | |
143 extension_id); | |
144 | |
145 // Decode PNG and resize on worker thread. | |
146 content::BrowserThread::PostBlockingPoolTask( | |
147 FROM_HERE, | |
148 base::Bind(&DecodeExtensionIconAndResize, | |
149 base::Passed(&response), | |
150 available_callback)); | |
151 } | |
152 | |
153 void IconLoader::OnExtensionIconAvailable( | |
154 const std::string& extension_id, | |
155 const gfx::Image& icon_image) { | |
156 model_->SetSuggestedExtensionIconWithId(extension_id, icon_image); | |
157 } | |
158 | |
159 } // namespace web_intents | |
OLD | NEW |