| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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/infobars/infobar_service.h" | 5 #include "chrome/browser/infobars/infobar_service.h" |
| 6 | 6 |
| 7 #include "chrome/browser/chrome_notification_types.h" | 7 #include "chrome/browser/chrome_notification_types.h" |
| 8 #include "chrome/browser/infobars/infobar.h" | 8 #include "chrome/browser/infobars/infobar.h" |
| 9 #include "chrome/browser/infobars/infobar_delegate.h" | 9 #include "chrome/browser/infobars/infobar_delegate.h" |
| 10 #include "chrome/browser/infobars/insecure_content_infobar_delegate.h" | 10 #include "chrome/browser/infobars/insecure_content_infobar_delegate.h" |
| 11 #include "chrome/common/render_messages.h" | 11 #include "chrome/common/render_messages.h" |
| 12 #include "content/public/browser/navigation_controller.h" | 12 #include "content/public/browser/navigation_controller.h" |
| 13 #include "content/public/browser/notification_service.h" | 13 #include "content/public/browser/notification_service.h" |
| 14 #include "content/public/browser/web_contents.h" | 14 #include "content/public/browser/web_contents.h" |
| 15 | 15 |
| 16 | 16 |
| 17 DEFINE_WEB_CONTENTS_USER_DATA_KEY(InfoBarService); | 17 DEFINE_WEB_CONTENTS_USER_DATA_KEY(InfoBarService); |
| 18 | 18 |
| 19 InfoBarDelegate* InfoBarService::AddInfoBar( | 19 InfoBar* InfoBarService::AddInfoBar(scoped_ptr<InfoBar> infobar) { |
| 20 scoped_ptr<InfoBarDelegate> infobar) { | |
| 21 DCHECK(infobar); | 20 DCHECK(infobar); |
| 22 if (!infobars_enabled_) | 21 if (!infobars_enabled_) |
| 23 return NULL; | 22 return NULL; |
| 24 | 23 |
| 25 for (InfoBars::const_iterator i(infobars_.begin()); i != infobars_.end(); | 24 for (InfoBars::const_iterator i(infobars_.begin()); i != infobars_.end(); |
| 26 ++i) { | 25 ++i) { |
| 27 if ((*i)->EqualsDelegate(infobar.get())) { | 26 if ((*i)->delegate()->EqualsDelegate(infobar->delegate())) { |
| 28 DCHECK_NE(*i, infobar.get()); | 27 DCHECK_NE((*i)->delegate(), infobar->delegate()); |
| 29 return NULL; | 28 return NULL; |
| 30 } | 29 } |
| 31 } | 30 } |
| 32 | 31 |
| 33 InfoBarDelegate* infobar_ptr = infobar.release(); | 32 InfoBar* infobar_ptr = infobar.release(); |
| 34 infobars_.push_back(infobar_ptr); | 33 infobars_.push_back(infobar_ptr); |
| 35 // TODO(pkasting): Remove InfoBarService arg from delegate constructors and | 34 infobar_ptr->SetOwner(this); |
| 36 // instead use a setter from here. | |
| 37 | 35 |
| 38 // Add ourselves as an observer for navigations the first time a delegate is | 36 // Add ourselves as an observer for navigations the first time a delegate is |
| 39 // added. We use this notification to expire InfoBars that need to expire on | 37 // added. We use this notification to expire InfoBars that need to expire on |
| 40 // page transitions. We must do this before calling Notify() below; | 38 // page transitions. We must do this before calling Notify() below; |
| 41 // otherwise, if that call causes a call to RemoveInfoBar(), we'll try to | 39 // otherwise, if that call causes a call to RemoveInfoBar(), we'll try to |
| 42 // unregister for the NAV_ENTRY_COMMITTED notification, which we won't have | 40 // unregister for the NAV_ENTRY_COMMITTED notification, which we won't have |
| 43 // yet registered here, and we'll fail the "was registered" DCHECK in | 41 // yet registered here, and we'll fail the "was registered" DCHECK in |
| 44 // NotificationRegistrar::Remove(). | 42 // NotificationRegistrar::Remove(). |
| 45 if (infobars_.size() == 1) { | 43 if (infobars_.size() == 1) { |
| 46 registrar_.Add( | 44 registrar_.Add( |
| 47 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | 45 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
| 48 content::Source<content::NavigationController>( | 46 content::Source<content::NavigationController>( |
| 49 &web_contents()->GetController())); | 47 &web_contents()->GetController())); |
| 50 } | 48 } |
| 51 | 49 |
| 52 content::NotificationService::current()->Notify( | 50 content::NotificationService::current()->Notify( |
| 53 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED, | 51 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED, |
| 54 content::Source<InfoBarService>(this), | 52 content::Source<InfoBarService>(this), |
| 55 content::Details<InfoBarAddedDetails>(infobar_ptr)); | 53 content::Details<InfoBar::AddedDetails>(infobar_ptr)); |
| 56 return infobar_ptr; | 54 return infobar_ptr; |
| 57 } | 55 } |
| 58 | 56 |
| 59 void InfoBarService::RemoveInfoBar(InfoBarDelegate* infobar) { | 57 void InfoBarService::RemoveInfoBar(InfoBar* infobar) { |
| 60 RemoveInfoBarInternal(infobar, true); | 58 RemoveInfoBarInternal(infobar, true); |
| 61 } | 59 } |
| 62 | 60 |
| 63 InfoBarDelegate* InfoBarService::ReplaceInfoBar( | 61 InfoBar* InfoBarService::ReplaceInfoBar(InfoBar* old_infobar, |
| 64 InfoBarDelegate* old_infobar, | 62 scoped_ptr<InfoBar> new_infobar) { |
| 65 scoped_ptr<InfoBarDelegate> new_infobar) { | |
| 66 DCHECK(old_infobar); | 63 DCHECK(old_infobar); |
| 67 if (!infobars_enabled_) | 64 if (!infobars_enabled_) |
| 68 return AddInfoBar(new_infobar.Pass()); // Deletes the delegate. | 65 return AddInfoBar(new_infobar.Pass()); // Deletes the infobar. |
| 69 DCHECK(new_infobar); | 66 DCHECK(new_infobar); |
| 70 | 67 |
| 71 InfoBars::iterator i(std::find(infobars_.begin(), infobars_.end(), | 68 InfoBars::iterator i(std::find(infobars_.begin(), infobars_.end(), |
| 72 old_infobar)); | 69 old_infobar)); |
| 73 DCHECK(i != infobars_.end()); | 70 DCHECK(i != infobars_.end()); |
| 74 | 71 |
| 75 InfoBarDelegate* new_infobar_ptr = new_infobar.release(); | 72 InfoBar* new_infobar_ptr = new_infobar.release(); |
| 76 i = infobars_.insert(i, new_infobar_ptr); | 73 i = infobars_.insert(i, new_infobar_ptr); |
| 77 InfoBarReplacedDetails replaced_details(old_infobar, new_infobar_ptr); | 74 new_infobar_ptr->SetOwner(this); |
| 75 InfoBar::ReplacedDetails replaced_details(old_infobar, new_infobar_ptr); |
| 78 | 76 |
| 79 // Remove the old infobar before notifying, so that if any observers call | 77 // Remove the old infobar before notifying, so that if any observers call back |
| 80 // back to AddInfoBar() or similar, we don't dupe-check against this infobar. | 78 // to AddInfoBar() or similar, we don't dupe-check against this infobar. |
| 81 infobars_.erase(++i); | 79 infobars_.erase(++i); |
| 82 | 80 |
| 83 old_infobar->clear_owner(); | |
| 84 content::NotificationService::current()->Notify( | 81 content::NotificationService::current()->Notify( |
| 85 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED, | 82 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED, |
| 86 content::Source<InfoBarService>(this), | 83 content::Source<InfoBarService>(this), |
| 87 content::Details<InfoBarReplacedDetails>(&replaced_details)); | 84 content::Details<InfoBar::ReplacedDetails>(&replaced_details)); |
| 85 |
| 86 old_infobar->CloseSoon(); |
| 88 return new_infobar_ptr; | 87 return new_infobar_ptr; |
| 89 } | 88 } |
| 90 | 89 |
| 91 InfoBarService::InfoBarService(content::WebContents* web_contents) | 90 InfoBarService::InfoBarService(content::WebContents* web_contents) |
| 92 : content::WebContentsObserver(web_contents), | 91 : content::WebContentsObserver(web_contents), |
| 93 infobars_enabled_(true) { | 92 infobars_enabled_(true) { |
| 94 DCHECK(web_contents); | 93 DCHECK(web_contents); |
| 95 registrar_.Add(this, | 94 registrar_.Add(this, |
| 96 content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | 95 content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
| 97 content::Source<content::WebContents>(web_contents)); | 96 content::Source<content::WebContents>(web_contents)); |
| 98 } | 97 } |
| 99 | 98 |
| 100 InfoBarService::~InfoBarService() { | 99 InfoBarService::~InfoBarService() { |
| 101 // Destroy all remaining InfoBars. It's important to not animate here so that | 100 // Destroy all remaining InfoBars. It's important to not animate here so that |
| 102 // we guarantee that we'll delete all delegates before we do anything else. | 101 // we guarantee that we'll delete all delegates before we do anything else. |
| 103 // | |
| 104 // TODO(pkasting): If there is no InfoBarContainer, this leaks all the | |
| 105 // InfoBarDelegates. This will be fixed once we call CloseSoon() directly on | |
| 106 // Infobars. | |
| 107 RemoveAllInfoBars(false); | 102 RemoveAllInfoBars(false); |
| 108 } | 103 } |
| 109 | 104 |
| 110 void InfoBarService::RenderProcessGone(base::TerminationStatus status) { | 105 void InfoBarService::RenderProcessGone(base::TerminationStatus status) { |
| 111 RemoveAllInfoBars(true); | 106 RemoveAllInfoBars(true); |
| 112 } | 107 } |
| 113 | 108 |
| 114 bool InfoBarService::OnMessageReceived(const IPC::Message& message) { | 109 bool InfoBarService::OnMessageReceived(const IPC::Message& message) { |
| 115 bool handled = true; | 110 bool handled = true; |
| 116 IPC_BEGIN_MESSAGE_MAP(InfoBarService, message) | 111 IPC_BEGIN_MESSAGE_MAP(InfoBarService, message) |
| (...skipping 13 matching lines...) Expand all Loading... |
| 130 DCHECK(&web_contents()->GetController() == | 125 DCHECK(&web_contents()->GetController() == |
| 131 content::Source<content::NavigationController>(source).ptr()); | 126 content::Source<content::NavigationController>(source).ptr()); |
| 132 | 127 |
| 133 content::LoadCommittedDetails& committed_details = | 128 content::LoadCommittedDetails& committed_details = |
| 134 *(content::Details<content::LoadCommittedDetails>(details).ptr()); | 129 *(content::Details<content::LoadCommittedDetails>(details).ptr()); |
| 135 | 130 |
| 136 // NOTE: It is not safe to change the following code to count upwards or | 131 // NOTE: It is not safe to change the following code to count upwards or |
| 137 // use iterators, as the RemoveInfoBar() call synchronously modifies our | 132 // use iterators, as the RemoveInfoBar() call synchronously modifies our |
| 138 // delegate list. | 133 // delegate list. |
| 139 for (size_t i = infobars_.size(); i > 0; --i) { | 134 for (size_t i = infobars_.size(); i > 0; --i) { |
| 140 InfoBarDelegate* infobar = infobars_[i - 1]; | 135 InfoBar* infobar = infobars_[i - 1]; |
| 141 if (infobar->ShouldExpire(committed_details)) | 136 if (infobar->delegate()->ShouldExpire(committed_details)) |
| 142 RemoveInfoBar(infobar); | 137 RemoveInfoBar(infobar); |
| 143 } | 138 } |
| 144 | 139 |
| 145 return; | 140 return; |
| 146 } | 141 } |
| 147 | 142 |
| 148 DCHECK_EQ(type, content::NOTIFICATION_WEB_CONTENTS_DESTROYED); | 143 DCHECK_EQ(type, content::NOTIFICATION_WEB_CONTENTS_DESTROYED); |
| 149 // The WebContents is going away; be aggressively paranoid and delete | 144 // The WebContents is going away; be aggressively paranoid and delete |
| 150 // ourselves lest other parts of the system attempt to add infobars or use | 145 // ourselves lest other parts of the system attempt to add infobars or use |
| 151 // us otherwise during the destruction. | 146 // us otherwise during the destruction. |
| 152 DCHECK_EQ(web_contents(), | 147 DCHECK_EQ(web_contents(), |
| 153 content::Source<content::WebContents>(source).ptr()); | 148 content::Source<content::WebContents>(source).ptr()); |
| 154 web_contents()->RemoveUserData(UserDataKey()); | 149 web_contents()->RemoveUserData(UserDataKey()); |
| 155 // That was the equivalent of "delete this". This object is now destroyed; | 150 // That was the equivalent of "delete this". This object is now destroyed; |
| 156 // returning from this function is the only safe thing to do. | 151 // returning from this function is the only safe thing to do. |
| 157 return; | 152 return; |
| 158 } | 153 } |
| 159 | 154 |
| 160 void InfoBarService::RemoveInfoBarInternal(InfoBarDelegate* infobar, | 155 void InfoBarService::RemoveInfoBarInternal(InfoBar* infobar, bool animate) { |
| 161 bool animate) { | |
| 162 DCHECK(infobar); | 156 DCHECK(infobar); |
| 163 if (!infobars_enabled_) { | 157 if (!infobars_enabled_) { |
| 164 DCHECK(infobars_.empty()); | 158 DCHECK(infobars_.empty()); |
| 165 return; | 159 return; |
| 166 } | 160 } |
| 167 | 161 |
| 168 InfoBars::iterator i(std::find(infobars_.begin(), infobars_.end(), infobar)); | 162 InfoBars::iterator i(std::find(infobars_.begin(), infobars_.end(), infobar)); |
| 169 DCHECK(i != infobars_.end()); | 163 DCHECK(i != infobars_.end()); |
| 170 | 164 |
| 171 infobar->clear_owner(); | |
| 172 // Remove the infobar before notifying, so that if any observers call back to | 165 // Remove the infobar before notifying, so that if any observers call back to |
| 173 // AddInfoBar() or similar, we don't dupe-check against this infobar. | 166 // AddInfoBar() or similar, we don't dupe-check against this infobar. |
| 174 infobars_.erase(i); | 167 infobars_.erase(i); |
| 175 | 168 |
| 176 // Remove ourselves as an observer if we are tracking no more InfoBars. We | 169 // Remove ourselves as an observer if we are tracking no more InfoBars. We |
| 177 // must do this before calling Notify() below; otherwise, if that call | 170 // must do this before calling Notify() below; otherwise, if that call |
| 178 // causes a call to AddInfoBar(), we'll try to register for the | 171 // causes a call to AddInfoBar(), we'll try to register for the |
| 179 // NAV_ENTRY_COMMITTED notification, which we won't have yet unregistered | 172 // NAV_ENTRY_COMMITTED notification, which we won't have yet unregistered |
| 180 // here, and we'll fail the "not already registered" DCHECK in | 173 // here, and we'll fail the "not already registered" DCHECK in |
| 181 // NotificationRegistrar::Add(). | 174 // NotificationRegistrar::Add(). |
| 182 if (infobars_.empty()) { | 175 if (infobars_.empty()) { |
| 183 registrar_.Remove( | 176 registrar_.Remove( |
| 184 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, | 177 this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
| 185 content::Source<content::NavigationController>( | 178 content::Source<content::NavigationController>( |
| 186 &web_contents()->GetController())); | 179 &web_contents()->GetController())); |
| 187 } | 180 } |
| 188 | 181 |
| 189 InfoBarRemovedDetails removed_details(infobar, animate); | 182 // This notification must happen before the call to CloseSoon() below, since |
| 183 // observers may want to access |infobar| and that call can delete it. |
| 184 InfoBar::RemovedDetails removed_details(infobar, animate); |
| 190 content::NotificationService::current()->Notify( | 185 content::NotificationService::current()->Notify( |
| 191 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, | 186 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, |
| 192 content::Source<InfoBarService>(this), | 187 content::Source<InfoBarService>(this), |
| 193 content::Details<InfoBarRemovedDetails>(&removed_details)); | 188 content::Details<InfoBar::RemovedDetails>(&removed_details)); |
| 189 |
| 190 infobar->CloseSoon(); |
| 194 } | 191 } |
| 195 | 192 |
| 196 void InfoBarService::RemoveAllInfoBars(bool animate) { | 193 void InfoBarService::RemoveAllInfoBars(bool animate) { |
| 197 while (!infobars_.empty()) | 194 while (!infobars_.empty()) |
| 198 RemoveInfoBarInternal(infobars_.back(), animate); | 195 RemoveInfoBarInternal(infobars_.back(), animate); |
| 199 } | 196 } |
| 200 | 197 |
| 201 void InfoBarService::OnDidBlockDisplayingInsecureContent() { | 198 void InfoBarService::OnDidBlockDisplayingInsecureContent() { |
| 202 InsecureContentInfoBarDelegate::Create( | 199 InsecureContentInfoBarDelegate::Create( |
| 203 this, InsecureContentInfoBarDelegate::DISPLAY); | 200 this, InsecureContentInfoBarDelegate::DISPLAY); |
| 204 } | 201 } |
| 205 | 202 |
| 206 void InfoBarService::OnDidBlockRunningInsecureContent() { | 203 void InfoBarService::OnDidBlockRunningInsecureContent() { |
| 207 InsecureContentInfoBarDelegate::Create(this, | 204 InsecureContentInfoBarDelegate::Create(this, |
| 208 InsecureContentInfoBarDelegate::RUN); | 205 InsecureContentInfoBarDelegate::RUN); |
| 209 } | 206 } |
| OLD | NEW |