blob: c928031f2f95ff0cc16fd0dcd12896e89c50f152 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 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.
initial.commit09911bf2008-07-26 23:55:294
[email protected]f3ec7742009-01-15 00:59:165#include "chrome/browser/tab_contents/tab_contents.h"
initial.commit09911bf2008-07-26 23:55:296
7#include "chrome/browser/cert_store.h"
initial.commit09911bf2008-07-26 23:55:298#include "chrome/browser/views/download_shelf_view.h"
9#include "chrome/browser/views/download_started_animation.h"
[email protected]d6598c052008-11-05 19:03:2510#include "chrome/browser/views/blocked_popup_container.h"
[email protected]f3ec7742009-01-15 00:59:1611#include "chrome/browser/tab_contents/infobar_delegate.h"
12#include "chrome/browser/tab_contents/navigation_entry.h"
13#include "chrome/browser/tab_contents/tab_contents_delegate.h"
14#include "chrome/browser/tab_contents/web_contents.h"
[email protected]a4feef82008-10-02 15:11:2215#include "chrome/common/l10n_util.h"
[email protected]bfd04a62009-02-01 18:16:5616#include "chrome/common/notification_service.h"
initial.commit09911bf2008-07-26 23:55:2917#include "chrome/common/pref_names.h"
[email protected]1eb89e82008-08-15 12:27:0318#include "chrome/common/pref_service.h"
initial.commit09911bf2008-07-26 23:55:2919#include "chrome/views/native_scroll_bar.h"
[email protected]1eb89e82008-08-15 12:27:0320#include "chrome/views/root_view.h"
initial.commit09911bf2008-07-26 23:55:2921#include "chrome/views/view.h"
22#include "chrome/views/view_storage.h"
[email protected]a0dde122008-11-21 20:51:2023#include "chrome/views/widget.h"
initial.commit09911bf2008-07-26 23:55:2924
25#include "generated_resources.h"
26
[email protected]d5f942ba2008-09-26 19:30:3427namespace {
28
29BOOL CALLBACK InvalidateWindow(HWND hwnd, LPARAM lparam) {
[email protected]4d0bd102008-10-16 00:26:3030 // Note: erase is required to properly paint some widgets borders. This can
31 // be seen with textfields.
[email protected]d5f942ba2008-09-26 19:30:3432 InvalidateRect(hwnd, NULL, TRUE);
33 return TRUE;
34}
35
36} // namespace
37
initial.commit09911bf2008-07-26 23:55:2938TabContents::TabContents(TabContentsType type)
[email protected]d5f942ba2008-09-26 19:30:3439 : type_(type),
initial.commit09911bf2008-07-26 23:55:2940 delegate_(NULL),
41 controller_(NULL),
[email protected]d5f942ba2008-09-26 19:30:3442 is_loading_(false),
43 is_active_(true),
initial.commit09911bf2008-07-26 23:55:2944 is_crashed_(false),
[email protected]d5f942ba2008-09-26 19:30:3445 waiting_for_response_(false),
[email protected]d5f942ba2008-09-26 19:30:3446 shelf_visible_(false),
47 max_page_id_(-1),
[email protected]d6598c052008-11-05 19:03:2548 blocked_popups_(NULL),
[email protected]2d843e62008-11-26 21:16:3549 capturing_contents_(false),
50 is_being_destroyed_(false) {
initial.commit09911bf2008-07-26 23:55:2951 last_focused_view_storage_id_ =
[email protected]c2dacc92008-10-16 23:51:3852 views::ViewStorage::GetSharedInstance()->CreateStorageID();
initial.commit09911bf2008-07-26 23:55:2953}
54
55TabContents::~TabContents() {
56 // Makes sure to remove any stored view we may still have in the ViewStorage.
57 //
58 // It is possible the view went away before us, so we only do this if the
59 // view is registered.
[email protected]c2dacc92008-10-16 23:51:3860 views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
initial.commit09911bf2008-07-26 23:55:2961 if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
62 view_storage->RemoveView(last_focused_view_storage_id_);
63}
64
[email protected]d5f942ba2008-09-26 19:30:3465// static
66void TabContents::RegisterUserPrefs(PrefService* prefs) {
67 prefs->RegisterBooleanPref(prefs::kBlockPopups, false);
initial.commit09911bf2008-07-26 23:55:2968}
69
initial.commit09911bf2008-07-26 23:55:2970void TabContents::CloseContents() {
71 // Destroy our NavigationController, which will Destroy all tabs it owns.
72 controller_->Destroy();
73 // Note that the controller may have deleted us at this point,
74 // so don't touch any member variables here.
75}
76
77void TabContents::Destroy() {
[email protected]9501428d2008-11-27 01:44:4478 DCHECK(!is_being_destroyed_);
[email protected]2d843e62008-11-26 21:16:3579 is_being_destroyed_ = true;
80
initial.commit09911bf2008-07-26 23:55:2981 // First cleanly close all child windows.
82 // TODO(mpcomplete): handle case if MaybeCloseChildWindows() already asked
83 // some of these to close. CloseWindows is async, so it might get called
84 // twice before it runs.
85 int size = static_cast<int>(child_windows_.size());
86 for (int i = size - 1; i >= 0; --i) {
87 ConstrainedWindow* window = child_windows_[i];
88 if (window)
89 window->CloseConstrainedWindow();
90 }
91
[email protected]b6187132009-01-21 23:20:4892 // Notify any lasting InfobarDelegates that have not yet been removed that
93 // whatever infobar they were handling in this TabContents has closed,
94 // because the TabContents is going away entirely.
95 for (int i = 0; i < infobar_delegate_count(); ++i) {
96 InfoBarDelegate* delegate = GetInfoBarDelegateAt(i);
97 delegate->InfoBarClosed();
98 }
99 infobar_delegates_.clear();
100
initial.commit09911bf2008-07-26 23:55:29101 // Notify any observer that have a reference on this tab contents.
[email protected]bfd04a62009-02-01 18:16:56102 NotificationService::current()->Notify(
103 NotificationType::TAB_CONTENTS_DESTROYED,
104 Source<TabContents>(this),
105 NotificationService::NoDetails());
initial.commit09911bf2008-07-26 23:55:29106
[email protected]92edc472009-02-10 20:32:06107 // If we still have a window handle, destroy it. GetNativeView can return
initial.commit09911bf2008-07-26 23:55:29108 // NULL if this contents was part of a window that closed.
[email protected]92edc472009-02-10 20:32:06109 if (GetNativeView())
110 ::DestroyWindow(GetNativeView());
initial.commit09911bf2008-07-26 23:55:29111
112 // Notify our NavigationController. Make sure we are deleted first, so
113 // that the controller is the last to die.
114 NavigationController* controller = controller_;
115 TabContentsType type = this->type();
116
117 delete this;
118
119 controller->TabContentsWasDestroyed(type);
120}
121
[email protected]d5f942ba2008-09-26 19:30:34122void TabContents::SetupController(Profile* profile) {
123 DCHECK(!controller_);
124 controller_ = new NavigationController(this, profile);
125}
126
127bool TabContents::SupportsURL(GURL* url) {
128 GURL u(*url);
129 if (TabContents::TypeForURL(&u) == type()) {
130 *url = u;
131 return true;
132 }
133 return false;
134}
135
136const GURL& TabContents::GetURL() const {
137 // We may not have a navigation entry yet
138 NavigationEntry* entry = controller_->GetActiveEntry();
139 return entry ? entry->display_url() : GURL::EmptyGURL();
140}
141
142const std::wstring& TabContents::GetTitle() const {
[email protected]cbab76d2008-10-13 22:42:47143 // We use the title for the last committed entry rather than a pending
144 // navigation entry. For example, when the user types in a URL, we want to
145 // keep the old page's title until the new load has committed and we get a new
146 // title.
147 // The exception is with transient pages, for which we really want to use
148 // their title, as they are not committed.
149 NavigationEntry* entry = controller_->GetTransientEntry();
[email protected]3d627bbc2008-10-23 20:49:07150 if (entry)
151 return entry->GetTitleForDisplay();
[email protected]cbab76d2008-10-13 22:42:47152
153 entry = controller_->GetLastCommittedEntry();
[email protected]d5f942ba2008-09-26 19:30:34154 if (entry)
[email protected]3d627bbc2008-10-23 20:49:07155 return entry->GetTitleForDisplay();
[email protected]d5f942ba2008-09-26 19:30:34156 else if (controller_->LoadingURLLazily())
157 return controller_->GetLazyTitle();
158 return EmptyWString();
159}
160
161int32 TabContents::GetMaxPageID() {
162 if (GetSiteInstance())
163 return GetSiteInstance()->max_page_id();
164 else
165 return max_page_id_;
166}
167
168void TabContents::UpdateMaxPageID(int32 page_id) {
169 // Ensure both the SiteInstance and RenderProcessHost update their max page
170 // IDs in sync. Only WebContents will also have site instances, except during
171 // testing.
172 if (GetSiteInstance())
173 GetSiteInstance()->UpdateMaxPageID(page_id);
174
175 if (AsWebContents())
176 AsWebContents()->process()->UpdateMaxPageID(page_id);
177 else
178 max_page_id_ = std::max(max_page_id_, page_id);
179}
180
181const std::wstring TabContents::GetDefaultTitle() const {
182 return l10n_util::GetString(IDS_DEFAULT_TAB_TITLE);
183}
184
185SkBitmap TabContents::GetFavIcon() const {
186 // Like GetTitle(), we also want to use the favicon for the last committed
187 // entry rather than a pending navigation entry.
[email protected]cbab76d2008-10-13 22:42:47188 NavigationEntry* entry = controller_->GetTransientEntry();
189 if (entry)
190 return entry->favicon().bitmap();
191
192 entry = controller_->GetLastCommittedEntry();
[email protected]d5f942ba2008-09-26 19:30:34193 if (entry)
194 return entry->favicon().bitmap();
195 else if (controller_->LoadingURLLazily())
196 return controller_->GetLazyFavIcon();
197 return SkBitmap();
198}
199
200SecurityStyle TabContents::GetSecurityStyle() const {
201 // We may not have a navigation entry yet.
202 NavigationEntry* entry = controller_->GetActiveEntry();
203 return entry ? entry->ssl().security_style() : SECURITY_STYLE_UNKNOWN;
204}
205
206bool TabContents::GetSSLEVText(std::wstring* ev_text,
207 std::wstring* ev_tooltip_text) const {
208 DCHECK(ev_text && ev_tooltip_text);
209 ev_text->clear();
210 ev_tooltip_text->clear();
211
212 NavigationEntry* entry = controller_->GetActiveEntry();
213 if (!entry ||
214 net::IsCertStatusError(entry->ssl().cert_status()) ||
215 ((entry->ssl().cert_status() & net::CERT_STATUS_IS_EV) == 0))
216 return false;
217
218 scoped_refptr<net::X509Certificate> cert;
219 CertStore::GetSharedInstance()->RetrieveCert(entry->ssl().cert_id(), &cert);
220 if (!cert.get()) {
221 NOTREACHED();
222 return false;
223 }
224
225 return SSLManager::GetEVCertNames(*cert, ev_text, ev_tooltip_text);
226}
227
228void TabContents::SetIsCrashed(bool state) {
229 if (state == is_crashed_)
230 return;
231
232 is_crashed_ = state;
233 if (delegate_)
234 delegate_->ContentsStateChanged(this);
235}
236
237void TabContents::NotifyNavigationStateChanged(unsigned changed_flags) {
238 if (delegate_)
239 delegate_->NavigationStateChanged(this, changed_flags);
240}
241
242void TabContents::DidBecomeSelected() {
243 if (controller_)
244 controller_->SetActive(true);
245
246 // Invalidate all descendants. (take care to exclude invalidating ourselves!)
[email protected]92edc472009-02-10 20:32:06247 EnumChildWindows(GetNativeView(), InvalidateWindow, 0);
[email protected]d5f942ba2008-09-26 19:30:34248}
249
250void TabContents::WasHidden() {
[email protected]bfd04a62009-02-01 18:16:56251 NotificationService::current()->Notify(
252 NotificationType::TAB_CONTENTS_HIDDEN,
253 Source<TabContents>(this),
254 NotificationService::NoDetails());
[email protected]d5f942ba2008-09-26 19:30:34255}
256
257void TabContents::Activate() {
258 if (delegate_)
259 delegate_->ActivateContents(this);
260}
261
[email protected]c0588052008-10-27 23:01:50262void TabContents::OpenURL(const GURL& url, const GURL& referrer,
[email protected]d5f942ba2008-09-26 19:30:34263 WindowOpenDisposition disposition,
264 PageTransition::Type transition) {
265 if (delegate_)
[email protected]c0588052008-10-27 23:01:50266 delegate_->OpenURLFromTab(this, url, referrer, disposition, transition);
[email protected]d5f942ba2008-09-26 19:30:34267}
268
269bool TabContents::NavigateToPendingEntry(bool reload) {
270 // Our benavior is just to report that the entry was committed.
271 controller()->GetPendingEntry()->set_title(GetDefaultTitle());
272 controller()->CommitPendingEntry();
273 return true;
274}
275
initial.commit09911bf2008-07-26 23:55:29276ConstrainedWindow* TabContents::CreateConstrainedDialog(
[email protected]c2dacc92008-10-16 23:51:38277 views::WindowDelegate* window_delegate,
278 views::View* contents_view) {
initial.commit09911bf2008-07-26 23:55:29279 ConstrainedWindow* window =
280 ConstrainedWindow::CreateConstrainedDialog(
281 this, gfx::Rect(), contents_view, window_delegate);
282 child_windows_.push_back(window);
283 return window;
284}
285
286void TabContents::AddNewContents(TabContents* new_contents,
287 WindowOpenDisposition disposition,
288 const gfx::Rect& initial_pos,
289 bool user_gesture) {
290 if (!delegate_)
291 return;
292
[email protected]3b0a45e82008-10-13 21:01:03293 if ((disposition == NEW_POPUP) && !user_gesture) {
294 // Unrequested popups from normal pages are constrained.
295 TabContents* popup_owner = this;
296 TabContents* our_owner = delegate_->GetConstrainingContents(this);
297 if (our_owner)
298 popup_owner = our_owner;
299 popup_owner->AddConstrainedPopup(new_contents, initial_pos);
initial.commit09911bf2008-07-26 23:55:29300 } else {
[email protected]0aa55312008-10-17 21:53:08301 new_contents->DisassociateFromPopupCount();
302
initial.commit09911bf2008-07-26 23:55:29303 delegate_->AddNewContents(this, new_contents, disposition, initial_pos,
304 user_gesture);
[email protected]634a6f92008-12-01 21:39:31305
306 PopupNotificationVisibilityChanged(ShowingBlockedPopupNotification());
initial.commit09911bf2008-07-26 23:55:29307 }
308}
309
310void TabContents::AddConstrainedPopup(TabContents* new_contents,
311 const gfx::Rect& initial_pos) {
[email protected]d6598c052008-11-05 19:03:25312 if (!blocked_popups_) {
313 CRect client_rect;
[email protected]92edc472009-02-10 20:32:06314 GetClientRect(GetNativeView(), &client_rect);
[email protected]d6598c052008-11-05 19:03:25315 gfx::Point anchor_position(
316 client_rect.Width() -
317 views::NativeScrollBar::GetVerticalScrollBarWidth(),
318 client_rect.Height());
initial.commit09911bf2008-07-26 23:55:29319
[email protected]d6598c052008-11-05 19:03:25320 blocked_popups_ = BlockedPopupContainer::Create(
321 this, profile(), anchor_position);
322 child_windows_.push_back(blocked_popups_);
323 }
324
325 blocked_popups_->AddTabContents(new_contents, initial_pos);
[email protected]634a6f92008-12-01 21:39:31326 PopupNotificationVisibilityChanged(ShowingBlockedPopupNotification());
initial.commit09911bf2008-07-26 23:55:29327}
328
initial.commit09911bf2008-07-26 23:55:29329void TabContents::CloseAllSuppressedPopups() {
[email protected]d6598c052008-11-05 19:03:25330 if (blocked_popups_)
331 blocked_popups_->CloseAllPopups();
initial.commit09911bf2008-07-26 23:55:29332}
333
initial.commit09911bf2008-07-26 23:55:29334void TabContents::Focus() {
[email protected]92edc472009-02-10 20:32:06335 HWND container_hwnd = GetNativeView();
[email protected]be3877f2009-01-14 15:51:10336 if (!container_hwnd)
337 return;
338
[email protected]c2dacc92008-10-16 23:51:38339 views::FocusManager* focus_manager =
[email protected]be3877f2009-01-14 15:51:10340 views::FocusManager::GetFocusManager(container_hwnd);
initial.commit09911bf2008-07-26 23:55:29341 DCHECK(focus_manager);
[email protected]be3877f2009-01-14 15:51:10342 views::View* v = focus_manager->GetViewForWindow(container_hwnd, true);
initial.commit09911bf2008-07-26 23:55:29343 DCHECK(v);
344 if (v)
345 v->RequestFocus();
346}
347
348void TabContents::StoreFocus() {
[email protected]c2dacc92008-10-16 23:51:38349 views::ViewStorage* view_storage =
350 views::ViewStorage::GetSharedInstance();
initial.commit09911bf2008-07-26 23:55:29351
352 if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
353 view_storage->RemoveView(last_focused_view_storage_id_);
354
[email protected]c2dacc92008-10-16 23:51:38355 views::FocusManager* focus_manager =
[email protected]92edc472009-02-10 20:32:06356 views::FocusManager::GetFocusManager(GetNativeView());
initial.commit09911bf2008-07-26 23:55:29357 if (focus_manager) {
358 // |focus_manager| can be NULL if the tab has been detached but still
359 // exists.
[email protected]c2dacc92008-10-16 23:51:38360 views::View* focused_view = focus_manager->GetFocusedView();
initial.commit09911bf2008-07-26 23:55:29361 if (focused_view)
362 view_storage->StoreView(last_focused_view_storage_id_, focused_view);
363
364 // If the focus was on the page, explicitly clear the focus so that we
365 // don't end up with the focused HWND not part of the window hierarchy.
[email protected]c80c5632008-10-10 20:34:35366 // TODO(brettw) this should move to the view somehow.
[email protected]92edc472009-02-10 20:32:06367 HWND container_hwnd = GetNativeView();
initial.commit09911bf2008-07-26 23:55:29368 if (container_hwnd) {
[email protected]c2dacc92008-10-16 23:51:38369 views::View* focused_view = focus_manager->GetFocusedView();
initial.commit09911bf2008-07-26 23:55:29370 if (focused_view) {
[email protected]a0dde122008-11-21 20:51:20371 HWND hwnd = focused_view->GetRootView()->GetWidget()->GetHWND();
initial.commit09911bf2008-07-26 23:55:29372 if (container_hwnd == hwnd || ::IsChild(container_hwnd, hwnd))
373 focus_manager->ClearFocus();
374 }
375 }
376 }
377}
378
379void TabContents::RestoreFocus() {
[email protected]c2dacc92008-10-16 23:51:38380 views::ViewStorage* view_storage =
381 views::ViewStorage::GetSharedInstance();
382 views::View* last_focused_view =
initial.commit09911bf2008-07-26 23:55:29383 view_storage->RetrieveView(last_focused_view_storage_id_);
384
385 if (!last_focused_view) {
386 SetInitialFocus();
387 } else {
[email protected]c2dacc92008-10-16 23:51:38388 views::FocusManager* focus_manager =
[email protected]92edc472009-02-10 20:32:06389 views::FocusManager::GetFocusManager(GetNativeView());
[email protected]6e2f2cec2008-09-23 22:59:06390
391 // If you hit this DCHECK, please report it to Jay (jcampan).
392 DCHECK(focus_manager != NULL) << "No focus manager when restoring focus.";
393
[email protected]830e2062009-02-13 18:27:38394 if (last_focused_view->IsFocusable() && focus_manager &&
395 focus_manager->ContainsView(last_focused_view)) {
initial.commit09911bf2008-07-26 23:55:29396 last_focused_view->RequestFocus();
397 } else {
[email protected]830e2062009-02-13 18:27:38398 // The focused view may not belong to the same window hierarchy (e.g.
399 // if the location bar was focused and the tab is dragged out), or it may
400 // no longer be focusable (e.g. if the location bar was focused and then
401 // we switched to fullscreen mode). In that case we default to the
402 // default focus.
initial.commit09911bf2008-07-26 23:55:29403 SetInitialFocus();
404 }
405 view_storage->RemoveView(last_focused_view_storage_id_);
406 }
407}
408
[email protected]d5f942ba2008-09-26 19:30:34409void TabContents::SetInitialFocus() {
[email protected]92edc472009-02-10 20:32:06410 ::SetFocus(GetNativeView());
initial.commit09911bf2008-07-26 23:55:29411}
412
[email protected]616ed5a2008-11-21 22:27:24413void TabContents::AddInfoBar(InfoBarDelegate* delegate) {
414 // Look through the existing InfoBarDelegates we have for a match. If we've
415 // already got one that matches, then we don't add the new one.
[email protected]f86a07022008-11-25 01:06:05416 for (int i = 0; i < infobar_delegate_count(); ++i) {
[email protected]616ed5a2008-11-21 22:27:24417 if (GetInfoBarDelegateAt(i)->EqualsDelegate(delegate))
418 return;
419 }
420
421 infobar_delegates_.push_back(delegate);
[email protected]bfd04a62009-02-01 18:16:56422 NotificationService::current()->Notify(
423 NotificationType::TAB_CONTENTS_INFOBAR_ADDED,
424 Source<TabContents>(this),
425 Details<InfoBarDelegate>(delegate));
[email protected]616ed5a2008-11-21 22:27:24426
427 // Add ourselves as an observer for navigations the first time a delegate is
428 // added. We use this notification to expire InfoBars that need to expire on
429 // page transitions.
430 if (infobar_delegates_.size() == 1) {
[email protected]6a02963e2009-01-06 16:58:03431 DCHECK(controller());
[email protected]bfd04a62009-02-01 18:16:56432 registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
[email protected]6a02963e2009-01-06 16:58:03433 Source<NavigationController>(controller()));
[email protected]616ed5a2008-11-21 22:27:24434 }
435}
436
437void TabContents::RemoveInfoBar(InfoBarDelegate* delegate) {
438 std::vector<InfoBarDelegate*>::iterator it =
439 find(infobar_delegates_.begin(), infobar_delegates_.end(), delegate);
440 if (it != infobar_delegates_.end()) {
441 InfoBarDelegate* delegate = *it;
[email protected]bfd04a62009-02-01 18:16:56442 NotificationService::current()->Notify(
443 NotificationType::TAB_CONTENTS_INFOBAR_REMOVED,
444 Source<TabContents>(this),
445 Details<InfoBarDelegate>(delegate));
[email protected]f86a07022008-11-25 01:06:05446 infobar_delegates_.erase(it);
[email protected]616ed5a2008-11-21 22:27:24447
[email protected]6a02963e2009-01-06 16:58:03448 // Remove ourselves as an observer if we are tracking no more InfoBars.
449 if (infobar_delegates_.empty()) {
[email protected]bfd04a62009-02-01 18:16:56450 registrar_.Remove(this, NotificationType::NAV_ENTRY_COMMITTED,
[email protected]6a02963e2009-01-06 16:58:03451 Source<NavigationController>(controller()));
452 }
[email protected]616ed5a2008-11-21 22:27:24453 }
454}
455
initial.commit09911bf2008-07-26 23:55:29456void TabContents::SetDownloadShelfVisible(bool visible) {
457 if (shelf_visible_ != visible) {
458 if (visible) {
459 // Invoke GetDownloadShelfView to force the shelf to be created.
460 GetDownloadShelfView();
461 }
462 shelf_visible_ = visible;
463
[email protected]019d83502008-07-30 22:44:50464 if (delegate_)
465 delegate_->ContentsStateChanged(this);
initial.commit09911bf2008-07-26 23:55:29466 }
[email protected]ce2390b682008-08-08 22:24:51467
468 // SetShelfVisible can force-close the shelf, so make sure we lay out
469 // everything correctly, as if the animation had finished. This doesn't
470 // matter for showing the shelf, as the show animation will do it.
471 ToolbarSizeChanged(false);
initial.commit09911bf2008-07-26 23:55:29472}
473
initial.commit09911bf2008-07-26 23:55:29474void TabContents::ToolbarSizeChanged(bool is_animating) {
475 TabContentsDelegate* d = delegate();
476 if (d)
477 d->ToolbarSizeChanged(this, is_animating);
478}
479
[email protected]d5f942ba2008-09-26 19:30:34480void TabContents::OnStartDownload(DownloadItem* download) {
481 DCHECK(download);
482 TabContents* tab_contents = this;
483
484 // Download in a constrained popup is shown in the tab that opened it.
485 TabContents* constraining_tab = delegate()->GetConstrainingContents(this);
486 if (constraining_tab)
487 tab_contents = constraining_tab;
488
489 // GetDownloadShelfView creates the download shelf if it was not yet created.
490 tab_contents->GetDownloadShelfView()->AddDownload(download);
491 tab_contents->SetDownloadShelfVisible(true);
492
493 // This animation will delete itself when it finishes, or if we become hidden
494 // or destroyed.
[email protected]92edc472009-02-10 20:32:06495 if (IsWindowVisible(GetNativeView())) { // For minimized windows, unit
496 // tests, etc.
[email protected]d5f942ba2008-09-26 19:30:34497 new DownloadStartedAnimation(tab_contents);
498 }
499}
500
initial.commit09911bf2008-07-26 23:55:29501DownloadShelfView* TabContents::GetDownloadShelfView() {
502 if (!download_shelf_view_.get()) {
503 download_shelf_view_.reset(new DownloadShelfView(this));
504 // The TabContents owns the download-shelf.
505 download_shelf_view_->SetParentOwned(false);
506 }
507 return download_shelf_view_.get();
508}
509
510void TabContents::MigrateShelfViewFrom(TabContents* tab_contents) {
511 download_shelf_view_.reset(tab_contents->GetDownloadShelfView());
512 download_shelf_view_->ChangeTabContents(tab_contents, this);
513 tab_contents->ReleaseDownloadShelfView();
514}
515
[email protected]d5f942ba2008-09-26 19:30:34516void TabContents::WillClose(ConstrainedWindow* window) {
517 ConstrainedWindowList::iterator it =
518 find(child_windows_.begin(), child_windows_.end(), window);
519 if (it != child_windows_.end())
520 child_windows_.erase(it);
521
[email protected]d6598c052008-11-05 19:03:25522 if (window == blocked_popups_)
523 blocked_popups_ = NULL;
524
[email protected]92edc472009-02-10 20:32:06525 if (::IsWindow(GetNativeView())) {
[email protected]d5f942ba2008-09-26 19:30:34526 CRect client_rect;
[email protected]92edc472009-02-10 20:32:06527 GetClientRect(GetNativeView(), &client_rect);
[email protected]d5f942ba2008-09-26 19:30:34528 RepositionSupressedPopupsToFit(
529 gfx::Size(client_rect.Width(), client_rect.Height()));
530 }
531}
532
[email protected]d5f942ba2008-09-26 19:30:34533void TabContents::DidMoveOrResize(ConstrainedWindow* window) {
[email protected]92edc472009-02-10 20:32:06534 UpdateWindow(GetNativeView());
[email protected]d5f942ba2008-09-26 19:30:34535}
536
[email protected]616ed5a2008-11-21 22:27:24537void TabContents::Observe(NotificationType type,
538 const NotificationSource& source,
539 const NotificationDetails& details) {
[email protected]bfd04a62009-02-01 18:16:56540 DCHECK(type == NotificationType::NAV_ENTRY_COMMITTED);
[email protected]616ed5a2008-11-21 22:27:24541 DCHECK(controller() == Source<NavigationController>(source).ptr());
542
543 NavigationController::LoadCommittedDetails& committed_details =
544 *(Details<NavigationController::LoadCommittedDetails>(details).ptr());
545 ExpireInfoBars(committed_details);
546}
547
initial.commit09911bf2008-07-26 23:55:29548// static
549void TabContents::MigrateShelfView(TabContents* from, TabContents* to) {
550 bool was_shelf_visible = from->IsDownloadShelfVisible();
551 if (was_shelf_visible)
552 to->MigrateShelfViewFrom(from);
553 to->SetDownloadShelfVisible(was_shelf_visible);
554}
555
[email protected]d5f942ba2008-09-26 19:30:34556void TabContents::SetIsLoading(bool is_loading,
557 LoadNotificationDetails* details) {
558 if (is_loading == is_loading_)
559 return;
560
561 is_loading_ = is_loading;
562 waiting_for_response_ = is_loading;
563
564 // Suppress notifications for this TabContents if we are not active.
565 if (!is_active_)
566 return;
567
568 if (delegate_)
569 delegate_->LoadingStateChanged(this);
570
[email protected]bfd04a62009-02-01 18:16:56571 NotificationType type = is_loading ? NotificationType::LOAD_START :
572 NotificationType::LOAD_STOP;
573 NotificationDetails det = details ?
574 Details<LoadNotificationDetails>(details) :
575 NotificationService::NoDetails();
576 NotificationService::current()->Notify(type,
577 Source<NavigationController>(this->controller()),
578 det);
initial.commit09911bf2008-07-26 23:55:29579}
license.botbf09a502008-08-24 00:55:55580
[email protected]9e0534b2008-10-21 15:03:01581// TODO(brettw) This should be on the WebContentsView.
[email protected]d5f942ba2008-09-26 19:30:34582void TabContents::RepositionSupressedPopupsToFit(const gfx::Size& new_size) {
583 // TODO(erg): There's no way to detect whether scroll bars are
584 // visible, so for beta, we're just going to assume that the
585 // vertical scroll bar is visible, and not care about covering up
586 // the horizontal scroll bar. Fixing this is half of
587 // http://b/1118139.
588 gfx::Point anchor_position(
589 new_size.width() -
[email protected]c2dacc92008-10-16 23:51:38590 views::NativeScrollBar::GetVerticalScrollBarWidth(),
[email protected]d5f942ba2008-09-26 19:30:34591 new_size.height());
[email protected]d6598c052008-11-05 19:03:25592
593 if (blocked_popups_)
594 blocked_popups_->RepositionConstrainedWindowTo(anchor_position);
[email protected]d5f942ba2008-09-26 19:30:34595}
596
597void TabContents::ReleaseDownloadShelfView() {
598 download_shelf_view_.release();
599}
[email protected]b9681312008-11-07 00:08:26600
601bool TabContents::ShowingBlockedPopupNotification() const {
602 return blocked_popups_ != NULL &&
603 blocked_popups_->GetTabContentsCount() != 0;
604}
[email protected]616ed5a2008-11-21 22:27:24605
606namespace {
607bool TransitionIsReload(PageTransition::Type transition) {
608 return PageTransition::StripQualifier(transition) == PageTransition::RELOAD;
609}
610}
611
612void TabContents::ExpireInfoBars(
613 const NavigationController::LoadCommittedDetails& details) {
614 // Only hide InfoBars when the user has done something that makes the main
615 // frame load. We don't want various automatic or subframe navigations making
616 // it disappear.
617 if (!details.is_user_initiated_main_frame_load())
618 return;
619
[email protected]f86a07022008-11-25 01:06:05620 for (int i = infobar_delegate_count() - 1; i >= 0; --i) {
[email protected]616ed5a2008-11-21 22:27:24621 InfoBarDelegate* delegate = GetInfoBarDelegateAt(i);
[email protected]f86a07022008-11-25 01:06:05622 if (delegate->ShouldExpire(details))
[email protected]616ed5a2008-11-21 22:27:24623 RemoveInfoBar(delegate);
[email protected]616ed5a2008-11-21 22:27:24624 }
625}