OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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. |
| 4 |
| 5 #include "chrome/browser/infobars/infobar_tab_helper.h" |
| 6 |
| 7 #include "chrome/browser/tab_contents/infobar.h" |
| 8 #include "chrome/browser/tab_contents/infobar_delegate.h" |
| 9 #include "chrome/browser/tab_contents/insecure_content_infobar_delegate.h" |
| 10 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| 11 #include "chrome/common/chrome_notification_types.h" |
| 12 #include "chrome/common/render_messages.h" |
| 13 #include "content/common/notification_service.h" |
| 14 #include "content/browser/tab_contents/tab_contents.h" |
| 15 |
| 16 InfoBarTabHelper::InfoBarTabHelper(TabContentsWrapper* tab_contents) |
| 17 : TabContentsObserver(tab_contents->tab_contents()), |
| 18 infobars_enabled_(true), |
| 19 tab_contents_wrapper_(tab_contents) { |
| 20 DCHECK(tab_contents); |
| 21 } |
| 22 |
| 23 InfoBarTabHelper::~InfoBarTabHelper() { |
| 24 // Destroy all remaining InfoBars. It's important to not animate here so that |
| 25 // we guarantee that we'll delete all delegates before we do anything else. |
| 26 // |
| 27 // TODO(pkasting): If there is no InfoBarContainer, this leaks all the |
| 28 // InfoBarDelegates. This will be fixed once we call CloseSoon() directly on |
| 29 // Infobars. |
| 30 RemoveAllInfoBars(false); |
| 31 } |
| 32 |
| 33 void InfoBarTabHelper::AddInfoBar(InfoBarDelegate* delegate) { |
| 34 if (!infobars_enabled_) { |
| 35 delegate->InfoBarClosed(); |
| 36 return; |
| 37 } |
| 38 |
| 39 for (size_t i = 0; i < infobars_.size(); ++i) { |
| 40 if (GetInfoBarDelegateAt(i)->EqualsDelegate(delegate)) { |
| 41 delegate->InfoBarClosed(); |
| 42 return; |
| 43 } |
| 44 } |
| 45 |
| 46 infobars_.push_back(delegate); |
| 47 NotificationService::current()->Notify( |
| 48 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED, |
| 49 Source<TabContentsWrapper>(tab_contents_wrapper_), |
| 50 Details<InfoBarAddedDetails>(delegate)); |
| 51 |
| 52 // Add ourselves as an observer for navigations the first time a delegate is |
| 53 // added. We use this notification to expire InfoBars that need to expire on |
| 54 // page transitions. |
| 55 if (infobars_.size() == 1) { |
| 56 registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
| 57 Source<NavigationController>(&tab_contents()->controller())); |
| 58 } |
| 59 } |
| 60 |
| 61 void InfoBarTabHelper::RemoveInfoBar(InfoBarDelegate* delegate) { |
| 62 RemoveInfoBarInternal(delegate, true); |
| 63 } |
| 64 |
| 65 void InfoBarTabHelper::ReplaceInfoBar(InfoBarDelegate* old_delegate, |
| 66 InfoBarDelegate* new_delegate) { |
| 67 if (!infobars_enabled_) { |
| 68 AddInfoBar(new_delegate); // Deletes the delegate. |
| 69 return; |
| 70 } |
| 71 |
| 72 size_t i; |
| 73 for (i = 0; i < infobars_.size(); ++i) { |
| 74 if (GetInfoBarDelegateAt(i) == old_delegate) |
| 75 break; |
| 76 } |
| 77 DCHECK_LT(i, infobars_.size()); |
| 78 |
| 79 infobars_.insert(infobars_.begin() + i, new_delegate); |
| 80 |
| 81 old_delegate->clear_owner(); |
| 82 InfoBarReplacedDetails replaced_details(old_delegate, new_delegate); |
| 83 NotificationService::current()->Notify( |
| 84 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED, |
| 85 Source<TabContentsWrapper>(tab_contents_wrapper_), |
| 86 Details<InfoBarReplacedDetails>(&replaced_details)); |
| 87 |
| 88 infobars_.erase(infobars_.begin() + i + 1); |
| 89 } |
| 90 |
| 91 InfoBarDelegate* InfoBarTabHelper::GetInfoBarDelegateAt(size_t index) { |
| 92 return infobars_[index]; |
| 93 } |
| 94 |
| 95 void InfoBarTabHelper::RemoveInfoBarInternal(InfoBarDelegate* delegate, |
| 96 bool animate) { |
| 97 if (!infobars_enabled_) { |
| 98 DCHECK(infobars_.empty()); |
| 99 return; |
| 100 } |
| 101 |
| 102 size_t i; |
| 103 for (i = 0; i < infobars_.size(); ++i) { |
| 104 if (GetInfoBarDelegateAt(i) == delegate) |
| 105 break; |
| 106 } |
| 107 DCHECK_LT(i, infobars_.size()); |
| 108 InfoBarDelegate* infobar = infobars_[i]; |
| 109 |
| 110 infobar->clear_owner(); |
| 111 InfoBarRemovedDetails removed_details(infobar, animate); |
| 112 NotificationService::current()->Notify( |
| 113 chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, |
| 114 Source<TabContentsWrapper>(tab_contents_wrapper_), |
| 115 Details<InfoBarRemovedDetails>(&removed_details)); |
| 116 |
| 117 infobars_.erase(infobars_.begin() + i); |
| 118 // Remove ourselves as an observer if we are tracking no more InfoBars. |
| 119 if (infobars_.empty()) { |
| 120 registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
| 121 Source<NavigationController>(&tab_contents()->controller())); |
| 122 } |
| 123 } |
| 124 |
| 125 void InfoBarTabHelper::RemoveAllInfoBars(bool animate) { |
| 126 while (!infobars_.empty()) |
| 127 RemoveInfoBarInternal(GetInfoBarDelegateAt(infobar_count() - 1), animate); |
| 128 } |
| 129 |
| 130 void InfoBarTabHelper::OnDidBlockDisplayingInsecureContent() { |
| 131 // At most one infobar and do not supersede the stronger running content bar. |
| 132 for (size_t i = 0; i < infobars_.size(); ++i) { |
| 133 if (GetInfoBarDelegateAt(i)->AsInsecureContentInfoBarDelegate()) |
| 134 return; |
| 135 } |
| 136 AddInfoBar(new InsecureContentInfoBarDelegate(tab_contents_wrapper_, |
| 137 InsecureContentInfoBarDelegate::DISPLAY)); |
| 138 } |
| 139 |
| 140 void InfoBarTabHelper::OnDidBlockRunningInsecureContent() { |
| 141 // At most one infobar superseding any weaker displaying content bar. |
| 142 for (size_t i = 0; i < infobars_.size(); ++i) { |
| 143 InsecureContentInfoBarDelegate* delegate = |
| 144 GetInfoBarDelegateAt(i)->AsInsecureContentInfoBarDelegate(); |
| 145 if (delegate) { |
| 146 if (delegate->type() != InsecureContentInfoBarDelegate::RUN) { |
| 147 ReplaceInfoBar(delegate, new InsecureContentInfoBarDelegate( |
| 148 tab_contents_wrapper_, |
| 149 InsecureContentInfoBarDelegate::RUN)); |
| 150 } |
| 151 return; |
| 152 } |
| 153 } |
| 154 AddInfoBar(new InsecureContentInfoBarDelegate(tab_contents_wrapper_, |
| 155 InsecureContentInfoBarDelegate::RUN)); |
| 156 } |
| 157 |
| 158 void InfoBarTabHelper::RenderViewGone() { |
| 159 RemoveAllInfoBars(true); |
| 160 } |
| 161 |
| 162 bool InfoBarTabHelper::OnMessageReceived(const IPC::Message& message) { |
| 163 bool handled = true; |
| 164 IPC_BEGIN_MESSAGE_MAP(InfoBarTabHelper, message) |
| 165 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DidBlockDisplayingInsecureContent, |
| 166 OnDidBlockDisplayingInsecureContent) |
| 167 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DidBlockRunningInsecureContent, |
| 168 OnDidBlockRunningInsecureContent) |
| 169 IPC_MESSAGE_UNHANDLED(handled = false) |
| 170 IPC_END_MESSAGE_MAP() |
| 171 return handled; |
| 172 } |
| 173 |
| 174 void InfoBarTabHelper::Observe(int type, |
| 175 const NotificationSource& source, |
| 176 const NotificationDetails& details) { |
| 177 switch (type) { |
| 178 case content::NOTIFICATION_NAV_ENTRY_COMMITTED: { |
| 179 DCHECK(&tab_contents()->controller() == |
| 180 Source<NavigationController>(source).ptr()); |
| 181 |
| 182 content::LoadCommittedDetails& committed_details = |
| 183 *(Details<content::LoadCommittedDetails>(details).ptr()); |
| 184 |
| 185 // NOTE: It is not safe to change the following code to count upwards or |
| 186 // use iterators, as the RemoveInfoBar() call synchronously modifies our |
| 187 // delegate list. |
| 188 for (size_t i = infobars_.size(); i > 0; --i) { |
| 189 InfoBarDelegate* delegate = GetInfoBarDelegateAt(i - 1); |
| 190 if (delegate->ShouldExpire(committed_details)) |
| 191 RemoveInfoBar(delegate); |
| 192 } |
| 193 |
| 194 break; |
| 195 } |
| 196 default: |
| 197 NOTREACHED(); |
| 198 } |
| 199 } |
OLD | NEW |