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
3 // found in the LICENSE file.
5 #include "chrome/browser/infobars/infobar_service.h"
7 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/infobars/infobar.h"
9 #include "chrome/browser/infobars/infobar_delegate.h"
10 #include "chrome/browser/infobars/insecure_content_infobar_delegate.h"
11 #include "chrome/common/render_messages.h"
12 #include "content/public/browser/navigation_controller.h"
13 #include "content/public/browser/notification_service.h"
14 #include "content/public/browser/web_contents.h"
17 DEFINE_WEB_CONTENTS_USER_DATA_KEY(InfoBarService);
19 InfoBarDelegate* InfoBarService::AddInfoBar(
20 scoped_ptr<InfoBarDelegate> infobar) {
22 if (!infobars_enabled_)
25 for (InfoBars::const_iterator i(infobars_.begin()); i != infobars_.end();
27 if ((*i)->EqualsDelegate(infobar.get())) {
28 DCHECK_NE(*i, infobar.get());
33 InfoBarDelegate* infobar_ptr = infobar.release();
34 infobars_.push_back(infobar_ptr);
35 // TODO(pkasting): Remove InfoBarService arg from delegate constructors and
36 // instead use a setter from here.
38 content::NotificationService::current()->Notify(
39 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
40 content::Source<InfoBarService>(this),
41 content::Details<InfoBarAddedDetails>(infobar_ptr));
45 void InfoBarService::RemoveInfoBar(InfoBarDelegate* infobar) {
46 RemoveInfoBarInternal(infobar, true);
49 InfoBarDelegate* InfoBarService::ReplaceInfoBar(
50 InfoBarDelegate* old_infobar,
51 scoped_ptr<InfoBarDelegate> new_infobar) {
53 if (!infobars_enabled_)
54 return AddInfoBar(new_infobar.Pass()); // Deletes the delegate.
57 InfoBars::iterator i(std::find(infobars_.begin(), infobars_.end(),
59 DCHECK(i != infobars_.end());
61 InfoBarDelegate* new_infobar_ptr = new_infobar.release();
62 i = infobars_.insert(i, new_infobar_ptr);
63 InfoBarReplacedDetails replaced_details(old_infobar, new_infobar_ptr);
65 // Remove the old infobar before notifying, so that if any observers call
66 // back to AddInfoBar() or similar, we don't dupe-check against this infobar.
69 old_infobar->clear_owner();
70 content::NotificationService::current()->Notify(
71 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED,
72 content::Source<InfoBarService>(this),
73 content::Details<InfoBarReplacedDetails>(&replaced_details));
74 return new_infobar_ptr;
77 InfoBarService::InfoBarService(content::WebContents* web_contents)
78 : content::WebContentsObserver(web_contents),
79 infobars_enabled_(true) {
83 InfoBarService::~InfoBarService() {
84 // Destroy all remaining InfoBars. It's important to not animate here so that
85 // we guarantee that we'll delete all delegates before we do anything else.
87 // TODO(pkasting): If there is no InfoBarContainer, this leaks all the
88 // InfoBarDelegates. This will be fixed once we call CloseSoon() directly on
90 RemoveAllInfoBars(false);
93 void InfoBarService::RenderProcessGone(base::TerminationStatus status) {
94 RemoveAllInfoBars(true);
97 void InfoBarService::NavigationEntryCommitted(
98 const content::LoadCommittedDetails& load_details) {
99 // NOTE: It is not safe to change the following code to count upwards or
100 // use iterators, as the RemoveInfoBar() call synchronously modifies our
102 for (size_t i = infobars_.size(); i > 0; --i) {
103 InfoBarDelegate* infobar = infobars_[i - 1];
104 if (infobar->ShouldExpire(load_details))
105 RemoveInfoBar(infobar);
109 void InfoBarService::WebContentsDestroyed(content::WebContents* web_contents) {
110 // The WebContents is going away; be aggressively paranoid and delete
111 // ourselves lest other parts of the system attempt to add infobars or use
112 // us otherwise during the destruction.
113 web_contents->RemoveUserData(UserDataKey());
114 // That was the equivalent of "delete this". This object is now destroyed;
115 // returning from this function is the only safe thing to do.
118 bool InfoBarService::OnMessageReceived(const IPC::Message& message) {
120 IPC_BEGIN_MESSAGE_MAP(InfoBarService, message)
121 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DidBlockDisplayingInsecureContent,
122 OnDidBlockDisplayingInsecureContent)
123 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DidBlockRunningInsecureContent,
124 OnDidBlockRunningInsecureContent)
125 IPC_MESSAGE_UNHANDLED(handled = false)
126 IPC_END_MESSAGE_MAP()
130 void InfoBarService::RemoveInfoBarInternal(InfoBarDelegate* infobar,
133 if (!infobars_enabled_) {
134 DCHECK(infobars_.empty());
138 InfoBars::iterator i(std::find(infobars_.begin(), infobars_.end(), infobar));
139 DCHECK(i != infobars_.end());
141 infobar->clear_owner();
142 // Remove the infobar before notifying, so that if any observers call back to
143 // AddInfoBar() or similar, we don't dupe-check against this infobar.
146 InfoBarRemovedDetails removed_details(infobar, animate);
147 content::NotificationService::current()->Notify(
148 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
149 content::Source<InfoBarService>(this),
150 content::Details<InfoBarRemovedDetails>(&removed_details));
153 void InfoBarService::RemoveAllInfoBars(bool animate) {
154 while (!infobars_.empty())
155 RemoveInfoBarInternal(infobars_.back(), animate);
158 void InfoBarService::OnDidBlockDisplayingInsecureContent() {
159 InsecureContentInfoBarDelegate::Create(
160 this, InsecureContentInfoBarDelegate::DISPLAY);
163 void InfoBarService::OnDidBlockRunningInsecureContent() {
164 InsecureContentInfoBarDelegate::Create(this,
165 InsecureContentInfoBarDelegate::RUN);