| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/web_contents/web_contents_impl.h" |
| |
| #include <stddef.h> |
| |
| #include <cmath> |
| #include <utility> |
| |
| #include "base/command_line.h" |
| #include "base/lazy_instance.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/metrics/histogram.h" |
| #include "base/process/process.h" |
| #include "base/profiler/scoped_tracker.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "base/trace_event/trace_event.h" |
| #include "build/build_config.h" |
| #include "components/mime_util/mime_util.h" |
| #include "components/url_formatter/url_formatter.h" |
| #include "content/browser/accessibility/accessibility_mode_helper.h" |
| #include "content/browser/accessibility/browser_accessibility_state_impl.h" |
| #include "content/browser/bad_message.h" |
| #include "content/browser/browser_plugin/browser_plugin_embedder.h" |
| #include "content/browser/browser_plugin/browser_plugin_guest.h" |
| #include "content/browser/child_process_security_policy_impl.h" |
| #include "content/browser/dom_storage/dom_storage_context_wrapper.h" |
| #include "content/browser/dom_storage/session_storage_namespace_impl.h" |
| #include "content/browser/download/download_stats.h" |
| #include "content/browser/download/mhtml_generation_manager.h" |
| #include "content/browser/download/save_package.h" |
| #include "content/browser/frame_host/cross_process_frame_connector.h" |
| #include "content/browser/frame_host/interstitial_page_impl.h" |
| #include "content/browser/frame_host/navigation_entry_impl.h" |
| #include "content/browser/frame_host/navigation_handle_impl.h" |
| #include "content/browser/frame_host/navigator_impl.h" |
| #include "content/browser/frame_host/render_frame_host_impl.h" |
| #include "content/browser/frame_host/render_widget_host_view_child_frame.h" |
| #include "content/browser/geolocation/geolocation_service_context.h" |
| #include "content/browser/host_zoom_map_impl.h" |
| #include "content/browser/loader/resource_dispatcher_host_impl.h" |
| #include "content/browser/manifest/manifest_manager_host.h" |
| #include "content/browser/media/audio_stream_monitor.h" |
| #include "content/browser/media/capture/web_contents_audio_muter.h" |
| #include "content/browser/media/media_web_contents_observer.h" |
| #include "content/browser/message_port_message_filter.h" |
| #include "content/browser/plugin_content_origin_whitelist.h" |
| #include "content/browser/renderer_host/render_process_host_impl.h" |
| #include "content/browser/renderer_host/render_view_host_delegate_view.h" |
| #include "content/browser/renderer_host/render_view_host_impl.h" |
| #include "content/browser/renderer_host/render_widget_host_impl.h" |
| #include "content/browser/renderer_host/render_widget_host_input_event_router.h" |
| #include "content/browser/renderer_host/render_widget_host_view_base.h" |
| #include "content/browser/screen_orientation/screen_orientation_dispatcher_host_impl.h" |
| #include "content/browser/site_instance_impl.h" |
| #include "content/browser/wake_lock/wake_lock_service_context.h" |
| #include "content/browser/web_contents/web_contents_view_guest.h" |
| #include "content/browser/webui/generic_handler.h" |
| #include "content/browser/webui/web_ui_controller_factory_registry.h" |
| #include "content/browser/webui/web_ui_impl.h" |
| #include "content/common/browser_plugin/browser_plugin_constants.h" |
| #include "content/common/browser_plugin/browser_plugin_messages.h" |
| #include "content/common/frame_messages.h" |
| #include "content/common/input_messages.h" |
| #include "content/common/site_isolation_policy.h" |
| #include "content/common/ssl_status_serialization.h" |
| #include "content/common/view_messages.h" |
| #include "content/public/browser/ax_event_notification_details.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/browser_plugin_guest_manager.h" |
| #include "content/public/browser/content_browser_client.h" |
| #include "content/public/browser/devtools_agent_host.h" |
| #include "content/public/browser/download_manager.h" |
| #include "content/public/browser/download_url_parameters.h" |
| #include "content/public/browser/invalidate_type.h" |
| #include "content/public/browser/javascript_dialog_manager.h" |
| #include "content/public/browser/load_from_memory_cache_details.h" |
| #include "content/public/browser/load_notification_details.h" |
| #include "content/public/browser/navigation_details.h" |
| #include "content/public/browser/notification_details.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/render_widget_host_iterator.h" |
| #include "content/public/browser/resource_request_details.h" |
| #include "content/public/browser/screen_orientation_dispatcher_host.h" |
| #include "content/public/browser/security_style_explanations.h" |
| #include "content/public/browser/storage_partition.h" |
| #include "content/public/browser/user_metrics.h" |
| #include "content/public/browser/web_contents_delegate.h" |
| #include "content/public/common/bindings_policy.h" |
| #include "content/public/common/browser_plugin_guest_mode.h" |
| #include "content/public/common/browser_side_navigation_policy.h" |
| #include "content/public/common/content_constants.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/common/page_zoom.h" |
| #include "content/public/common/result_codes.h" |
| #include "content/public/common/security_style.h" |
| #include "content/public/common/url_constants.h" |
| #include "content/public/common/url_utils.h" |
| #include "content/public/common/web_preferences.h" |
| #include "mojo/common/url_type_converters.h" |
| #include "mojo/converters/geometry/geometry_type_converters.h" |
| #include "net/http/http_cache.h" |
| #include "net/http/http_transaction_factory.h" |
| #include "net/url_request/url_request_context.h" |
| #include "net/url_request/url_request_context_getter.h" |
| #include "skia/public/type_converters.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "ui/base/layout.h" |
| #include "ui/gfx/display.h" |
| #include "ui/gfx/screen.h" |
| #include "ui/gl/gl_switches.h" |
| |
| #if defined(OS_ANDROID) |
| #include "content/browser/android/content_video_view.h" |
| #include "content/browser/media/android/media_session.h" |
| #include "content/browser/media/android/media_web_contents_observer_android.h" |
| #endif // OS_ANDROID |
| |
| #if defined(OS_ANDROID) && !defined(USE_AURA) |
| #include "content/browser/android/date_time_chooser_android.h" |
| #include "content/browser/web_contents/web_contents_android.h" |
| #endif // OS_ANDROID && !USE_AURA |
| |
| #if defined(OS_MACOSX) |
| #include "base/mac/foundation_util.h" |
| #endif |
| |
| #if defined(MOJO_SHELL_CLIENT) |
| #include "content/browser/web_contents/web_contents_view_mus.h" |
| #include "content/public/common/mojo_shell_connection.h" |
| #include "ui/aura/mus/mus_util.h" |
| #endif |
| |
| namespace content { |
| namespace { |
| |
| const int kMinimumDelayBetweenLoadingUpdatesMS = 100; |
| const char kDotGoogleDotCom[] = ".google.com"; |
| |
| #if defined(OS_ANDROID) |
| const char kWebContentsAndroidKey[] = "web_contents_android"; |
| #endif // OS_ANDROID |
| |
| base::LazyInstance<std::vector<WebContentsImpl::CreatedCallback> > |
| g_created_callbacks = LAZY_INSTANCE_INITIALIZER; |
| |
| void NotifyCacheOnIO( |
| scoped_refptr<net::URLRequestContextGetter> request_context, |
| const GURL& url, |
| const std::string& http_method) { |
| net::HttpCache* cache = request_context->GetURLRequestContext()-> |
| http_transaction_factory()->GetCache(); |
| if (cache) |
| cache->OnExternalCacheHit(url, http_method); |
| } |
| |
| bool FindMatchingProcess(int render_process_id, |
| bool* did_match_process, |
| FrameTreeNode* node) { |
| if (node->current_frame_host()->GetProcess()->GetID() == render_process_id) { |
| *did_match_process = true; |
| return false; |
| } |
| return true; |
| } |
| |
| bool ForEachFrameInternal( |
| const base::Callback<void(RenderFrameHost*)>& on_frame, |
| FrameTreeNode* node) { |
| on_frame.Run(node->current_frame_host()); |
| return true; |
| } |
| |
| bool ForEachPendingFrameInternal( |
| const base::Callback<void(RenderFrameHost*)>& on_frame, |
| FrameTreeNode* node) { |
| RenderFrameHost* pending_frame_host = |
| node->render_manager()->pending_frame_host(); |
| if (pending_frame_host) |
| on_frame.Run(pending_frame_host); |
| return true; |
| } |
| |
| void SendToAllFramesInternal(int* number_of_messages, |
| IPC::Message* message, |
| RenderFrameHost* rfh) { |
| *number_of_messages = *number_of_messages + 1; |
| IPC::Message* message_copy = new IPC::Message(*message); |
| message_copy->set_routing_id(rfh->GetRoutingID()); |
| rfh->Send(message_copy); |
| } |
| |
| void AddRenderWidgetHostViewToSet(std::set<RenderWidgetHostView*>* set, |
| RenderFrameHost* rfh) { |
| RenderWidgetHostView* rwhv = static_cast<RenderFrameHostImpl*>(rfh) |
| ->frame_tree_node() |
| ->render_manager() |
| ->GetRenderWidgetHostView(); |
| set->insert(rwhv); |
| } |
| |
| void SetAccessibilityModeOnFrame(AccessibilityMode mode, |
| RenderFrameHost* frame_host) { |
| static_cast<RenderFrameHostImpl*>(frame_host)->SetAccessibilityMode(mode); |
| } |
| |
| void ResetAccessibility(RenderFrameHost* rfh) { |
| static_cast<RenderFrameHostImpl*>(rfh)->AccessibilityReset(); |
| } |
| |
| } // namespace |
| |
| WebContents* WebContents::Create(const WebContents::CreateParams& params) { |
| FrameTreeNode* opener_node = nullptr; |
| if (params.opener_render_frame_id != MSG_ROUTING_NONE) { |
| RenderFrameHostImpl* opener_rfh = RenderFrameHostImpl::FromID( |
| params.opener_render_process_id, params.opener_render_frame_id); |
| if (opener_rfh) |
| opener_node = opener_rfh->frame_tree_node(); |
| } |
| return WebContentsImpl::CreateWithOpener(params, opener_node); |
| } |
| |
| WebContents* WebContents::CreateWithSessionStorage( |
| const WebContents::CreateParams& params, |
| const SessionStorageNamespaceMap& session_storage_namespace_map) { |
| WebContentsImpl* new_contents = new WebContentsImpl(params.browser_context); |
| |
| for (SessionStorageNamespaceMap::const_iterator it = |
| session_storage_namespace_map.begin(); |
| it != session_storage_namespace_map.end(); |
| ++it) { |
| new_contents->GetController() |
| .SetSessionStorageNamespace(it->first, it->second.get()); |
| } |
| |
| new_contents->Init(params); |
| return new_contents; |
| } |
| |
| void WebContentsImpl::FriendZone::AddCreatedCallbackForTesting( |
| const CreatedCallback& callback) { |
| g_created_callbacks.Get().push_back(callback); |
| } |
| |
| void WebContentsImpl::FriendZone::RemoveCreatedCallbackForTesting( |
| const CreatedCallback& callback) { |
| for (size_t i = 0; i < g_created_callbacks.Get().size(); ++i) { |
| if (g_created_callbacks.Get().at(i).Equals(callback)) { |
| g_created_callbacks.Get().erase(g_created_callbacks.Get().begin() + i); |
| return; |
| } |
| } |
| } |
| |
| WebContents* WebContents::FromRenderViewHost(RenderViewHost* rvh) { |
| if (!rvh) |
| return nullptr; |
| return rvh->GetDelegate()->GetAsWebContents(); |
| } |
| |
| WebContents* WebContents::FromRenderFrameHost(RenderFrameHost* rfh) { |
| if (!rfh) |
| return nullptr; |
| return static_cast<RenderFrameHostImpl*>(rfh)->delegate()->GetAsWebContents(); |
| } |
| |
| // WebContentsImpl::DestructionObserver ---------------------------------------- |
| |
| class WebContentsImpl::DestructionObserver : public WebContentsObserver { |
| public: |
| DestructionObserver(WebContentsImpl* owner, WebContents* watched_contents) |
| : WebContentsObserver(watched_contents), |
| owner_(owner) { |
| } |
| |
| // WebContentsObserver: |
| void WebContentsDestroyed() override { |
| owner_->OnWebContentsDestroyed( |
| static_cast<WebContentsImpl*>(web_contents())); |
| } |
| |
| private: |
| WebContentsImpl* owner_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DestructionObserver); |
| }; |
| |
| WebContentsImpl::ColorChooserInfo::ColorChooserInfo(int render_process_id, |
| int render_frame_id, |
| ColorChooser* chooser, |
| int identifier) |
| : render_process_id(render_process_id), |
| render_frame_id(render_frame_id), |
| chooser(chooser), |
| identifier(identifier) { |
| } |
| |
| WebContentsImpl::ColorChooserInfo::~ColorChooserInfo() { |
| } |
| |
| // WebContentsImpl::WebContentsTreeNode ---------------------------------------- |
| WebContentsImpl::WebContentsTreeNode::WebContentsTreeNode() |
| : outer_web_contents_(nullptr), |
| outer_contents_frame_tree_node_id_( |
| FrameTreeNode::kFrameTreeNodeInvalidId) { |
| } |
| |
| WebContentsImpl::WebContentsTreeNode::~WebContentsTreeNode() { |
| // Remove child pointer from our parent. |
| if (outer_web_contents_) { |
| ChildrenSet& child_ptrs_in_parent = |
| outer_web_contents_->node_->inner_web_contents_tree_nodes_; |
| ChildrenSet::iterator iter = child_ptrs_in_parent.find(this); |
| DCHECK(iter != child_ptrs_in_parent.end()); |
| child_ptrs_in_parent.erase(this); |
| } |
| |
| // Remove parent pointers from our children. |
| // TODO(lazyboy): We should destroy the children WebContentses too. If the |
| // children do not manage their own lifetime, then we would leak their |
| // WebContentses. |
| for (WebContentsTreeNode* child : inner_web_contents_tree_nodes_) |
| child->outer_web_contents_ = nullptr; |
| } |
| |
| void WebContentsImpl::WebContentsTreeNode::ConnectToOuterWebContents( |
| WebContentsImpl* outer_web_contents, |
| RenderFrameHostImpl* outer_contents_frame) { |
| outer_web_contents_ = outer_web_contents; |
| outer_contents_frame_tree_node_id_ = |
| outer_contents_frame->frame_tree_node()->frame_tree_node_id(); |
| |
| if (!outer_web_contents_->node_) |
| outer_web_contents_->node_.reset(new WebContentsTreeNode()); |
| |
| outer_web_contents_->node_->inner_web_contents_tree_nodes_.insert(this); |
| } |
| |
| // WebContentsImpl ------------------------------------------------------------- |
| |
| WebContentsImpl::WebContentsImpl(BrowserContext* browser_context) |
| : delegate_(NULL), |
| controller_(this, browser_context), |
| render_view_host_delegate_view_(NULL), |
| created_with_opener_(false), |
| #if defined(OS_WIN) |
| accessible_parent_(NULL), |
| #endif |
| frame_tree_(new NavigatorImpl(&controller_, this), |
| this, |
| this, |
| this, |
| this), |
| is_loading_(false), |
| is_load_to_different_document_(false), |
| crashed_status_(base::TERMINATION_STATUS_STILL_RUNNING), |
| crashed_error_code_(0), |
| waiting_for_response_(false), |
| load_state_(net::LOAD_STATE_IDLE, base::string16()), |
| upload_size_(0), |
| upload_position_(0), |
| is_resume_pending_(false), |
| displayed_insecure_content_(false), |
| has_accessed_initial_document_(false), |
| theme_color_(SK_ColorTRANSPARENT), |
| last_sent_theme_color_(SK_ColorTRANSPARENT), |
| did_first_visually_non_empty_paint_(false), |
| capturer_count_(0), |
| should_normally_be_visible_(true), |
| is_being_destroyed_(false), |
| notify_disconnection_(false), |
| dialog_manager_(NULL), |
| is_showing_before_unload_dialog_(false), |
| last_active_time_(base::TimeTicks::Now()), |
| closed_by_user_gesture_(false), |
| minimum_zoom_percent_(static_cast<int>(kMinimumZoomFactor * 100)), |
| maximum_zoom_percent_(static_cast<int>(kMaximumZoomFactor * 100)), |
| zoom_scroll_remainder_(0), |
| render_view_message_source_(NULL), |
| render_frame_message_source_(NULL), |
| fullscreen_widget_routing_id_(MSG_ROUTING_NONE), |
| fullscreen_widget_had_focus_at_shutdown_(false), |
| is_subframe_(false), |
| force_disable_overscroll_content_(false), |
| last_dialog_suppressed_(false), |
| geolocation_service_context_(new GeolocationServiceContext()), |
| accessibility_mode_( |
| BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode()), |
| audio_stream_monitor_(this), |
| virtual_keyboard_requested_(false), |
| page_scale_factor_is_one_(true), |
| loading_weak_factory_(this), |
| weak_factory_(this) { |
| frame_tree_.SetFrameRemoveListener( |
| base::Bind(&WebContentsImpl::OnFrameRemoved, |
| base::Unretained(this))); |
| #if defined(OS_ANDROID) |
| media_web_contents_observer_.reset(new MediaWebContentsObserverAndroid(this)); |
| #else |
| media_web_contents_observer_.reset(new MediaWebContentsObserver(this)); |
| #endif |
| wake_lock_service_context_.reset(new WakeLockServiceContext(this)); |
| } |
| |
| WebContentsImpl::~WebContentsImpl() { |
| is_being_destroyed_ = true; |
| |
| rwh_input_event_router_.reset(); |
| |
| // Delete all RFH pending shutdown, which will lead the corresponding RVH to |
| // shutdown and be deleted as well. |
| frame_tree_.ForEach( |
| base::Bind(&RenderFrameHostManager::ClearRFHsPendingShutdown)); |
| |
| // Destroy all WebUI instances. |
| frame_tree_.ForEach(base::Bind(&RenderFrameHostManager::ClearWebUIInstances)); |
| |
| for (std::set<RenderWidgetHostImpl*>::iterator iter = |
| created_widgets_.begin(); iter != created_widgets_.end(); ++iter) { |
| (*iter)->DetachDelegate(); |
| } |
| created_widgets_.clear(); |
| |
| // Clear out any JavaScript state. |
| if (dialog_manager_) |
| dialog_manager_->ResetDialogState(this); |
| |
| if (color_chooser_info_.get()) |
| color_chooser_info_->chooser->End(); |
| |
| NotifyDisconnected(); |
| |
| // Notify any observer that have a reference on this WebContents. |
| NotificationService::current()->Notify( |
| NOTIFICATION_WEB_CONTENTS_DESTROYED, |
| Source<WebContents>(this), |
| NotificationService::NoDetails()); |
| |
| // Destroy all frame tree nodes except for the root; this notifies observers. |
| frame_tree_.root()->ResetForNewProcess(); |
| GetRenderManager()->ResetProxyHosts(); |
| |
| // Manually call the observer methods for the root frame tree node. It is |
| // necessary to manually delete all objects tracking navigations |
| // (NavigationHandle, NavigationRequest) for observers to be properly |
| // notified of these navigations stopping before the WebContents is |
| // destroyed. |
| RenderFrameHostManager* root = GetRenderManager(); |
| |
| if (root->pending_frame_host()) { |
| root->pending_frame_host()->SetRenderFrameCreated(false); |
| root->pending_frame_host()->SetNavigationHandle( |
| scoped_ptr<NavigationHandleImpl>()); |
| } |
| root->current_frame_host()->SetRenderFrameCreated(false); |
| root->current_frame_host()->SetNavigationHandle( |
| scoped_ptr<NavigationHandleImpl>()); |
| |
| // PlzNavigate: clear up state specific to browser-side navigation. |
| if (IsBrowserSideNavigationEnabled()) { |
| frame_tree_.root()->ResetNavigationRequest(false); |
| if (root->speculative_frame_host()) { |
| root->speculative_frame_host()->SetRenderFrameCreated(false); |
| root->speculative_frame_host()->SetNavigationHandle( |
| scoped_ptr<NavigationHandleImpl>()); |
| } |
| } |
| |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, |
| FrameDeleted(root->current_frame_host())); |
| |
| if (root->pending_render_view_host()) { |
| FOR_EACH_OBSERVER(WebContentsObserver, |
| observers_, |
| RenderViewDeleted(root->pending_render_view_host())); |
| } |
| |
| FOR_EACH_OBSERVER(WebContentsObserver, |
| observers_, |
| RenderViewDeleted(root->current_host())); |
| |
| FOR_EACH_OBSERVER(WebContentsObserver, |
| observers_, |
| WebContentsDestroyed()); |
| |
| FOR_EACH_OBSERVER(WebContentsObserver, |
| observers_, |
| ResetWebContents()); |
| |
| SetDelegate(NULL); |
| |
| STLDeleteContainerPairSecondPointers(destruction_observers_.begin(), |
| destruction_observers_.end()); |
| } |
| |
| WebContentsImpl* WebContentsImpl::CreateWithOpener( |
| const WebContents::CreateParams& params, |
| FrameTreeNode* opener) { |
| TRACE_EVENT0("browser", "WebContentsImpl::CreateWithOpener"); |
| WebContentsImpl* new_contents = new WebContentsImpl(params.browser_context); |
| |
| if (!params.opener_suppressed && opener) { |
| new_contents->GetFrameTree()->root()->SetOpener(opener); |
| new_contents->created_with_opener_ = true; |
| } |
| |
| // This may be true even when opener is null, such as when opening blocked |
| // popups. |
| if (params.created_with_opener) |
| new_contents->created_with_opener_ = true; |
| |
| if (params.guest_delegate) { |
| // This makes |new_contents| act as a guest. |
| // For more info, see comment above class BrowserPluginGuest. |
| BrowserPluginGuest::Create(new_contents, params.guest_delegate); |
| // We are instantiating a WebContents for browser plugin. Set its subframe |
| // bit to true. |
| new_contents->is_subframe_ = true; |
| } |
| new_contents->Init(params); |
| return new_contents; |
| } |
| |
| // static |
| std::vector<WebContentsImpl*> WebContentsImpl::GetAllWebContents() { |
| std::vector<WebContentsImpl*> result; |
| scoped_ptr<RenderWidgetHostIterator> widgets( |
| RenderWidgetHostImpl::GetRenderWidgetHosts()); |
| while (RenderWidgetHost* rwh = widgets->GetNextHost()) { |
| RenderViewHost* rvh = RenderViewHost::From(rwh); |
| if (!rvh) |
| continue; |
| WebContents* web_contents = WebContents::FromRenderViewHost(rvh); |
| if (!web_contents) |
| continue; |
| if (web_contents->GetRenderViewHost() != rvh) |
| continue; |
| // Because a WebContents can only have one current RVH at a time, there will |
| // be no duplicate WebContents here. |
| result.push_back(static_cast<WebContentsImpl*>(web_contents)); |
| } |
| return result; |
| } |
| |
| // static |
| WebContentsImpl* WebContentsImpl::FromFrameTreeNode( |
| FrameTreeNode* frame_tree_node) { |
| return static_cast<WebContentsImpl*>( |
| WebContents::FromRenderFrameHost(frame_tree_node->current_frame_host())); |
| } |
| |
| // static |
| WebContents* WebContentsImpl::FromRenderFrameHostID(int render_process_host_id, |
| int render_frame_host_id) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| RenderFrameHost* render_frame_host = |
| RenderFrameHost::FromID(render_process_host_id, render_frame_host_id); |
| if (!render_frame_host) |
| return nullptr; |
| |
| return WebContents::FromRenderFrameHost(render_frame_host); |
| } |
| |
| RenderFrameHostManager* WebContentsImpl::GetRenderManagerForTesting() { |
| return GetRenderManager(); |
| } |
| |
| bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host, |
| const IPC::Message& message) { |
| return OnMessageReceived(render_view_host, NULL, message); |
| } |
| |
| bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host, |
| RenderFrameHost* render_frame_host, |
| const IPC::Message& message) { |
| DCHECK(render_view_host || render_frame_host); |
| if (GetWebUI() && |
| static_cast<WebUIImpl*>(GetWebUI())->OnMessageReceived(message)) { |
| return true; |
| } |
| |
| base::ObserverListBase<WebContentsObserver>::Iterator it(&observers_); |
| WebContentsObserver* observer; |
| if (render_frame_host) { |
| while ((observer = it.GetNext()) != NULL) |
| if (observer->OnMessageReceived(message, render_frame_host)) |
| return true; |
| } else { |
| while ((observer = it.GetNext()) != NULL) |
| if (observer->OnMessageReceived(message)) |
| return true; |
| } |
| |
| // Message handlers should be aware of which |
| // RenderViewHost/RenderFrameHost sent the message, which is temporarily |
| // stored in render_(view|frame)_message_source_. |
| if (render_frame_host) |
| render_frame_message_source_ = render_frame_host; |
| else |
| render_view_message_source_ = render_view_host; |
| |
| bool handled = true; |
| IPC_BEGIN_MESSAGE_MAP(WebContentsImpl, message) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_DomOperationResponse, |
| OnDomOperationResponse) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeThemeColor, |
| OnThemeColorChanged) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_DidFinishDocumentLoad, |
| OnDocumentLoadedInFrame) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_DidFinishLoad, OnDidFinishLoad) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_OpenColorChooser, OnOpenColorChooser) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_EndColorChooser, OnEndColorChooser) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_SetSelectedColorInColorChooser, |
| OnSetSelectedColorInColorChooser) |
| |
| IPC_MESSAGE_HANDLER(ViewHostMsg_DidFirstVisuallyNonEmptyPaint, |
| OnFirstVisuallyNonEmptyPaint) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_DidLoadResourceFromMemoryCache, |
| OnDidLoadResourceFromMemoryCache) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_DidDisplayInsecureContent, |
| OnDidDisplayInsecureContent) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_DidRunInsecureContent, |
| OnDidRunInsecureContent) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_DidDisplayContentWithCertificateErrors, |
| OnDidDisplayContentWithCertificateErrors) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_DidRunContentWithCertificateErrors, |
| OnDidRunContentWithCertificateErrors) |
| IPC_MESSAGE_HANDLER(ViewHostMsg_GoToEntryAtOffset, OnGoToEntryAtOffset) |
| IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateZoomLimits, OnUpdateZoomLimits) |
| IPC_MESSAGE_HANDLER(ViewHostMsg_PageScaleFactorChanged, |
| OnPageScaleFactorChanged) |
| IPC_MESSAGE_HANDLER(ViewHostMsg_EnumerateDirectory, OnEnumerateDirectory) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_RegisterProtocolHandler, |
| OnRegisterProtocolHandler) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_UnregisterProtocolHandler, |
| OnUnregisterProtocolHandler) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_UpdatePageImportanceSignals, |
| OnUpdatePageImportanceSignals) |
| IPC_MESSAGE_HANDLER(ViewHostMsg_Find_Reply, OnFindReply) |
| IPC_MESSAGE_HANDLER(ViewHostMsg_AppCacheAccessed, OnAppCacheAccessed) |
| IPC_MESSAGE_HANDLER(ViewHostMsg_WebUISend, OnWebUISend) |
| #if defined(ENABLE_PLUGINS) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_PepperInstanceCreated, |
| OnPepperInstanceCreated) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_PepperInstanceDeleted, |
| OnPepperInstanceDeleted) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_PepperPluginHung, OnPepperPluginHung) |
| IPC_MESSAGE_HANDLER(FrameHostMsg_PluginCrashed, OnPluginCrashed) |
| IPC_MESSAGE_HANDLER(ViewHostMsg_RequestPpapiBrokerPermission, |
| OnRequestPpapiBrokerPermission) |
| IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginHostMsg_Attach, |
| OnBrowserPluginMessage(render_frame_host, |
| message)) |
| #endif |
| IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFaviconURL, OnUpdateFaviconURL) |
| IPC_MESSAGE_HANDLER(ViewHostMsg_ShowValidationMessage, |
| OnShowValidationMessage) |
| IPC_MESSAGE_HANDLER(ViewHostMsg_HideValidationMessage, |
| OnHideValidationMessage) |
| IPC_MESSAGE_HANDLER(ViewHostMsg_MoveValidationMessage, |
| OnMoveValidationMessage) |
| #if defined(OS_ANDROID) && !defined(USE_AURA) |
| IPC_MESSAGE_HANDLER(ViewHostMsg_FindMatchRects_Reply, |
| OnFindMatchRectsReply) |
| IPC_MESSAGE_HANDLER(ViewHostMsg_OpenDateTimeDialog, |
| OnOpenDateTimeDialog) |
| #endif |
| IPC_MESSAGE_UNHANDLED(handled = false) |
| IPC_END_MESSAGE_MAP() |
| render_view_message_source_ = NULL; |
| render_frame_message_source_ = NULL; |
| |
| return handled; |
| } |
| |
| bool WebContentsImpl::HasValidFrameSource() { |
| if (!render_frame_message_source_) { |
| DCHECK(render_view_message_source_); |
| bad_message::ReceivedBadMessage(GetRenderProcessHost(), |
| bad_message::WC_INVALID_FRAME_SOURCE); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void WebContentsImpl::RunFileChooser( |
| RenderViewHost* render_view_host, |
| const FileChooserParams& params) { |
| if (delegate_) |
| delegate_->RunFileChooser(this, params); |
| } |
| |
| NavigationControllerImpl& WebContentsImpl::GetController() { |
| return controller_; |
| } |
| |
| const NavigationControllerImpl& WebContentsImpl::GetController() const { |
| return controller_; |
| } |
| |
| BrowserContext* WebContentsImpl::GetBrowserContext() const { |
| return controller_.GetBrowserContext(); |
| } |
| |
| const GURL& WebContentsImpl::GetURL() const { |
| // We may not have a navigation entry yet. |
| NavigationEntry* entry = controller_.GetVisibleEntry(); |
| return entry ? entry->GetVirtualURL() : GURL::EmptyGURL(); |
| } |
| |
| const GURL& WebContentsImpl::GetVisibleURL() const { |
| // We may not have a navigation entry yet. |
| NavigationEntry* entry = controller_.GetVisibleEntry(); |
| return entry ? entry->GetVirtualURL() : GURL::EmptyGURL(); |
| } |
| |
| const GURL& WebContentsImpl::GetLastCommittedURL() const { |
| // We may not have a navigation entry yet. |
| NavigationEntry* entry = controller_.GetLastCommittedEntry(); |
| return entry ? entry->GetVirtualURL() : GURL::EmptyGURL(); |
| } |
| |
| WebContentsDelegate* WebContentsImpl::GetDelegate() { |
| return delegate_; |
| } |
| |
| void WebContentsImpl::SetDelegate(WebContentsDelegate* delegate) { |
| // TODO(cbentzel): remove this debugging code? |
| if (delegate == delegate_) |
| return; |
| if (delegate_) |
| delegate_->Detach(this); |
| delegate_ = delegate; |
| if (delegate_) { |
| delegate_->Attach(this); |
| // Ensure the visible RVH reflects the new delegate's preferences. |
| if (view_) |
| view_->SetOverscrollControllerEnabled(CanOverscrollContent()); |
| } |
| } |
| |
| RenderProcessHost* WebContentsImpl::GetRenderProcessHost() const { |
| RenderViewHostImpl* host = GetRenderManager()->current_host(); |
| return host ? host->GetProcess() : NULL; |
| } |
| |
| RenderFrameHostImpl* WebContentsImpl::GetMainFrame() { |
| return frame_tree_.root()->current_frame_host(); |
| } |
| |
| RenderFrameHostImpl* WebContentsImpl::GetFocusedFrame() { |
| FrameTreeNode* focused_node = frame_tree_.GetFocusedFrame(); |
| if (!focused_node) |
| return nullptr; |
| return focused_node->current_frame_host(); |
| } |
| |
| RenderFrameHostImpl* WebContentsImpl::FindFrameByFrameTreeNodeId( |
| int frame_tree_node_id) { |
| FrameTreeNode* frame = frame_tree_.FindByID(frame_tree_node_id); |
| return frame ? frame->current_frame_host() : nullptr; |
| } |
| |
| void WebContentsImpl::ForEachFrame( |
| const base::Callback<void(RenderFrameHost*)>& on_frame) { |
| frame_tree_.ForEach(base::Bind(&ForEachFrameInternal, on_frame)); |
| } |
| |
| int WebContentsImpl::SendToAllFrames(IPC::Message* message) { |
| int number_of_messages = 0; |
| ForEachFrame( |
| base::Bind(&SendToAllFramesInternal, &number_of_messages, message)); |
| delete message; |
| return number_of_messages; |
| } |
| |
| RenderViewHostImpl* WebContentsImpl::GetRenderViewHost() const { |
| return GetRenderManager()->current_host(); |
| } |
| |
| int WebContentsImpl::GetRoutingID() const { |
| if (!GetRenderViewHost()) |
| return MSG_ROUTING_NONE; |
| |
| return GetRenderViewHost()->GetRoutingID(); |
| } |
| |
| void WebContentsImpl::CancelActiveAndPendingDialogs() { |
| if (dialog_manager_) |
| dialog_manager_->CancelActiveAndPendingDialogs(this); |
| if (browser_plugin_embedder_) |
| browser_plugin_embedder_->CancelGuestDialogs(); |
| } |
| |
| int WebContentsImpl::GetFullscreenWidgetRoutingID() const { |
| return fullscreen_widget_routing_id_; |
| } |
| |
| void WebContentsImpl::ClosePage() { |
| GetRenderViewHost()->ClosePage(); |
| } |
| |
| RenderWidgetHostView* WebContentsImpl::GetRenderWidgetHostView() const { |
| return GetRenderManager()->GetRenderWidgetHostView(); |
| } |
| |
| RenderWidgetHostView* WebContentsImpl::GetFullscreenRenderWidgetHostView() |
| const { |
| RenderWidgetHost* const widget_host = |
| RenderWidgetHostImpl::FromID(GetRenderProcessHost()->GetID(), |
| GetFullscreenWidgetRoutingID()); |
| return widget_host ? widget_host->GetView() : NULL; |
| } |
| |
| WebContentsView* WebContentsImpl::GetView() const { |
| return view_.get(); |
| } |
| |
| SkColor WebContentsImpl::GetThemeColor() const { |
| return theme_color_; |
| } |
| |
| void WebContentsImpl::SetAccessibilityMode(AccessibilityMode mode) { |
| if (mode == accessibility_mode_) |
| return; |
| |
| accessibility_mode_ = mode; |
| frame_tree_.ForEach( |
| base::Bind(&ForEachFrameInternal, |
| base::Bind(&SetAccessibilityModeOnFrame, mode))); |
| frame_tree_.ForEach( |
| base::Bind(&ForEachPendingFrameInternal, |
| base::Bind(&SetAccessibilityModeOnFrame, mode))); |
| } |
| |
| void WebContentsImpl::AddAccessibilityMode(AccessibilityMode mode) { |
| SetAccessibilityMode(AddAccessibilityModeTo(accessibility_mode_, mode)); |
| } |
| |
| void WebContentsImpl::RemoveAccessibilityMode(AccessibilityMode mode) { |
| SetAccessibilityMode(RemoveAccessibilityModeFrom(accessibility_mode_, mode)); |
| } |
| |
| void WebContentsImpl::RequestAXTreeSnapshot(AXTreeSnapshotCallback callback) { |
| // TODO(dmazzoni): http://crbug.com/475608 This only returns the |
| // accessibility tree from the main frame and everything in the |
| // same site instance. |
| GetMainFrame()->RequestAXTreeSnapshot(callback); |
| } |
| |
| WebUI* WebContentsImpl::CreateSubframeWebUI(const GURL& url, |
| const std::string& frame_name) { |
| DCHECK(!frame_name.empty()); |
| return CreateWebUI(url, frame_name); |
| } |
| |
| WebUI* WebContentsImpl::GetWebUI() const { |
| WebUI* commited_web_ui = GetCommittedWebUI(); |
| return commited_web_ui ? commited_web_ui |
| : GetRenderManager()->GetNavigatingWebUI(); |
| } |
| |
| WebUI* WebContentsImpl::GetCommittedWebUI() const { |
| return frame_tree_.root()->current_frame_host()->web_ui(); |
| } |
| |
| void WebContentsImpl::SetUserAgentOverride(const std::string& override) { |
| if (GetUserAgentOverride() == override) |
| return; |
| |
| renderer_preferences_.user_agent_override = override; |
| |
| // Send the new override string to the renderer. |
| RenderViewHost* host = GetRenderViewHost(); |
| if (host) |
| host->SyncRendererPrefs(); |
| |
| // Reload the page if a load is currently in progress to avoid having |
| // different parts of the page loaded using different user agents. |
| NavigationEntry* entry = controller_.GetVisibleEntry(); |
| if (is_loading_ && entry != NULL && entry->GetIsOverridingUserAgent()) |
| controller_.ReloadIgnoringCache(true); |
| |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, |
| UserAgentOverrideSet(override)); |
| } |
| |
| const std::string& WebContentsImpl::GetUserAgentOverride() const { |
| return renderer_preferences_.user_agent_override; |
| } |
| |
| void WebContentsImpl::EnableTreeOnlyAccessibilityMode() { |
| if (GetAccessibilityMode() != AccessibilityModeOff) |
| ForEachFrame(base::Bind(&ResetAccessibility)); |
| else |
| AddAccessibilityMode(AccessibilityModeTreeOnly); |
| } |
| |
| bool WebContentsImpl::IsTreeOnlyAccessibilityModeForTesting() const { |
| return accessibility_mode_ == AccessibilityModeTreeOnly; |
| } |
| |
| bool WebContentsImpl::IsFullAccessibilityModeForTesting() const { |
| return accessibility_mode_ == AccessibilityModeComplete; |
| } |
| |
| #if defined(OS_WIN) |
| void WebContentsImpl::SetParentNativeViewAccessible( |
| gfx::NativeViewAccessible accessible_parent) { |
| accessible_parent_ = accessible_parent; |
| RenderFrameHostImpl* rfh = GetMainFrame(); |
| if (rfh) |
| rfh->SetParentNativeViewAccessible(accessible_parent); |
| } |
| #endif |
| |
| const PageImportanceSignals& WebContentsImpl::GetPageImportanceSignals() const { |
| return page_importance_signals_; |
| } |
| |
| const base::string16& WebContentsImpl::GetTitle() const { |
| // Transient entries take precedence. They are used for interstitial pages |
| // that are shown on top of existing pages. |
| NavigationEntry* entry = controller_.GetTransientEntry(); |
| std::string accept_languages = |
| GetContentClient()->browser()->GetAcceptLangs( |
| GetBrowserContext()); |
| if (entry) { |
| return entry->GetTitleForDisplay(accept_languages); |
| } |
| |
| WebUI* navigating_web_ui = GetRenderManager()->GetNavigatingWebUI(); |
| WebUI* our_web_ui = navigating_web_ui |
| ? navigating_web_ui |
| : GetRenderManager()->current_frame_host()->web_ui(); |
| |
| if (our_web_ui) { |
| // Don't override the title in view source mode. |
| entry = controller_.GetVisibleEntry(); |
| if (!(entry && entry->IsViewSourceMode())) { |
| // Give the Web UI the chance to override our title. |
| const base::string16& title = our_web_ui->GetOverriddenTitle(); |
| if (!title.empty()) |
| return title; |
| } |
| } |
| |
| // We use the title for the last committed entry rather than a pending |
| // navigation entry. For example, when the user types in a URL, we want to |
| // keep the old page's title until the new load has committed and we get a new |
| // title. |
| entry = controller_.GetLastCommittedEntry(); |
| |
| // We make an exception for initial navigations. We only want to use the title |
| // from the visible entry if: |
| // 1. The pending entry has been explicitly assigned a title to display. |
| // 2. The user is doing a history navigation in a new tab (e.g., Ctrl+Back), |
| // which case there is a pending entry index other than -1. |
| // |
| // Otherwise, we want to stick with the last committed entry's title during |
| // new navigations, which have pending entries at index -1 with no title. |
| if (controller_.IsInitialNavigation() && |
| ((controller_.GetVisibleEntry() && |
| !controller_.GetVisibleEntry()->GetTitle().empty()) || |
| controller_.GetPendingEntryIndex() != -1)) { |
| entry = controller_.GetVisibleEntry(); |
| } |
| |
| if (entry) { |
| return entry->GetTitleForDisplay(accept_languages); |
| } |
| |
| // |page_title_when_no_navigation_entry_| is finally used |
| // if no title cannot be retrieved. |
| return page_title_when_no_navigation_entry_; |
| } |
| |
| int32_t WebContentsImpl::GetMaxPageID() { |
| return GetMaxPageIDForSiteInstance(GetSiteInstance()); |
| } |
| |
| int32_t WebContentsImpl::GetMaxPageIDForSiteInstance( |
| SiteInstance* site_instance) { |
| if (max_page_ids_.find(site_instance->GetId()) == max_page_ids_.end()) |
| max_page_ids_[site_instance->GetId()] = -1; |
| |
| return max_page_ids_[site_instance->GetId()]; |
| } |
| |
| void WebContentsImpl::UpdateMaxPageID(int32_t page_id) { |
| UpdateMaxPageIDForSiteInstance(GetSiteInstance(), page_id); |
| } |
| |
| void WebContentsImpl::UpdateMaxPageIDForSiteInstance( |
| SiteInstance* site_instance, |
| int32_t page_id) { |
| if (GetMaxPageIDForSiteInstance(site_instance) < page_id) |
| max_page_ids_[site_instance->GetId()] = page_id; |
| } |
| |
| void WebContentsImpl::CopyMaxPageIDsFrom(WebContents* web_contents) { |
| WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents); |
| max_page_ids_ = contents->max_page_ids_; |
| } |
| |
| SiteInstanceImpl* WebContentsImpl::GetSiteInstance() const { |
| return GetRenderManager()->current_host()->GetSiteInstance(); |
| } |
| |
| SiteInstanceImpl* WebContentsImpl::GetPendingSiteInstance() const { |
| RenderViewHostImpl* dest_rvh = |
| GetRenderManager()->pending_render_view_host() ? |
| GetRenderManager()->pending_render_view_host() : |
| GetRenderManager()->current_host(); |
| return dest_rvh->GetSiteInstance(); |
| } |
| |
| bool WebContentsImpl::IsLoading() const { |
| return is_loading_; |
| } |
| |
| bool WebContentsImpl::IsLoadingToDifferentDocument() const { |
| return is_loading_ && is_load_to_different_document_; |
| } |
| |
| bool WebContentsImpl::IsWaitingForResponse() const { |
| return waiting_for_response_ && is_load_to_different_document_; |
| } |
| |
| const net::LoadStateWithParam& WebContentsImpl::GetLoadState() const { |
| return load_state_; |
| } |
| |
| const base::string16& WebContentsImpl::GetLoadStateHost() const { |
| return load_state_host_; |
| } |
| |
| uint64_t WebContentsImpl::GetUploadSize() const { |
| return upload_size_; |
| } |
| |
| uint64_t WebContentsImpl::GetUploadPosition() const { |
| return upload_position_; |
| } |
| |
| const std::string& WebContentsImpl::GetEncoding() const { |
| return canonical_encoding_; |
| } |
| |
| bool WebContentsImpl::DisplayedInsecureContent() const { |
| return displayed_insecure_content_; |
| } |
| |
| void WebContentsImpl::IncrementCapturerCount(const gfx::Size& capture_size) { |
| DCHECK(!is_being_destroyed_); |
| ++capturer_count_; |
| DVLOG(1) << "There are now " << capturer_count_ |
| << " capturing(s) of WebContentsImpl@" << this; |
| |
| // Note: This provides a hint to upstream code to size the views optimally |
| // for quality (e.g., to avoid scaling). |
| if (!capture_size.IsEmpty() && preferred_size_for_capture_.IsEmpty()) { |
| preferred_size_for_capture_ = capture_size; |
| OnPreferredSizeChanged(preferred_size_); |
| } |
| |
| // Ensure that all views are un-occluded before capture begins. |
| WasUnOccluded(); |
| } |
| |
| void WebContentsImpl::DecrementCapturerCount() { |
| --capturer_count_; |
| DVLOG(1) << "There are now " << capturer_count_ |
| << " capturing(s) of WebContentsImpl@" << this; |
| DCHECK_LE(0, capturer_count_); |
| |
| if (is_being_destroyed_) |
| return; |
| |
| if (capturer_count_ == 0) { |
| const gfx::Size old_size = preferred_size_for_capture_; |
| preferred_size_for_capture_ = gfx::Size(); |
| OnPreferredSizeChanged(old_size); |
| } |
| |
| if (IsHidden()) { |
| DVLOG(1) << "Executing delayed WasHidden()."; |
| WasHidden(); |
| } |
| } |
| |
| int WebContentsImpl::GetCapturerCount() const { |
| return capturer_count_; |
| } |
| |
| bool WebContentsImpl::IsAudioMuted() const { |
| return audio_muter_.get() && audio_muter_->is_muting(); |
| } |
| |
| void WebContentsImpl::SetAudioMuted(bool mute) { |
| DVLOG(1) << "SetAudioMuted(mute=" << mute << "), was " << IsAudioMuted() |
| << " for WebContentsImpl@" << this; |
| |
| if (mute == IsAudioMuted()) |
| return; |
| |
| if (mute) { |
| if (!audio_muter_) |
| audio_muter_.reset(new WebContentsAudioMuter(this)); |
| audio_muter_->StartMuting(); |
| } else { |
| DCHECK(audio_muter_); |
| audio_muter_->StopMuting(); |
| } |
| |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, |
| DidUpdateAudioMutingState(mute)); |
| |
| // Notification for UI updates in response to the changed muting state. |
| NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB); |
| } |
| |
| bool WebContentsImpl::IsCrashed() const { |
| return (crashed_status_ == base::TERMINATION_STATUS_PROCESS_CRASHED || |
| crashed_status_ == base::TERMINATION_STATUS_ABNORMAL_TERMINATION || |
| crashed_status_ == base::TERMINATION_STATUS_PROCESS_WAS_KILLED || |
| #if defined(OS_CHROMEOS) |
| crashed_status_ == |
| base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM || |
| #endif |
| crashed_status_ == base::TERMINATION_STATUS_LAUNCH_FAILED |
| ); |
| } |
| |
| void WebContentsImpl::SetIsCrashed(base::TerminationStatus status, |
| int error_code) { |
| if (status == crashed_status_) |
| return; |
| |
| crashed_status_ = status; |
| crashed_error_code_ = error_code; |
| NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB); |
| } |
| |
| base::TerminationStatus WebContentsImpl::GetCrashedStatus() const { |
| return crashed_status_; |
| } |
| |
| bool WebContentsImpl::IsBeingDestroyed() const { |
| return is_being_destroyed_; |
| } |
| |
| void WebContentsImpl::NotifyNavigationStateChanged( |
| InvalidateTypes changed_flags) { |
| // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466285 |
| // is fixed. |
| tracked_objects::ScopedTracker tracking_profile( |
| FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| "466285 WebContentsImpl::NotifyNavigationStateChanged")); |
| // Notify the media observer of potential audibility changes. |
| if (changed_flags & INVALIDATE_TYPE_TAB) { |
| media_web_contents_observer_->MaybeUpdateAudibleState(); |
| } |
| |
| if (delegate_) |
| delegate_->NavigationStateChanged(this, changed_flags); |
| } |
| |
| base::TimeTicks WebContentsImpl::GetLastActiveTime() const { |
| return last_active_time_; |
| } |
| |
| void WebContentsImpl::SetLastActiveTime(base::TimeTicks last_active_time) { |
| last_active_time_ = last_active_time; |
| } |
| |
| void WebContentsImpl::WasShown() { |
| controller_.SetActive(true); |
| |
| for (RenderWidgetHostView* view : GetRenderWidgetHostViewsInTree()) { |
| if (view) { |
| view->Show(); |
| #if defined(OS_MACOSX) |
| view->SetActive(true); |
| #endif |
| } |
| } |
| |
| last_active_time_ = base::TimeTicks::Now(); |
| |
| // The resize rect might have changed while this was inactive -- send the new |
| // one to make sure it's up to date. |
| RenderViewHostImpl* rvh = GetRenderViewHost(); |
| if (rvh) { |
| rvh->GetWidget()->ResizeRectChanged( |
| GetRootWindowResizerRect(rvh->GetWidget())); |
| } |
| |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasShown()); |
| |
| should_normally_be_visible_ = true; |
| } |
| |
| void WebContentsImpl::WasHidden() { |
| // If there are entities capturing screenshots or video (e.g., mirroring), |
| // don't activate the "disable rendering" optimization. |
| if (capturer_count_ == 0) { |
| // |GetRenderViewHost()| can be NULL if the user middle clicks a link to |
| // open a tab in the background, then closes the tab before selecting it. |
| // This is because closing the tab calls WebContentsImpl::Destroy(), which |
| // removes the |GetRenderViewHost()|; then when we actually destroy the |
| // window, OnWindowPosChanged() notices and calls WasHidden() (which |
| // calls us). |
| for (RenderWidgetHostView* view : GetRenderWidgetHostViewsInTree()) { |
| if (view) |
| view->Hide(); |
| } |
| } |
| |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasHidden()); |
| |
| should_normally_be_visible_ = false; |
| } |
| |
| void WebContentsImpl::WasOccluded() { |
| if (capturer_count_ > 0) |
| return; |
| |
| for (RenderWidgetHostView* view : GetRenderWidgetHostViewsInTree()) { |
| if (view) |
| view->WasOccluded(); |
| } |
| } |
| |
| void WebContentsImpl::WasUnOccluded() { |
| for (RenderWidgetHostView* view : GetRenderWidgetHostViewsInTree()) { |
| if (view) |
| view->WasUnOccluded(); |
| } |
| } |
| |
| bool WebContentsImpl::NeedToFireBeforeUnload() { |
| // TODO(creis): Should we fire even for interstitial pages? |
| return WillNotifyDisconnection() && !ShowingInterstitialPage() && |
| !GetRenderViewHost()->SuddenTerminationAllowed(); |
| } |
| |
| void WebContentsImpl::DispatchBeforeUnload(bool for_cross_site_transition) { |
| GetMainFrame()->DispatchBeforeUnload(for_cross_site_transition); |
| } |
| |
| void WebContentsImpl::AttachToOuterWebContentsFrame( |
| WebContents* outer_web_contents, |
| RenderFrameHost* outer_contents_frame) { |
| CHECK(BrowserPluginGuestMode::UseCrossProcessFramesForGuests()); |
| // Create a link to our outer WebContents. |
| node_.reset(new WebContentsTreeNode()); |
| node_->ConnectToOuterWebContents( |
| static_cast<WebContentsImpl*>(outer_web_contents), |
| static_cast<RenderFrameHostImpl*>(outer_contents_frame)); |
| |
| DCHECK(outer_contents_frame); |
| |
| // Create a proxy in top-level RenderFrameHostManager, pointing to the |
| // SiteInstance of the outer WebContents. The proxy will be used to send |
| // postMessage to the inner WebContents. |
| GetRenderManager()->CreateOuterDelegateProxy( |
| outer_contents_frame->GetSiteInstance(), |
| static_cast<RenderFrameHostImpl*>(outer_contents_frame)); |
| |
| GetRenderManager()->SetRWHViewForInnerContents( |
| GetRenderManager()->GetRenderWidgetHostView()); |
| } |
| |
| void WebContentsImpl::Stop() { |
| frame_tree_.ForEach(base::Bind(&FrameTreeNode::StopLoading)); |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, NavigationStopped()); |
| } |
| |
| WebContents* WebContentsImpl::Clone() { |
| // We use our current SiteInstance since the cloned entry will use it anyway. |
| // We pass our own opener so that the cloned page can access it if it was set |
| // before. |
| CreateParams create_params(GetBrowserContext(), GetSiteInstance()); |
| create_params.initial_size = GetContainerBounds().size(); |
| WebContentsImpl* tc = |
| CreateWithOpener(create_params, frame_tree_.root()->opener()); |
| tc->GetController().CopyStateFrom(controller_); |
| FOR_EACH_OBSERVER(WebContentsObserver, |
| observers_, |
| DidCloneToNewWebContents(this, tc)); |
| return tc; |
| } |
| |
| void WebContentsImpl::Observe(int type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| switch (type) { |
| case NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: { |
| RenderWidgetHost* host = Source<RenderWidgetHost>(source).ptr(); |
| RenderWidgetHostView* view = host->GetView(); |
| if (view == GetFullscreenRenderWidgetHostView()) { |
| // We cannot just call view_->RestoreFocus() here. On some platforms, |
| // attempting to focus the currently-invisible WebContentsView will be |
| // flat-out ignored. Therefore, this boolean is used to track whether |
| // we will request focus after the fullscreen widget has been |
| // destroyed. |
| fullscreen_widget_had_focus_at_shutdown_ = (view && view->HasFocus()); |
| } else { |
| for (PendingWidgetViews::iterator i = pending_widget_views_.begin(); |
| i != pending_widget_views_.end(); ++i) { |
| if (host->GetView() == i->second) { |
| pending_widget_views_.erase(i); |
| break; |
| } |
| } |
| } |
| break; |
| } |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| WebContents* WebContentsImpl::GetWebContents() { |
| return this; |
| } |
| |
| void WebContentsImpl::Init(const WebContents::CreateParams& params) { |
| // This is set before initializing the render manager since |
| // RenderFrameHostManager::Init calls back into us via its delegate to ask if |
| // it should be hidden. |
| should_normally_be_visible_ = !params.initially_hidden; |
| |
| // The routing ids must either all be set or all be unset. |
| DCHECK((params.routing_id == MSG_ROUTING_NONE && |
| params.main_frame_routing_id == MSG_ROUTING_NONE && |
| params.main_frame_widget_routing_id == MSG_ROUTING_NONE) || |
| (params.routing_id != MSG_ROUTING_NONE && |
| params.main_frame_routing_id != MSG_ROUTING_NONE && |
| params.main_frame_widget_routing_id != MSG_ROUTING_NONE)); |
| |
| scoped_refptr<SiteInstance> site_instance = params.site_instance; |
| if (!site_instance) |
| site_instance = SiteInstance::Create(params.browser_context); |
| |
| // A main RenderFrameHost always has a RenderWidgetHost, since it is always a |
| // local root by definition. |
| // TODO(avi): Once RenderViewHostImpl has-a RenderWidgetHostImpl, it will no |
| // longer be necessary to eagerly grab a routing ID for the view. |
| // https://crbug.com/545684 |
| int32_t view_routing_id = params.routing_id; |
| int32_t main_frame_widget_routing_id = params.main_frame_widget_routing_id; |
| if (main_frame_widget_routing_id == MSG_ROUTING_NONE) { |
| view_routing_id = main_frame_widget_routing_id = |
| site_instance->GetProcess()->GetNextRoutingID(); |
| } |
| |
| GetRenderManager()->Init(site_instance.get(), view_routing_id, |
| params.main_frame_routing_id, |
| main_frame_widget_routing_id); |
| frame_tree_.root()->SetFrameName(params.main_frame_name); |
| |
| WebContentsViewDelegate* delegate = |
| GetContentClient()->browser()->GetWebContentsViewDelegate(this); |
| |
| #if defined(MOJO_SHELL_CLIENT) |
| if (MojoShellConnection::Get() && |
| base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kUseMusInRenderer)) { |
| mus::Window* mus_window = aura::GetMusWindow(params.context); |
| if (mus_window) { |
| view_.reset(new WebContentsViewMus(mus_window, this, delegate, |
| &render_view_host_delegate_view_)); |
| } |
| } |
| #endif |
| |
| if (!view_) { |
| view_.reset(CreateWebContentsView(this, delegate, |
| &render_view_host_delegate_view_)); |
| } |
| |
| if (browser_plugin_guest_ && |
| !BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) { |
| view_.reset(new WebContentsViewGuest(this, browser_plugin_guest_.get(), |
| std::move(view_), |
| &render_view_host_delegate_view_)); |
| } |
| CHECK(render_view_host_delegate_view_); |
| CHECK(view_.get()); |
| |
| gfx::Size initial_size = params.initial_size; |
| view_->CreateView(initial_size, params.context); |
| |
| #if defined(ENABLE_PLUGINS) |
| plugin_content_origin_whitelist_.reset( |
| new PluginContentOriginWhitelist(this)); |
| #endif |
| |
| registrar_.Add(this, |
| NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, |
| NotificationService::AllBrowserContextsAndSources()); |
| |
| screen_orientation_dispatcher_host_.reset( |
| new ScreenOrientationDispatcherHostImpl(this)); |
| |
| manifest_manager_host_.reset(new ManifestManagerHost(this)); |
| |
| #if defined(OS_ANDROID) && !defined(USE_AURA) |
| date_time_chooser_.reset(new DateTimeChooserAndroid()); |
| #endif |
| |
| // BrowserPluginGuest::Init needs to be called after this WebContents has |
| // a RenderWidgetHostViewGuest. That is, |view_->CreateView| above. |
| if (browser_plugin_guest_) |
| browser_plugin_guest_->Init(); |
| |
| for (size_t i = 0; i < g_created_callbacks.Get().size(); i++) |
| g_created_callbacks.Get().at(i).Run(this); |
| |
| // If the WebContents creation was renderer-initiated, it means that the |
| // corresponding RenderView and main RenderFrame have already been created. |
| // Ensure observers are notified about this. |
| if (params.renderer_initiated_creation) { |
| GetRenderViewHost()->GetWidget()->set_renderer_initialized(true); |
| RenderViewCreated(GetRenderViewHost()); |
| GetRenderManager()->current_frame_host()->SetRenderFrameCreated(true); |
| } |
| |
| // Ensure that observers are notified of the creation of this WebContents's |
| // main RenderFrameHost. It must be done here for main frames, since the |
| // NotifySwappedFromRenderManager expects view_ to already be created and that |
| // happens after RenderFrameHostManager::Init. |
| NotifySwappedFromRenderManager( |
| nullptr, GetRenderManager()->current_frame_host(), true); |
| } |
| |
| void WebContentsImpl::OnWebContentsDestroyed(WebContentsImpl* web_contents) { |
| RemoveDestructionObserver(web_contents); |
| |
| // Clear a pending contents that has been closed before being shown. |
| for (PendingContents::iterator iter = pending_contents_.begin(); |
| iter != pending_contents_.end(); |
| ++iter) { |
| if (iter->second != web_contents) |
| continue; |
| pending_contents_.erase(iter); |
| return; |
| } |
| NOTREACHED(); |
| } |
| |
| void WebContentsImpl::AddDestructionObserver(WebContentsImpl* web_contents) { |
| if (!ContainsKey(destruction_observers_, web_contents)) { |
| destruction_observers_[web_contents] = |
| new DestructionObserver(this, web_contents); |
| } |
| } |
| |
| void WebContentsImpl::RemoveDestructionObserver(WebContentsImpl* web_contents) { |
| DestructionObservers::iterator iter = |
| destruction_observers_.find(web_contents); |
| if (iter != destruction_observers_.end()) { |
| delete destruction_observers_[web_contents]; |
| destruction_observers_.erase(iter); |
| } |
| } |
| |
| void WebContentsImpl::AddObserver(WebContentsObserver* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void WebContentsImpl::RemoveObserver(WebContentsObserver* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| std::set<RenderWidgetHostView*> |
| WebContentsImpl::GetRenderWidgetHostViewsInTree() { |
| std::set<RenderWidgetHostView*> set; |
| if (ShowingInterstitialPage()) { |
| set.insert(GetRenderWidgetHostView()); |
| } else { |
| ForEachFrame( |
| base::Bind(&AddRenderWidgetHostViewToSet, base::Unretained(&set))); |
| } |
| return set; |
| } |
| |
| void WebContentsImpl::Activate() { |
| if (delegate_) |
| delegate_->ActivateContents(this); |
| } |
| |
| void WebContentsImpl::LostCapture(RenderWidgetHostImpl* render_widget_host) { |
| if (!RenderViewHostImpl::From(render_widget_host)) |
| return; |
| |
| if (delegate_) |
| delegate_->LostCapture(); |
| } |
| |
| void WebContentsImpl::RenderWidgetCreated( |
| RenderWidgetHostImpl* render_widget_host) { |
| created_widgets_.insert(render_widget_host); |
| } |
| |
| void WebContentsImpl::RenderWidgetDeleted( |
| RenderWidgetHostImpl* render_widget_host) { |
| // Note that |is_being_destroyed_| can be true at this point as |
| // ~WebContentsImpl() calls RFHM::ClearRFHsPendingShutdown(), which might lead |
| // us here. |
| created_widgets_.erase(render_widget_host); |
| |
| if (is_being_destroyed_) |
| return; |
| |
| if (render_widget_host && |
| render_widget_host->GetRoutingID() == fullscreen_widget_routing_id_) { |
| if (delegate_ && delegate_->EmbedsFullscreenWidget()) |
| delegate_->ExitFullscreenModeForTab(this); |
| FOR_EACH_OBSERVER(WebContentsObserver, |
| observers_, |
| DidDestroyFullscreenWidget( |
| fullscreen_widget_routing_id_)); |
| fullscreen_widget_routing_id_ = MSG_ROUTING_NONE; |
| if (fullscreen_widget_had_focus_at_shutdown_) |
| view_->RestoreFocus(); |
| } |
| } |
| |
| void WebContentsImpl::RenderWidgetGotFocus( |
| RenderWidgetHostImpl* render_widget_host) { |
| // Notify the observers if an embedded fullscreen widget was focused. |
| if (delegate_ && render_widget_host && delegate_->EmbedsFullscreenWidget() && |
| render_widget_host->GetView() == GetFullscreenRenderWidgetHostView()) { |
| NotifyWebContentsFocused(); |
| } |
| } |
| |
| void WebContentsImpl::RenderWidgetWasResized( |
| RenderWidgetHostImpl* render_widget_host, |
| bool width_changed) { |
| RenderFrameHostImpl* rfh = GetMainFrame(); |
| if (!rfh || render_widget_host != rfh->GetRenderWidgetHost()) |
| return; |
| |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, |
| MainFrameWasResized(width_changed)); |
| } |
| |
| void WebContentsImpl::ScreenInfoChanged() { |
| if (browser_plugin_embedder_) |
| browser_plugin_embedder_->ScreenInfoChanged(); |
| } |
| |
| bool WebContentsImpl::PreHandleKeyboardEvent( |
| const NativeWebKeyboardEvent& event, |
| bool* is_keyboard_shortcut) { |
| return delegate_ && |
| delegate_->PreHandleKeyboardEvent(this, event, is_keyboard_shortcut); |
| } |
| |
| void WebContentsImpl::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) { |
| if (browser_plugin_embedder_ && |
| browser_plugin_embedder_->HandleKeyboardEvent(event)) { |
| return; |
| } |
| if (delegate_) |
| delegate_->HandleKeyboardEvent(this, event); |
| } |
| |
| bool WebContentsImpl::HandleWheelEvent( |
| const blink::WebMouseWheelEvent& event) { |
| #if !defined(OS_MACOSX) |
| // On platforms other than Mac, control+mousewheel may change zoom. On Mac, |
| // this isn't done for two reasons: |
| // -the OS already has a gesture to do this through pinch-zoom |
| // -if a user starts an inertial scroll, let's go, and presses control |
| // (i.e. control+tab) then the OS's buffered scroll events will come in |
| // with control key set which isn't what the user wants |
| if (delegate_ && event.wheelTicksY && |
| (event.modifiers & blink::WebInputEvent::ControlKey) && |
| !event.canScroll) { |
| // Count only integer cumulative scrolls as zoom events; this handles |
| // smooth scroll and regular scroll device behavior. |
| zoom_scroll_remainder_ += event.wheelTicksY; |
| int whole_zoom_scroll_remainder_ = std::lround(zoom_scroll_remainder_); |
| zoom_scroll_remainder_ -= whole_zoom_scroll_remainder_; |
| if (whole_zoom_scroll_remainder_ != 0) { |
| delegate_->ContentsZoomChange(whole_zoom_scroll_remainder_ > 0); |
| } |
| return true; |
| } |
| #endif |
| return false; |
| } |
| |
| bool WebContentsImpl::PreHandleGestureEvent( |
| const blink::WebGestureEvent& event) { |
| return delegate_ && delegate_->PreHandleGestureEvent(this, event); |
| } |
| |
| RenderWidgetHostInputEventRouter* WebContentsImpl::GetInputEventRouter() { |
| if (!is_being_destroyed_ && GetOuterWebContents()) |
| return GetOuterWebContents()->GetInputEventRouter(); |
| |
| if (!rwh_input_event_router_.get() && !is_being_destroyed_) |
| rwh_input_event_router_.reset(new RenderWidgetHostInputEventRouter); |
| return rwh_input_event_router_.get(); |
| } |
| |
| void WebContentsImpl::ReplicatePageFocus(bool is_focused) { |
| // Focus loss may occur while this WebContents is being destroyed. Don't |
| // send the message in this case, as the main frame's RenderFrameHost and |
| // other state has already been cleared. |
| if (is_being_destroyed_) |
| return; |
| |
| frame_tree_.ReplicatePageFocus(is_focused); |
| } |
| |
| RenderWidgetHostImpl* WebContentsImpl::GetFocusedRenderWidgetHost( |
| RenderWidgetHostImpl* receiving_widget) { |
| if (!SiteIsolationPolicy::AreCrossProcessFramesPossible()) |
| return receiving_widget; |
| |
| // Events for widgets other than the main frame (e.g., popup menus) should be |
| // forwarded directly to the widget they arrived on. |
| if (receiving_widget != GetMainFrame()->GetRenderWidgetHost()) |
| return receiving_widget; |
| |
| FrameTreeNode* focused_frame = frame_tree_.GetFocusedFrame(); |
| if (!focused_frame) |
| return receiving_widget; |
| |
| // The view may be null if a subframe's renderer process has crashed while |
| // the subframe has focus. Drop the event in that case. Do not give |
| // it to the main frame, so that the user doesn't unexpectedly type into the |
| // wrong frame if a focused subframe renderer crashes while they type. |
| RenderWidgetHostView* view = focused_frame->current_frame_host()->GetView(); |
| if (!view) |
| return nullptr; |
| |
| return RenderWidgetHostImpl::From(view->GetRenderWidgetHost()); |
| } |
| |
| void WebContentsImpl::EnterFullscreenMode(const GURL& origin) { |
| // This method is being called to enter renderer-initiated fullscreen mode. |
| // Make sure any existing fullscreen widget is shut down first. |
| RenderWidgetHostView* const widget_view = GetFullscreenRenderWidgetHostView(); |
| if (widget_view) { |
| RenderWidgetHostImpl::From(widget_view->GetRenderWidgetHost()) |
| ->ShutdownAndDestroyWidget(true); |
| } |
| |
| if (delegate_) |
| delegate_->EnterFullscreenModeForTab(this, origin); |
| |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, |
| DidToggleFullscreenModeForTab(IsFullscreenForCurrentTab( |
| GetRenderViewHost()->GetWidget()))); |
| } |
| |
| void WebContentsImpl::ExitFullscreenMode() { |
| // This method is being called to leave renderer-initiated fullscreen mode. |
| // Make sure any existing fullscreen widget is shut down first. |
| RenderWidgetHostView* const widget_view = GetFullscreenRenderWidgetHostView(); |
| if (widget_view) { |
| RenderWidgetHostImpl::From(widget_view->GetRenderWidgetHost()) |
| ->ShutdownAndDestroyWidget(true); |
| } |
| |
| #if defined(OS_ANDROID) |
| ContentVideoView* video_view = ContentVideoView::GetInstance(); |
| if (video_view != NULL) |
| video_view->OnExitFullscreen(); |
| #endif |
| |
| if (delegate_) |
| delegate_->ExitFullscreenModeForTab(this); |
| |
| // Ensure web contents exit fullscreen state by sending a resize message, |
| // which includes the fullscreen state. This is required for the situation |
| // of the browser moving the view into a fullscreen state "browser fullscreen" |
| // and then the contents entering "tab fullscreen". Exiting the contents |
| // "tab fullscreen" then won't have the side effect of the view resizing, |
| // hence the explicit call here is required. |
| if (RenderWidgetHostView* rwh_view = GetRenderWidgetHostView()) { |
| if (RenderWidgetHost* render_widget_host = rwh_view->GetRenderWidgetHost()) |
| render_widget_host->WasResized(); |
| } |
| |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, |
| DidToggleFullscreenModeForTab(IsFullscreenForCurrentTab( |
| GetRenderViewHost()->GetWidget()))); |
| } |
| |
| bool WebContentsImpl::IsFullscreenForCurrentTab( |
| RenderWidgetHostImpl* render_widget_host) const { |
| if (!RenderViewHostImpl::From(render_widget_host)) |
| return false; |
| |
| return delegate_ ? delegate_->IsFullscreenForTabOrPending(this) : false; |
| } |
| |
| blink::WebDisplayMode WebContentsImpl::GetDisplayMode( |
| RenderWidgetHostImpl* render_widget_host) const { |
| if (!RenderViewHostImpl::From(render_widget_host)) |
| return blink::WebDisplayModeBrowser; |
| |
| return delegate_ ? delegate_->GetDisplayMode(this) |
| : blink::WebDisplayModeBrowser; |
| } |
| |
| void WebContentsImpl::RequestToLockMouse( |
| RenderWidgetHostImpl* render_widget_host, |
| bool user_gesture, |
| bool last_unlocked_by_target) { |
| if (render_widget_host != GetRenderViewHost()->GetWidget()) { |
| render_widget_host->GotResponseToLockMouseRequest(false); |
| return; |
| } |
| |
| if (delegate_) |
| delegate_->RequestToLockMouse(this, user_gesture, last_unlocked_by_target); |
| else |
| GotResponseToLockMouseRequest(false); |
| } |
| |
| void WebContentsImpl::LostMouseLock(RenderWidgetHostImpl* render_widget_host) { |
| if (!RenderViewHostImpl::From(render_widget_host)) |
| return; |
| |
| if (delegate_) |
| delegate_->LostMouseLock(); |
| } |
| |
| void WebContentsImpl::ForwardCompositorProto( |
| RenderWidgetHostImpl* render_widget_host, |
| const std::vector<uint8_t>& proto) { |
| if (render_widget_host != GetRenderViewHost()->GetWidget()) |
| return; |
| |
| if (delegate_) |
| delegate_->ForwardCompositorProto(proto); |
| } |
| |
| void WebContentsImpl::CreateNewWindow( |
| SiteInstance* source_site_instance, |
| int32_t route_id, |
| int32_t main_frame_route_id, |
| int32_t main_frame_widget_route_id, |
| const ViewHostMsg_CreateWindow_Params& params, |
| SessionStorageNamespace* session_storage_namespace) { |
| // We usually create the new window in the same BrowsingInstance (group of |
| // script-related windows), by passing in the current SiteInstance. However, |
| // if the opener is being suppressed (in a non-guest), we create a new |
| // SiteInstance in its own BrowsingInstance. |
| bool is_guest = BrowserPluginGuest::IsGuest(this); |
| |
| if (is_guest && BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) { |
| // TODO(lazyboy): CreateNewWindow doesn't work for OOPIF-based <webview> |
| // yet. |
| NOTREACHED(); |
| } |
| |
| // If the opener is to be suppressed, the new window can be in any process. |
| // Since routing ids are process specific, we must not have one passed in |
| // as argument here. |
| DCHECK(!params.opener_suppressed || route_id == MSG_ROUTING_NONE); |
| |
| scoped_refptr<SiteInstance> site_instance = |
| params.opener_suppressed && !is_guest |
| ? SiteInstance::CreateForURL(GetBrowserContext(), params.target_url) |
| : source_site_instance; |
| |
| // A message to create a new window can only come from a process for a frame |
| // in this WebContents' FrameTree. If any other process sends the request, it |
| // is invalid and the process must be terminated. |
| int render_process_id = source_site_instance->GetProcess()->GetID(); |
| bool did_match_process = false; |
| frame_tree_.ForEach( |
| base::Bind(&FindMatchingProcess, render_process_id, &did_match_process)); |
| if (!did_match_process) { |
| RenderProcessHost* rph = source_site_instance->GetProcess(); |
| base::ProcessHandle process_handle = rph->GetHandle(); |
| if (process_handle != base::kNullProcessHandle) { |
| RecordAction( |
| base::UserMetricsAction("Terminate_ProcessMismatch_CreateNewWindow")); |
| rph->Shutdown(RESULT_CODE_KILLED, false); |
| } |
| return; |
| } |
| |
| // We must assign the SessionStorageNamespace before calling Init(). |
| // |
| // http://crbug.com/142685 |
| const std::string& partition_id = |
| GetContentClient()->browser()-> |
| GetStoragePartitionIdForSite(GetBrowserContext(), |
| site_instance->GetSiteURL()); |
| StoragePartition* partition = BrowserContext::GetStoragePartition( |
| GetBrowserContext(), site_instance.get()); |
| DOMStorageContextWrapper* dom_storage_context = |
| static_cast<DOMStorageContextWrapper*>(partition->GetDOMStorageContext()); |
| SessionStorageNamespaceImpl* session_storage_namespace_impl = |
| static_cast<SessionStorageNamespaceImpl*>(session_storage_namespace); |
| CHECK(session_storage_namespace_impl->IsFromContext(dom_storage_context)); |
| |
| if (delegate_ && |
| !delegate_->ShouldCreateWebContents( |
| this, route_id, main_frame_route_id, main_frame_widget_route_id, |
| params.window_container_type, params.frame_name, params.target_url, |
| partition_id, session_storage_namespace)) { |
| if (route_id != MSG_ROUTING_NONE && |
| !RenderViewHost::FromID(render_process_id, route_id)) { |
| // If the embedder didn't create a WebContents for this route, we need to |
| // delete the RenderView that had already been created. |
| Send(new ViewMsg_Close(route_id)); |
| } |
| GetRenderViewHost()->GetProcess()->ResumeRequestsForView(route_id); |
| return; |
| } |
| |
| // Create the new web contents. This will automatically create the new |
| // WebContentsView. In the future, we may want to create the view separately. |
| CreateParams create_params(GetBrowserContext(), site_instance.get()); |
| create_params.routing_id = route_id; |
| create_params.main_frame_routing_id = main_frame_route_id; |
| create_params.main_frame_widget_routing_id = main_frame_widget_route_id; |
| create_params.main_frame_name = params.frame_name; |
| create_params.opener_render_process_id = render_process_id; |
| create_params.opener_render_frame_id = params.opener_render_frame_id; |
| create_params.opener_suppressed = params.opener_suppressed; |
| if (params.disposition == NEW_BACKGROUND_TAB) |
| create_params.initially_hidden = true; |
| create_params.renderer_initiated_creation = |
| main_frame_route_id != MSG_ROUTING_NONE; |
| |
| WebContentsImpl* new_contents = NULL; |
| if (!is_guest) { |
| create_params.context = view_->GetNativeView(); |
| create_params.initial_size = GetContainerBounds().size(); |
| new_contents = static_cast<WebContentsImpl*>( |
| WebContents::Create(create_params)); |
| } else { |
| new_contents = GetBrowserPluginGuest()->CreateNewGuestWindow(create_params); |
| } |
| new_contents->GetController().SetSessionStorageNamespace( |
| partition_id, |
| session_storage_namespace); |
| |
| // If the new frame has a name, make sure any SiteInstances that can find |
| // this named frame have proxies for it. Must be called after |
| // SetSessionStorageNamespace, since this calls CreateRenderView, which uses |
| // GetSessionStorageNamespace. |
| if (!params.frame_name.empty()) |
| new_contents->GetRenderManager()->CreateProxiesForNewNamedFrame(); |
| |
| // Save the window for later if we're not suppressing the opener (since it |
| // will be shown immediately). |
| if (!params.opener_suppressed) { |
| if (!is_guest) { |
| WebContentsView* new_view = new_contents->view_.get(); |
| |
| // TODO(brettw): It seems bogus that we have to call this function on the |
| // newly created object and give it one of its own member variables. |
| new_view->CreateViewForWidget( |
| new_contents->GetRenderViewHost()->GetWidget(), false); |
| } |
| // Save the created window associated with the route so we can show it |
| // later. |
| DCHECK_NE(MSG_ROUTING_NONE, route_id); |
| pending_contents_[route_id] = new_contents; |
| AddDestructionObserver(new_contents); |
| } |
| |
| if (delegate_) { |
| delegate_->WebContentsCreated( |
| this, params.opener_render_frame_id, params.frame_name, |
| params.target_url, new_contents); |
| } |
| |
| if (params.opener_suppressed) { |
| // When the opener is suppressed, the original renderer cannot access the |
| // new window. As a result, we need to show and navigate the window here. |
| bool was_blocked = false; |
| if (delegate_) { |
| gfx::Rect initial_rect; |
| delegate_->AddNewContents( |
| this, new_contents, params.disposition, initial_rect, |
| params.user_gesture, &was_blocked); |
| } |
| if (!was_blocked) { |
| OpenURLParams open_params(params.target_url, |
| Referrer(), |
| CURRENT_TAB, |
| ui::PAGE_TRANSITION_LINK, |
| true /* is_renderer_initiated */); |
| open_params.user_gesture = params.user_gesture; |
| |
| if (delegate_ && !is_guest && |
| !delegate_->ShouldResumeRequestsForCreatedWindow()) { |
| // We are in asynchronous add new contents path, delay opening url |
| new_contents->delayed_open_url_params_.reset( |
| new OpenURLParams(open_params)); |
| } else { |
| new_contents->OpenURL(open_params); |
| } |
| } |
| } |
| } |
| |
| void WebContentsImpl::CreateNewWidget(int32_t render_process_id, |
| int32_t route_id, |
| blink::WebPopupType popup_type) { |
| CreateNewWidget(render_process_id, route_id, false, popup_type); |
| } |
| |
| void WebContentsImpl::CreateNewFullscreenWidget(int32_t render_process_id, |
| int32_t route_id) { |
| CreateNewWidget(render_process_id, route_id, true, blink::WebPopupTypeNone); |
| } |
| |
| void WebContentsImpl::CreateNewWidget(int32_t render_process_id, |
| int32_t route_id, |
| bool is_fullscreen, |
| blink::WebPopupType popup_type) { |
| RenderProcessHost* process = GetRenderProcessHost(); |
| // A message to create a new widget can only come from an active process for |
| // this WebContentsImpl instance. If any other process sends the request, |
| // it is invalid and the process must be terminated. |
| bool did_match_process = false; |
| frame_tree_.ForEach( |
| base::Bind(&FindMatchingProcess, render_process_id, &did_match_process)); |
| if (!did_match_process) { |
| RenderProcessHost* rph = RenderProcessHost::FromID(render_process_id); |
| base::ProcessHandle process_handle = rph->GetHandle(); |
| if (process_handle != base::kNullProcessHandle) { |
| RecordAction( |
| base::UserMetricsAction("Terminate_ProcessMismatch_CreateNewWidget")); |
| rph->Shutdown(RESULT_CODE_KILLED, false); |
| } |
| return; |
| } |
| |
| RenderWidgetHostImpl* widget_host = |
| new RenderWidgetHostImpl(this, process, route_id, IsHidden()); |
| |
| RenderWidgetHostViewBase* widget_view = |
| static_cast<RenderWidgetHostViewBase*>( |
| view_->CreateViewForPopupWidget(widget_host)); |
| if (!widget_view) |
| return; |
| if (!is_fullscreen) { |
| // Popups should not get activated. |
| widget_view->SetPopupType(popup_type); |
| } |
| // Save the created widget associated with the route so we can show it later. |
| pending_widget_views_[route_id] = widget_view; |
| |
| #if defined(OS_MACOSX) |
| // A RenderWidgetHostViewMac has lifetime scoped to the view. We'll retain it |
| // to allow it to survive the trip without being hosted. |
| base::mac::NSObjectRetain(widget_view->GetNativeView()); |
| #endif |
| } |
| |
| void WebContentsImpl::ShowCreatedWindow(int route_id, |
| WindowOpenDisposition disposition, |
| const gfx::Rect& initial_rect, |
| bool user_gesture) { |
| WebContentsImpl* contents = GetCreatedWindow(route_id); |
| if (contents) { |
| WebContentsDelegate* delegate = GetDelegate(); |
| contents->is_resume_pending_ = true; |
| if (!delegate || delegate->ShouldResumeRequestsForCreatedWindow()) |
| contents->ResumeLoadingCreatedWebContents(); |
| |
| if (delegate) { |
| delegate->AddNewContents( |
| this, contents, disposition, initial_rect, user_gesture, NULL); |
| } |
| } |
| } |
| |
| void WebContentsImpl::ShowCreatedWidget(int route_id, |
| const gfx::Rect& initial_rect) { |
| ShowCreatedWidget(route_id, false, initial_rect); |
| } |
| |
| void WebContentsImpl::ShowCreatedFullscreenWidget(int route_id) { |
| ShowCreatedWidget(route_id, true, gfx::Rect()); |
| } |
| |
| void WebContentsImpl::ShowCreatedWidget(int route_id, |
| bool is_fullscreen, |
| const gfx::Rect& initial_rect) { |
| RenderWidgetHostViewBase* widget_host_view = |
| static_cast<RenderWidgetHostViewBase*>(GetCreatedWidget(route_id)); |
| if (!widget_host_view) |
| return; |
| |
| RenderWidgetHostView* view = NULL; |
| BrowserPluginGuest* guest = GetBrowserPluginGuest(); |
| if (guest && guest->embedder_web_contents()) { |
| view = guest->embedder_web_contents()->GetRenderWidgetHostView(); |
| } else { |
| view = GetRenderWidgetHostView(); |
| } |
| |
| if (is_fullscreen) { |
| DCHECK_EQ(MSG_ROUTING_NONE, fullscreen_widget_routing_id_); |
| view_->StoreFocus(); |
| fullscreen_widget_routing_id_ = route_id; |
| if (delegate_ && delegate_->EmbedsFullscreenWidget()) { |
| widget_host_view->InitAsChild(GetRenderWidgetHostView()->GetNativeView()); |
| delegate_->EnterFullscreenModeForTab(this, GURL()); |
| } else { |
| widget_host_view->InitAsFullscreen(view); |
| } |
| FOR_EACH_OBSERVER(WebContentsObserver, |
| observers_, |
| DidShowFullscreenWidget(route_id)); |
| if (!widget_host_view->HasFocus()) |
| widget_host_view->Focus(); |
| } else { |
| widget_host_view->InitAsPopup(view, initial_rect); |
| } |
| |
| RenderWidgetHostImpl* render_widget_host_impl = |
| RenderWidgetHostImpl::From(widget_host_view->GetRenderWidgetHost()); |
| render_widget_host_impl->Init(); |
| // Only allow privileged mouse lock for fullscreen render widget, which is |
| // used to implement Pepper Flash fullscreen. |
| render_widget_host_impl->set_allow_privileged_mouse_lock(is_fullscreen); |
| |
| #if defined(OS_MACOSX) |
| // A RenderWidgetHostViewMac has lifetime scoped to the view. Now that it's |
| // properly embedded (or purposefully ignored) we can release the retain we |
| // took in CreateNewWidget(). |
| base::mac::NSObjectRelease(widget_host_view->GetNativeView()); |
| #endif |
| } |
| |
| WebContentsImpl* WebContentsImpl::GetCreatedWindow(int route_id) { |
| PendingContents::iterator iter = pending_contents_.find(route_id); |
| |
| // Certain systems can block the creation of new windows. If we didn't succeed |
| // in creating one, just return NULL. |
| if (iter == pending_contents_.end()) { |
| return NULL; |
| } |
| |
| WebContentsImpl* new_contents = iter->second; |
| pending_contents_.erase(route_id); |
| RemoveDestructionObserver(new_contents); |
| |
| // Don't initialize the guest WebContents immediately. |
| if (BrowserPluginGuest::IsGuest(new_contents)) |
| return new_contents; |
| |
| if (!new_contents->GetRenderProcessHost()->HasConnection() || |
| !new_contents->GetRenderViewHost()->GetWidget()->GetView()) |
| return NULL; |
| |
| return new_contents; |
| } |
| |
| RenderWidgetHostView* WebContentsImpl::GetCreatedWidget(int route_id) { |
| PendingWidgetViews::iterator iter = pending_widget_views_.find(route_id); |
| if (iter == pending_widget_views_.end()) { |
| DCHECK(false); |
| return NULL; |
| } |
| |
| RenderWidgetHostView* widget_host_view = iter->second; |
| pending_widget_views_.erase(route_id); |
| |
| RenderWidgetHost* widget_host = widget_host_view->GetRenderWidgetHost(); |
| if (!widget_host->GetProcess()->HasConnection()) { |
| // The view has gone away or the renderer crashed. Nothing to do. |
| return NULL; |
| } |
| |
| return widget_host_view; |
| } |
| |
| void WebContentsImpl::RequestMediaAccessPermission( |
| const MediaStreamRequest& request, |
| const MediaResponseCallback& callback) { |
| if (delegate_) { |
| delegate_->RequestMediaAccessPermission(this, request, callback); |
| } else { |
| callback.Run(MediaStreamDevices(), |
| MEDIA_DEVICE_FAILED_DUE_TO_SHUTDOWN, |
| scoped_ptr<MediaStreamUI>()); |
| } |
| } |
| |
| bool WebContentsImpl::CheckMediaAccessPermission(const GURL& security_origin, |
| MediaStreamType type) { |
| DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE || |
| type == MEDIA_DEVICE_VIDEO_CAPTURE); |
| return delegate_ && |
| delegate_->CheckMediaAccessPermission(this, security_origin, type); |
| } |
| |
| SessionStorageNamespace* WebContentsImpl::GetSessionStorageNamespace( |
| SiteInstance* instance) { |
| return controller_.GetSessionStorageNamespace(instance); |
| } |
| |
| SessionStorageNamespaceMap WebContentsImpl::GetSessionStorageNamespaceMap() { |
| return controller_.GetSessionStorageNamespaceMap(); |
| } |
| |
| FrameTree* WebContentsImpl::GetFrameTree() { |
| return &frame_tree_; |
| } |
| |
| void WebContentsImpl::SetIsVirtualKeyboardRequested(bool requested) { |
| virtual_keyboard_requested_ = requested; |
| } |
| |
| bool WebContentsImpl::IsVirtualKeyboardRequested() { |
| return virtual_keyboard_requested_; |
| } |
| |
| AccessibilityMode WebContentsImpl::GetAccessibilityMode() const { |
| return accessibility_mode_; |
| } |
| |
| void WebContentsImpl::AccessibilityEventReceived( |
| const std::vector<AXEventNotificationDetails>& details) { |
| FOR_EACH_OBSERVER( |
| WebContentsObserver, observers_, AccessibilityEventReceived(details)); |
| } |
| |
| RenderFrameHost* WebContentsImpl::GetGuestByInstanceID( |
| RenderFrameHost* render_frame_host, |
| int browser_plugin_instance_id) { |
| BrowserPluginGuestManager* guest_manager = |
| GetBrowserContext()->GetGuestManager(); |
| if (!guest_manager) |
| return nullptr; |
| |
| WebContents* guest = guest_manager->GetGuestByInstanceID( |
| render_frame_host->GetProcess()->GetID(), browser_plugin_instance_id); |
| if (!guest) |
| return nullptr; |
| |
| return guest->GetMainFrame(); |
| } |
| |
| GeolocationServiceContext* WebContentsImpl::GetGeolocationServiceContext() { |
| return geolocation_service_context_.get(); |
| } |
| |
| WakeLockServiceContext* WebContentsImpl::GetWakeLockServiceContext() { |
| return wake_lock_service_context_.get(); |
| } |
| |
| void WebContentsImpl::OnShowValidationMessage( |
| const gfx::Rect& anchor_in_root_view, |
| const base::string16& main_text, |
| const base::string16& sub_text) { |
| if (delegate_) |
| delegate_->ShowValidationMessage( |
| this, anchor_in_root_view, main_text, sub_text); |
| } |
| |
| void WebContentsImpl::OnHideValidationMessage() { |
| if (delegate_) |
| delegate_->HideValidationMessage(this); |
| } |
| |
| void WebContentsImpl::OnMoveValidationMessage( |
| const gfx::Rect& anchor_in_root_view) { |
| if (delegate_) |
| delegate_->MoveValidationMessage(this, anchor_in_root_view); |
| } |
| |
| void WebContentsImpl::DidSendScreenRects(RenderWidgetHostImpl* rwh) { |
| if (browser_plugin_embedder_) |
| browser_plugin_embedder_->DidSendScreenRects(); |
| } |
| |
| BrowserAccessibilityManager* |
| WebContentsImpl::GetRootBrowserAccessibilityManager() { |
| RenderFrameHostImpl* rfh = GetMainFrame(); |
| return rfh ? rfh->browser_accessibility_manager() : nullptr; |
| } |
| |
| BrowserAccessibilityManager* |
| WebContentsImpl::GetOrCreateRootBrowserAccessibilityManager() { |
| RenderFrameHostImpl* rfh = GetMainFrame(); |
| return rfh ? rfh->GetOrCreateBrowserAccessibilityManager() : nullptr; |
| } |
| |
| void WebContentsImpl::MoveRangeSelectionExtent(const gfx::Point& extent) { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send(new InputMsg_MoveRangeSelectionExtent( |
| focused_frame->GetRoutingID(), extent)); |
| } |
| |
| void WebContentsImpl::SelectRange(const gfx::Point& base, |
| const gfx::Point& extent) { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send( |
| new InputMsg_SelectRange(focused_frame->GetRoutingID(), base, extent)); |
| } |
| |
| void WebContentsImpl::AdjustSelectionByCharacterOffset(int start_adjust, |
| int end_adjust) { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send(new InputMsg_AdjustSelectionByCharacterOffset( |
| focused_frame->GetRoutingID(), start_adjust, end_adjust)); |
| } |
| |
| void WebContentsImpl::UpdatePreferredSize(const gfx::Size& pref_size) { |
| const gfx::Size old_size = GetPreferredSize(); |
| preferred_size_ = pref_size; |
| OnPreferredSizeChanged(old_size); |
| } |
| |
| void WebContentsImpl::ResizeDueToAutoResize( |
| RenderWidgetHostImpl* render_widget_host, |
| const gfx::Size& new_size) { |
| if (render_widget_host != GetRenderViewHost()->GetWidget()) |
| return; |
| |
| if (delegate_) |
| delegate_->ResizeDueToAutoResize(this, new_size); |
| } |
| |
| WebContents* WebContentsImpl::OpenURL(const OpenURLParams& params) { |
| if (!delegate_) |
| return NULL; |
| |
| WebContents* new_contents = delegate_->OpenURLFromTab(this, params); |
| return new_contents; |
| } |
| |
| bool WebContentsImpl::Send(IPC::Message* message) { |
| if (!GetRenderViewHost()) { |
| delete message; |
| return false; |
| } |
| |
| return GetRenderViewHost()->Send(message); |
| } |
| |
| void WebContentsImpl::RenderFrameForInterstitialPageCreated( |
| RenderFrameHost* render_frame_host) { |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, |
| RenderFrameForInterstitialPageCreated(render_frame_host)); |
| } |
| |
| void WebContentsImpl::AttachInterstitialPage( |
| InterstitialPageImpl* interstitial_page) { |
| DCHECK(interstitial_page); |
| GetRenderManager()->set_interstitial_page(interstitial_page); |
| |
| // Cancel any visible dialogs so that they don't interfere with the |
| // interstitial. |
| CancelActiveAndPendingDialogs(); |
| |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, |
| DidAttachInterstitialPage()); |
| } |
| |
| void WebContentsImpl::DetachInterstitialPage() { |
| if (ShowingInterstitialPage()) |
| GetRenderManager()->remove_interstitial_page(); |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, |
| DidDetachInterstitialPage()); |
| } |
| |
| void WebContentsImpl::SetHistoryOffsetAndLength(int history_offset, |
| int history_length) { |
| SetHistoryOffsetAndLengthForView( |
| GetRenderViewHost(), history_offset, history_length); |
| } |
| |
| void WebContentsImpl::SetHistoryOffsetAndLengthForView( |
| RenderViewHost* render_view_host, |
| int history_offset, |
| int history_length) { |
| render_view_host->Send(new ViewMsg_SetHistoryOffsetAndLength( |
| render_view_host->GetRoutingID(), history_offset, history_length)); |
| } |
| |
| void WebContentsImpl::ReloadFocusedFrame(bool ignore_cache) { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send(new FrameMsg_Reload( |
| focused_frame->GetRoutingID(), ignore_cache)); |
| } |
| |
| void WebContentsImpl::Undo() { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send(new InputMsg_Undo(focused_frame->GetRoutingID())); |
| RecordAction(base::UserMetricsAction("Undo")); |
| } |
| |
| void WebContentsImpl::Redo() { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| focused_frame->Send(new InputMsg_Redo(focused_frame->GetRoutingID())); |
| RecordAction(base::UserMetricsAction("Redo")); |
| } |
| |
| void WebContentsImpl::Cut() { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send(new InputMsg_Cut(focused_frame->GetRoutingID())); |
| RecordAction(base::UserMetricsAction("Cut")); |
| } |
| |
| void WebContentsImpl::Copy() { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send(new InputMsg_Copy(focused_frame->GetRoutingID())); |
| RecordAction(base::UserMetricsAction("Copy")); |
| } |
| |
| void WebContentsImpl::CopyToFindPboard() { |
| #if defined(OS_MACOSX) |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| // Windows/Linux don't have the concept of a find pasteboard. |
| focused_frame->Send( |
| new InputMsg_CopyToFindPboard(focused_frame->GetRoutingID())); |
| RecordAction(base::UserMetricsAction("CopyToFindPboard")); |
| #endif |
| } |
| |
| void WebContentsImpl::Paste() { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send(new InputMsg_Paste(focused_frame->GetRoutingID())); |
| RecordAction(base::UserMetricsAction("Paste")); |
| } |
| |
| void WebContentsImpl::PasteAndMatchStyle() { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send(new InputMsg_PasteAndMatchStyle( |
| focused_frame->GetRoutingID())); |
| RecordAction(base::UserMetricsAction("PasteAndMatchStyle")); |
| } |
| |
| void WebContentsImpl::Delete() { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send(new InputMsg_Delete(focused_frame->GetRoutingID())); |
| RecordAction(base::UserMetricsAction("DeleteSelection")); |
| } |
| |
| void WebContentsImpl::SelectAll() { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send(new InputMsg_SelectAll(focused_frame->GetRoutingID())); |
| RecordAction(base::UserMetricsAction("SelectAll")); |
| } |
| |
| void WebContentsImpl::Unselect() { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send(new InputMsg_Unselect(focused_frame->GetRoutingID())); |
| RecordAction(base::UserMetricsAction("Unselect")); |
| } |
| |
| void WebContentsImpl::Replace(const base::string16& word) { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send(new InputMsg_Replace( |
| focused_frame->GetRoutingID(), word)); |
| } |
| |
| void WebContentsImpl::ReplaceMisspelling(const base::string16& word) { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send(new InputMsg_ReplaceMisspelling( |
| focused_frame->GetRoutingID(), word)); |
| } |
| |
| void WebContentsImpl::NotifyContextMenuClosed( |
| const CustomContextMenuContext& context) { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send(new FrameMsg_ContextMenuClosed( |
| focused_frame->GetRoutingID(), context)); |
| } |
| |
| void WebContentsImpl::ExecuteCustomContextMenuCommand( |
| int action, const CustomContextMenuContext& context) { |
| RenderFrameHost* focused_frame = GetFocusedFrame(); |
| if (!focused_frame) |
| return; |
| |
| focused_frame->Send(new FrameMsg_CustomContextMenuAction( |
| focused_frame->GetRoutingID(), context, action)); |
| } |
| |
| gfx::NativeView WebContentsImpl::GetNativeView() { |
| return view_->GetNativeView(); |
| } |
| |
| gfx::NativeView WebContentsImpl::GetContentNativeView() { |
| return view_->GetContentNativeView(); |
| } |
| |
| gfx::NativeWindow WebContentsImpl::GetTopLevelNativeWindow() { |
| return view_->GetTopLevelNativeWindow(); |
| } |
| |
| gfx::Rect WebContentsImpl::GetViewBounds() { |
| return view_->GetViewBounds(); |
| } |
| |
| gfx::Rect WebContentsImpl::GetContainerBounds() { |
| gfx::Rect rv; |
| view_->GetContainerBounds(&rv); |
| return rv; |
| } |
| |
| DropData* WebContentsImpl::GetDropData() { |
| return view_->GetDropData(); |
| } |
| |
| void WebContentsImpl::Focus() { |
| view_->Focus(); |
| } |
| |
| void WebContentsImpl::SetInitialFocus() { |
| view_->SetInitialFocus(); |
| } |
| |
| void WebContentsImpl::StoreFocus() { |
| view_->StoreFocus(); |
| } |
| |
| void WebContentsImpl::RestoreFocus() { |
| view_->RestoreFocus(); |
| } |
| |
| void WebContentsImpl::FocusThroughTabTraversal(bool reverse) { |
| if (ShowingInterstitialPage()) { |
| GetRenderManager()->interstitial_page()->FocusThroughTabTraversal(reverse); |
| return; |
| } |
| RenderWidgetHostView* const fullscreen_view = |
| GetFullscreenRenderWidgetHostView(); |
| if (fullscreen_view) { |
| fullscreen_view->Focus(); |
| return; |
| } |
| GetRenderViewHost()->SetInitialFocus(reverse); |
| } |
| |
| bool WebContentsImpl::ShowingInterstitialPage() const { |
| return GetRenderManager()->interstitial_page() != NULL; |
| } |
| |
| InterstitialPage* WebContentsImpl::GetInterstitialPage() const { |
| return GetRenderManager()->interstitial_page(); |
| } |
| |
| bool WebContentsImpl::IsSavable() { |
| // WebKit creates Document object when MIME type is application/xhtml+xml, |
| // so we also support this MIME type. |
| return contents_mime_type_ == "text/html" || |
| contents_mime_type_ == "text/xml" || |
| contents_mime_type_ == "application/xhtml+xml" || |
| contents_mime_type_ == "text/plain" || |
| contents_mime_type_ == "text/css" || |
| mime_util::IsSupportedJavascriptMimeType(contents_mime_type_); |
| } |
| |
| void WebContentsImpl::OnSavePage() { |
| // If we can not save the page, try to download it. |
| if (!IsSavable()) { |
| RecordDownloadSource(INITIATED_BY_SAVE_PACKAGE_ON_NON_HTML); |
| SaveFrame(GetLastCommittedURL(), Referrer()); |
| return; |
| } |
| |
| Stop(); |
| |
| // Create the save package and possibly prompt the user for the name to save |
| // the page as. The user prompt is an asynchronous operation that runs on |
| // another thread. |
| save_package_ = new SavePackage(this); |
| save_package_->GetSaveInfo(); |
| } |
| |
| // Used in automated testing to bypass prompting the user for file names. |
| // Instead, the names and paths are hard coded rather than running them through |
| // file name sanitation and extension / mime checking. |
| bool WebContentsImpl::SavePage(const base::FilePath& main_file, |
| const base::FilePath& dir_path, |
| SavePageType save_type) { |
| // Stop the page from navigating. |
| Stop(); |
| |
| save_package_ = new SavePackage(this, save_type, main_file, dir_path); |
| return save_package_->Init(SavePackageDownloadCreatedCallback()); |
| } |
| |
| void WebContentsImpl::SaveFrame(const GURL& url, |
| const Referrer& referrer) { |
| SaveFrameWithHeaders(url, referrer, std::string()); |
| } |
| |
| void WebContentsImpl::SaveFrameWithHeaders(const GURL& url, |
| const Referrer& referrer, |
| const std::string& headers) { |
| if (!GetLastCommittedURL().is_valid()) |
| return; |
| if (delegate_ && delegate_->SaveFrame(url, referrer)) |
| return; |
| |
| // TODO(nasko): This check for main frame is incorrect and should be fixed |
| // by explicitly passing in which frame this method should target. |
| bool is_main_frame = (url == GetLastCommittedURL()); |
| |
| DownloadManager* dlm = |
| BrowserContext::GetDownloadManager(GetBrowserContext()); |
| if (!dlm) |
| return; |
| int64_t post_id = -1; |
| if (is_main_frame) { |
| const NavigationEntry* entry = controller_.GetLastCommittedEntry(); |
| if (entry) |
| post_id = entry->GetPostID(); |
| } |
| scoped_ptr<DownloadUrlParameters> params( |
| DownloadUrlParameters::FromWebContents(this, url)); |
| params->set_referrer(referrer); |
| params->set_post_id(post_id); |
| if (post_id >= 0) |
| params->set_method("POST"); |
| params->set_prompt(true); |
| |
| if (headers.empty()) { |
| params->set_prefer_cache(true); |
| } else { |
| for (const base::StringPiece& key_value : |
| base::SplitStringPiece( |
| headers, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { |
| std::vector<std::string> pair = base::SplitString( |
| key_value, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
| DCHECK_EQ(2ul, pair.size()); |
| params->add_request_header(pair[0], pair[1]); |
| } |
| } |
| dlm->DownloadUrl(std::move(params)); |
| } |
| |
| void WebContentsImpl::GenerateMHTML( |
| const base::FilePath& file, |
| const base::Callback<void(int64_t)>& callback) { |
| MHTMLGenerationManager::GetInstance()->SaveMHTML(this, file, callback); |
| } |
| |
| const std::string& WebContentsImpl::GetContentsMimeType() const { |
| return contents_mime_type_; |
| } |
| |
| bool WebContentsImpl::WillNotifyDisconnection() const { |
| return notify_disconnection_; |
| } |
| |
| void WebContentsImpl::SetOverrideEncoding(const std::string& encoding) { |
| SetEncoding(encoding); |
| Send(new ViewMsg_SetPageEncoding(GetRoutingID(), encoding)); |
| } |
| |
| void WebContentsImpl::ResetOverrideEncoding() { |
| canonical_encoding_.clear(); |
| Send(new ViewMsg_ResetPageEncodingToDefault(GetRoutingID())); |
| } |
| |
| RendererPreferences* WebContentsImpl::GetMutableRendererPrefs() { |
| return &renderer_preferences_; |
| } |
| |
| void WebContentsImpl::Close() { |
| Close(GetRenderViewHost()); |
| } |
| |
| void WebContentsImpl::DragSourceEndedAt(int client_x, int client_y, |
| int screen_x, int screen_y, blink::WebDragOperation operation) { |
| if (browser_plugin_embedder_.get()) |
| browser_plugin_embedder_->DragSourceEndedAt(client_x, client_y, |
| screen_x, screen_y, operation); |
| if (GetRenderViewHost()) |
| GetRenderViewHost()->DragSourceEndedAt(client_x, client_y, screen_x, |
| screen_y, operation); |
| } |
| |
| void WebContentsImpl::DidGetResourceResponseStart( |
| const ResourceRequestDetails& details) { |
| controller_.ssl_manager()->DidStartResourceResponse(details); |
| |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, |
| DidGetResourceResponseStart(details)); |
| } |
| |
| void WebContentsImpl::DidGetRedirectForResourceRequest( |
| RenderFrameHost* render_frame_host, |
| const ResourceRedirectDetails& details) { |
| controller_.ssl_manager()->DidReceiveResourceRedirect(details); |
| |
| FOR_EACH_OBSERVER( |
| WebContentsObserver, |
| observers_, |
| DidGetRedirectForResourceRequest(render_frame_host, details)); |
| |
| // TODO(avi): Remove. http://crbug.com/170921 |
| NotificationService::current()->Notify( |
| NOTIFICATION_RESOURCE_RECEIVED_REDIRECT, |
| Source<WebContents>(this), |
| Details<const ResourceRedirectDetails>(&details)); |
| |
| if (IsResourceTypeFrame(details.resource_type)) { |
| NavigationHandleImpl* navigation_handle = |
| static_cast<RenderFrameHostImpl*>(render_frame_host) |
| ->navigation_handle(); |
| if (navigation_handle) |
| navigation_handle->DidRedirectNavigation(details.new_url); |
| } |
| } |
| |
| void WebContentsImpl::NotifyWebContentsFocused() { |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, OnWebContentsFocused()); |
| } |
| |
| void WebContentsImpl::SystemDragEnded() { |
| if (GetRenderViewHost()) |
| GetRenderViewHost()->DragSourceSystemDragEnded(); |
| if (browser_plugin_embedder_.get()) |
| browser_plugin_embedder_->SystemDragEnded(); |
| } |
| |
| void WebContentsImpl::UserGestureDone() { |
| OnUserGesture(GetRenderViewHost()->GetWidget()); |
| } |
| |
| void WebContentsImpl::SetClosedByUserGesture(bool value) { |
| closed_by_user_gesture_ = value; |
| } |
| |
| bool WebContentsImpl::GetClosedByUserGesture() const { |
| return closed_by_user_gesture_; |
| } |
| |
| void WebContentsImpl::ViewSource() { |
| if (!delegate_) |
| return; |
| |
| NavigationEntry* entry = GetController().GetLastCommittedEntry(); |
| if (!entry) |
| return; |
| |
| delegate_->ViewSourceForTab(this, entry->GetURL()); |
| } |
| |
| void WebContentsImpl::ViewFrameSource(const GURL& url, |
| const PageState& page_state) { |
| if (!delegate_) |
| return; |
| |
| delegate_->ViewSourceForFrame(this, url, page_state); |
| } |
| |
| int WebContentsImpl::GetMinimumZoomPercent() const { |
| return minimum_zoom_percent_; |
| } |
| |
| int WebContentsImpl::GetMaximumZoomPercent() const { |
| return maximum_zoom_percent_; |
| } |
| |
| void WebContentsImpl::SetPageScale(float page_scale_factor) { |
| Send(new ViewMsg_SetPageScale(GetRoutingID(), page_scale_factor)); |
| } |
| |
| gfx::Size WebContentsImpl::GetPreferredSize() const { |
| return capturer_count_ == 0 ? preferred_size_ : preferred_size_for_capture_; |
| } |
| |
| bool WebContentsImpl::GotResponseToLockMouseRequest(bool allowed) { |
| if (GetBrowserPluginGuest()) |
| return GetBrowserPluginGuest()->LockMouse(allowed); |
| |
| return GetRenderViewHost() |
| ? GetRenderViewHost()->GetWidget()->GotResponseToLockMouseRequest( |
| allowed) |
| : false; |
| } |
| |
| bool WebContentsImpl::HasOpener() const { |
| return GetOpener() != NULL; |
| } |
| |
| WebContentsImpl* WebContentsImpl::GetOpener() const { |
| FrameTreeNode* opener_ftn = frame_tree_.root()->opener(); |
| return opener_ftn ? FromFrameTreeNode(opener_ftn) : nullptr; |
| } |
| |
| void WebContentsImpl::DidChooseColorInColorChooser(SkColor color) { |
| if (!color_chooser_info_.get()) |
| return; |
| RenderFrameHost* rfh = RenderFrameHost::FromID( |
| color_chooser_info_->render_process_id, |
| color_chooser_info_->render_frame_id); |
| if (!rfh) |
| return; |
| |
| rfh->Send(new FrameMsg_DidChooseColorResponse( |
| rfh->GetRoutingID(), color_chooser_info_->identifier, color)); |
| } |
| |
| void WebContentsImpl::DidEndColorChooser() { |
| if (!color_chooser_info_.get()) |
| return; |
| RenderFrameHost* rfh = RenderFrameHost::FromID( |
| color_chooser_info_->render_process_id, |
| color_chooser_info_->render_frame_id); |
| if (!rfh) |
| return; |
| |
| rfh->Send(new FrameMsg_DidEndColorChooser( |
| rfh->GetRoutingID(), color_chooser_info_->identifier)); |
| color_chooser_info_.reset(); |
| } |
| |
| int WebContentsImpl::DownloadImage( |
| const GURL& url, |
| bool is_favicon, |
| uint32_t max_bitmap_size, |
| bool bypass_cache, |
| const WebContents::ImageDownloadCallback& callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| static int next_image_download_id = 0; |
| const image_downloader::ImageDownloaderPtr& mojo_image_downloader = |
| GetMainFrame()->GetMojoImageDownloader(); |
| const int download_id = ++next_image_download_id; |
| if (!mojo_image_downloader) { |
| // If the renderer process is dead (i.e. crash, or memory pressure on |
| // Android), the downloader service will be invalid. Pre-Mojo, this would |
| // hang the callback indefinetly since the IPC would be dropped. Now, |
| // respond with a 400 HTTP error code to indicate that something went wrong. |
| image_downloader::DownloadResultPtr result = |
| image_downloader::DownloadResult::New(); |
| result->http_status_code = 400; |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind(&WebContentsImpl::OnDidDownloadImage, |
| weak_factory_.GetWeakPtr(), callback, download_id, url, |
| base::Passed(&result))); |
| return download_id; |
| } |
| |
| image_downloader::DownloadRequestPtr req = |
| image_downloader::DownloadRequest::New(); |
| |
| req->url = mojo::String::From(url); |
| req->is_favicon = is_favicon; |
| req->max_bitmap_size = max_bitmap_size; |
| req->bypass_cache = bypass_cache; |
| |
| mojo_image_downloader->DownloadImage( |
| std::move(req), base::Bind(&WebContentsImpl::OnDidDownloadImage, |
| weak_factory_.GetWeakPtr(), callback, |
| download_id, url)); |
| return download_id; |
| } |
| |
| bool WebContentsImpl::IsSubframe() const { |
| return is_subframe_; |
| } |
| |
| void WebContentsImpl::Find(int request_id, |
| const base::string16& search_text, |
| const blink::WebFindOptions& options) { |
| // Cowardly refuse to search for no text. |
| if (search_text.empty()) { |
| NOTREACHED(); |
| return; |
| } |
| |
| // See if a top level browser plugin handles the find request first. |
| if (browser_plugin_embedder_ && |
| browser_plugin_embedder_->Find(request_id, search_text, options)) { |
| return; |
| } |
| Send(new ViewMsg_Find(GetRoutingID(), request_id, search_text, options)); |
| } |
| |
| void WebContentsImpl::StopFinding(StopFindAction action) { |
| // See if a top level browser plugin handles the stop finding request first. |
| if (browser_plugin_embedder_ && |
| browser_plugin_embedder_->StopFinding(action)) { |
| return; |
| } |
| Send(new ViewMsg_StopFinding(GetRoutingID(), action)); |
| } |
| |
| void WebContentsImpl::InsertCSS(const std::string& css) { |
| GetMainFrame()->Send(new FrameMsg_CSSInsertRequest( |
| GetMainFrame()->GetRoutingID(), css)); |
| } |
| |
| bool WebContentsImpl::WasRecentlyAudible() { |
| return audio_stream_monitor_.WasRecentlyAudible(); |
| } |
| |
| void WebContentsImpl::GetManifest(const GetManifestCallback& callback) { |
| manifest_manager_host_->GetManifest(GetMainFrame(), callback); |
| } |
| |
| void WebContentsImpl::HasManifest(const HasManifestCallback& callback) { |
| manifest_manager_host_->HasManifest(GetMainFrame(), callback); |
| } |
| |
| void WebContentsImpl::ExitFullscreen() { |
| // Clean up related state and initiate the fullscreen exit. |
| GetRenderViewHost()->GetWidget()->RejectMouseLockOrUnlockIfNecessary(); |
| ExitFullscreenMode(); |
| } |
| |
| void WebContentsImpl::ResumeLoadingCreatedWebContents() { |
| if (delayed_open_url_params_.get()) { |
| OpenURL(*delayed_open_url_params_.get()); |
| delayed_open_url_params_.reset(nullptr); |
| return; |
| } |
| |
| // Resume blocked requests for both the RenderViewHost and RenderFrameHost. |
| // TODO(brettw): It seems bogus to reach into here and initialize the host. |
| if (is_resume_pending_) { |
| is_resume_pending_ = false; |
| GetRenderViewHost()->GetWidget()->Init(); |
| GetMainFrame()->Init(); |
| } |
| } |
| |
| bool WebContentsImpl::FocusLocationBarByDefault() { |
| NavigationEntry* entry = controller_.GetVisibleEntry(); |
| if (entry && entry->GetURL() == GURL(url::kAboutBlankURL)) |
| return true; |
| return delegate_ && delegate_->ShouldFocusLocationBarByDefault(this); |
| } |
| |
| void WebContentsImpl::SetFocusToLocationBar(bool select_all) { |
| if (delegate_) |
| delegate_->SetFocusToLocationBar(select_all); |
| } |
| |
| void WebContentsImpl::DidStartNavigation(NavigationHandle* navigation_handle) { |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, |
| DidStartNavigation(navigation_handle)); |
| } |
| |
| void WebContentsImpl::DidRedirectNavigation( |
| NavigationHandle* navigation_handle) { |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, |
| DidRedirectNavigation(navigation_handle)); |
| } |
| |
| void WebContentsImpl::ReadyToCommitNavigation( |
| NavigationHandle* navigation_handle) { |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, |
| ReadyToCommitNavigation(navigation_handle)); |
| } |
| |
| void WebContentsImpl::DidFinishNavigation(NavigationHandle* navigation_handle) { |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, |
| DidFinishNavigation(navigation_handle)); |
| } |
| |
| void WebContentsImpl::DidStartProvisionalLoad( |
| RenderFrameHostImpl* render_frame_host, |
| const GURL& validated_url, |
| bool is_error_page, |
| bool is_iframe_srcdoc) { |
| // Notify observers about the start of the provisional load. |
| FOR_EACH_OBSERVER( |
| WebContentsObserver, |
| observers_, |
| DidStartProvisionalLoadForFrame( |
| render_frame_host, validated_url, is_error_page, is_iframe_srcdoc)); |
| |
| // Notify accessibility if this is a reload. |
| NavigationEntry* entry = controller_.GetVisibleEntry(); |
| if (entry && ui::PageTransitionCoreTypeIs( |
| entry->GetTransitionType(), ui::PAGE_TRANSITION_RELOAD)) { |
| FrameTreeNode* ftn = render_frame_host->frame_tree_node(); |
| BrowserAccessibilityManager* manager = |
| ftn->current_frame_host()->browser_accessibility_manager(); |
| if (manager) |
| manager->UserIsReloading(); |
| } |
| } |
| |
| void WebContentsImpl::DidFailProvisionalLoadWithError( |
| RenderFrameHostImpl* render_frame_host, |
| const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) { |
| GURL validated_url(params.url); |
| FOR_EACH_OBSERVER(WebContentsObserver, |
| observers_, |
| DidFailProvisionalLoad(render_frame_host, |
| validated_url, |
| params.error_code, |
| params.error_description, |
| params.was_ignored_by_handler)); |
| |
| FrameTreeNode* ftn = render_frame_host->frame_tree_node(); |
| BrowserAccessibilityManager* manager = |
| ftn->current_frame_host()->browser_accessibility_manager(); |
| if (manager) |
| manager->NavigationFailed(); |
| } |
| |
| void WebContentsImpl::DidFailLoadWithError( |
| RenderFrameHostImpl* render_frame_host, |
| const GURL& url, |
| int error_code, |
| const base::string16& error_description, |
| bool was_ignored_by_handler) { |
| FOR_EACH_OBSERVER( |
| WebContentsObserver, |
| observers_, |
| DidFailLoad(render_frame_host, url, error_code, error_description, |
| was_ignored_by_handler)); |
| } |
| |
| void WebContentsImpl::NotifyChangedNavigationState( |
| InvalidateTypes changed_flags) { |
| NotifyNavigationStateChanged(changed_flags); |
| } |
| |
| void WebContentsImpl::DidStartNavigationToPendingEntry( |
| const GURL& url, |
| NavigationController::ReloadType reload_type) { |
| // Notify observers about navigation. |
| FOR_EACH_OBSERVER( |
| WebContentsObserver, |
| observers_, |
| DidStartNavigationToPendingEntry(url, reload_type)); |
| } |
| |
| void WebContentsImpl::RequestOpenURL(RenderFrameHostImpl* render_frame_host, |
| const OpenURLParams& params) { |
| // OpenURL can blow away the source RFH. Use the process/frame routing ID as a |
| // weak pointer of sorts. |
| const int32_t process_id = render_frame_host->GetProcess()->GetID(); |
| const int32_t frame_id = render_frame_host->GetRoutingID(); |
| |
| WebContents* new_contents = OpenURL(params); |
| |
| if (new_contents && RenderFrameHost::FromID(process_id, frame_id)) { |
| // Notify observers. |
| FOR_EACH_OBSERVER(WebContentsObserver, observers_, |
| DidOpenRequestedURL(new_contents, |
| render_frame_host, |
| params.url, |
| params.referrer, |
| params.disposition, |
| params.transition)); |
| } |
| } |
| |
| bool WebContentsImpl::ShouldTransferNavigation() { |
| if (!delegate_) |
| return true; |
| return delegate_->ShouldTransferNavigation(); |
| } |
| |
| bool WebContentsImpl::ShouldPreserveAbortedURLs() { |
| if (!delegate_) |
| return false; |
| return delegate_->ShouldPreserveAbortedURLs(this); |
| } |
| |
| void WebContentsImpl::DidCommitProvisionalLoad( |
| RenderFrameHostImpl* render_frame_host, |
| const GURL& url, |
| ui::PageTransition transition_type) { |
| // Notify observers about the commit of the provisional load. |
| FOR_EACH_OBSERVER(WebContentsObserver, |
| observers_, |
| DidCommitProvisionalLoadForFrame( |
| render_frame_host, url, transition_type)); |
| |
| BrowserAccessibilityManager* manager = |
| render_frame_host->browser_accessibility_manager(); |
| if (manager) |
| manager->NavigationSucceeded(); |
| } |
| |
| void WebContentsImpl::DidNavigateMainFramePreCommit( |
| bool navigation_is_within_page) { |
| // Ensure fullscreen mode is exited before committing the navigation to a |
| // different page. The next page will not start out assuming it is in |
| // fullscreen mode. |
| if (navigation_is_within_page) { |
|