Index: chrome/browser/extensions/api/downloads/downloads_api.cc |
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc |
index 9b0f0a6099c201a761380b2826fcedc31b773744..5ab2663be7efa4c885489d2ae6d0f905e7fcadd7 100644 |
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc |
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc |
@@ -64,6 +64,8 @@ |
#include "third_party/skia/include/core/SkBitmap.h" |
#include "ui/webui/web_ui_util.h" |
+namespace events = extensions::event_names; |
+ |
using content::BrowserContext; |
using content::BrowserThread; |
using content::DownloadId; |
@@ -523,6 +525,10 @@ class ExtensionDownloadsEventRouterData : public base::SupportsUserData::Data { |
static_cast<ExtensionDownloadsEventRouterData*>(data); |
} |
+ static void Remove(DownloadItem* download_item) { |
+ download_item->RemoveUserData(kKey); |
+ } |
+ |
explicit ExtensionDownloadsEventRouterData( |
DownloadItem* download_item, |
scoped_ptr<base::DictionaryValue> json_item) |
@@ -1199,16 +1205,15 @@ ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter( |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
DCHECK(profile_); |
extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)-> |
- event_router(); |
+ event_router(); |
if (router) |
- router->RegisterObserver( |
- this, extensions::event_names::kOnDownloadDeterminingFilename); |
+ router->RegisterObserver(this, events::kOnDownloadDeterminingFilename); |
} |
ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)-> |
- event_router(); |
+ event_router(); |
if (router) |
router->UnregisterObserver(this); |
} |
@@ -1246,13 +1251,17 @@ void ExtensionDownloadsEventRouter::OnDeterminingFilename( |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
ExtensionDownloadsEventRouterData* data = |
ExtensionDownloadsEventRouterData::Get(item); |
+ if (!data) { |
+ no_change.Run(); |
+ return; |
+ } |
data->ClearPendingDeterminers(); |
data->set_filename_change_callbacks(no_change, change); |
bool any_determiners = false; |
base::DictionaryValue* json = DownloadItemToJSON( |
item, profile_->IsOffTheRecord()).release(); |
json->SetString(kFilenameKey, suggested_path.LossyDisplayName()); |
- DispatchEvent(extensions::event_names::kOnDownloadDeterminingFilename, |
+ DispatchEvent(events::kOnDownloadDeterminingFilename, |
false, |
base::Bind(&OnDeterminingFilenameWillDispatchCallback, |
&any_determiners, |
@@ -1313,26 +1322,38 @@ bool ExtensionDownloadsEventRouter::DetermineFilename( |
void ExtensionDownloadsEventRouter::OnListenerRemoved( |
const extensions::EventListenerInfo& details) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- if (details.event_name != |
- extensions::event_names::kOnDownloadDeterminingFilename) |
- return; |
DownloadManager* manager = notifier_.GetManager(); |
if (!manager) |
return; |
+ bool determiner_removed = ( |
+ details.event_name == events::kOnDownloadDeterminingFilename); |
+ extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)-> |
+ event_router(); |
+ bool any_listeners = |
+ router->HasEventListener(events::kOnDownloadChanged) || |
+ router->HasEventListener(events::kOnDownloadDeterminingFilename); |
+ if (!determiner_removed && any_listeners) |
+ return; |
DownloadManager::DownloadVector items; |
manager->GetAllDownloads(&items); |
- // Notify any items that may be waiting for callbacks from this |
- // extension/determiner. |
for (DownloadManager::DownloadVector::const_iterator iter = |
items.begin(); |
iter != items.end(); ++iter) { |
ExtensionDownloadsEventRouterData* data = |
ExtensionDownloadsEventRouterData::Get(*iter); |
- // This will almost always be a no-op, however, it is possible for an |
- // extension renderer to be unloaded while a download item is waiting |
- // for a determiner. In that case, the download item should proceed. |
- if (data) |
+ if (!data) |
+ continue; |
+ if (determiner_removed) { |
+ // Notify any items that may be waiting for callbacks from this |
+ // extension/determiner. This will almost always be a no-op, however, it |
+ // is possible for an extension renderer to be unloaded while a download |
+ // item is waiting for a determiner. In that case, the download item |
+ // should proceed. |
data->DeterminerRemoved(details.extension_id); |
+ } |
+ if (!any_listeners) { |
+ ExtensionDownloadsEventRouterData::Remove(*iter); |
+ } |
} |
} |
@@ -1345,29 +1366,47 @@ void ExtensionDownloadsEventRouter::OnDownloadCreated( |
if (download_item->IsTemporary()) |
return; |
+ extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)-> |
+ event_router(); |
+ // Avoid allocating a bunch of memory in DownloadItemToJSON if it isn't going |
+ // to be used. |
+ if (!router || |
+ (!router->HasEventListener(events::kOnDownloadCreated) && |
+ !router->HasEventListener(events::kOnDownloadChanged) && |
+ !router->HasEventListener(events::kOnDownloadDeterminingFilename))) { |
+ return; |
+ } |
scoped_ptr<base::DictionaryValue> json_item( |
DownloadItemToJSON(download_item, profile_->IsOffTheRecord())); |
- DispatchEvent(extensions::event_names::kOnDownloadCreated, |
+ DispatchEvent(events::kOnDownloadCreated, |
true, |
extensions::Event::WillDispatchCallback(), |
json_item->DeepCopy()); |
- if (!ExtensionDownloadsEventRouterData::Get(download_item)) |
+ if (!ExtensionDownloadsEventRouterData::Get(download_item) && |
+ (router->HasEventListener(events::kOnDownloadChanged) || |
+ router->HasEventListener(events::kOnDownloadDeterminingFilename))) { |
new ExtensionDownloadsEventRouterData(download_item, json_item.Pass()); |
+ } |
} |
void ExtensionDownloadsEventRouter::OnDownloadUpdated( |
DownloadManager* manager, DownloadItem* download_item) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- if (download_item->IsTemporary()) |
- return; |
- |
+ extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)-> |
+ event_router(); |
ExtensionDownloadsEventRouterData* data = |
ExtensionDownloadsEventRouterData::Get(download_item); |
- if (!data) { |
- // The download_item probably transitioned from temporary to not temporary. |
- OnDownloadCreated(manager, download_item); |
+ if (download_item->IsTemporary() || |
+ !router->HasEventListener(events::kOnDownloadChanged)) { |
return; |
} |
+ if (!data) { |
+ // The download_item probably transitioned from temporary to not temporary, |
+ // or else an event listener was added. |
+ data = new ExtensionDownloadsEventRouterData( |
+ download_item, |
+ scoped_ptr<base::DictionaryValue>(new base::DictionaryValue())); |
+ } |
scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON( |
download_item, profile_->IsOffTheRecord())); |
scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue()); |
@@ -1409,7 +1448,7 @@ void ExtensionDownloadsEventRouter::OnDownloadUpdated( |
// changed. Replace the stored json with the new json. |
data->OnItemUpdated(); |
if (changed) { |
- DispatchEvent(extensions::event_names::kOnDownloadChanged, |
+ DispatchEvent(events::kOnDownloadChanged, |
true, |
extensions::Event::WillDispatchCallback(), |
delta.release()); |
@@ -1423,7 +1462,7 @@ void ExtensionDownloadsEventRouter::OnDownloadRemoved( |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
if (download_item->IsTemporary()) |
return; |
- DispatchEvent(extensions::event_names::kOnDownloadErased, |
+ DispatchEvent(events::kOnDownloadErased, |
true, |
extensions::Event::WillDispatchCallback(), |
base::Value::CreateIntegerValue(download_item->GetId())); |