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

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: DO NOT SUBMIT/ having only Update() 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/command_line.h" 7 #include "base/command_line.h"
8 #include "base/json/json_writer.h" 8 #include "base/json/json_writer.h"
9 #include "base/values.h" 9 #include "base/values.h"
10 #include "chrome/browser/chrome_notification_types.h" 10 #include "chrome/browser/chrome_notification_types.h"
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 57
58 // Overwrite the third arg with our tab value as seen by this extension. 58 // Overwrite the third arg with our tab value as seen by this extension.
59 event_args->Set(2, ExtensionTabUtil::CreateTabValue(contents, extension)); 59 event_args->Set(2, ExtensionTabUtil::CreateTabValue(contents, extension));
60 return true; 60 return true;
61 } 61 }
62 62
63 } // namespace 63 } // namespace
64 64
65 TabsEventRouter::TabEntry::TabEntry(content::WebContents* contents) 65 TabsEventRouter::TabEntry::TabEntry(content::WebContents* contents)
66 : contents_(contents), 66 : contents_(contents),
67 complete_waiting_on_load_(false),
68 was_audible_(contents->WasRecentlyAudible()), 67 was_audible_(contents->WasRecentlyAudible()),
69 was_muted_(contents->IsAudioMuted()) { 68 was_muted_(contents->IsAudioMuted()) {
70 } 69 }
71 70
72 scoped_ptr<base::DictionaryValue> TabsEventRouter::TabEntry::UpdateLoadState() { 71 scoped_ptr<base::DictionaryValue> TabsEventRouter::TabEntry::Update() {
73 // The tab may go in & out of loading (for instance if iframes navigate).
74 // We only want to respond to the first change from loading to !loading after
75 // the NAV_ENTRY_COMMITTED was fired.
76 scoped_ptr<base::DictionaryValue> changed_properties( 72 scoped_ptr<base::DictionaryValue> changed_properties(
77 new base::DictionaryValue()); 73 new base::DictionaryValue());
78 if (!complete_waiting_on_load_ || contents_->IsLoading()) { 74 if (status_ != "loading" && contents_->IsLoading() &&
79 return changed_properties.Pass(); 75 contents_->GetLastCommittedURL() != url_) {
76 changed_properties->SetString(tabs_constants::kStatusKey,
77 tabs_constants::kStatusValueLoading);
78 status_ = "loading";
79 } else if (status_ == "loading" && !contents_->IsLoading()) {
80 changed_properties->SetString(tabs_constants::kStatusKey,
81 tabs_constants::kStatusValueComplete);
82 status_ = "complete";
80 } 83 }
81 84
82 // Send "complete" state change. 85 if (contents_->GetLastCommittedURL() != url_) {
83 complete_waiting_on_load_ = false; 86 url_ = contents_->GetLastCommittedURL();
84 changed_properties->SetString(tabs_constants::kStatusKey, 87 changed_properties->SetString(tabs_constants::kUrlKey, url_.spec());
85 tabs_constants::kStatusValueComplete); 88 }
86 return changed_properties.Pass(); 89 return changed_properties.Pass();
87 } 90 }
88 91
89 scoped_ptr<base::DictionaryValue> TabsEventRouter::TabEntry::DidNavigate() {
90 // Send "loading" state change.
91 complete_waiting_on_load_ = true;
92 scoped_ptr<base::DictionaryValue> changed_properties(
93 new base::DictionaryValue());
94 changed_properties->SetString(tabs_constants::kStatusKey,
95 tabs_constants::kStatusValueLoading);
96
97 if (contents_->GetURL() != url_) {
98 url_ = contents_->GetURL();
99 changed_properties->SetString(tabs_constants::kUrlKey, url_.spec());
100 }
101
102 return changed_properties.Pass();
103 }
104
105 bool TabsEventRouter::TabEntry::SetAudible(bool new_val) { 92 bool TabsEventRouter::TabEntry::SetAudible(bool new_val) {
106 if (was_audible_ == new_val) 93 if (was_audible_ == new_val)
107 return false; 94 return false;
108 was_audible_ = new_val; 95 was_audible_ = new_val;
109 return true; 96 return true;
110 } 97 }
111 98
112 bool TabsEventRouter::TabEntry::SetMuted(bool new_val) { 99 bool TabsEventRouter::TabEntry::SetMuted(bool new_val) {
113 if (was_muted_ == new_val) 100 if (was_muted_ == new_val)
114 return false; 101 return false;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 // Start listening to TabStripModel events for this browser. 140 // Start listening to TabStripModel events for this browser.
154 TabStripModel* tab_strip = browser->tab_strip_model(); 141 TabStripModel* tab_strip = browser->tab_strip_model();
155 tab_strip->AddObserver(this); 142 tab_strip->AddObserver(this);
156 143
157 for (int i = 0; i < tab_strip->count(); ++i) { 144 for (int i = 0; i < tab_strip->count(); ++i) {
158 RegisterForTabNotifications(tab_strip->GetWebContentsAt(i)); 145 RegisterForTabNotifications(tab_strip->GetWebContentsAt(i));
159 } 146 }
160 } 147 }
161 148
162 void TabsEventRouter::RegisterForTabNotifications(WebContents* contents) { 149 void TabsEventRouter::RegisterForTabNotifications(WebContents* contents) {
150 // TODO(limasdf): Attach WebContentsObservers to |contents| rather than
151 // registering for notifications.
163 registrar_.Add( 152 registrar_.Add(
164 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, 153 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
165 content::Source<NavigationController>(&contents->GetController())); 154 content::Source<NavigationController>(&contents->GetController()));
166 155
167 // Observing NOTIFICATION_WEB_CONTENTS_DESTROYED is necessary because it's 156 // Observing NOTIFICATION_WEB_CONTENTS_DESTROYED is necessary because it's
168 // possible for tabs to be created, detached and then destroyed without 157 // possible for tabs to be created, detached and then destroyed without
169 // ever having been re-attached and closed. This happens in the case of 158 // ever having been re-attached and closed. This happens in the case of
170 // a devtools WebContents that is opened in window, docked, then closed. 159 // a devtools WebContents that is opened in window, docked, then closed.
171 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 160 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
172 content::Source<WebContents>(contents)); 161 content::Source<WebContents>(contents));
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after
499 488
500 TabEntryMap::iterator i = tab_entries_.find(tab_id); 489 TabEntryMap::iterator i = tab_entries_.find(tab_id);
501 if (tab_entries_.end() == i) 490 if (tab_entries_.end() == i)
502 return linked_ptr<TabEntry>(NULL); 491 return linked_ptr<TabEntry>(NULL);
503 return i->second; 492 return i->second;
504 } 493 }
505 494
506 void TabsEventRouter::Observe(int type, 495 void TabsEventRouter::Observe(int type,
507 const content::NotificationSource& source, 496 const content::NotificationSource& source,
508 const content::NotificationDetails& details) { 497 const content::NotificationDetails& details) {
509 if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED) { 498 switch (type) {
499 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: {
510 NavigationController* source_controller = 500 NavigationController* source_controller =
511 content::Source<NavigationController>(source).ptr(); 501 content::Source<NavigationController>(source).ptr();
512 linked_ptr<TabEntry> entry = 502 linked_ptr<TabEntry> entry =
513 GetTabEntry(source_controller->GetWebContents()); 503 GetTabEntry(source_controller->GetWebContents());
514 CHECK(entry.get()); 504 CHECK(entry.get());
515 TabUpdated(entry, (entry.get())->DidNavigate()); 505 TabUpdated(entry, (entry.get())->Update());
516 } else if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { 506 }
507 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
517 // Tab was destroyed after being detached (without being re-attached). 508 // Tab was destroyed after being detached (without being re-attached).
518 WebContents* contents = content::Source<WebContents>(source).ptr(); 509 WebContents* contents = content::Source<WebContents>(source).ptr();
519 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, 510 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
520 content::Source<NavigationController>(&contents->GetController())); 511 content::Source<NavigationController>(&contents->GetController()));
521 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 512 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
522 content::Source<WebContents>(contents)); 513 content::Source<WebContents>(contents));
523 favicon_scoped_observer_.Remove( 514 favicon_scoped_observer_.Remove(
524 favicon::ContentFaviconDriver::FromWebContents(contents)); 515 favicon::ContentFaviconDriver::FromWebContents(contents));
525 } else { 516 }
526 NOTREACHED(); 517 default:
518 NOTREACHED();
527 } 519 }
528 } 520 }
529 521
530 void TabsEventRouter::TabChangedAt(WebContents* contents, 522 void TabsEventRouter::TabChangedAt(WebContents* contents,
531 int index, 523 int index,
532 TabChangeType change_type) { 524 TabChangeType change_type) {
533 linked_ptr<TabEntry> entry = GetTabEntry(contents); 525 linked_ptr<TabEntry> entry = GetTabEntry(contents);
534 CHECK(entry.get()); 526 CHECK(entry.get());
535 TabUpdated(entry, (entry.get())->UpdateLoadState()); 527 TabUpdated(entry, (entry.get())->Update());
536 } 528 }
537 529
538 void TabsEventRouter::TabReplacedAt(TabStripModel* tab_strip_model, 530 void TabsEventRouter::TabReplacedAt(TabStripModel* tab_strip_model,
539 WebContents* old_contents, 531 WebContents* old_contents,
540 WebContents* new_contents, 532 WebContents* new_contents,
541 int index) { 533 int index) {
542 // Notify listeners that the next tabs closing or being added are due to 534 // Notify listeners that the next tabs closing or being added are due to
543 // WebContents being swapped. 535 // WebContents being swapped.
544 const int new_tab_id = ExtensionTabUtil::GetTabId(new_contents); 536 const int new_tab_id = ExtensionTabUtil::GetTabId(new_contents);
545 const int old_tab_id = ExtensionTabUtil::GetTabId(old_contents); 537 const int old_tab_id = ExtensionTabUtil::GetTabId(old_contents);
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
607 void TabsEventRouter::OnFaviconUpdated(favicon::FaviconDriver* favicon_driver, 599 void TabsEventRouter::OnFaviconUpdated(favicon::FaviconDriver* favicon_driver,
608 bool icon_url_changed) { 600 bool icon_url_changed) {
609 if (icon_url_changed) { 601 if (icon_url_changed) {
610 favicon::ContentFaviconDriver* content_favicon_driver = 602 favicon::ContentFaviconDriver* content_favicon_driver =
611 static_cast<favicon::ContentFaviconDriver*>(favicon_driver); 603 static_cast<favicon::ContentFaviconDriver*>(favicon_driver);
612 FaviconUrlUpdated(content_favicon_driver->web_contents()); 604 FaviconUrlUpdated(content_favicon_driver->web_contents());
613 } 605 }
614 } 606 }
615 607
616 } // namespace extensions 608 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698