Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: content/browser/web_contents/web_contents_impl.cc

Issue 23841002: Create a new RenderFrameHost per child frame when --site-per-process is enabled. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase and add some comments. Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "content/browser/web_contents/web_contents_impl.h" 5 #include "content/browser/web_contents/web_contents_impl.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/debug/trace_event.h" 10 #include "base/debug/trace_event.h"
(...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after
367 is_showing_before_unload_dialog_(false), 367 is_showing_before_unload_dialog_(false),
368 closed_by_user_gesture_(false), 368 closed_by_user_gesture_(false),
369 minimum_zoom_percent_(static_cast<int>(kMinimumZoomFactor * 100)), 369 minimum_zoom_percent_(static_cast<int>(kMinimumZoomFactor * 100)),
370 maximum_zoom_percent_(static_cast<int>(kMaximumZoomFactor * 100)), 370 maximum_zoom_percent_(static_cast<int>(kMaximumZoomFactor * 100)),
371 temporary_zoom_settings_(false), 371 temporary_zoom_settings_(false),
372 color_chooser_identifier_(0), 372 color_chooser_identifier_(0),
373 message_source_(NULL), 373 message_source_(NULL),
374 fullscreen_widget_routing_id_(MSG_ROUTING_NONE) { 374 fullscreen_widget_routing_id_(MSG_ROUTING_NONE) {
375 for (size_t i = 0; i < g_created_callbacks.Get().size(); i++) 375 for (size_t i = 0; i < g_created_callbacks.Get().size(); i++)
376 g_created_callbacks.Get().at(i).Run(this); 376 g_created_callbacks.Get().at(i).Run(this);
377 frame_tree_.SetFrameRemoveListener(
378 base::Bind(&WebContentsImpl::OnFrameRemoved,
379 base::Unretained(this)));
380
377 } 381 }
378 382
379 WebContentsImpl::~WebContentsImpl() { 383 WebContentsImpl::~WebContentsImpl() {
380 is_being_destroyed_ = true; 384 is_being_destroyed_ = true;
381 385
382 ClearAllPowerSaveBlockers(); 386 ClearAllPowerSaveBlockers();
383 387
384 for (std::set<RenderWidgetHostImpl*>::iterator iter = 388 for (std::set<RenderWidgetHostImpl*>::iterator iter =
385 created_widgets_.begin(); iter != created_widgets_.end(); ++iter) { 389 created_widgets_.begin(); iter != created_widgets_.end(); ++iter) {
386 (*iter)->DetachDelegate(); 390 (*iter)->DetachDelegate();
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after
711 IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginHostMsg_Attach, 715 IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginHostMsg_Attach,
712 OnBrowserPluginMessage(message)) 716 OnBrowserPluginMessage(message))
713 IPC_MESSAGE_HANDLER(ImageHostMsg_DidDownloadImage, OnDidDownloadImage) 717 IPC_MESSAGE_HANDLER(ImageHostMsg_DidDownloadImage, OnDidDownloadImage)
714 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFaviconURL, OnUpdateFaviconURL) 718 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFaviconURL, OnUpdateFaviconURL)
715 #if defined(OS_ANDROID) 719 #if defined(OS_ANDROID)
716 IPC_MESSAGE_HANDLER(ViewHostMsg_FindMatchRects_Reply, 720 IPC_MESSAGE_HANDLER(ViewHostMsg_FindMatchRects_Reply,
717 OnFindMatchRectsReply) 721 OnFindMatchRectsReply)
718 IPC_MESSAGE_HANDLER(ViewHostMsg_OpenDateTimeDialog, 722 IPC_MESSAGE_HANDLER(ViewHostMsg_OpenDateTimeDialog,
719 OnOpenDateTimeDialog) 723 OnOpenDateTimeDialog)
720 #endif 724 #endif
721 IPC_MESSAGE_HANDLER(ViewHostMsg_FrameAttached, OnFrameAttached)
722 IPC_MESSAGE_HANDLER(ViewHostMsg_FrameDetached, OnFrameDetached)
723 IPC_MESSAGE_HANDLER(ViewHostMsg_MediaNotification, OnMediaNotification) 725 IPC_MESSAGE_HANDLER(ViewHostMsg_MediaNotification, OnMediaNotification)
724 IPC_MESSAGE_UNHANDLED(handled = false) 726 IPC_MESSAGE_UNHANDLED(handled = false)
725 IPC_END_MESSAGE_MAP_EX() 727 IPC_END_MESSAGE_MAP_EX()
726 message_source_ = NULL; 728 message_source_ = NULL;
727 729
728 if (!message_is_ok) { 730 if (!message_is_ok) {
729 RecordAction(UserMetricsAction("BadMessageTerminate_RVD")); 731 RecordAction(UserMetricsAction("BadMessageTerminate_RVD"));
730 GetRenderProcessHost()->ReceivedBadMessage(); 732 GetRenderProcessHost()->ReceivedBadMessage();
731 } 733 }
732 734
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after
1006 1008
1007 uint64 WebContentsImpl::GetUploadSize() const { 1009 uint64 WebContentsImpl::GetUploadSize() const {
1008 return upload_size_; 1010 return upload_size_;
1009 } 1011 }
1010 1012
1011 uint64 WebContentsImpl::GetUploadPosition() const { 1013 uint64 WebContentsImpl::GetUploadPosition() const {
1012 return upload_position_; 1014 return upload_position_;
1013 } 1015 }
1014 1016
1015 std::set<GURL> WebContentsImpl::GetSitesInTab() const { 1017 std::set<GURL> WebContentsImpl::GetSitesInTab() const {
1016 BrowserContext* browser_context = GetBrowserContext();
1017 std::set<GURL> sites; 1018 std::set<GURL> sites;
1018 if (!frame_tree_root_.get()) 1019 // TODO(ajwong): Why don't people just dump these at the top of most .cc
1019 return sites; 1020 // files??
1021 using base::Bind;
1022 using base::Unretained;
1020 1023
1021 // Iterates over the FrameTreeNodes to find each unique site URL that is 1024 // TODO(ajwong): Using a local class like this almost certainly won't compile
1022 // currently committed. 1025 // on MSVC or some bot. Hoist it up to file-local function.
1023 FrameTreeNode* node = NULL; 1026 struct Foo {
1024 std::queue<FrameTreeNode*> queue; 1027 static bool Do(BrowserContext* context, std::set<GURL>* s,
1025 queue.push(frame_tree_root_.get()); 1028 FrameTreeNode* node) {
1026 1029 s->insert(SiteInstance::GetSiteForURL(context, node->current_url()));
1027 while (!queue.empty()) { 1030 return true;
1028 node = queue.front(); 1031 }
1029 queue.pop(); 1032 };
1030 sites.insert(SiteInstance::GetSiteForURL(browser_context, 1033 frame_tree_.ForEach(Bind(&Foo::Do, Unretained(GetBrowserContext()),
1031 node->current_url())); 1034 Unretained(&sites)));
1032
1033 for (size_t i = 0; i < node->child_count(); ++i)
1034 queue.push(node->child_at(i));
1035 }
1036 1035
1037 return sites; 1036 return sites;
1038 } 1037 }
1039 1038
1040 const std::string& WebContentsImpl::GetEncoding() const { 1039 const std::string& WebContentsImpl::GetEncoding() const {
1041 return encoding_; 1040 return encoding_;
1042 } 1041 }
1043 1042
1044 bool WebContentsImpl::DisplayedInsecureContent() const { 1043 bool WebContentsImpl::DisplayedInsecureContent() const {
1045 return displayed_insecure_content_; 1044 return displayed_insecure_content_;
(...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after
1699 delegate_->RequestMediaAccessPermission(this, request, callback); 1698 delegate_->RequestMediaAccessPermission(this, request, callback);
1700 else 1699 else
1701 callback.Run(MediaStreamDevices(), scoped_ptr<MediaStreamUI>()); 1700 callback.Run(MediaStreamDevices(), scoped_ptr<MediaStreamUI>());
1702 } 1701 }
1703 1702
1704 SessionStorageNamespace* WebContentsImpl::GetSessionStorageNamespace( 1703 SessionStorageNamespace* WebContentsImpl::GetSessionStorageNamespace(
1705 SiteInstance* instance) { 1704 SiteInstance* instance) {
1706 return controller_.GetSessionStorageNamespace(instance); 1705 return controller_.GetSessionStorageNamespace(instance);
1707 } 1706 }
1708 1707
1708 FrameTree* WebContentsImpl::GetFrameTree() {
1709 return &frame_tree_;
1710 }
1711
1709 void WebContentsImpl::DidSendScreenRects(RenderWidgetHostImpl* rwh) { 1712 void WebContentsImpl::DidSendScreenRects(RenderWidgetHostImpl* rwh) {
1710 if (browser_plugin_embedder_) 1713 if (browser_plugin_embedder_)
1711 browser_plugin_embedder_->DidSendScreenRects(); 1714 browser_plugin_embedder_->DidSendScreenRects();
1712 } 1715 }
1713 1716
1714 void WebContentsImpl::UpdatePreferredSize(const gfx::Size& pref_size) { 1717 void WebContentsImpl::UpdatePreferredSize(const gfx::Size& pref_size) {
1715 preferred_size_ = pref_size; 1718 preferred_size_ = pref_size;
1716 if (delegate_) 1719 if (delegate_)
1717 delegate_->UpdatePreferredSize(this, pref_size); 1720 delegate_->UpdatePreferredSize(this, pref_size);
1718 } 1721 }
(...skipping 874 matching lines...) Expand 10 before | Expand all | Expand 10 after
2593 image_download_map_.erase(id); 2596 image_download_map_.erase(id);
2594 } 2597 }
2595 2598
2596 void WebContentsImpl::OnUpdateFaviconURL( 2599 void WebContentsImpl::OnUpdateFaviconURL(
2597 int32 page_id, 2600 int32 page_id,
2598 const std::vector<FaviconURL>& candidates) { 2601 const std::vector<FaviconURL>& candidates) {
2599 FOR_EACH_OBSERVER(WebContentsObserver, observers_, 2602 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2600 DidUpdateFaviconURL(page_id, candidates)); 2603 DidUpdateFaviconURL(page_id, candidates));
2601 } 2604 }
2602 2605
2603 FrameTreeNode* WebContentsImpl::FindFrameTreeNodeByID(int64 frame_id) {
2604 // TODO(nasko): Remove this check once we move to creating the root node
2605 // through RenderFrameHost creation.
2606 if (!frame_tree_root_.get())
2607 return NULL;
2608
2609 FrameTreeNode* node = NULL;
2610 std::queue<FrameTreeNode*> queue;
2611 queue.push(frame_tree_root_.get());
2612
2613 while (!queue.empty()) {
2614 node = queue.front();
2615 queue.pop();
2616 if (node->frame_id() == frame_id)
2617 return node;
2618
2619 for (size_t i = 0; i < node->child_count(); ++i)
2620 queue.push(node->child_at(i));
2621 }
2622
2623 return NULL;
2624 }
2625
2626 void WebContentsImpl::OnFrameAttached(
2627 int64 parent_frame_id,
2628 int64 frame_id,
2629 const std::string& frame_name) {
2630 FrameTreeNode* parent = FindFrameTreeNodeByID(parent_frame_id);
2631 if (!parent)
2632 return;
2633
2634 FrameTreeNode* node = new FrameTreeNode(frame_id, frame_name);
2635 parent->AddChild(node);
2636 }
2637
2638 void WebContentsImpl::OnFrameDetached(int64 parent_frame_id, int64 frame_id) {
2639 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2640 FrameDetached(message_source_, frame_id));
2641
2642 FrameTreeNode* parent = FindFrameTreeNodeByID(parent_frame_id);
2643 if (!parent)
2644 return;
2645
2646 parent->RemoveChild(frame_id);
2647 }
2648
2649 void WebContentsImpl::OnMediaNotification(int64 player_cookie, 2606 void WebContentsImpl::OnMediaNotification(int64 player_cookie,
2650 bool has_video, 2607 bool has_video,
2651 bool has_audio, 2608 bool has_audio,
2652 bool is_playing) { 2609 bool is_playing) {
2653 // Chrome OS does its own detection of audio and video. 2610 // Chrome OS does its own detection of audio and video.
2654 #if !defined(OS_CHROMEOS) 2611 #if !defined(OS_CHROMEOS)
2655 if (is_playing) { 2612 if (is_playing) {
2656 scoped_ptr<PowerSaveBlocker> blocker; 2613 scoped_ptr<PowerSaveBlocker> blocker;
2657 if (has_video) { 2614 if (has_video) {
2658 blocker = PowerSaveBlocker::Create( 2615 blocker = PowerSaveBlocker::Create(
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after
3008 // TODO(avi): Remove. http://crbug.com/170921 2965 // TODO(avi): Remove. http://crbug.com/170921
3009 NotificationService::current()->Notify( 2966 NotificationService::current()->Notify(
3010 NOTIFICATION_RESOURCE_RECEIVED_REDIRECT, 2967 NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
3011 Source<WebContents>(this), 2968 Source<WebContents>(this),
3012 Details<const ResourceRedirectDetails>(&details)); 2969 Details<const ResourceRedirectDetails>(&details));
3013 } 2970 }
3014 2971
3015 void WebContentsImpl::DidNavigate( 2972 void WebContentsImpl::DidNavigate(
3016 RenderViewHost* rvh, 2973 RenderViewHost* rvh,
3017 const ViewHostMsg_FrameNavigate_Params& params) { 2974 const ViewHostMsg_FrameNavigate_Params& params) {
3018 // If we don't have a frame tree root yet, this is the first navigation in 2975 if (frame_tree_.IsFirstNavigation()) {
3019 // using the current RenderViewHost, so we need to create it with the proper 2976 // First navigation should be a main frame navigation.
3020 // frame id.
3021 if (!frame_tree_root_.get()) {
3022 DCHECK(PageTransitionIsMainFrame(params.transition)); 2977 DCHECK(PageTransitionIsMainFrame(params.transition));
3023 frame_tree_root_.reset(new FrameTreeNode(params.frame_id, std::string())); 2978 frame_tree_.OnFirstNavigation(params.frame_id);
3024 } 2979 }
3025 2980
3026 if (PageTransitionIsMainFrame(params.transition)) { 2981 if (PageTransitionIsMainFrame(params.transition)) {
3027 // When overscroll navigation gesture is enabled, a screenshot of the page 2982 // When overscroll navigation gesture is enabled, a screenshot of the page
3028 // in its current state is taken so that it can be used during the 2983 // in its current state is taken so that it can be used during the
3029 // nav-gesture. It is necessary to take the screenshot here, before calling 2984 // nav-gesture. It is necessary to take the screenshot here, before calling
3030 // RenderViewHostManager::DidNavigateMainFrame, because that can change 2985 // RenderViewHostManager::DidNavigateMainFrame, because that can change
3031 // WebContents::GetRenderViewHost to return the new host, instead of the one 2986 // WebContents::GetRenderViewHost to return the new host, instead of the one
3032 // that may have just been swapped out. 2987 // that may have just been swapped out.
3033 if (delegate_ && delegate_->CanOverscrollContent()) 2988 if (delegate_ && delegate_->CanOverscrollContent())
3034 controller_.TakeScreenshot(); 2989 controller_.TakeScreenshot();
3035 2990
3036 render_manager_.DidNavigateMainFrame(rvh); 2991 render_manager_.DidNavigateMainFrame(rvh);
3037 } 2992 }
3038 2993
3039 // We expect to have a valid frame tree root node at all times when
3040 // navigating.
3041 DCHECK(frame_tree_root_.get());
3042
3043 // Update the site of the SiteInstance if it doesn't have one yet, unless 2994 // Update the site of the SiteInstance if it doesn't have one yet, unless
3044 // assigning a site is not necessary for this URL. In that case, the 2995 // assigning a site is not necessary for this URL. In that case, the
3045 // SiteInstance can still be considered unused until a navigation to a real 2996 // SiteInstance can still be considered unused until a navigation to a real
3046 // page. 2997 // page.
3047 if (!static_cast<SiteInstanceImpl*>(GetSiteInstance())->HasSite() && 2998 if (!static_cast<SiteInstanceImpl*>(GetSiteInstance())->HasSite() &&
3048 ShouldAssignSiteForURL(params.url)) { 2999 ShouldAssignSiteForURL(params.url)) {
3049 static_cast<SiteInstanceImpl*>(GetSiteInstance())->SetSite(params.url); 3000 static_cast<SiteInstanceImpl*>(GetSiteInstance())->SetSite(params.url);
3050 } 3001 }
3051 3002
3052 // Need to update MIME type here because it's referred to in 3003 // Need to update MIME type here because it's referred to in
3053 // UpdateNavigationCommands() called by RendererDidNavigate() to 3004 // UpdateNavigationCommands() called by RendererDidNavigate() to
3054 // determine whether or not to enable the encoding menu. 3005 // determine whether or not to enable the encoding menu.
3055 // It's updated only for the main frame. For a subframe, 3006 // It's updated only for the main frame. For a subframe,
3056 // RenderView::UpdateURL does not set params.contents_mime_type. 3007 // RenderView::UpdateURL does not set params.contents_mime_type.
3057 // (see http://code.google.com/p/chromium/issues/detail?id=2929 ) 3008 // (see http://code.google.com/p/chromium/issues/detail?id=2929 )
3058 // TODO(jungshik): Add a test for the encoding menu to avoid 3009 // TODO(jungshik): Add a test for the encoding menu to avoid
3059 // regressing it again. 3010 // regressing it again.
3060 if (PageTransitionIsMainFrame(params.transition)) 3011 if (PageTransitionIsMainFrame(params.transition))
3061 contents_mime_type_ = params.contents_mime_type; 3012 contents_mime_type_ = params.contents_mime_type;
3062 3013
3063 LoadCommittedDetails details; 3014 LoadCommittedDetails details;
3064 bool did_navigate = controller_.RendererDidNavigate(params, &details); 3015 bool did_navigate = controller_.RendererDidNavigate(params, &details);
3065 3016
3066 // For now, keep track of each frame's URL in its FrameTreeNode. This lets 3017 // For now, keep track of each frame's URL in its FrameTreeNode. This lets
3067 // us estimate our process count for implementing OOP iframes. 3018 // us estimate our process count for implementing OOP iframes.
3068 // TODO(creis): Remove this when we track which pages commit in each frame. 3019 // TODO(creis): Remove this when we track which pages commit in each frame.
3069 FrameTreeNode* node = FindFrameTreeNodeByID(params.frame_id); 3020 frame_tree_.SetFrameUrl(params.frame_id, params.url);
3070 if (node)
3071 node->set_current_url(params.url);
3072 3021
3073 // Send notification about committed provisional loads. This notification is 3022 // Send notification about committed provisional loads. This notification is
3074 // different from the NAV_ENTRY_COMMITTED notification which doesn't include 3023 // different from the NAV_ENTRY_COMMITTED notification which doesn't include
3075 // the actual URL navigated to and isn't sent for AUTO_SUBFRAME navigations. 3024 // the actual URL navigated to and isn't sent for AUTO_SUBFRAME navigations.
3076 if (details.type != NAVIGATION_TYPE_NAV_IGNORE) { 3025 if (details.type != NAVIGATION_TYPE_NAV_IGNORE) {
3077 // For AUTO_SUBFRAME navigations, an event for the main frame is generated 3026 // For AUTO_SUBFRAME navigations, an event for the main frame is generated
3078 // that is not recorded in the navigation history. For the purpose of 3027 // that is not recorded in the navigation history. For the purpose of
3079 // tracking navigation events, we treat this event as a sub frame navigation 3028 // tracking navigation events, we treat this event as a sub frame navigation
3080 // event. 3029 // event.
3081 bool is_main_frame = did_navigate ? details.is_main_frame : false; 3030 bool is_main_frame = did_navigate ? details.is_main_frame : false;
(...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after
3633 } 3582 }
3634 3583
3635 void WebContentsImpl::NotifySwappedFromRenderManager(RenderViewHost* rvh) { 3584 void WebContentsImpl::NotifySwappedFromRenderManager(RenderViewHost* rvh) {
3636 NotifySwapped(rvh); 3585 NotifySwapped(rvh);
3637 3586
3638 // Make sure the visible RVH reflects the new delegate's preferences. 3587 // Make sure the visible RVH reflects the new delegate's preferences.
3639 if (delegate_) 3588 if (delegate_)
3640 view_->SetOverscrollControllerEnabled(delegate_->CanOverscrollContent()); 3589 view_->SetOverscrollControllerEnabled(delegate_->CanOverscrollContent());
3641 3590
3642 view_->RenderViewSwappedIn(render_manager_.current_host()); 3591 view_->RenderViewSwappedIn(render_manager_.current_host());
3643
3644 FrameTreeNode* root = NULL;
3645 RenderViewHostImpl* new_rvh = static_cast<RenderViewHostImpl*>(
3646 render_manager_.current_host());
3647
3648 // We are doing a cross-site navigation and swapping processes. Since frame
3649 // ids are unique to a process, we need to recreate the frame tree with the
3650 // proper main frame id.
3651 // Note that it is possible for this method to be called before the new RVH
3652 // has committed a navigation (if RenderViewHostManager short-circuits the
3653 // CommitPending call because the current RVH is dead). In that case, we
3654 // haven't heard a valid frame id to use to initialize the root node, so clear
3655 // out the root node and the first subsequent navigation message will set it
3656 // correctly.
3657 if (new_rvh->main_frame_id() != -1)
3658 root = new FrameTreeNode(new_rvh->main_frame_id(), std::string());
3659
3660 frame_tree_root_.reset(root);
3661 } 3592 }
3662 3593
3663 int WebContentsImpl::CreateOpenerRenderViewsForRenderManager( 3594 int WebContentsImpl::CreateOpenerRenderViewsForRenderManager(
3664 SiteInstance* instance) { 3595 SiteInstance* instance) {
3665 if (!opener_) 3596 if (!opener_)
3666 return MSG_ROUTING_NONE; 3597 return MSG_ROUTING_NONE;
3667 3598
3668 // Recursively create RenderViews for anything else in the opener chain. 3599 // Recursively create RenderViews for anything else in the opener chain.
3669 return opener_->CreateOpenerRenderViews(instance); 3600 return opener_->CreateOpenerRenderViews(instance);
3670 } 3601 }
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
3824 3755
3825 gfx::Size WebContentsImpl::GetSizeForNewRenderView() const { 3756 gfx::Size WebContentsImpl::GetSizeForNewRenderView() const {
3826 gfx::Size size; 3757 gfx::Size size;
3827 if (delegate_) 3758 if (delegate_)
3828 size = delegate_->GetSizeForNewRenderView(this); 3759 size = delegate_->GetSizeForNewRenderView(this);
3829 if (size.IsEmpty()) 3760 if (size.IsEmpty())
3830 size = view_->GetContainerSize(); 3761 size = view_->GetContainerSize();
3831 return size; 3762 return size;
3832 } 3763 }
3833 3764
3765 void WebContentsImpl::OnFrameRemoved(int64 frame_id) {
3766 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3767 FrameDetached(message_source_, frame_id));
3768 }
3769
3834 } // namespace content 3770 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698