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

Side by Side Diff: chrome/browser/extensions/api/tabs/tabs_event_router.cc

Issue 1156043002: chrome.tabs.onUpdated doesn't called with 'loading' twice. Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 5 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
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/tabs/tabs_event_router.h" 5 #include "chrome/browser/extensions/api/tabs/tabs_event_router.h"
6 6
7 #include "base/json/json_writer.h" 7 #include "base/json/json_writer.h"
8 #include "base/values.h" 8 #include "base/values.h"
9 #include "chrome/browser/chrome_notification_types.h" 9 #include "chrome/browser/chrome_notification_types.h"
10 #include "chrome/browser/extensions/api/tabs/tabs_constants.h" 10 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
11 #include "chrome/browser/extensions/api/tabs/tabs_windows_api.h" 11 #include "chrome/browser/extensions/api/tabs/tabs_windows_api.h"
12 #include "chrome/browser/extensions/api/tabs/windows_event_router.h" 12 #include "chrome/browser/extensions/api/tabs/windows_event_router.h"
13 #include "chrome/browser/extensions/extension_tab_util.h" 13 #include "chrome/browser/extensions/extension_tab_util.h"
14 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser.h" 15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/browser_iterator.h" 16 #include "chrome/browser/ui/browser_iterator.h"
17 #include "chrome/browser/ui/browser_list.h" 17 #include "chrome/browser/ui/browser_list.h"
18 #include "chrome/browser/ui/tabs/tab_strip_model.h" 18 #include "chrome/browser/ui/tabs/tab_strip_model.h"
19 #include "chrome/common/extensions/extension_constants.h" 19 #include "chrome/common/extensions/extension_constants.h"
20 #include "components/favicon/content/content_favicon_driver.h" 20 #include "components/favicon/content/content_favicon_driver.h"
21 #include "content/public/browser/favicon_status.h" 21 #include "content/public/browser/favicon_status.h"
22 #include "content/public/browser/navigation_controller.h" 22 #include "content/public/browser/navigation_controller.h"
23 #include "content/public/browser/navigation_entry.h" 23 #include "content/public/browser/navigation_entry.h"
24 #include "content/public/browser/notification_service.h" 24 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/notification_types.h" 25 #include "content/public/browser/notification_types.h"
26 #include "content/public/browser/web_contents.h" 26 #include "content/public/browser/web_contents.h"
27 27
28 using base::DictionaryValue;
29 using base::ListValue; 28 using base::ListValue;
30 using base::FundamentalValue; 29 using base::FundamentalValue;
31 using content::NavigationController; 30 using content::NavigationController;
32 using content::WebContents; 31 using content::WebContents;
33 using ui_zoom::ZoomController; 32 using ui_zoom::ZoomController;
34 33
35 namespace extensions { 34 namespace extensions {
36 35
37 namespace { 36 namespace {
38 37
(...skipping 17 matching lines...) Expand all
56 event_args->Set(2, ExtensionTabUtil::CreateTabValue(contents, extension)); 55 event_args->Set(2, ExtensionTabUtil::CreateTabValue(contents, extension));
57 return true; 56 return true;
58 } 57 }
59 58
60 } // namespace 59 } // namespace
61 60
62 TabsEventRouter::TabEntry::TabEntry() : complete_waiting_on_load_(false), 61 TabsEventRouter::TabEntry::TabEntry() : complete_waiting_on_load_(false),
63 url_() { 62 url_() {
64 } 63 }
65 64
66 base::DictionaryValue* TabsEventRouter::TabEntry::UpdateLoadState( 65 scoped_ptr<base::DictionaryValue> TabsEventRouter::TabEntry::UpdateComplete(
67 const WebContents* contents) { 66 const WebContents* contents) {
68 // The tab may go in & out of loading (for instance if iframes navigate). 67 // The tab may go in & out of loading (for instance if iframes navigate).
69 // We only want to respond to the first change from loading to !loading after 68 // We only want to respond to the first change from loading to !loading after
70 // the NAV_ENTRY_COMMITTED was fired. 69 // the NAV_ENTRY_COMMITTED was fired.
71 if (!complete_waiting_on_load_ || contents->IsLoading()) 70 if (!complete_waiting_on_load_ || contents->IsLoading())
72 return NULL; 71 return nullptr;
73 72
74 // Send "complete" state change. 73 // Send "complete" state change.
75 complete_waiting_on_load_ = false; 74 complete_waiting_on_load_ = false;
76 base::DictionaryValue* changed_properties = new base::DictionaryValue(); 75 scoped_ptr<base::DictionaryValue> changed(new base::DictionaryValue);
77 changed_properties->SetString(tabs_constants::kStatusKey, 76 changed->SetString(tabs_constants::kStatusKey,
78 tabs_constants::kStatusValueComplete); 77 tabs_constants::kStatusValueComplete);
79 return changed_properties; 78 return changed.Pass();
80 } 79 }
81 80
82 base::DictionaryValue* TabsEventRouter::TabEntry::DidNavigate( 81 scoped_ptr<base::DictionaryValue> TabsEventRouter::TabEntry::Update(
83 const WebContents* contents) { 82 const WebContents* contents) {
84 // Send "loading" state change. 83 scoped_ptr<base::DictionaryValue> changed(new base::DictionaryValue);
85 complete_waiting_on_load_ = true;
86 base::DictionaryValue* changed_properties = new base::DictionaryValue();
87 changed_properties->SetString(tabs_constants::kStatusKey,
88 tabs_constants::kStatusValueLoading);
89 84
90 if (contents->GetURL() != url_) { 85 if (!complete_waiting_on_load_ && contents->IsLoading()) {
limasdf 2015/07/06 17:14:44 'loading' is not included if previous status is 'l
91 url_ = contents->GetURL(); 86 changed->SetString(tabs_constants::kStatusKey,
92 changed_properties->SetString(tabs_constants::kUrlKey, url_.spec()); 87 tabs_constants::kStatusValueLoading);
88 complete_waiting_on_load_ = true;
93 } 89 }
94 90
95 return changed_properties; 91 GURL new_url = contents->GetLastCommittedURL();
92 if (url_ != new_url) {
93 changed->SetString(tabs_constants::kUrlKey, new_url.spec());
94 url_ = new_url;
95 }
96
97 if (changed->empty())
98 return nullptr;
99
100 return changed.Pass();
96 } 101 }
97 102
98 TabsEventRouter::TabsEventRouter(Profile* profile) 103 TabsEventRouter::TabsEventRouter(Profile* profile)
99 : profile_(profile), favicon_scoped_observer_(this) { 104 : profile_(profile), favicon_scoped_observer_(this) {
100 DCHECK(!profile->IsOffTheRecord()); 105 DCHECK(!profile->IsOffTheRecord());
101 106
102 BrowserList::AddObserver(this); 107 BrowserList::AddObserver(this);
103 108
104 // Init() can happen after the browser is running, so catch up with any 109 // Init() can happen after the browser is running, so catch up with any
105 // windows that already exist. 110 // windows that already exist.
(...skipping 26 matching lines...) Expand all
132 // Start listening to TabStripModel events for this browser. 137 // Start listening to TabStripModel events for this browser.
133 TabStripModel* tab_strip = browser->tab_strip_model(); 138 TabStripModel* tab_strip = browser->tab_strip_model();
134 tab_strip->AddObserver(this); 139 tab_strip->AddObserver(this);
135 140
136 for (int i = 0; i < tab_strip->count(); ++i) { 141 for (int i = 0; i < tab_strip->count(); ++i) {
137 RegisterForTabNotifications(tab_strip->GetWebContentsAt(i)); 142 RegisterForTabNotifications(tab_strip->GetWebContentsAt(i));
138 } 143 }
139 } 144 }
140 145
141 void TabsEventRouter::RegisterForTabNotifications(WebContents* contents) { 146 void TabsEventRouter::RegisterForTabNotifications(WebContents* contents) {
147 // TODO(limasdf): Attach WebContentsObservers to |contents| rather than
148 // registering for notifications.
142 registrar_.Add( 149 registrar_.Add(
143 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, 150 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
144 content::Source<NavigationController>(&contents->GetController())); 151 content::Source<NavigationController>(&contents->GetController()));
145 152
146 // Observing NOTIFICATION_WEB_CONTENTS_DESTROYED is necessary because it's 153 // Observing NOTIFICATION_WEB_CONTENTS_DESTROYED is necessary because it's
147 // possible for tabs to be created, detached and then destroyed without 154 // possible for tabs to be created, detached and then destroyed without
148 // ever having been re-attached and closed. This happens in the case of 155 // ever having been re-attached and closed. This happens in the case of
149 // a devtools WebContents that is opened in window, docked, then closed. 156 // a devtools WebContents that is opened in window, docked, then closed.
150 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 157 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
151 content::Source<WebContents>(contents)); 158 content::Source<WebContents>(contents));
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 394
388 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); 395 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
389 DispatchEvent(profile, 396 DispatchEvent(profile,
390 tabs::OnMoved::kEventName, 397 tabs::OnMoved::kEventName,
391 args.Pass(), 398 args.Pass(),
392 EventRouter::USER_GESTURE_UNKNOWN); 399 EventRouter::USER_GESTURE_UNKNOWN);
393 } 400 }
394 401
395 void TabsEventRouter::TabUpdated(WebContents* contents, bool did_navigate) { 402 void TabsEventRouter::TabUpdated(WebContents* contents, bool did_navigate) {
396 TabEntry* entry = GetTabEntry(contents); 403 TabEntry* entry = GetTabEntry(contents);
397 scoped_ptr<base::DictionaryValue> changed_properties;
398
399 if (!entry) 404 if (!entry)
400 return; 405 return;
401 406
407 scoped_ptr<base::DictionaryValue> changed_properties;
402 if (did_navigate) 408 if (did_navigate)
403 changed_properties.reset(entry->DidNavigate(contents)); 409 changed_properties = entry->Update(contents);
404 else 410 else
405 changed_properties.reset(entry->UpdateLoadState(contents)); 411 changed_properties = entry->UpdateComplete(contents);
406 412
407 if (changed_properties) 413 if (changed_properties)
408 DispatchTabUpdatedEvent(contents, changed_properties.Pass()); 414 DispatchTabUpdatedEvent(contents, changed_properties.Pass());
409 } 415 }
410 416
411 void TabsEventRouter::FaviconUrlUpdated(WebContents* contents) { 417 void TabsEventRouter::FaviconUrlUpdated(WebContents* contents) {
412 content::NavigationEntry* entry = 418 content::NavigationEntry* entry =
413 contents->GetController().GetVisibleEntry(); 419 contents->GetController().GetVisibleEntry();
414 if (!entry || !entry->GetFavicon().valid) 420 if (!entry || !entry->GetFavicon().valid)
415 return; 421 return;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
486 int tab_id = ExtensionTabUtil::GetTabId(contents); 492 int tab_id = ExtensionTabUtil::GetTabId(contents);
487 std::map<int, TabEntry>::iterator i = tab_entries_.find(tab_id); 493 std::map<int, TabEntry>::iterator i = tab_entries_.find(tab_id);
488 if (tab_entries_.end() == i) 494 if (tab_entries_.end() == i)
489 return NULL; 495 return NULL;
490 return &i->second; 496 return &i->second;
491 } 497 }
492 498
493 void TabsEventRouter::Observe(int type, 499 void TabsEventRouter::Observe(int type,
494 const content::NotificationSource& source, 500 const content::NotificationSource& source,
495 const content::NotificationDetails& details) { 501 const content::NotificationDetails& details) {
496 if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) { 502 switch (type) {
497 NavigationController* source_controller = 503 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: {
498 content::Source<NavigationController>(source).ptr(); 504 NavigationController* source_controller =
499 TabUpdated(source_controller->GetWebContents(), true); 505 content::Source<NavigationController>(source).ptr();
500 } else if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { 506 TabUpdated(source_controller->GetWebContents(), true);
501 // Tab was destroyed after being detached (without being re-attached). 507 break;
502 WebContents* contents = content::Source<WebContents>(source).ptr(); 508 }
503 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, 509 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
504 content::Source<NavigationController>(&contents->GetController())); 510 // Tab was destroyed after being detached (without being re-attached).
505 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 511 WebContents* contents = content::Source<WebContents>(source).ptr();
506 content::Source<WebContents>(contents)); 512 registrar_.Remove(
507 favicon_scoped_observer_.Remove( 513 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
508 favicon::ContentFaviconDriver::FromWebContents(contents)); 514 content::Source<NavigationController>(&contents->GetController()));
509 } else { 515 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
510 NOTREACHED(); 516 content::Source<WebContents>(contents));
517 favicon_scoped_observer_.Remove(
518 favicon::ContentFaviconDriver::FromWebContents(contents));
519 break;
520 }
521 default:
522 NOTREACHED();
511 } 523 }
512 } 524 }
513 525
514 void TabsEventRouter::TabChangedAt(WebContents* contents, 526 void TabsEventRouter::TabChangedAt(WebContents* contents,
515 int index, 527 int index,
516 TabChangeType change_type) { 528 TabChangeType change_type) {
517 TabUpdated(contents, false); 529 TabUpdated(contents, false);
518 } 530 }
519 531
520 void TabsEventRouter::TabReplacedAt(TabStripModel* tab_strip_model, 532 void TabsEventRouter::TabReplacedAt(TabStripModel* tab_strip_model,
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 void TabsEventRouter::OnFaviconUpdated(favicon::FaviconDriver* favicon_driver, 602 void TabsEventRouter::OnFaviconUpdated(favicon::FaviconDriver* favicon_driver,
591 bool icon_url_changed) { 603 bool icon_url_changed) {
592 if (icon_url_changed) { 604 if (icon_url_changed) {
593 favicon::ContentFaviconDriver* content_favicon_driver = 605 favicon::ContentFaviconDriver* content_favicon_driver =
594 static_cast<favicon::ContentFaviconDriver*>(favicon_driver); 606 static_cast<favicon::ContentFaviconDriver*>(favicon_driver);
595 FaviconUrlUpdated(content_favicon_driver->web_contents()); 607 FaviconUrlUpdated(content_favicon_driver->web_contents());
596 } 608 }
597 } 609 }
598 610
599 } // namespace extensions 611 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698