blob: fcd2b93f2b654ee9f908faaed62eb44d41620ee5 [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
5#include "chrome/browser/tab_contents.h"
6
7#include "chrome/browser/cert_store.h"
8#include "chrome/browser/navigation_entry.h"
9#include "chrome/browser/views/download_shelf_view.h"
10#include "chrome/browser/views/download_started_animation.h"
11#include "chrome/browser/web_contents.h"
12#include "chrome/browser/tab_contents_delegate.h"
[email protected]a4feef82008-10-02 15:11:2213#include "chrome/common/l10n_util.h"
initial.commit09911bf2008-07-26 23:55:2914#include "chrome/common/pref_names.h"
[email protected]1eb89e82008-08-15 12:27:0315#include "chrome/common/pref_service.h"
[email protected]4d0bd102008-10-16 00:26:3016#include "chrome/views/container.h"
initial.commit09911bf2008-07-26 23:55:2917#include "chrome/views/native_scroll_bar.h"
[email protected]1eb89e82008-08-15 12:27:0318#include "chrome/views/root_view.h"
initial.commit09911bf2008-07-26 23:55:2919#include "chrome/views/view.h"
20#include "chrome/views/view_storage.h"
21
22#include "generated_resources.h"
23
[email protected]92db5372008-09-26 23:40:4524static size_t kMaxNumberOfConstrainedPopups = 20;
25
[email protected]d5f942ba2008-09-26 19:30:3426namespace {
27
28BOOL CALLBACK InvalidateWindow(HWND hwnd, LPARAM lparam) {
[email protected]4d0bd102008-10-16 00:26:3029 // Note: erase is required to properly paint some widgets borders. This can
30 // be seen with textfields.
[email protected]d5f942ba2008-09-26 19:30:3431 InvalidateRect(hwnd, NULL, TRUE);
32 return TRUE;
33}
34
35} // namespace
36
initial.commit09911bf2008-07-26 23:55:2937TabContents::TabContents(TabContentsType type)
[email protected]d5f942ba2008-09-26 19:30:3438 : type_(type),
initial.commit09911bf2008-07-26 23:55:2939 delegate_(NULL),
40 controller_(NULL),
[email protected]d5f942ba2008-09-26 19:30:3441 is_loading_(false),
42 is_active_(true),
initial.commit09911bf2008-07-26 23:55:2943 is_crashed_(false),
[email protected]d5f942ba2008-09-26 19:30:3444 waiting_for_response_(false),
45 saved_location_bar_state_(NULL),
46 shelf_visible_(false),
47 max_page_id_(-1),
48 capturing_contents_(false) {
initial.commit09911bf2008-07-26 23:55:2949 last_focused_view_storage_id_ =
[email protected]c2dacc92008-10-16 23:51:3850 views::ViewStorage::GetSharedInstance()->CreateStorageID();
initial.commit09911bf2008-07-26 23:55:2951}
52
53TabContents::~TabContents() {
54 // Makes sure to remove any stored view we may still have in the ViewStorage.
55 //
56 // It is possible the view went away before us, so we only do this if the
57 // view is registered.
[email protected]c2dacc92008-10-16 23:51:3858 views::ViewStorage* view_storage = views::ViewStorage::GetSharedInstance();
initial.commit09911bf2008-07-26 23:55:2959 if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
60 view_storage->RemoveView(last_focused_view_storage_id_);
61}
62
[email protected]d5f942ba2008-09-26 19:30:3463// static
64void TabContents::RegisterUserPrefs(PrefService* prefs) {
65 prefs->RegisterBooleanPref(prefs::kBlockPopups, false);
initial.commit09911bf2008-07-26 23:55:2966}
67
initial.commit09911bf2008-07-26 23:55:2968
69void TabContents::CloseContents() {
70 // Destroy our NavigationController, which will Destroy all tabs it owns.
71 controller_->Destroy();
72 // Note that the controller may have deleted us at this point,
73 // so don't touch any member variables here.
74}
75
76void TabContents::Destroy() {
77 // First cleanly close all child windows.
78 // TODO(mpcomplete): handle case if MaybeCloseChildWindows() already asked
79 // some of these to close. CloseWindows is async, so it might get called
80 // twice before it runs.
81 int size = static_cast<int>(child_windows_.size());
82 for (int i = size - 1; i >= 0; --i) {
83 ConstrainedWindow* window = child_windows_[i];
84 if (window)
85 window->CloseConstrainedWindow();
86 }
87
88 // Notify any observer that have a reference on this tab contents.
89 NotificationService::current()->Notify(NOTIFY_TAB_CONTENTS_DESTROYED,
90 Source<TabContents>(this),
91 NotificationService::NoDetails());
92
93 // If we still have a window handle, destroy it. GetContainerHWND can return
94 // NULL if this contents was part of a window that closed.
95 if (GetContainerHWND())
96 ::DestroyWindow(GetContainerHWND());
97
98 // Notify our NavigationController. Make sure we are deleted first, so
99 // that the controller is the last to die.
100 NavigationController* controller = controller_;
101 TabContentsType type = this->type();
102
103 delete this;
104
105 controller->TabContentsWasDestroyed(type);
106}
107
[email protected]d5f942ba2008-09-26 19:30:34108void TabContents::SetupController(Profile* profile) {
109 DCHECK(!controller_);
110 controller_ = new NavigationController(this, profile);
111}
112
113bool TabContents::SupportsURL(GURL* url) {
114 GURL u(*url);
115 if (TabContents::TypeForURL(&u) == type()) {
116 *url = u;
117 return true;
118 }
119 return false;
120}
121
122const GURL& TabContents::GetURL() const {
123 // We may not have a navigation entry yet
124 NavigationEntry* entry = controller_->GetActiveEntry();
125 return entry ? entry->display_url() : GURL::EmptyGURL();
126}
127
128const std::wstring& TabContents::GetTitle() const {
[email protected]cbab76d2008-10-13 22:42:47129 // We use the title for the last committed entry rather than a pending
130 // navigation entry. For example, when the user types in a URL, we want to
131 // keep the old page's title until the new load has committed and we get a new
132 // title.
133 // The exception is with transient pages, for which we really want to use
134 // their title, as they are not committed.
135 NavigationEntry* entry = controller_->GetTransientEntry();
136 if (entry && !entry->title().empty())
137 return entry->title();
138
139 entry = controller_->GetLastCommittedEntry();
[email protected]d5f942ba2008-09-26 19:30:34140 if (entry)
141 return entry->title();
142 else if (controller_->LoadingURLLazily())
143 return controller_->GetLazyTitle();
144 return EmptyWString();
145}
146
147int32 TabContents::GetMaxPageID() {
148 if (GetSiteInstance())
149 return GetSiteInstance()->max_page_id();
150 else
151 return max_page_id_;
152}
153
154void TabContents::UpdateMaxPageID(int32 page_id) {
155 // Ensure both the SiteInstance and RenderProcessHost update their max page
156 // IDs in sync. Only WebContents will also have site instances, except during
157 // testing.
158 if (GetSiteInstance())
159 GetSiteInstance()->UpdateMaxPageID(page_id);
160
161 if (AsWebContents())
162 AsWebContents()->process()->UpdateMaxPageID(page_id);
163 else
164 max_page_id_ = std::max(max_page_id_, page_id);
165}
166
167const std::wstring TabContents::GetDefaultTitle() const {
168 return l10n_util::GetString(IDS_DEFAULT_TAB_TITLE);
169}
170
171SkBitmap TabContents::GetFavIcon() const {
172 // Like GetTitle(), we also want to use the favicon for the last committed
173 // entry rather than a pending navigation entry.
[email protected]cbab76d2008-10-13 22:42:47174 NavigationEntry* entry = controller_->GetTransientEntry();
175 if (entry)
176 return entry->favicon().bitmap();
177
178 entry = controller_->GetLastCommittedEntry();
[email protected]d5f942ba2008-09-26 19:30:34179 if (entry)
180 return entry->favicon().bitmap();
181 else if (controller_->LoadingURLLazily())
182 return controller_->GetLazyFavIcon();
183 return SkBitmap();
184}
185
186SecurityStyle TabContents::GetSecurityStyle() const {
187 // We may not have a navigation entry yet.
188 NavigationEntry* entry = controller_->GetActiveEntry();
189 return entry ? entry->ssl().security_style() : SECURITY_STYLE_UNKNOWN;
190}
191
192bool TabContents::GetSSLEVText(std::wstring* ev_text,
193 std::wstring* ev_tooltip_text) const {
194 DCHECK(ev_text && ev_tooltip_text);
195 ev_text->clear();
196 ev_tooltip_text->clear();
197
198 NavigationEntry* entry = controller_->GetActiveEntry();
199 if (!entry ||
200 net::IsCertStatusError(entry->ssl().cert_status()) ||
201 ((entry->ssl().cert_status() & net::CERT_STATUS_IS_EV) == 0))
202 return false;
203
204 scoped_refptr<net::X509Certificate> cert;
205 CertStore::GetSharedInstance()->RetrieveCert(entry->ssl().cert_id(), &cert);
206 if (!cert.get()) {
207 NOTREACHED();
208 return false;
209 }
210
211 return SSLManager::GetEVCertNames(*cert, ev_text, ev_tooltip_text);
212}
213
214void TabContents::SetIsCrashed(bool state) {
215 if (state == is_crashed_)
216 return;
217
218 is_crashed_ = state;
219 if (delegate_)
220 delegate_->ContentsStateChanged(this);
221}
222
223void TabContents::NotifyNavigationStateChanged(unsigned changed_flags) {
224 if (delegate_)
225 delegate_->NavigationStateChanged(this, changed_flags);
226}
227
228void TabContents::DidBecomeSelected() {
229 if (controller_)
230 controller_->SetActive(true);
231
232 // Invalidate all descendants. (take care to exclude invalidating ourselves!)
233 EnumChildWindows(GetContainerHWND(), InvalidateWindow, 0);
234}
235
236void TabContents::WasHidden() {
237 NotificationService::current()->Notify(NOTIFY_TAB_CONTENTS_HIDDEN,
238 Source<TabContents>(this),
239 NotificationService::NoDetails());
240}
241
242void TabContents::Activate() {
243 if (delegate_)
244 delegate_->ActivateContents(this);
245}
246
247void TabContents::OpenURL(const GURL& url,
248 WindowOpenDisposition disposition,
249 PageTransition::Type transition) {
250 if (delegate_)
251 delegate_->OpenURLFromTab(this, url, disposition, transition);
252}
253
254bool TabContents::NavigateToPendingEntry(bool reload) {
255 // Our benavior is just to report that the entry was committed.
256 controller()->GetPendingEntry()->set_title(GetDefaultTitle());
257 controller()->CommitPendingEntry();
258 return true;
259}
260
initial.commit09911bf2008-07-26 23:55:29261ConstrainedWindow* TabContents::CreateConstrainedDialog(
[email protected]c2dacc92008-10-16 23:51:38262 views::WindowDelegate* window_delegate,
263 views::View* contents_view) {
initial.commit09911bf2008-07-26 23:55:29264 ConstrainedWindow* window =
265 ConstrainedWindow::CreateConstrainedDialog(
266 this, gfx::Rect(), contents_view, window_delegate);
267 child_windows_.push_back(window);
268 return window;
269}
270
271void TabContents::AddNewContents(TabContents* new_contents,
272 WindowOpenDisposition disposition,
273 const gfx::Rect& initial_pos,
274 bool user_gesture) {
275 if (!delegate_)
276 return;
277
[email protected]3b0a45e82008-10-13 21:01:03278 if ((disposition == NEW_POPUP) && !user_gesture) {
279 // Unrequested popups from normal pages are constrained.
280 TabContents* popup_owner = this;
281 TabContents* our_owner = delegate_->GetConstrainingContents(this);
282 if (our_owner)
283 popup_owner = our_owner;
284 popup_owner->AddConstrainedPopup(new_contents, initial_pos);
initial.commit09911bf2008-07-26 23:55:29285 } else {
286 delegate_->AddNewContents(this, new_contents, disposition, initial_pos,
287 user_gesture);
288 }
289}
290
291void TabContents::AddConstrainedPopup(TabContents* new_contents,
292 const gfx::Rect& initial_pos) {
[email protected]92db5372008-09-26 23:40:45293 if (child_windows_.size() > kMaxNumberOfConstrainedPopups) {
294 new_contents->CloseContents();
295 return;
296 }
297
initial.commit09911bf2008-07-26 23:55:29298 ConstrainedWindow* window =
299 ConstrainedWindow::CreateConstrainedPopup(
300 this, initial_pos, new_contents);
301 child_windows_.push_back(window);
302
303 CRect client_rect;
304 GetClientRect(GetContainerHWND(), &client_rect);
305 gfx::Size new_size(client_rect.Width(), client_rect.Height());
306 RepositionSupressedPopupsToFit(new_size);
307}
308
initial.commit09911bf2008-07-26 23:55:29309void TabContents::CloseAllSuppressedPopups() {
310 // Close all auto positioned child windows to "clean up" the workspace.
311 int count = static_cast<int>(child_windows_.size());
312 for (int i = count - 1; i >= 0; --i) {
313 ConstrainedWindow* window = child_windows_.at(i);
314 if (window->IsSuppressedConstrainedWindow())
315 window->CloseConstrainedWindow();
316 }
317}
318
[email protected]d5f942ba2008-09-26 19:30:34319void TabContents::HideContents() {
320 // Hide the contents before adjusting its parent to avoid a full desktop
321 // flicker.
322 ShowWindow(GetContainerHWND(), SW_HIDE);
initial.commit09911bf2008-07-26 23:55:29323
[email protected]d5f942ba2008-09-26 19:30:34324 // Reset the parent to NULL to ensure hidden tabs don't receive messages.
325 SetParent(GetContainerHWND(), NULL);
initial.commit09911bf2008-07-26 23:55:29326
[email protected]d5f942ba2008-09-26 19:30:34327 // Remove any focus manager related information.
[email protected]c2dacc92008-10-16 23:51:38328 views::FocusManager::UninstallFocusSubclass(GetContainerHWND());
initial.commit09911bf2008-07-26 23:55:29329
[email protected]d5f942ba2008-09-26 19:30:34330 WasHidden();
initial.commit09911bf2008-07-26 23:55:29331}
332
initial.commit09911bf2008-07-26 23:55:29333void TabContents::Focus() {
[email protected]c2dacc92008-10-16 23:51:38334 views::FocusManager* focus_manager =
335 views::FocusManager::GetFocusManager(GetContainerHWND());
initial.commit09911bf2008-07-26 23:55:29336 DCHECK(focus_manager);
[email protected]c2dacc92008-10-16 23:51:38337 views::View* v =
initial.commit09911bf2008-07-26 23:55:29338 focus_manager->GetViewForWindow(GetContainerHWND(), true);
339 DCHECK(v);
340 if (v)
341 v->RequestFocus();
342}
343
344void TabContents::StoreFocus() {
[email protected]c2dacc92008-10-16 23:51:38345 views::ViewStorage* view_storage =
346 views::ViewStorage::GetSharedInstance();
initial.commit09911bf2008-07-26 23:55:29347
348 if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
349 view_storage->RemoveView(last_focused_view_storage_id_);
350
[email protected]c2dacc92008-10-16 23:51:38351 views::FocusManager* focus_manager =
352 views::FocusManager::GetFocusManager(GetContainerHWND());
initial.commit09911bf2008-07-26 23:55:29353 if (focus_manager) {
354 // |focus_manager| can be NULL if the tab has been detached but still
355 // exists.
[email protected]c2dacc92008-10-16 23:51:38356 views::View* focused_view = focus_manager->GetFocusedView();
initial.commit09911bf2008-07-26 23:55:29357 if (focused_view)
358 view_storage->StoreView(last_focused_view_storage_id_, focused_view);
359
360 // If the focus was on the page, explicitly clear the focus so that we
361 // don't end up with the focused HWND not part of the window hierarchy.
[email protected]c80c5632008-10-10 20:34:35362 // TODO(brettw) this should move to the view somehow.
initial.commit09911bf2008-07-26 23:55:29363 HWND container_hwnd = GetContainerHWND();
364 if (container_hwnd) {
[email protected]c2dacc92008-10-16 23:51:38365 views::View* focused_view = focus_manager->GetFocusedView();
initial.commit09911bf2008-07-26 23:55:29366 if (focused_view) {
[email protected]4d0bd102008-10-16 00:26:30367 HWND hwnd = focused_view->GetRootView()->GetContainer()->GetHWND();
initial.commit09911bf2008-07-26 23:55:29368 if (container_hwnd == hwnd || ::IsChild(container_hwnd, hwnd))
369 focus_manager->ClearFocus();
370 }
371 }
372 }
373}
374
375void TabContents::RestoreFocus() {
[email protected]c2dacc92008-10-16 23:51:38376 views::ViewStorage* view_storage =
377 views::ViewStorage::GetSharedInstance();
378 views::View* last_focused_view =
initial.commit09911bf2008-07-26 23:55:29379 view_storage->RetrieveView(last_focused_view_storage_id_);
380
381 if (!last_focused_view) {
382 SetInitialFocus();
383 } else {
[email protected]c2dacc92008-10-16 23:51:38384 views::FocusManager* focus_manager =
385 views::FocusManager::GetFocusManager(GetContainerHWND());
[email protected]6e2f2cec2008-09-23 22:59:06386
387 // If you hit this DCHECK, please report it to Jay (jcampan).
388 DCHECK(focus_manager != NULL) << "No focus manager when restoring focus.";
389
390 if (focus_manager && focus_manager->ContainsView(last_focused_view)) {
initial.commit09911bf2008-07-26 23:55:29391 last_focused_view->RequestFocus();
392 } else {
393 // The focused view may not belong to the same window hierarchy (for
394 // example if the location bar was focused and the tab is dragged out).
395 // In that case we default to the default focus.
396 SetInitialFocus();
397 }
398 view_storage->RemoveView(last_focused_view_storage_id_);
399 }
400}
401
[email protected]d5f942ba2008-09-26 19:30:34402void TabContents::SetInitialFocus() {
403 ::SetFocus(GetContainerHWND());
initial.commit09911bf2008-07-26 23:55:29404}
405
406void TabContents::SetDownloadShelfVisible(bool visible) {
407 if (shelf_visible_ != visible) {
408 if (visible) {
409 // Invoke GetDownloadShelfView to force the shelf to be created.
410 GetDownloadShelfView();
411 }
412 shelf_visible_ = visible;
413
[email protected]019d83502008-07-30 22:44:50414 if (delegate_)
415 delegate_->ContentsStateChanged(this);
initial.commit09911bf2008-07-26 23:55:29416 }
[email protected]ce2390b682008-08-08 22:24:51417
418 // SetShelfVisible can force-close the shelf, so make sure we lay out
419 // everything correctly, as if the animation had finished. This doesn't
420 // matter for showing the shelf, as the show animation will do it.
421 ToolbarSizeChanged(false);
initial.commit09911bf2008-07-26 23:55:29422}
423
initial.commit09911bf2008-07-26 23:55:29424void TabContents::ToolbarSizeChanged(bool is_animating) {
425 TabContentsDelegate* d = delegate();
426 if (d)
427 d->ToolbarSizeChanged(this, is_animating);
428}
429
[email protected]d5f942ba2008-09-26 19:30:34430void TabContents::OnStartDownload(DownloadItem* download) {
431 DCHECK(download);
432 TabContents* tab_contents = this;
433
434 // Download in a constrained popup is shown in the tab that opened it.
435 TabContents* constraining_tab = delegate()->GetConstrainingContents(this);
436 if (constraining_tab)
437 tab_contents = constraining_tab;
438
439 // GetDownloadShelfView creates the download shelf if it was not yet created.
440 tab_contents->GetDownloadShelfView()->AddDownload(download);
441 tab_contents->SetDownloadShelfVisible(true);
442
443 // This animation will delete itself when it finishes, or if we become hidden
444 // or destroyed.
445 if (IsWindowVisible(GetContainerHWND())) { // For minimized windows, unit
446 // tests, etc.
447 new DownloadStartedAnimation(tab_contents);
448 }
449}
450
initial.commit09911bf2008-07-26 23:55:29451DownloadShelfView* TabContents::GetDownloadShelfView() {
452 if (!download_shelf_view_.get()) {
453 download_shelf_view_.reset(new DownloadShelfView(this));
454 // The TabContents owns the download-shelf.
455 download_shelf_view_->SetParentOwned(false);
456 }
457 return download_shelf_view_.get();
458}
459
460void TabContents::MigrateShelfViewFrom(TabContents* tab_contents) {
461 download_shelf_view_.reset(tab_contents->GetDownloadShelfView());
462 download_shelf_view_->ChangeTabContents(tab_contents, this);
463 tab_contents->ReleaseDownloadShelfView();
464}
465
[email protected]d5f942ba2008-09-26 19:30:34466void TabContents::AddNewContents(ConstrainedWindow* window,
467 TabContents* new_contents,
468 WindowOpenDisposition disposition,
469 const gfx::Rect& initial_pos,
470 bool user_gesture) {
471 AddNewContents(new_contents, disposition, initial_pos, user_gesture);
472}
473
474void TabContents::OpenURL(ConstrainedWindow* window,
475 const GURL& url,
476 WindowOpenDisposition disposition,
477 PageTransition::Type transition) {
478 OpenURL(url, disposition, transition);
479}
480
481void TabContents::WillClose(ConstrainedWindow* window) {
482 ConstrainedWindowList::iterator it =
483 find(child_windows_.begin(), child_windows_.end(), window);
484 if (it != child_windows_.end())
485 child_windows_.erase(it);
486
487 if (::IsWindow(GetContainerHWND())) {
488 CRect client_rect;
489 GetClientRect(GetContainerHWND(), &client_rect);
490 RepositionSupressedPopupsToFit(
491 gfx::Size(client_rect.Width(), client_rect.Height()));
492 }
493}
494
495void TabContents::DetachContents(ConstrainedWindow* window,
496 TabContents* contents,
497 const gfx::Rect& contents_bounds,
498 const gfx::Point& mouse_pt,
499 int frame_component) {
500 WillClose(window);
501 if (delegate_) {
502 delegate_->StartDraggingDetachedContents(
503 this, contents, contents_bounds, mouse_pt, frame_component);
504 }
505}
506
507void TabContents::DidMoveOrResize(ConstrainedWindow* window) {
508 UpdateWindow(GetContainerHWND());
509}
510
initial.commit09911bf2008-07-26 23:55:29511// static
512void TabContents::MigrateShelfView(TabContents* from, TabContents* to) {
513 bool was_shelf_visible = from->IsDownloadShelfVisible();
514 if (was_shelf_visible)
515 to->MigrateShelfViewFrom(from);
516 to->SetDownloadShelfVisible(was_shelf_visible);
517}
518
[email protected]d5f942ba2008-09-26 19:30:34519void TabContents::SetIsLoading(bool is_loading,
520 LoadNotificationDetails* details) {
521 if (is_loading == is_loading_)
522 return;
523
524 is_loading_ = is_loading;
525 waiting_for_response_ = is_loading;
526
527 // Suppress notifications for this TabContents if we are not active.
528 if (!is_active_)
529 return;
530
531 if (delegate_)
532 delegate_->LoadingStateChanged(this);
533
534 NotificationService::current()->
535 Notify((is_loading ? NOTIFY_LOAD_START : NOTIFY_LOAD_STOP),
536 Source<NavigationController>(this->controller()),
537 details ? Details<LoadNotificationDetails>(details) :
538 NotificationService::NoDetails());
initial.commit09911bf2008-07-26 23:55:29539}
license.botbf09a502008-08-24 00:55:55540
[email protected]d5f942ba2008-09-26 19:30:34541void TabContents::RepositionSupressedPopupsToFit(const gfx::Size& new_size) {
542 // TODO(erg): There's no way to detect whether scroll bars are
543 // visible, so for beta, we're just going to assume that the
544 // vertical scroll bar is visible, and not care about covering up
545 // the horizontal scroll bar. Fixing this is half of
546 // http://b/1118139.
547 gfx::Point anchor_position(
548 new_size.width() -
[email protected]c2dacc92008-10-16 23:51:38549 views::NativeScrollBar::GetVerticalScrollBarWidth(),
[email protected]d5f942ba2008-09-26 19:30:34550 new_size.height());
551 int window_count = static_cast<int>(child_windows_.size());
552 for (int i = window_count - 1; i >= 0; --i) {
553 ConstrainedWindow* window = child_windows_.at(i);
554 if (window->IsSuppressedConstrainedWindow())
555 window->RepositionConstrainedWindowTo(anchor_position);
556 }
557}
558
559void TabContents::ReleaseDownloadShelfView() {
560 download_shelf_view_.release();
561}