Chromium Code Reviews| Index: chrome/browser/ui/intents/web_intent_picker_controller.cc |
| diff --git a/chrome/browser/ui/intents/web_intent_picker_controller.cc b/chrome/browser/ui/intents/web_intent_picker_controller.cc |
| index fbe21840679e0917dff040c7dda430bb257b33c8..32fb7fd34113422b70275f9bd5a9acae1f423212 100644 |
| --- a/chrome/browser/ui/intents/web_intent_picker_controller.cc |
| +++ b/chrome/browser/ui/intents/web_intent_picker_controller.cc |
| @@ -23,10 +23,16 @@ |
| #include "chrome/browser/webdata/web_data_service.h" |
| #include "chrome/common/chrome_notification_types.h" |
| #include "content/browser/intents/intent_injector.h" |
| +#include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/notification_source.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/browser/web_intents_dispatcher.h" |
| +#include "content/public/common/url_fetcher.h" |
| +#include "content/public/common/url_fetcher_delegate.h" |
| +#include "net/base/load_flags.h" |
| +#include "skia/ext/image_operations.h" |
| #include "ui/gfx/codec/png_codec.h" |
| +#include "ui/gfx/favicon_size.h" |
| #include "ui/gfx/image/image.h" |
| #include "webkit/glue/web_intent_service_data.h" |
| @@ -60,6 +66,25 @@ WebIntentPickerModel::Disposition ConvertDisposition( |
| } |
| } |
| +class URLFetcherTrampoline : public content::URLFetcherDelegate { |
| + public: |
| + typedef base::Callback<void(const content::URLFetcher* source)> Callback; |
| + |
| + explicit URLFetcherTrampoline(const Callback& callback) |
| + : callback_(callback) {} |
| + ~URLFetcherTrampoline() {} |
| + |
| + // content::URLFetcherDelegate implementation. |
| + virtual void OnURLFetchComplete(const content::URLFetcher* source) OVERRIDE { |
| + callback_.Run(source); |
| + delete source; |
| + delete this; |
| + } |
| + |
| + private: |
| + Callback callback_; |
| +}; |
| + |
| } // namespace |
| WebIntentPickerController::WebIntentPickerController( |
| @@ -285,6 +310,9 @@ void WebIntentPickerController::OnFaviconDataAvailable( |
| void WebIntentPickerController::OnCWSIntentServicesAvailable( |
| const CWSIntentsRegistry::IntentExtensionList& extensions) { |
| + net::URLRequestContextGetter* context = |
|
Greg Billock
2012/02/23 22:15:50
It looks like this can just move down to SetReques
binji
2012/02/23 22:33:41
Done.
|
| + wrapper_->profile()->GetRequestContext(); |
| + |
| for (size_t i = 0; i < extensions.size(); ++i) { |
| const CWSIntentsRegistry::IntentExtensionInfo& info = extensions[i]; |
| picker_model_->AddSuggestedExtension( |
| @@ -292,13 +320,97 @@ void WebIntentPickerController::OnCWSIntentServicesAvailable( |
| info.id, |
| info.average_rating); |
| - // TODO(binji): Fetch extension icon. |
| + pending_async_count_++; |
| + content::URLFetcher* icon_url_fetcher = content::URLFetcher::Create( |
| + 0, |
| + info.icon_url, |
| + content::URLFetcher::GET, |
| + new URLFetcherTrampoline( |
| + base::Bind( |
| + &WebIntentPickerController::OnExtensionIconURLFetchComplete, |
| + weak_ptr_factory_.GetWeakPtr(), info.id))); |
| + |
| + icon_url_fetcher->SetLoadFlags( |
| + net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES); |
| + icon_url_fetcher->SetRequestContext(context); |
| + icon_url_fetcher->Start(); |
|
Greg Billock
2012/02/23 22:15:50
So the URLFetcher always delegates the callback to
binji
2012/02/23 22:33:41
I wasn't 100% on this, so I took a look. It looks
|
| + } |
| + |
| + AsyncOperationFinished(); |
| +} |
| + |
| +void WebIntentPickerController::OnExtensionIconURLFetchComplete( |
| + const string16& extension_id, const content::URLFetcher* source) { |
| + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| + if (source->GetResponseCode() != 200) { |
| + AsyncOperationFinished(); |
| + return; |
| + } |
| + |
| + scoped_ptr<std::string> response(new std::string); |
| + if (source->GetResponseAsString(response.get())) { |
|
Greg Billock
2012/02/23 22:15:50
How about if (!...) { AsyncOpFinished; return; }
binji
2012/02/23 22:33:41
Done.
|
| + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
|
Greg Billock
2012/02/23 22:15:50
Can take this out (you have it above now).
binji
2012/02/23 22:33:41
Oh, right. :-)
|
| + |
| + // Decode PNG and resize on worker thread. |
| + content::BrowserThread::PostBlockingPoolTask( |
| + FROM_HERE, |
| + base::Bind(&DecodeExtensionIconAndResize, |
| + base::Passed(&response), |
| + base::Bind( |
|
Greg Billock
2012/02/23 22:15:50
I think it'd read easier to extract these two call
binji
2012/02/23 22:33:41
Done.
|
| + &WebIntentPickerController::OnExtensionIconAvailable, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + extension_id), |
| + base::Bind( |
| + &WebIntentPickerController::OnExtensionIconUnavailable, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + extension_id))); |
| + } else { |
| + AsyncOperationFinished(); |
| + } |
| +} |
| + |
| +// static |
| +void WebIntentPickerController::DecodeExtensionIconAndResize( |
| + scoped_ptr<std::string> icon_response, |
| + const ExtensionIconAvailableCallback& callback, |
| + const base::Closure& unavailable_callback) { |
| + SkBitmap icon_bitmap; |
| + if (gfx::PNGCodec::Decode( |
| + reinterpret_cast<const unsigned char*>(icon_response->data()), |
| + icon_response->length(), |
| + &icon_bitmap)) { |
| + SkBitmap resized_icon = skia::ImageOperations::Resize( |
| + icon_bitmap, |
| + skia::ImageOperations::RESIZE_BEST, |
| + gfx::kFaviconSize, gfx::kFaviconSize); |
| + gfx::Image icon_image(new SkBitmap(resized_icon)); |
| + |
| + content::BrowserThread::PostTask( |
| + content::BrowserThread::UI, |
| + FROM_HERE, |
| + base::Bind(callback, icon_image)); |
|
Greg Billock
2012/02/23 22:15:50
It might be easier to get a WebIntentPickerControl
binji
2012/02/23 22:33:41
This was the original way I wrote it, but it didn'
Greg Billock
2012/02/23 22:51:30
You want to put some of these threading constraint
binji
2012/02/23 23:34:48
Done.
|
| + } else { |
| + content::BrowserThread::PostTask( |
| + content::BrowserThread::UI, |
| + FROM_HERE, |
| + unavailable_callback); |
| } |
| +} |
| + |
| +void WebIntentPickerController::OnExtensionIconAvailable( |
| + const string16& extension_id, |
| + const gfx::Image& icon_image) { |
| + picker_model_->SetSuggestedExtensionIconWithId(extension_id, icon_image); |
| + AsyncOperationFinished(); |
| +} |
| +void WebIntentPickerController::OnExtensionIconUnavailable( |
| + const string16& extension_id) { |
| AsyncOperationFinished(); |
| } |
| void WebIntentPickerController::AsyncOperationFinished() { |
| + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| if (--pending_async_count_ == 0) { |
| picker_->OnPendingAsyncCompleted(); |
| } |