Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: chrome/browser/extensions/api/downloads/downloads_api.cc

Issue 14308002: Save memory in the downloads extension API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: @r195142 Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | chrome/browser/extensions/api/downloads/downloads_api_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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 "chrome/browser/extensions/api/downloads/downloads_api.h" 5 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cctype> 8 #include <cctype>
9 #include <iterator> 9 #include <iterator>
10 #include <set> 10 #include <set>
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 #include "content/public/browser/resource_context.h" 57 #include "content/public/browser/resource_context.h"
58 #include "content/public/browser/resource_dispatcher_host.h" 58 #include "content/public/browser/resource_dispatcher_host.h"
59 #include "content/public/browser/web_contents.h" 59 #include "content/public/browser/web_contents.h"
60 #include "content/public/browser/web_contents_view.h" 60 #include "content/public/browser/web_contents_view.h"
61 #include "net/base/load_flags.h" 61 #include "net/base/load_flags.h"
62 #include "net/http/http_util.h" 62 #include "net/http/http_util.h"
63 #include "net/url_request/url_request.h" 63 #include "net/url_request/url_request.h"
64 #include "third_party/skia/include/core/SkBitmap.h" 64 #include "third_party/skia/include/core/SkBitmap.h"
65 #include "ui/webui/web_ui_util.h" 65 #include "ui/webui/web_ui_util.h"
66 66
67 namespace events = extensions::event_names;
68
67 using content::BrowserContext; 69 using content::BrowserContext;
68 using content::BrowserThread; 70 using content::BrowserThread;
69 using content::DownloadId; 71 using content::DownloadId;
70 using content::DownloadItem; 72 using content::DownloadItem;
71 using content::DownloadManager; 73 using content::DownloadManager;
72 74
73 namespace download_extension_errors { 75 namespace download_extension_errors {
74 76
75 // Error messages 77 // Error messages
76 const char kGenericError[] = "I'm afraid I can't do that"; 78 const char kGenericError[] = "I'm afraid I can't do that";
(...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after
516 } 518 }
517 519
518 class ExtensionDownloadsEventRouterData : public base::SupportsUserData::Data { 520 class ExtensionDownloadsEventRouterData : public base::SupportsUserData::Data {
519 public: 521 public:
520 static ExtensionDownloadsEventRouterData* Get(DownloadItem* download_item) { 522 static ExtensionDownloadsEventRouterData* Get(DownloadItem* download_item) {
521 base::SupportsUserData::Data* data = download_item->GetUserData(kKey); 523 base::SupportsUserData::Data* data = download_item->GetUserData(kKey);
522 return (data == NULL) ? NULL : 524 return (data == NULL) ? NULL :
523 static_cast<ExtensionDownloadsEventRouterData*>(data); 525 static_cast<ExtensionDownloadsEventRouterData*>(data);
524 } 526 }
525 527
528 static void Remove(DownloadItem* download_item) {
529 download_item->RemoveUserData(kKey);
530 }
531
526 explicit ExtensionDownloadsEventRouterData( 532 explicit ExtensionDownloadsEventRouterData(
527 DownloadItem* download_item, 533 DownloadItem* download_item,
528 scoped_ptr<base::DictionaryValue> json_item) 534 scoped_ptr<base::DictionaryValue> json_item)
529 : updated_(0), 535 : updated_(0),
530 changed_fired_(0), 536 changed_fired_(0),
531 json_(json_item.Pass()), 537 json_(json_item.Pass()),
532 determined_conflict_action_( 538 determined_conflict_action_(
533 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY) { 539 extensions::api::downloads::FILENAME_CONFLICT_ACTION_UNIQUIFY) {
534 download_item->SetUserData(kKey, this); 540 download_item->SetUserData(kKey, this);
535 } 541 }
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after
1192 } 1198 }
1193 1199
1194 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter( 1200 ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter(
1195 Profile* profile, 1201 Profile* profile,
1196 DownloadManager* manager) 1202 DownloadManager* manager)
1197 : profile_(profile), 1203 : profile_(profile),
1198 ALLOW_THIS_IN_INITIALIZER_LIST(notifier_(manager, this)) { 1204 ALLOW_THIS_IN_INITIALIZER_LIST(notifier_(manager, this)) {
1199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1200 DCHECK(profile_); 1206 DCHECK(profile_);
1201 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)-> 1207 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)->
1202 event_router(); 1208 event_router();
1203 if (router) 1209 if (router)
1204 router->RegisterObserver( 1210 router->RegisterObserver(this, events::kOnDownloadDeterminingFilename);
1205 this, extensions::event_names::kOnDownloadDeterminingFilename);
1206 } 1211 }
1207 1212
1208 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() { 1213 ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() {
1209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1214 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1210 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)-> 1215 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)->
1211 event_router(); 1216 event_router();
1212 if (router) 1217 if (router)
1213 router->UnregisterObserver(this); 1218 router->UnregisterObserver(this);
1214 } 1219 }
1215 1220
1216 // The method by which extensions hook into the filename determination process 1221 // The method by which extensions hook into the filename determination process
1217 // is based on the method by which the omnibox API allows extensions to hook 1222 // is based on the method by which the omnibox API allows extensions to hook
1218 // into the omnibox autocompletion process. Extensions that wish to play a part 1223 // into the omnibox autocompletion process. Extensions that wish to play a part
1219 // in the filename determination process call 1224 // in the filename determination process call
1220 // chrome.downloads.onDeterminingFilename.addListener, which adds an 1225 // chrome.downloads.onDeterminingFilename.addListener, which adds an
1221 // EventListener object to ExtensionEventRouter::listeners(). 1226 // EventListener object to ExtensionEventRouter::listeners().
(...skipping 17 matching lines...) Expand all
1239 // then the extension that was last installed wins. 1244 // then the extension that was last installed wins.
1240 1245
1241 void ExtensionDownloadsEventRouter::OnDeterminingFilename( 1246 void ExtensionDownloadsEventRouter::OnDeterminingFilename(
1242 DownloadItem* item, 1247 DownloadItem* item,
1243 const base::FilePath& suggested_path, 1248 const base::FilePath& suggested_path,
1244 const base::Closure& no_change, 1249 const base::Closure& no_change,
1245 const FilenameChangedCallback& change) { 1250 const FilenameChangedCallback& change) {
1246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1247 ExtensionDownloadsEventRouterData* data = 1252 ExtensionDownloadsEventRouterData* data =
1248 ExtensionDownloadsEventRouterData::Get(item); 1253 ExtensionDownloadsEventRouterData::Get(item);
1254 if (!data) {
1255 no_change.Run();
1256 return;
1257 }
1249 data->ClearPendingDeterminers(); 1258 data->ClearPendingDeterminers();
1250 data->set_filename_change_callbacks(no_change, change); 1259 data->set_filename_change_callbacks(no_change, change);
1251 bool any_determiners = false; 1260 bool any_determiners = false;
1252 base::DictionaryValue* json = DownloadItemToJSON( 1261 base::DictionaryValue* json = DownloadItemToJSON(
1253 item, profile_->IsOffTheRecord()).release(); 1262 item, profile_->IsOffTheRecord()).release();
1254 json->SetString(kFilenameKey, suggested_path.LossyDisplayName()); 1263 json->SetString(kFilenameKey, suggested_path.LossyDisplayName());
1255 DispatchEvent(extensions::event_names::kOnDownloadDeterminingFilename, 1264 DispatchEvent(events::kOnDownloadDeterminingFilename,
1256 false, 1265 false,
1257 base::Bind(&OnDeterminingFilenameWillDispatchCallback, 1266 base::Bind(&OnDeterminingFilenameWillDispatchCallback,
1258 &any_determiners, 1267 &any_determiners,
1259 data), 1268 data),
1260 json); 1269 json);
1261 if (!any_determiners) { 1270 if (!any_determiners) {
1262 data->ClearPendingDeterminers(); 1271 data->ClearPendingDeterminers();
1263 no_change.Run(); 1272 no_change.Run();
1264 } 1273 }
1265 } 1274 }
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1306 // forever waiting for this ext_id to report. 1315 // forever waiting for this ext_id to report.
1307 *error = download_extension_errors::kInvalidFilenameError; 1316 *error = download_extension_errors::kInvalidFilenameError;
1308 return false; 1317 return false;
1309 } 1318 }
1310 return true; 1319 return true;
1311 } 1320 }
1312 1321
1313 void ExtensionDownloadsEventRouter::OnListenerRemoved( 1322 void ExtensionDownloadsEventRouter::OnListenerRemoved(
1314 const extensions::EventListenerInfo& details) { 1323 const extensions::EventListenerInfo& details) {
1315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1324 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1316 if (details.event_name !=
1317 extensions::event_names::kOnDownloadDeterminingFilename)
1318 return;
1319 DownloadManager* manager = notifier_.GetManager(); 1325 DownloadManager* manager = notifier_.GetManager();
1320 if (!manager) 1326 if (!manager)
1321 return; 1327 return;
1328 bool determiner_removed = (
1329 details.event_name == events::kOnDownloadDeterminingFilename);
1330 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)->
1331 event_router();
1332 bool any_listeners =
1333 router->HasEventListener(events::kOnDownloadChanged) ||
1334 router->HasEventListener(events::kOnDownloadDeterminingFilename);
1335 if (!determiner_removed && any_listeners)
1336 return;
1322 DownloadManager::DownloadVector items; 1337 DownloadManager::DownloadVector items;
1323 manager->GetAllDownloads(&items); 1338 manager->GetAllDownloads(&items);
1324 // Notify any items that may be waiting for callbacks from this
1325 // extension/determiner.
1326 for (DownloadManager::DownloadVector::const_iterator iter = 1339 for (DownloadManager::DownloadVector::const_iterator iter =
1327 items.begin(); 1340 items.begin();
1328 iter != items.end(); ++iter) { 1341 iter != items.end(); ++iter) {
1329 ExtensionDownloadsEventRouterData* data = 1342 ExtensionDownloadsEventRouterData* data =
1330 ExtensionDownloadsEventRouterData::Get(*iter); 1343 ExtensionDownloadsEventRouterData::Get(*iter);
1331 // This will almost always be a no-op, however, it is possible for an 1344 if (!data)
1332 // extension renderer to be unloaded while a download item is waiting 1345 continue;
1333 // for a determiner. In that case, the download item should proceed. 1346 if (determiner_removed) {
1334 if (data) 1347 // Notify any items that may be waiting for callbacks from this
1348 // extension/determiner. This will almost always be a no-op, however, it
1349 // is possible for an extension renderer to be unloaded while a download
1350 // item is waiting for a determiner. In that case, the download item
1351 // should proceed.
1335 data->DeterminerRemoved(details.extension_id); 1352 data->DeterminerRemoved(details.extension_id);
1353 }
1354 if (!any_listeners) {
1355 ExtensionDownloadsEventRouterData::Remove(*iter);
1356 }
1336 } 1357 }
1337 } 1358 }
1338 1359
1339 // That's all the methods that have to do with filename determination. The rest 1360 // That's all the methods that have to do with filename determination. The rest
1340 // have to do with the other, less special events. 1361 // have to do with the other, less special events.
1341 1362
1342 void ExtensionDownloadsEventRouter::OnDownloadCreated( 1363 void ExtensionDownloadsEventRouter::OnDownloadCreated(
1343 DownloadManager* manager, DownloadItem* download_item) { 1364 DownloadManager* manager, DownloadItem* download_item) {
1344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1365 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1345 if (download_item->IsTemporary()) 1366 if (download_item->IsTemporary())
1346 return; 1367 return;
1347 1368
1369 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)->
1370 event_router();
1371 // Avoid allocating a bunch of memory in DownloadItemToJSON if it isn't going
1372 // to be used.
1373 if (!router ||
1374 (!router->HasEventListener(events::kOnDownloadCreated) &&
1375 !router->HasEventListener(events::kOnDownloadChanged) &&
1376 !router->HasEventListener(events::kOnDownloadDeterminingFilename))) {
1377 return;
1378 }
1348 scoped_ptr<base::DictionaryValue> json_item( 1379 scoped_ptr<base::DictionaryValue> json_item(
1349 DownloadItemToJSON(download_item, profile_->IsOffTheRecord())); 1380 DownloadItemToJSON(download_item, profile_->IsOffTheRecord()));
1350 DispatchEvent(extensions::event_names::kOnDownloadCreated, 1381 DispatchEvent(events::kOnDownloadCreated,
1351 true, 1382 true,
1352 extensions::Event::WillDispatchCallback(), 1383 extensions::Event::WillDispatchCallback(),
1353 json_item->DeepCopy()); 1384 json_item->DeepCopy());
1354 if (!ExtensionDownloadsEventRouterData::Get(download_item)) 1385 if (!ExtensionDownloadsEventRouterData::Get(download_item) &&
1386 (router->HasEventListener(events::kOnDownloadChanged) ||
1387 router->HasEventListener(events::kOnDownloadDeterminingFilename))) {
1355 new ExtensionDownloadsEventRouterData(download_item, json_item.Pass()); 1388 new ExtensionDownloadsEventRouterData(download_item, json_item.Pass());
1389 }
1356 } 1390 }
1357 1391
1358 void ExtensionDownloadsEventRouter::OnDownloadUpdated( 1392 void ExtensionDownloadsEventRouter::OnDownloadUpdated(
1359 DownloadManager* manager, DownloadItem* download_item) { 1393 DownloadManager* manager, DownloadItem* download_item) {
1360 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1394 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1361 if (download_item->IsTemporary()) 1395 extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)->
1362 return; 1396 event_router();
1363
1364 ExtensionDownloadsEventRouterData* data = 1397 ExtensionDownloadsEventRouterData* data =
1365 ExtensionDownloadsEventRouterData::Get(download_item); 1398 ExtensionDownloadsEventRouterData::Get(download_item);
1399 if (download_item->IsTemporary() ||
1400 !router->HasEventListener(events::kOnDownloadChanged)) {
1401 return;
1402 }
1366 if (!data) { 1403 if (!data) {
1367 // The download_item probably transitioned from temporary to not temporary. 1404 // The download_item probably transitioned from temporary to not temporary,
1368 OnDownloadCreated(manager, download_item); 1405 // or else an event listener was added.
1369 return; 1406 data = new ExtensionDownloadsEventRouterData(
1407 download_item,
1408 scoped_ptr<base::DictionaryValue>(new base::DictionaryValue()));
1370 } 1409 }
1371 scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON( 1410 scoped_ptr<base::DictionaryValue> new_json(DownloadItemToJSON(
1372 download_item, profile_->IsOffTheRecord())); 1411 download_item, profile_->IsOffTheRecord()));
1373 scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue()); 1412 scoped_ptr<base::DictionaryValue> delta(new base::DictionaryValue());
1374 delta->SetInteger(kIdKey, download_item->GetId()); 1413 delta->SetInteger(kIdKey, download_item->GetId());
1375 std::set<std::string> new_fields; 1414 std::set<std::string> new_fields;
1376 bool changed = false; 1415 bool changed = false;
1377 1416
1378 // For each field in the new json representation of the download_item except 1417 // For each field in the new json representation of the download_item except
1379 // the bytesReceived field, if the field has changed from the previous old 1418 // the bytesReceived field, if the field has changed from the previous old
(...skipping 22 matching lines...) Expand all
1402 if (new_fields.find(iter.key()) == new_fields.end()) { 1441 if (new_fields.find(iter.key()) == new_fields.end()) {
1403 delta->Set(iter.key() + ".previous", iter.value().DeepCopy()); 1442 delta->Set(iter.key() + ".previous", iter.value().DeepCopy());
1404 changed = true; 1443 changed = true;
1405 } 1444 }
1406 } 1445 }
1407 1446
1408 // Update the OnChangedStat and dispatch the event if something significant 1447 // Update the OnChangedStat and dispatch the event if something significant
1409 // changed. Replace the stored json with the new json. 1448 // changed. Replace the stored json with the new json.
1410 data->OnItemUpdated(); 1449 data->OnItemUpdated();
1411 if (changed) { 1450 if (changed) {
1412 DispatchEvent(extensions::event_names::kOnDownloadChanged, 1451 DispatchEvent(events::kOnDownloadChanged,
1413 true, 1452 true,
1414 extensions::Event::WillDispatchCallback(), 1453 extensions::Event::WillDispatchCallback(),
1415 delta.release()); 1454 delta.release());
1416 data->OnChangedFired(); 1455 data->OnChangedFired();
1417 } 1456 }
1418 data->set_json(new_json.Pass()); 1457 data->set_json(new_json.Pass());
1419 } 1458 }
1420 1459
1421 void ExtensionDownloadsEventRouter::OnDownloadRemoved( 1460 void ExtensionDownloadsEventRouter::OnDownloadRemoved(
1422 DownloadManager* manager, DownloadItem* download_item) { 1461 DownloadManager* manager, DownloadItem* download_item) {
1423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1462 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1424 if (download_item->IsTemporary()) 1463 if (download_item->IsTemporary())
1425 return; 1464 return;
1426 DispatchEvent(extensions::event_names::kOnDownloadErased, 1465 DispatchEvent(events::kOnDownloadErased,
1427 true, 1466 true,
1428 extensions::Event::WillDispatchCallback(), 1467 extensions::Event::WillDispatchCallback(),
1429 base::Value::CreateIntegerValue(download_item->GetId())); 1468 base::Value::CreateIntegerValue(download_item->GetId()));
1430 } 1469 }
1431 1470
1432 void ExtensionDownloadsEventRouter::DispatchEvent( 1471 void ExtensionDownloadsEventRouter::DispatchEvent(
1433 const char* event_name, 1472 const char* event_name,
1434 bool include_incognito, 1473 bool include_incognito,
1435 const extensions::Event::WillDispatchCallback& will_dispatch_callback, 1474 const extensions::Event::WillDispatchCallback& will_dispatch_callback,
1436 base::Value* arg) { 1475 base::Value* arg) {
(...skipping 19 matching lines...) Expand all
1456 DownloadsNotificationSource notification_source; 1495 DownloadsNotificationSource notification_source;
1457 notification_source.event_name = event_name; 1496 notification_source.event_name = event_name;
1458 notification_source.profile = profile_; 1497 notification_source.profile = profile_;
1459 content::Source<DownloadsNotificationSource> content_source( 1498 content::Source<DownloadsNotificationSource> content_source(
1460 &notification_source); 1499 &notification_source);
1461 content::NotificationService::current()->Notify( 1500 content::NotificationService::current()->Notify(
1462 chrome::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT, 1501 chrome::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT,
1463 content_source, 1502 content_source,
1464 content::Details<std::string>(&json_args)); 1503 content::Details<std::string>(&json_args));
1465 } 1504 }
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/extensions/api/downloads/downloads_api_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698