Revert of Gardening: Revert "Use AudioStreamMonitor to control power save blocking...
[chromium-blink-merge.git] / content / browser / web_contents / web_contents_impl.cc
blob5331f495c576d2b562dc2a803df473f1341b9976
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/web_contents/web_contents_impl.h"
7 #include <utility>
9 #include "base/command_line.h"
10 #include "base/debug/trace_event.h"
11 #include "base/lazy_instance.h"
12 #include "base/logging.h"
13 #include "base/metrics/histogram.h"
14 #include "base/metrics/stats_counters.h"
15 #include "base/process/process.h"
16 #include "base/strings/string16.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/time/time.h"
21 #include "content/browser/accessibility/accessibility_mode_helper.h"
22 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
23 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
24 #include "content/browser/browser_plugin/browser_plugin_guest.h"
25 #include "content/browser/child_process_security_policy_impl.h"
26 #include "content/browser/devtools/render_view_devtools_agent_host.h"
27 #include "content/browser/dom_storage/dom_storage_context_wrapper.h"
28 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
29 #include "content/browser/download/download_stats.h"
30 #include "content/browser/download/mhtml_generation_manager.h"
31 #include "content/browser/download/save_package.h"
32 #include "content/browser/frame_host/cross_process_frame_connector.h"
33 #include "content/browser/frame_host/interstitial_page_impl.h"
34 #include "content/browser/frame_host/navigation_entry_impl.h"
35 #include "content/browser/frame_host/navigator_impl.h"
36 #include "content/browser/frame_host/render_frame_host_impl.h"
37 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
38 #include "content/browser/geolocation/geolocation_dispatcher_host.h"
39 #include "content/browser/host_zoom_map_impl.h"
40 #include "content/browser/loader/resource_dispatcher_host_impl.h"
41 #include "content/browser/media/audio_stream_monitor.h"
42 #include "content/browser/media/midi_dispatcher_host.h"
43 #include "content/browser/message_port_message_filter.h"
44 #include "content/browser/message_port_service.h"
45 #include "content/browser/power_save_blocker_impl.h"
46 #include "content/browser/renderer_host/render_process_host_impl.h"
47 #include "content/browser/renderer_host/render_view_host_delegate_view.h"
48 #include "content/browser/renderer_host/render_view_host_impl.h"
49 #include "content/browser/renderer_host/render_widget_host_impl.h"
50 #include "content/browser/renderer_host/render_widget_host_view_base.h"
51 #include "content/browser/screen_orientation/screen_orientation_dispatcher_host.h"
52 #include "content/browser/site_instance_impl.h"
53 #include "content/browser/web_contents/web_contents_view_guest.h"
54 #include "content/browser/webui/generic_handler.h"
55 #include "content/browser/webui/web_ui_controller_factory_registry.h"
56 #include "content/browser/webui/web_ui_impl.h"
57 #include "content/common/browser_plugin/browser_plugin_constants.h"
58 #include "content/common/browser_plugin/browser_plugin_messages.h"
59 #include "content/common/frame_messages.h"
60 #include "content/common/image_messages.h"
61 #include "content/common/input_messages.h"
62 #include "content/common/ssl_status_serialization.h"
63 #include "content/common/view_messages.h"
64 #include "content/public/browser/ax_event_notification_details.h"
65 #include "content/public/browser/browser_context.h"
66 #include "content/public/browser/browser_plugin_guest_manager.h"
67 #include "content/public/browser/content_browser_client.h"
68 #include "content/public/browser/devtools_agent_host.h"
69 #include "content/public/browser/download_manager.h"
70 #include "content/public/browser/download_url_parameters.h"
71 #include "content/public/browser/invalidate_type.h"
72 #include "content/public/browser/javascript_dialog_manager.h"
73 #include "content/public/browser/load_from_memory_cache_details.h"
74 #include "content/public/browser/load_notification_details.h"
75 #include "content/public/browser/navigation_details.h"
76 #include "content/public/browser/notification_details.h"
77 #include "content/public/browser/notification_service.h"
78 #include "content/public/browser/render_widget_host_iterator.h"
79 #include "content/public/browser/resource_request_details.h"
80 #include "content/public/browser/storage_partition.h"
81 #include "content/public/browser/user_metrics.h"
82 #include "content/public/browser/web_contents_delegate.h"
83 #include "content/public/browser/web_contents_observer.h"
84 #include "content/public/common/bindings_policy.h"
85 #include "content/public/common/content_constants.h"
86 #include "content/public/common/content_switches.h"
87 #include "content/public/common/page_zoom.h"
88 #include "content/public/common/result_codes.h"
89 #include "content/public/common/url_constants.h"
90 #include "content/public/common/url_utils.h"
91 #include "content/public/common/web_preferences.h"
92 #include "net/base/mime_util.h"
93 #include "net/base/net_util.h"
94 #include "net/http/http_cache.h"
95 #include "net/http/http_transaction_factory.h"
96 #include "net/url_request/url_request_context.h"
97 #include "net/url_request/url_request_context_getter.h"
98 #include "ui/base/layout.h"
99 #include "ui/gfx/display.h"
100 #include "ui/gfx/screen.h"
101 #include "ui/gl/gl_switches.h"
103 #if defined(OS_ANDROID)
104 #include "content/browser/android/content_view_core_impl.h"
105 #include "content/browser/android/date_time_chooser_android.h"
106 #include "content/browser/media/android/browser_media_player_manager.h"
107 #include "content/browser/web_contents/web_contents_android.h"
108 #include "content/public/browser/android/content_view_core.h"
109 #endif
111 #if defined(OS_MACOSX)
112 #include "base/mac/foundation_util.h"
113 #endif
115 // Cross-Site Navigations
117 // If a WebContentsImpl is told to navigate to a different web site (as
118 // determined by SiteInstance), it will replace its current RenderViewHost with
119 // a new RenderViewHost dedicated to the new SiteInstance. This works as
120 // follows:
122 // - RVHM::Navigate determines whether the destination is cross-site, and if so,
123 // it creates a pending_render_view_host_.
124 // - The pending RVH is "suspended," so that no navigation messages are sent to
125 // its renderer until the beforeunload JavaScript handler has a chance to
126 // run in the current RVH.
127 // - The pending RVH tells CrossSiteRequestManager (a thread-safe singleton)
128 // that it has a pending cross-site request. We will check this on the IO
129 // thread when deciding how to handle the response.
130 // - The current RVH runs its beforeunload handler. If it returns false, we
131 // cancel all the pending logic. Otherwise we allow the pending RVH to send
132 // the navigation request to its renderer.
133 // - ResourceDispatcherHost receives a ResourceRequest on the IO thread for the
134 // main resource load on the pending RVH. It creates a
135 // CrossSiteResourceHandler to check whether a process swap is needed when
136 // the request is ready to commit.
137 // - When RDH receives a response, the BufferedResourceHandler determines
138 // whether it is a download. If so, it sends a message to the new renderer
139 // causing it to cancel the request, and the download proceeds. For now, the
140 // pending RVH remains until the next DidNavigate event for this
141 // WebContentsImpl. This isn't ideal, but it doesn't affect any functionality.
142 // - After RDH receives a response and determines that it is safe and not a
143 // download, the CrossSiteResourceHandler checks whether a process swap is
144 // needed (either because CrossSiteRequestManager has state for it or because
145 // a transfer was needed for a redirect).
146 // - If so, CrossSiteResourceHandler pauses the response to first run the old
147 // page's unload handler. It does this by asynchronously calling the
148 // OnCrossSiteResponse method of RenderFrameHostManager on the UI thread,
149 // which sends a SwapOut message to the current RVH.
150 // - Once the unload handler is finished, RVHM::SwappedOut checks if a transfer
151 // to a new process is needed, based on the stored pending_nav_params_. (This
152 // is independent of whether we started out with a cross-process navigation.)
153 // - If not, it just tells the ResourceDispatcherHost to resume the response
154 // to its current RenderViewHost.
155 // - If so, it cancels the current pending RenderViewHost and sets up a new
156 // navigation using RequestTransferURL. When the transferred request
157 // arrives in the ResourceDispatcherHost, we transfer the response and
158 // resume it.
159 // - The pending renderer sends a FrameNavigate message that invokes the
160 // DidNavigate method. This replaces the current RVH with the
161 // pending RVH.
162 // - The previous renderer is kept swapped out in RenderFrameHostManager in case
163 // the user goes back. The process only stays live if another tab is using
164 // it, but if so, the existing frame relationships will be maintained.
166 namespace content {
167 namespace {
169 const int kMinimumDelayBetweenLoadingUpdatesMS = 100;
171 // This matches what Blink's ProgressTracker has traditionally used for a
172 // minimum progress value.
173 const double kMinimumLoadingProgress = 0.1;
175 const char kDotGoogleDotCom[] = ".google.com";
177 #if defined(OS_ANDROID)
178 const char kWebContentsAndroidKey[] = "web_contents_android";
179 #endif // OS_ANDROID
181 base::LazyInstance<std::vector<WebContentsImpl::CreatedCallback> >
182 g_created_callbacks = LAZY_INSTANCE_INITIALIZER;
184 static int StartDownload(RenderFrameHost* rfh,
185 const GURL& url,
186 bool is_favicon,
187 uint32_t max_bitmap_size) {
188 static int g_next_image_download_id = 0;
189 rfh->Send(new ImageMsg_DownloadImage(rfh->GetRoutingID(),
190 ++g_next_image_download_id,
191 url,
192 is_favicon,
193 max_bitmap_size));
194 return g_next_image_download_id;
197 void NotifyCacheOnIO(
198 scoped_refptr<net::URLRequestContextGetter> request_context,
199 const GURL& url,
200 const std::string& http_method) {
201 request_context->GetURLRequestContext()->http_transaction_factory()->
202 GetCache()->OnExternalCacheHit(url, http_method);
205 // Helper function for retrieving all the sites in a frame tree.
206 bool CollectSites(BrowserContext* context,
207 std::set<GURL>* sites,
208 FrameTreeNode* node) {
209 sites->insert(SiteInstance::GetSiteForURL(context, node->current_url()));
210 return true;
213 bool ForEachFrameInternal(
214 const base::Callback<void(RenderFrameHost*)>& on_frame,
215 FrameTreeNode* node) {
216 on_frame.Run(node->current_frame_host());
217 return true;
220 bool ForEachPendingFrameInternal(
221 const base::Callback<void(RenderFrameHost*)>& on_frame,
222 FrameTreeNode* node) {
223 RenderFrameHost* pending_frame_host =
224 node->render_manager()->pending_frame_host();
225 if (pending_frame_host)
226 on_frame.Run(pending_frame_host);
227 return true;
230 void SendToAllFramesInternal(IPC::Message* message, RenderFrameHost* rfh) {
231 IPC::Message* message_copy = new IPC::Message(*message);
232 message_copy->set_routing_id(rfh->GetRoutingID());
233 rfh->Send(message_copy);
236 void AddRenderWidgetHostViewToSet(std::set<RenderWidgetHostView*>* set,
237 RenderFrameHost* rfh) {
238 RenderWidgetHostView* rwhv = static_cast<RenderFrameHostImpl*>(rfh)
239 ->frame_tree_node()
240 ->render_manager()
241 ->GetRenderWidgetHostView();
242 set->insert(rwhv);
245 void SetAccessibilityModeOnFrame(AccessibilityMode mode,
246 RenderFrameHost* frame_host) {
247 static_cast<RenderFrameHostImpl*>(frame_host)->SetAccessibilityMode(mode);
250 } // namespace
252 WebContents* WebContents::Create(const WebContents::CreateParams& params) {
253 return WebContentsImpl::CreateWithOpener(
254 params, static_cast<WebContentsImpl*>(params.opener));
257 WebContents* WebContents::CreateWithSessionStorage(
258 const WebContents::CreateParams& params,
259 const SessionStorageNamespaceMap& session_storage_namespace_map) {
260 WebContentsImpl* new_contents = new WebContentsImpl(
261 params.browser_context, NULL);
263 for (SessionStorageNamespaceMap::const_iterator it =
264 session_storage_namespace_map.begin();
265 it != session_storage_namespace_map.end();
266 ++it) {
267 new_contents->GetController()
268 .SetSessionStorageNamespace(it->first, it->second.get());
271 new_contents->Init(params);
272 return new_contents;
275 void WebContentsImpl::AddCreatedCallback(const CreatedCallback& callback) {
276 g_created_callbacks.Get().push_back(callback);
279 void WebContentsImpl::RemoveCreatedCallback(const CreatedCallback& callback) {
280 for (size_t i = 0; i < g_created_callbacks.Get().size(); ++i) {
281 if (g_created_callbacks.Get().at(i).Equals(callback)) {
282 g_created_callbacks.Get().erase(g_created_callbacks.Get().begin() + i);
283 return;
288 WebContents* WebContents::FromRenderViewHost(const RenderViewHost* rvh) {
289 return rvh->GetDelegate()->GetAsWebContents();
292 WebContents* WebContents::FromRenderFrameHost(RenderFrameHost* rfh) {
293 RenderFrameHostImpl* rfh_impl = static_cast<RenderFrameHostImpl*>(rfh);
294 if (!rfh_impl)
295 return NULL;
296 return rfh_impl->delegate()->GetAsWebContents();
299 // WebContentsImpl::DestructionObserver ----------------------------------------
301 class WebContentsImpl::DestructionObserver : public WebContentsObserver {
302 public:
303 DestructionObserver(WebContentsImpl* owner, WebContents* watched_contents)
304 : WebContentsObserver(watched_contents),
305 owner_(owner) {
308 // WebContentsObserver:
309 virtual void WebContentsDestroyed() OVERRIDE {
310 owner_->OnWebContentsDestroyed(
311 static_cast<WebContentsImpl*>(web_contents()));
314 private:
315 WebContentsImpl* owner_;
317 DISALLOW_COPY_AND_ASSIGN(DestructionObserver);
320 WebContentsImpl::ColorChooserInfo::ColorChooserInfo(int render_process_id,
321 int render_frame_id,
322 ColorChooser* chooser,
323 int identifier)
324 : render_process_id(render_process_id),
325 render_frame_id(render_frame_id),
326 chooser(chooser),
327 identifier(identifier) {
330 WebContentsImpl::ColorChooserInfo::~ColorChooserInfo() {
333 // WebContentsImpl -------------------------------------------------------------
335 WebContentsImpl::WebContentsImpl(
336 BrowserContext* browser_context,
337 WebContentsImpl* opener)
338 : delegate_(NULL),
339 controller_(this, browser_context),
340 render_view_host_delegate_view_(NULL),
341 opener_(opener),
342 created_with_opener_(!!opener),
343 #if defined(OS_WIN)
344 accessible_parent_(NULL),
345 #endif
346 frame_tree_(new NavigatorImpl(&controller_, this),
347 this, this, this, this),
348 is_loading_(false),
349 is_load_to_different_document_(false),
350 crashed_status_(base::TERMINATION_STATUS_STILL_RUNNING),
351 crashed_error_code_(0),
352 waiting_for_response_(false),
353 load_state_(net::LOAD_STATE_IDLE, base::string16()),
354 loading_total_progress_(0.0),
355 loading_weak_factory_(this),
356 loading_frames_in_progress_(0),
357 upload_size_(0),
358 upload_position_(0),
359 displayed_insecure_content_(false),
360 has_accessed_initial_document_(false),
361 capturer_count_(0),
362 should_normally_be_visible_(true),
363 is_being_destroyed_(false),
364 notify_disconnection_(false),
365 dialog_manager_(NULL),
366 is_showing_before_unload_dialog_(false),
367 last_active_time_(base::TimeTicks::Now()),
368 closed_by_user_gesture_(false),
369 minimum_zoom_percent_(static_cast<int>(kMinimumZoomFactor * 100)),
370 maximum_zoom_percent_(static_cast<int>(kMaximumZoomFactor * 100)),
371 totalPinchGestureAmount_(0),
372 currentPinchZoomStepDelta_(0),
373 render_view_message_source_(NULL),
374 fullscreen_widget_routing_id_(MSG_ROUTING_NONE),
375 fullscreen_widget_had_focus_at_shutdown_(false),
376 is_subframe_(false),
377 force_disable_overscroll_content_(false),
378 last_dialog_suppressed_(false),
379 accessibility_mode_(
380 BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode()),
381 audio_stream_monitor_(this) {
382 for (size_t i = 0; i < g_created_callbacks.Get().size(); i++)
383 g_created_callbacks.Get().at(i).Run(this);
384 frame_tree_.SetFrameRemoveListener(
385 base::Bind(&WebContentsImpl::OnFrameRemoved,
386 base::Unretained(this)));
389 WebContentsImpl::~WebContentsImpl() {
390 is_being_destroyed_ = true;
392 // Delete all RFH pending shutdown, which will lead the corresponding RVH to
393 // shutdown and be deleted as well.
394 frame_tree_.ForEach(
395 base::Bind(&RenderFrameHostManager::ClearRFHsPendingShutdown));
397 ClearAllPowerSaveBlockers();
399 for (std::set<RenderWidgetHostImpl*>::iterator iter =
400 created_widgets_.begin(); iter != created_widgets_.end(); ++iter) {
401 (*iter)->DetachDelegate();
403 created_widgets_.clear();
405 // Clear out any JavaScript state.
406 if (dialog_manager_)
407 dialog_manager_->WebContentsDestroyed(this);
409 if (color_chooser_info_.get())
410 color_chooser_info_->chooser->End();
412 NotifyDisconnected();
414 // Notify any observer that have a reference on this WebContents.
415 NotificationService::current()->Notify(
416 NOTIFICATION_WEB_CONTENTS_DESTROYED,
417 Source<WebContents>(this),
418 NotificationService::NoDetails());
420 // Destroy all frame tree nodes except for the root; this notifies observers.
421 frame_tree_.ResetForMainFrameSwap();
422 GetRenderManager()->ResetProxyHosts();
424 // Manually call the observer methods for the root frame tree node.
425 RenderFrameHostManager* root = GetRenderManager();
426 if (root->pending_frame_host()) {
427 FOR_EACH_OBSERVER(WebContentsObserver,
428 observers_,
429 RenderFrameDeleted(root->pending_frame_host()));
431 FOR_EACH_OBSERVER(WebContentsObserver,
432 observers_,
433 RenderFrameDeleted(root->current_frame_host()));
435 if (root->pending_render_view_host()) {
436 FOR_EACH_OBSERVER(WebContentsObserver,
437 observers_,
438 RenderViewDeleted(root->pending_render_view_host()));
441 FOR_EACH_OBSERVER(WebContentsObserver,
442 observers_,
443 RenderViewDeleted(root->current_host()));
445 FOR_EACH_OBSERVER(WebContentsObserver,
446 observers_,
447 WebContentsDestroyed());
449 FOR_EACH_OBSERVER(WebContentsObserver,
450 observers_,
451 ResetWebContents());
453 SetDelegate(NULL);
455 STLDeleteContainerPairSecondPointers(destruction_observers_.begin(),
456 destruction_observers_.end());
459 WebContentsImpl* WebContentsImpl::CreateWithOpener(
460 const WebContents::CreateParams& params,
461 WebContentsImpl* opener) {
462 TRACE_EVENT0("browser", "WebContentsImpl::CreateWithOpener");
463 WebContentsImpl* new_contents = new WebContentsImpl(
464 params.browser_context, params.opener_suppressed ? NULL : opener);
466 if (params.guest_delegate) {
467 // This makes |new_contents| act as a guest.
468 // For more info, see comment above class BrowserPluginGuest.
469 BrowserPluginGuest::Create(new_contents, params.guest_delegate);
470 // We are instantiating a WebContents for browser plugin. Set its subframe
471 // bit to true.
472 new_contents->is_subframe_ = true;
474 new_contents->Init(params);
475 return new_contents;
478 // static
479 std::vector<WebContentsImpl*> WebContentsImpl::GetAllWebContents() {
480 std::vector<WebContentsImpl*> result;
481 scoped_ptr<RenderWidgetHostIterator> widgets(
482 RenderWidgetHostImpl::GetRenderWidgetHosts());
483 std::set<WebContentsImpl*> web_contents_set;
484 while (RenderWidgetHost* rwh = widgets->GetNextHost()) {
485 if (!rwh->IsRenderView())
486 continue;
487 RenderViewHost* rvh = RenderViewHost::From(rwh);
488 if (!rvh)
489 continue;
490 WebContents* web_contents = WebContents::FromRenderViewHost(rvh);
491 if (!web_contents)
492 continue;
493 WebContentsImpl* wci = static_cast<WebContentsImpl*>(web_contents);
494 if (web_contents_set.find(wci) == web_contents_set.end()) {
495 web_contents_set.insert(wci);
496 result.push_back(wci);
499 return result;
502 RenderFrameHostManager* WebContentsImpl::GetRenderManagerForTesting() {
503 return GetRenderManager();
506 bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host,
507 const IPC::Message& message) {
508 return OnMessageReceived(render_view_host, NULL, message);
511 bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host,
512 RenderFrameHost* render_frame_host,
513 const IPC::Message& message) {
514 DCHECK(render_view_host || render_frame_host);
515 if (GetWebUI() &&
516 static_cast<WebUIImpl*>(GetWebUI())->OnMessageReceived(message)) {
517 return true;
520 ObserverListBase<WebContentsObserver>::Iterator it(observers_);
521 WebContentsObserver* observer;
522 if (render_frame_host) {
523 while ((observer = it.GetNext()) != NULL)
524 if (observer->OnMessageReceived(message, render_frame_host))
525 return true;
526 } else {
527 while ((observer = it.GetNext()) != NULL)
528 if (observer->OnMessageReceived(message))
529 return true;
532 // Message handlers should be aware of which
533 // RenderViewHost/RenderFrameHost sent the message, which is temporarily
534 // stored in render_(view|frame)_message_source_.
535 if (render_frame_host)
536 render_frame_message_source_ = render_frame_host;
537 else
538 render_view_message_source_ = render_view_host;
540 bool handled = true;
541 IPC_BEGIN_MESSAGE_MAP(WebContentsImpl, message)
542 IPC_MESSAGE_HANDLER(FrameHostMsg_PepperPluginHung, OnPepperPluginHung)
543 IPC_MESSAGE_HANDLER(FrameHostMsg_PluginCrashed, OnPluginCrashed)
544 IPC_MESSAGE_HANDLER(FrameHostMsg_DomOperationResponse,
545 OnDomOperationResponse)
546 IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeThemeColor,
547 OnThemeColorChanged)
548 IPC_MESSAGE_HANDLER(FrameHostMsg_DidFinishDocumentLoad,
549 OnDocumentLoadedInFrame)
550 IPC_MESSAGE_HANDLER(FrameHostMsg_DidFinishLoad, OnDidFinishLoad)
551 IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartLoading, OnDidStartLoading)
552 IPC_MESSAGE_HANDLER(FrameHostMsg_DidStopLoading, OnDidStopLoading)
553 IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeLoadProgress,
554 OnDidChangeLoadProgress)
555 IPC_MESSAGE_HANDLER(FrameHostMsg_OpenColorChooser, OnOpenColorChooser)
556 IPC_MESSAGE_HANDLER(FrameHostMsg_EndColorChooser, OnEndColorChooser)
557 IPC_MESSAGE_HANDLER(FrameHostMsg_SetSelectedColorInColorChooser,
558 OnSetSelectedColorInColorChooser)
559 IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPlayingNotification,
560 OnMediaPlayingNotification)
561 IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPausedNotification,
562 OnMediaPausedNotification)
563 IPC_MESSAGE_HANDLER(FrameHostMsg_DidFirstVisuallyNonEmptyPaint,
564 OnFirstVisuallyNonEmptyPaint)
565 IPC_MESSAGE_HANDLER(ViewHostMsg_DidLoadResourceFromMemoryCache,
566 OnDidLoadResourceFromMemoryCache)
567 IPC_MESSAGE_HANDLER(ViewHostMsg_DidDisplayInsecureContent,
568 OnDidDisplayInsecureContent)
569 IPC_MESSAGE_HANDLER(ViewHostMsg_DidRunInsecureContent,
570 OnDidRunInsecureContent)
571 IPC_MESSAGE_HANDLER(ViewHostMsg_GoToEntryAtOffset, OnGoToEntryAtOffset)
572 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateZoomLimits, OnUpdateZoomLimits)
573 IPC_MESSAGE_HANDLER(ViewHostMsg_EnumerateDirectory, OnEnumerateDirectory)
574 IPC_MESSAGE_HANDLER(ViewHostMsg_RegisterProtocolHandler,
575 OnRegisterProtocolHandler)
576 IPC_MESSAGE_HANDLER(ViewHostMsg_UnregisterProtocolHandler,
577 OnUnregisterProtocolHandler)
578 IPC_MESSAGE_HANDLER(ViewHostMsg_Find_Reply, OnFindReply)
579 IPC_MESSAGE_HANDLER(ViewHostMsg_AppCacheAccessed, OnAppCacheAccessed)
580 IPC_MESSAGE_HANDLER(ViewHostMsg_WebUISend, OnWebUISend)
581 #if defined(ENABLE_PLUGINS)
582 IPC_MESSAGE_HANDLER(ViewHostMsg_RequestPpapiBrokerPermission,
583 OnRequestPpapiBrokerPermission)
584 IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginHostMsg_Attach,
585 OnBrowserPluginMessage(message))
586 #endif
587 IPC_MESSAGE_HANDLER(ImageHostMsg_DidDownloadImage, OnDidDownloadImage)
588 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFaviconURL, OnUpdateFaviconURL)
589 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowValidationMessage,
590 OnShowValidationMessage)
591 IPC_MESSAGE_HANDLER(ViewHostMsg_HideValidationMessage,
592 OnHideValidationMessage)
593 IPC_MESSAGE_HANDLER(ViewHostMsg_MoveValidationMessage,
594 OnMoveValidationMessage)
595 #if defined(OS_ANDROID)
596 IPC_MESSAGE_HANDLER(ViewHostMsg_FindMatchRects_Reply,
597 OnFindMatchRectsReply)
598 IPC_MESSAGE_HANDLER(ViewHostMsg_OpenDateTimeDialog,
599 OnOpenDateTimeDialog)
600 #endif
601 IPC_MESSAGE_UNHANDLED(handled = false)
602 IPC_END_MESSAGE_MAP()
603 render_view_message_source_ = NULL;
604 render_frame_message_source_ = NULL;
606 return handled;
609 void WebContentsImpl::RunFileChooser(
610 RenderViewHost* render_view_host,
611 const FileChooserParams& params) {
612 if (delegate_)
613 delegate_->RunFileChooser(this, params);
616 NavigationControllerImpl& WebContentsImpl::GetController() {
617 return controller_;
620 const NavigationControllerImpl& WebContentsImpl::GetController() const {
621 return controller_;
624 BrowserContext* WebContentsImpl::GetBrowserContext() const {
625 return controller_.GetBrowserContext();
628 const GURL& WebContentsImpl::GetURL() const {
629 // We may not have a navigation entry yet.
630 NavigationEntry* entry = controller_.GetVisibleEntry();
631 return entry ? entry->GetVirtualURL() : GURL::EmptyGURL();
634 const GURL& WebContentsImpl::GetVisibleURL() const {
635 // We may not have a navigation entry yet.
636 NavigationEntry* entry = controller_.GetVisibleEntry();
637 return entry ? entry->GetVirtualURL() : GURL::EmptyGURL();
640 const GURL& WebContentsImpl::GetLastCommittedURL() const {
641 // We may not have a navigation entry yet.
642 NavigationEntry* entry = controller_.GetLastCommittedEntry();
643 return entry ? entry->GetVirtualURL() : GURL::EmptyGURL();
646 WebContentsDelegate* WebContentsImpl::GetDelegate() {
647 return delegate_;
650 void WebContentsImpl::SetDelegate(WebContentsDelegate* delegate) {
651 // TODO(cbentzel): remove this debugging code?
652 if (delegate == delegate_)
653 return;
654 if (delegate_)
655 delegate_->Detach(this);
656 delegate_ = delegate;
657 if (delegate_) {
658 delegate_->Attach(this);
659 // Ensure the visible RVH reflects the new delegate's preferences.
660 if (view_)
661 view_->SetOverscrollControllerEnabled(CanOverscrollContent());
665 RenderProcessHost* WebContentsImpl::GetRenderProcessHost() const {
666 RenderViewHostImpl* host = GetRenderManager()->current_host();
667 return host ? host->GetProcess() : NULL;
670 RenderFrameHost* WebContentsImpl::GetMainFrame() {
671 return frame_tree_.root()->current_frame_host();
674 RenderFrameHost* WebContentsImpl::GetFocusedFrame() {
675 if (!frame_tree_.GetFocusedFrame())
676 return NULL;
677 return frame_tree_.GetFocusedFrame()->current_frame_host();
680 void WebContentsImpl::ForEachFrame(
681 const base::Callback<void(RenderFrameHost*)>& on_frame) {
682 frame_tree_.ForEach(base::Bind(&ForEachFrameInternal, on_frame));
685 void WebContentsImpl::SendToAllFrames(IPC::Message* message) {
686 ForEachFrame(base::Bind(&SendToAllFramesInternal, message));
687 delete message;
690 RenderViewHost* WebContentsImpl::GetRenderViewHost() const {
691 return GetRenderManager()->current_host();
694 int WebContentsImpl::GetRoutingID() const {
695 if (!GetRenderViewHost())
696 return MSG_ROUTING_NONE;
698 return GetRenderViewHost()->GetRoutingID();
701 int WebContentsImpl::GetFullscreenWidgetRoutingID() const {
702 return fullscreen_widget_routing_id_;
705 RenderWidgetHostView* WebContentsImpl::GetRenderWidgetHostView() const {
706 return GetRenderManager()->GetRenderWidgetHostView();
709 RenderWidgetHostView* WebContentsImpl::GetFullscreenRenderWidgetHostView()
710 const {
711 RenderWidgetHost* const widget_host =
712 RenderWidgetHostImpl::FromID(GetRenderProcessHost()->GetID(),
713 GetFullscreenWidgetRoutingID());
714 return widget_host ? widget_host->GetView() : NULL;
717 WebContentsView* WebContentsImpl::GetView() const {
718 return view_.get();
721 void WebContentsImpl::SetAccessibilityMode(AccessibilityMode mode) {
722 if (mode == accessibility_mode_)
723 return;
725 accessibility_mode_ = mode;
726 frame_tree_.ForEach(
727 base::Bind(&ForEachFrameInternal,
728 base::Bind(&SetAccessibilityModeOnFrame, mode)));
729 frame_tree_.ForEach(
730 base::Bind(&ForEachPendingFrameInternal,
731 base::Bind(&SetAccessibilityModeOnFrame, mode)));
734 void WebContentsImpl::AddAccessibilityMode(AccessibilityMode mode) {
735 SetAccessibilityMode(AddAccessibilityModeTo(accessibility_mode_, mode));
738 void WebContentsImpl::RemoveAccessibilityMode(AccessibilityMode mode) {
739 SetAccessibilityMode(RemoveAccessibilityModeFrom(accessibility_mode_, mode));
742 WebUI* WebContentsImpl::CreateWebUI(const GURL& url) {
743 WebUIImpl* web_ui = new WebUIImpl(this);
744 WebUIController* controller = WebUIControllerFactoryRegistry::GetInstance()->
745 CreateWebUIControllerForURL(web_ui, url);
746 if (controller) {
747 web_ui->AddMessageHandler(new GenericHandler());
748 web_ui->SetController(controller);
749 return web_ui;
752 delete web_ui;
753 return NULL;
756 WebUI* WebContentsImpl::GetWebUI() const {
757 return GetRenderManager()->web_ui() ? GetRenderManager()->web_ui()
758 : GetRenderManager()->pending_web_ui();
761 WebUI* WebContentsImpl::GetCommittedWebUI() const {
762 return GetRenderManager()->web_ui();
765 void WebContentsImpl::SetUserAgentOverride(const std::string& override) {
766 if (GetUserAgentOverride() == override)
767 return;
769 renderer_preferences_.user_agent_override = override;
771 // Send the new override string to the renderer.
772 RenderViewHost* host = GetRenderViewHost();
773 if (host)
774 host->SyncRendererPrefs();
776 // Reload the page if a load is currently in progress to avoid having
777 // different parts of the page loaded using different user agents.
778 NavigationEntry* entry = controller_.GetVisibleEntry();
779 if (is_loading_ && entry != NULL && entry->GetIsOverridingUserAgent())
780 controller_.ReloadIgnoringCache(true);
782 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
783 UserAgentOverrideSet(override));
786 const std::string& WebContentsImpl::GetUserAgentOverride() const {
787 return renderer_preferences_.user_agent_override;
790 void WebContentsImpl::EnableTreeOnlyAccessibilityMode() {
791 AddAccessibilityMode(AccessibilityModeTreeOnly);
794 bool WebContentsImpl::IsTreeOnlyAccessibilityModeForTesting() const {
795 return accessibility_mode_ == AccessibilityModeTreeOnly;
798 bool WebContentsImpl::IsFullAccessibilityModeForTesting() const {
799 return accessibility_mode_ == AccessibilityModeComplete;
802 #if defined(OS_WIN)
803 void WebContentsImpl::SetParentNativeViewAccessible(
804 gfx::NativeViewAccessible accessible_parent) {
805 accessible_parent_ = accessible_parent;
806 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(GetMainFrame());
807 if (rfh)
808 rfh->SetParentNativeViewAccessible(accessible_parent);
810 #endif
812 const base::string16& WebContentsImpl::GetTitle() const {
813 // Transient entries take precedence. They are used for interstitial pages
814 // that are shown on top of existing pages.
815 NavigationEntry* entry = controller_.GetTransientEntry();
816 std::string accept_languages =
817 GetContentClient()->browser()->GetAcceptLangs(
818 GetBrowserContext());
819 if (entry) {
820 return entry->GetTitleForDisplay(accept_languages);
822 WebUI* our_web_ui = GetRenderManager()->pending_web_ui() ?
823 GetRenderManager()->pending_web_ui() : GetRenderManager()->web_ui();
824 if (our_web_ui) {
825 // Don't override the title in view source mode.
826 entry = controller_.GetVisibleEntry();
827 if (!(entry && entry->IsViewSourceMode())) {
828 // Give the Web UI the chance to override our title.
829 const base::string16& title = our_web_ui->GetOverriddenTitle();
830 if (!title.empty())
831 return title;
835 // We use the title for the last committed entry rather than a pending
836 // navigation entry. For example, when the user types in a URL, we want to
837 // keep the old page's title until the new load has committed and we get a new
838 // title.
839 entry = controller_.GetLastCommittedEntry();
841 // We make an exception for initial navigations.
842 if (controller_.IsInitialNavigation()) {
843 // We only want to use the title from the visible entry in one of two cases:
844 // 1. There's already a committed entry for an initial navigation, in which
845 // case we are doing a history navigation in a new tab (e.g., Ctrl+Back).
846 // 2. The pending entry has been explicitly assigned a title to display.
848 // If there's no last committed entry and no assigned title, we should fall
849 // back to |page_title_when_no_navigation_entry_| rather than showing the
850 // URL.
851 if (entry ||
852 (controller_.GetVisibleEntry() &&
853 !controller_.GetVisibleEntry()->GetTitle().empty())) {
854 entry = controller_.GetVisibleEntry();
858 if (entry) {
859 return entry->GetTitleForDisplay(accept_languages);
862 // |page_title_when_no_navigation_entry_| is finally used
863 // if no title cannot be retrieved.
864 return page_title_when_no_navigation_entry_;
867 int32 WebContentsImpl::GetMaxPageID() {
868 return GetMaxPageIDForSiteInstance(GetSiteInstance());
871 int32 WebContentsImpl::GetMaxPageIDForSiteInstance(
872 SiteInstance* site_instance) {
873 if (max_page_ids_.find(site_instance->GetId()) == max_page_ids_.end())
874 max_page_ids_[site_instance->GetId()] = -1;
876 return max_page_ids_[site_instance->GetId()];
879 void WebContentsImpl::UpdateMaxPageID(int32 page_id) {
880 UpdateMaxPageIDForSiteInstance(GetSiteInstance(), page_id);
883 void WebContentsImpl::UpdateMaxPageIDForSiteInstance(
884 SiteInstance* site_instance, int32 page_id) {
885 if (GetMaxPageIDForSiteInstance(site_instance) < page_id)
886 max_page_ids_[site_instance->GetId()] = page_id;
889 void WebContentsImpl::CopyMaxPageIDsFrom(WebContents* web_contents) {
890 WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents);
891 max_page_ids_ = contents->max_page_ids_;
894 SiteInstance* WebContentsImpl::GetSiteInstance() const {
895 return GetRenderManager()->current_host()->GetSiteInstance();
898 SiteInstance* WebContentsImpl::GetPendingSiteInstance() const {
899 RenderViewHost* dest_rvh = GetRenderManager()->pending_render_view_host() ?
900 GetRenderManager()->pending_render_view_host() :
901 GetRenderManager()->current_host();
902 return dest_rvh->GetSiteInstance();
905 bool WebContentsImpl::IsLoading() const {
906 return is_loading_;
909 bool WebContentsImpl::IsLoadingToDifferentDocument() const {
910 return is_loading_ && is_load_to_different_document_;
913 bool WebContentsImpl::IsWaitingForResponse() const {
914 return waiting_for_response_ && is_load_to_different_document_;
917 const net::LoadStateWithParam& WebContentsImpl::GetLoadState() const {
918 return load_state_;
921 const base::string16& WebContentsImpl::GetLoadStateHost() const {
922 return load_state_host_;
925 uint64 WebContentsImpl::GetUploadSize() const {
926 return upload_size_;
929 uint64 WebContentsImpl::GetUploadPosition() const {
930 return upload_position_;
933 std::set<GURL> WebContentsImpl::GetSitesInTab() const {
934 std::set<GURL> sites;
935 frame_tree_.ForEach(base::Bind(&CollectSites,
936 base::Unretained(GetBrowserContext()),
937 base::Unretained(&sites)));
938 return sites;
941 const std::string& WebContentsImpl::GetEncoding() const {
942 return canonical_encoding_;
945 bool WebContentsImpl::DisplayedInsecureContent() const {
946 return displayed_insecure_content_;
949 void WebContentsImpl::IncrementCapturerCount(const gfx::Size& capture_size) {
950 DCHECK(!is_being_destroyed_);
951 ++capturer_count_;
952 DVLOG(1) << "There are now " << capturer_count_
953 << " capturing(s) of WebContentsImpl@" << this;
955 // Note: This provides a hint to upstream code to size the views optimally
956 // for quality (e.g., to avoid scaling).
957 if (!capture_size.IsEmpty() && preferred_size_for_capture_.IsEmpty()) {
958 preferred_size_for_capture_ = capture_size;
959 OnPreferredSizeChanged(preferred_size_);
963 void WebContentsImpl::DecrementCapturerCount() {
964 --capturer_count_;
965 DVLOG(1) << "There are now " << capturer_count_
966 << " capturing(s) of WebContentsImpl@" << this;
967 DCHECK_LE(0, capturer_count_);
969 if (is_being_destroyed_)
970 return;
972 if (capturer_count_ == 0) {
973 const gfx::Size old_size = preferred_size_for_capture_;
974 preferred_size_for_capture_ = gfx::Size();
975 OnPreferredSizeChanged(old_size);
978 if (IsHidden()) {
979 DVLOG(1) << "Executing delayed WasHidden().";
980 WasHidden();
984 int WebContentsImpl::GetCapturerCount() const {
985 return capturer_count_;
988 bool WebContentsImpl::IsCrashed() const {
989 return (crashed_status_ == base::TERMINATION_STATUS_PROCESS_CRASHED ||
990 crashed_status_ == base::TERMINATION_STATUS_ABNORMAL_TERMINATION ||
991 crashed_status_ == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
994 void WebContentsImpl::SetIsCrashed(base::TerminationStatus status,
995 int error_code) {
996 if (status == crashed_status_)
997 return;
999 crashed_status_ = status;
1000 crashed_error_code_ = error_code;
1001 NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
1004 base::TerminationStatus WebContentsImpl::GetCrashedStatus() const {
1005 return crashed_status_;
1008 bool WebContentsImpl::IsBeingDestroyed() const {
1009 return is_being_destroyed_;
1012 void WebContentsImpl::NotifyNavigationStateChanged(
1013 InvalidateTypes changed_flags) {
1014 // Create and release the audio power save blocker depending on whether the
1015 // tab is actively producing audio or not.
1016 if (changed_flags == INVALIDATE_TYPE_TAB &&
1017 AudioStreamMonitor::monitoring_available()) {
1018 if (WasRecentlyAudible()) {
1019 if (!audio_power_save_blocker_)
1020 CreateAudioPowerSaveBlocker();
1021 } else {
1022 audio_power_save_blocker_.reset();
1026 if (delegate_)
1027 delegate_->NavigationStateChanged(this, changed_flags);
1030 base::TimeTicks WebContentsImpl::GetLastActiveTime() const {
1031 return last_active_time_;
1034 void WebContentsImpl::WasShown() {
1035 controller_.SetActive(true);
1037 std::set<RenderWidgetHostView*> widgets = GetRenderWidgetHostViewsInTree();
1038 for (std::set<RenderWidgetHostView*>::iterator iter = widgets.begin();
1039 iter != widgets.end();
1040 iter++) {
1041 if (*iter) {
1042 (*iter)->Show();
1043 #if defined(OS_MACOSX)
1044 (*iter)->SetActive(true);
1045 #endif
1049 last_active_time_ = base::TimeTicks::Now();
1051 // The resize rect might have changed while this was inactive -- send the new
1052 // one to make sure it's up to date.
1053 RenderViewHostImpl* rvh =
1054 static_cast<RenderViewHostImpl*>(GetRenderViewHost());
1055 if (rvh) {
1056 rvh->ResizeRectChanged(GetRootWindowResizerRect());
1059 // Restore power save blocker if there are active video players running.
1060 if (!active_video_players_.empty() && !video_power_save_blocker_)
1061 CreateVideoPowerSaveBlocker();
1063 FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasShown());
1065 should_normally_be_visible_ = true;
1068 void WebContentsImpl::WasHidden() {
1069 // If there are entities capturing screenshots or video (e.g., mirroring),
1070 // don't activate the "disable rendering" optimization.
1071 if (capturer_count_ == 0) {
1072 // |GetRenderViewHost()| can be NULL if the user middle clicks a link to
1073 // open a tab in the background, then closes the tab before selecting it.
1074 // This is because closing the tab calls WebContentsImpl::Destroy(), which
1075 // removes the |GetRenderViewHost()|; then when we actually destroy the
1076 // window, OnWindowPosChanged() notices and calls WasHidden() (which
1077 // calls us).
1078 std::set<RenderWidgetHostView*> widgets = GetRenderWidgetHostViewsInTree();
1079 for (std::set<RenderWidgetHostView*>::iterator iter = widgets.begin();
1080 iter != widgets.end();
1081 iter++) {
1082 if (*iter)
1083 (*iter)->Hide();
1086 // Release any video power save blockers held as video is not visible.
1087 video_power_save_blocker_.reset();
1090 FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasHidden());
1092 should_normally_be_visible_ = false;
1095 bool WebContentsImpl::NeedToFireBeforeUnload() {
1096 // TODO(creis): Should we fire even for interstitial pages?
1097 return WillNotifyDisconnection() &&
1098 !ShowingInterstitialPage() &&
1099 !static_cast<RenderViewHostImpl*>(
1100 GetRenderViewHost())->SuddenTerminationAllowed();
1103 void WebContentsImpl::DispatchBeforeUnload(bool for_cross_site_transition) {
1104 static_cast<RenderFrameHostImpl*>(GetMainFrame())->DispatchBeforeUnload(
1105 for_cross_site_transition);
1108 void WebContentsImpl::Stop() {
1109 GetRenderManager()->Stop();
1110 FOR_EACH_OBSERVER(WebContentsObserver, observers_, NavigationStopped());
1113 WebContents* WebContentsImpl::Clone() {
1114 // We use our current SiteInstance since the cloned entry will use it anyway.
1115 // We pass our own opener so that the cloned page can access it if it was
1116 // before.
1117 CreateParams create_params(GetBrowserContext(), GetSiteInstance());
1118 create_params.initial_size = GetContainerBounds().size();
1119 WebContentsImpl* tc = CreateWithOpener(create_params, opener_);
1120 tc->GetController().CopyStateFrom(controller_);
1121 FOR_EACH_OBSERVER(WebContentsObserver,
1122 observers_,
1123 DidCloneToNewWebContents(this, tc));
1124 return tc;
1127 void WebContentsImpl::Observe(int type,
1128 const NotificationSource& source,
1129 const NotificationDetails& details) {
1130 switch (type) {
1131 case NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: {
1132 RenderWidgetHost* host = Source<RenderWidgetHost>(source).ptr();
1133 RenderWidgetHostView* view = host->GetView();
1134 if (view == GetFullscreenRenderWidgetHostView()) {
1135 // We cannot just call view_->RestoreFocus() here. On some platforms,
1136 // attempting to focus the currently-invisible WebContentsView will be
1137 // flat-out ignored. Therefore, this boolean is used to track whether
1138 // we will request focus after the fullscreen widget has been
1139 // destroyed.
1140 fullscreen_widget_had_focus_at_shutdown_ = (view && view->HasFocus());
1141 } else {
1142 for (PendingWidgetViews::iterator i = pending_widget_views_.begin();
1143 i != pending_widget_views_.end(); ++i) {
1144 if (host->GetView() == i->second) {
1145 pending_widget_views_.erase(i);
1146 break;
1150 break;
1152 default:
1153 NOTREACHED();
1157 WebContents* WebContentsImpl::GetWebContents() {
1158 return this;
1161 void WebContentsImpl::Init(const WebContents::CreateParams& params) {
1162 // This is set before initializing the render manager since
1163 // RenderFrameHostManager::Init calls back into us via its delegate to ask if
1164 // it should be hidden.
1165 should_normally_be_visible_ = !params.initially_hidden;
1167 GetRenderManager()->Init(
1168 params.browser_context, params.site_instance, params.routing_id,
1169 params.main_frame_routing_id);
1171 WebContentsViewDelegate* delegate =
1172 GetContentClient()->browser()->GetWebContentsViewDelegate(this);
1174 if (browser_plugin_guest_) {
1175 scoped_ptr<WebContentsView> platform_view(CreateWebContentsView(
1176 this, delegate, &render_view_host_delegate_view_));
1178 WebContentsViewGuest* rv = new WebContentsViewGuest(
1179 this, browser_plugin_guest_.get(), platform_view.Pass(),
1180 render_view_host_delegate_view_);
1181 render_view_host_delegate_view_ = rv;
1182 view_.reset(rv);
1183 } else {
1184 // Regular WebContentsView.
1185 view_.reset(CreateWebContentsView(
1186 this, delegate, &render_view_host_delegate_view_));
1188 CHECK(render_view_host_delegate_view_);
1189 CHECK(view_.get());
1191 gfx::Size initial_size = params.initial_size;
1192 view_->CreateView(initial_size, params.context);
1194 // Listen for whether our opener gets destroyed.
1195 if (opener_)
1196 AddDestructionObserver(opener_);
1198 registrar_.Add(this,
1199 NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
1200 NotificationService::AllBrowserContextsAndSources());
1202 geolocation_dispatcher_host_.reset(new GeolocationDispatcherHost(this));
1203 midi_dispatcher_host_.reset(new MidiDispatcherHost(this));
1205 screen_orientation_dispatcher_host_.reset(
1206 new ScreenOrientationDispatcherHost(this));
1208 #if defined(OS_ANDROID)
1209 date_time_chooser_.reset(new DateTimeChooserAndroid());
1210 #endif
1213 void WebContentsImpl::OnWebContentsDestroyed(WebContentsImpl* web_contents) {
1214 RemoveDestructionObserver(web_contents);
1216 // Clear the opener if it has been closed.
1217 if (web_contents == opener_) {
1218 opener_ = NULL;
1219 return;
1221 // Clear a pending contents that has been closed before being shown.
1222 for (PendingContents::iterator iter = pending_contents_.begin();
1223 iter != pending_contents_.end();
1224 ++iter) {
1225 if (iter->second != web_contents)
1226 continue;
1227 pending_contents_.erase(iter);
1228 return;
1230 NOTREACHED();
1233 void WebContentsImpl::AddDestructionObserver(WebContentsImpl* web_contents) {
1234 if (!ContainsKey(destruction_observers_, web_contents)) {
1235 destruction_observers_[web_contents] =
1236 new DestructionObserver(this, web_contents);
1240 void WebContentsImpl::RemoveDestructionObserver(WebContentsImpl* web_contents) {
1241 DestructionObservers::iterator iter =
1242 destruction_observers_.find(web_contents);
1243 if (iter != destruction_observers_.end()) {
1244 delete destruction_observers_[web_contents];
1245 destruction_observers_.erase(iter);
1249 void WebContentsImpl::AddObserver(WebContentsObserver* observer) {
1250 observers_.AddObserver(observer);
1253 void WebContentsImpl::RemoveObserver(WebContentsObserver* observer) {
1254 observers_.RemoveObserver(observer);
1257 std::set<RenderWidgetHostView*>
1258 WebContentsImpl::GetRenderWidgetHostViewsInTree() {
1259 std::set<RenderWidgetHostView*> set;
1260 if (ShowingInterstitialPage()) {
1261 set.insert(GetRenderWidgetHostView());
1262 } else {
1263 ForEachFrame(
1264 base::Bind(&AddRenderWidgetHostViewToSet, base::Unretained(&set)));
1266 return set;
1269 void WebContentsImpl::Activate() {
1270 if (delegate_)
1271 delegate_->ActivateContents(this);
1274 void WebContentsImpl::Deactivate() {
1275 if (delegate_)
1276 delegate_->DeactivateContents(this);
1279 void WebContentsImpl::LostCapture() {
1280 if (delegate_)
1281 delegate_->LostCapture();
1284 void WebContentsImpl::RenderWidgetDeleted(
1285 RenderWidgetHostImpl* render_widget_host) {
1286 if (is_being_destroyed_) {
1287 // |created_widgets_| might have been destroyed.
1288 return;
1291 std::set<RenderWidgetHostImpl*>::iterator iter =
1292 created_widgets_.find(render_widget_host);
1293 if (iter != created_widgets_.end())
1294 created_widgets_.erase(iter);
1296 if (render_widget_host &&
1297 render_widget_host->GetRoutingID() == fullscreen_widget_routing_id_) {
1298 if (delegate_ && delegate_->EmbedsFullscreenWidget())
1299 delegate_->ToggleFullscreenModeForTab(this, false);
1300 FOR_EACH_OBSERVER(WebContentsObserver,
1301 observers_,
1302 DidDestroyFullscreenWidget(
1303 fullscreen_widget_routing_id_));
1304 fullscreen_widget_routing_id_ = MSG_ROUTING_NONE;
1305 if (fullscreen_widget_had_focus_at_shutdown_)
1306 view_->RestoreFocus();
1310 bool WebContentsImpl::PreHandleKeyboardEvent(
1311 const NativeWebKeyboardEvent& event,
1312 bool* is_keyboard_shortcut) {
1313 return delegate_ &&
1314 delegate_->PreHandleKeyboardEvent(this, event, is_keyboard_shortcut);
1317 void WebContentsImpl::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
1318 if (browser_plugin_embedder_ &&
1319 browser_plugin_embedder_->HandleKeyboardEvent(event)) {
1320 return;
1322 if (delegate_)
1323 delegate_->HandleKeyboardEvent(this, event);
1326 bool WebContentsImpl::HandleWheelEvent(
1327 const blink::WebMouseWheelEvent& event) {
1328 #if !defined(OS_MACOSX)
1329 // On platforms other than Mac, control+mousewheel changes zoom. On Mac, this
1330 // isn't done for two reasons:
1331 // -the OS already has a gesture to do this through pinch-zoom
1332 // -if a user starts an inertial scroll, let's go, and presses control
1333 // (i.e. control+tab) then the OS's buffered scroll events will come in
1334 // with control key set which isn't what the user wants
1335 if (delegate_ &&
1336 event.wheelTicksY &&
1337 (event.modifiers & blink::WebInputEvent::ControlKey) &&
1338 // Avoid adjusting the zoom in response to two-finger-scrolling touchpad
1339 // gestures, which are regrettably easy to trigger accidentally.
1340 !event.hasPreciseScrollingDeltas) {
1341 delegate_->ContentsZoomChange(event.wheelTicksY > 0);
1342 return true;
1344 #endif
1345 return false;
1348 bool WebContentsImpl::PreHandleGestureEvent(
1349 const blink::WebGestureEvent& event) {
1350 return delegate_ && delegate_->PreHandleGestureEvent(this, event);
1353 bool WebContentsImpl::HandleGestureEvent(
1354 const blink::WebGestureEvent& event) {
1355 // Some platforms (eg. Mac) send GesturePinch events for trackpad pinch-zoom.
1356 // Use them to implement browser zoom, as for HandleWheelEvent above.
1357 if (event.type == blink::WebInputEvent::GesturePinchUpdate &&
1358 event.sourceDevice == blink::WebGestureDeviceTouchpad) {
1359 // The scale difference necessary to trigger a zoom action. Derived from
1360 // experimentation to find a value that feels reasonable.
1361 const float kZoomStepValue = 0.6f;
1363 // Find the (absolute) thresholds on either side of the current zoom factor,
1364 // then convert those to actual numbers to trigger a zoom in or out.
1365 // This logic deliberately makes the range around the starting zoom value
1366 // for the gesture twice as large as the other ranges (i.e., the notches are
1367 // at ..., -3*step, -2*step, -step, step, 2*step, 3*step, ... but not at 0)
1368 // so that it's easier to get back to your starting point than it is to
1369 // overshoot.
1370 float nextStep = (abs(currentPinchZoomStepDelta_) + 1) * kZoomStepValue;
1371 float backStep = abs(currentPinchZoomStepDelta_) * kZoomStepValue;
1372 float zoomInThreshold = (currentPinchZoomStepDelta_ >= 0) ? nextStep
1373 : -backStep;
1374 float zoomOutThreshold = (currentPinchZoomStepDelta_ <= 0) ? -nextStep
1375 : backStep;
1377 totalPinchGestureAmount_ += (event.data.pinchUpdate.scale - 1.0);
1378 if (totalPinchGestureAmount_ > zoomInThreshold) {
1379 currentPinchZoomStepDelta_++;
1380 if (delegate_)
1381 delegate_->ContentsZoomChange(true);
1382 } else if (totalPinchGestureAmount_ < zoomOutThreshold) {
1383 currentPinchZoomStepDelta_--;
1384 if (delegate_)
1385 delegate_->ContentsZoomChange(false);
1387 return true;
1390 return false;
1393 void WebContentsImpl::HandleMouseDown() {
1394 if (delegate_)
1395 delegate_->HandleMouseDown();
1398 void WebContentsImpl::HandleMouseUp() {
1399 if (delegate_)
1400 delegate_->HandleMouseUp();
1403 void WebContentsImpl::HandlePointerActivate() {
1404 if (delegate_)
1405 delegate_->HandlePointerActivate();
1408 void WebContentsImpl::HandleGestureBegin() {
1409 if (delegate_)
1410 delegate_->HandleGestureBegin();
1413 void WebContentsImpl::HandleGestureEnd() {
1414 if (delegate_)
1415 delegate_->HandleGestureEnd();
1418 void WebContentsImpl::ToggleFullscreenMode(bool enter_fullscreen) {
1419 // This method is being called to enter or leave renderer-initiated fullscreen
1420 // mode. Either way, make sure any existing fullscreen widget is shut down
1421 // first.
1422 RenderWidgetHostView* const widget_view = GetFullscreenRenderWidgetHostView();
1423 if (widget_view)
1424 RenderWidgetHostImpl::From(widget_view->GetRenderWidgetHost())->Shutdown();
1426 if (delegate_)
1427 delegate_->ToggleFullscreenModeForTab(this, enter_fullscreen);
1429 FOR_EACH_OBSERVER(WebContentsObserver,
1430 observers_,
1431 DidToggleFullscreenModeForTab(IsFullscreenForCurrentTab()));
1434 bool WebContentsImpl::IsFullscreenForCurrentTab() const {
1435 return delegate_ ? delegate_->IsFullscreenForTabOrPending(this) : false;
1438 void WebContentsImpl::RequestToLockMouse(bool user_gesture,
1439 bool last_unlocked_by_target) {
1440 if (delegate_) {
1441 delegate_->RequestToLockMouse(this, user_gesture, last_unlocked_by_target);
1442 } else {
1443 GotResponseToLockMouseRequest(false);
1447 void WebContentsImpl::LostMouseLock() {
1448 if (delegate_)
1449 delegate_->LostMouseLock();
1452 void WebContentsImpl::CreateNewWindow(
1453 int render_process_id,
1454 int route_id,
1455 int main_frame_route_id,
1456 const ViewHostMsg_CreateWindow_Params& params,
1457 SessionStorageNamespace* session_storage_namespace) {
1458 // We usually create the new window in the same BrowsingInstance (group of
1459 // script-related windows), by passing in the current SiteInstance. However,
1460 // if the opener is being suppressed (in a non-guest), we create a new
1461 // SiteInstance in its own BrowsingInstance.
1462 bool is_guest = BrowserPluginGuest::IsGuest(this);
1464 // If the opener is to be suppressed, the new window can be in any process.
1465 // Since routing ids are process specific, we must not have one passed in
1466 // as argument here.
1467 DCHECK(!params.opener_suppressed || route_id == MSG_ROUTING_NONE);
1469 scoped_refptr<SiteInstance> site_instance =
1470 params.opener_suppressed && !is_guest ?
1471 SiteInstance::CreateForURL(GetBrowserContext(), params.target_url) :
1472 GetSiteInstance();
1474 // A message to create a new window can only come from the active process for
1475 // this WebContentsImpl instance. If any other process sends the request,
1476 // it is invalid and the process must be terminated.
1477 if (GetRenderProcessHost()->GetID() != render_process_id) {
1478 base::ProcessHandle process_handle =
1479 RenderProcessHost::FromID(render_process_id)->GetHandle();
1480 if (process_handle != base::kNullProcessHandle) {
1481 RecordAction(
1482 base::UserMetricsAction("Terminate_ProcessMismatch_CreateNewWindow"));
1483 base::KillProcess(process_handle, RESULT_CODE_KILLED, false);
1485 return;
1488 // We must assign the SessionStorageNamespace before calling Init().
1490 // http://crbug.com/142685
1491 const std::string& partition_id =
1492 GetContentClient()->browser()->
1493 GetStoragePartitionIdForSite(GetBrowserContext(),
1494 site_instance->GetSiteURL());
1495 StoragePartition* partition = BrowserContext::GetStoragePartition(
1496 GetBrowserContext(), site_instance.get());
1497 DOMStorageContextWrapper* dom_storage_context =
1498 static_cast<DOMStorageContextWrapper*>(partition->GetDOMStorageContext());
1499 SessionStorageNamespaceImpl* session_storage_namespace_impl =
1500 static_cast<SessionStorageNamespaceImpl*>(session_storage_namespace);
1501 CHECK(session_storage_namespace_impl->IsFromContext(dom_storage_context));
1503 if (delegate_ &&
1504 !delegate_->ShouldCreateWebContents(this,
1505 route_id,
1506 params.window_container_type,
1507 params.frame_name,
1508 params.target_url,
1509 partition_id,
1510 session_storage_namespace)) {
1511 if (route_id != MSG_ROUTING_NONE &&
1512 !RenderViewHost::FromID(render_process_id, route_id)) {
1513 // If the embedder didn't create a WebContents for this route, we need to
1514 // delete the RenderView that had already been created.
1515 Send(new ViewMsg_Close(route_id));
1517 GetRenderViewHost()->GetProcess()->ResumeRequestsForView(route_id);
1518 GetRenderViewHost()->GetProcess()->ResumeRequestsForView(
1519 main_frame_route_id);
1520 return;
1523 // Create the new web contents. This will automatically create the new
1524 // WebContentsView. In the future, we may want to create the view separately.
1525 CreateParams create_params(GetBrowserContext(), site_instance.get());
1526 create_params.routing_id = route_id;
1527 create_params.main_frame_routing_id = main_frame_route_id;
1528 create_params.opener = this;
1529 create_params.opener_suppressed = params.opener_suppressed;
1530 if (params.disposition == NEW_BACKGROUND_TAB)
1531 create_params.initially_hidden = true;
1533 WebContentsImpl* new_contents = NULL;
1534 if (!is_guest) {
1535 create_params.context = view_->GetNativeView();
1536 create_params.initial_size = GetContainerBounds().size();
1537 new_contents = static_cast<WebContentsImpl*>(
1538 WebContents::Create(create_params));
1539 } else {
1540 new_contents = GetBrowserPluginGuest()->CreateNewGuestWindow(create_params);
1542 new_contents->GetController().SetSessionStorageNamespace(
1543 partition_id,
1544 session_storage_namespace);
1545 new_contents->RenderViewCreated(new_contents->GetRenderViewHost());
1547 // Save the window for later if we're not suppressing the opener (since it
1548 // will be shown immediately).
1549 if (!params.opener_suppressed) {
1550 if (!is_guest) {
1551 WebContentsView* new_view = new_contents->view_.get();
1553 // TODO(brettw): It seems bogus that we have to call this function on the
1554 // newly created object and give it one of its own member variables.
1555 new_view->CreateViewForWidget(new_contents->GetRenderViewHost());
1557 // Save the created window associated with the route so we can show it
1558 // later.
1559 DCHECK_NE(MSG_ROUTING_NONE, route_id);
1560 pending_contents_[route_id] = new_contents;
1561 AddDestructionObserver(new_contents);
1564 if (delegate_) {
1565 delegate_->WebContentsCreated(
1566 this, params.opener_render_frame_id, params.frame_name,
1567 params.target_url, new_contents);
1570 if (params.opener_suppressed) {
1571 // When the opener is suppressed, the original renderer cannot access the
1572 // new window. As a result, we need to show and navigate the window here.
1573 bool was_blocked = false;
1574 if (delegate_) {
1575 gfx::Rect initial_pos;
1576 delegate_->AddNewContents(
1577 this, new_contents, params.disposition, initial_pos,
1578 params.user_gesture, &was_blocked);
1580 if (!was_blocked) {
1581 OpenURLParams open_params(params.target_url,
1582 Referrer(),
1583 CURRENT_TAB,
1584 PAGE_TRANSITION_LINK,
1585 true /* is_renderer_initiated */);
1586 open_params.user_gesture = params.user_gesture;
1587 new_contents->OpenURL(open_params);
1592 void WebContentsImpl::CreateNewWidget(int render_process_id,
1593 int route_id,
1594 blink::WebPopupType popup_type) {
1595 CreateNewWidget(render_process_id, route_id, false, popup_type);
1598 void WebContentsImpl::CreateNewFullscreenWidget(int render_process_id,
1599 int route_id) {
1600 CreateNewWidget(render_process_id, route_id, true, blink::WebPopupTypeNone);
1603 void WebContentsImpl::CreateNewWidget(int render_process_id,
1604 int route_id,
1605 bool is_fullscreen,
1606 blink::WebPopupType popup_type) {
1607 RenderProcessHost* process = GetRenderProcessHost();
1608 // A message to create a new widget can only come from the active process for
1609 // this WebContentsImpl instance. If any other process sends the request,
1610 // it is invalid and the process must be terminated.
1611 if (process->GetID() != render_process_id) {
1612 base::ProcessHandle process_handle =
1613 RenderProcessHost::FromID(render_process_id)->GetHandle();
1614 if (process_handle != base::kNullProcessHandle) {
1615 RecordAction(
1616 base::UserMetricsAction("Terminate_ProcessMismatch_CreateNewWidget"));
1617 base::KillProcess(process_handle, RESULT_CODE_KILLED, false);
1619 return;
1622 RenderWidgetHostImpl* widget_host =
1623 new RenderWidgetHostImpl(this, process, route_id, IsHidden());
1624 created_widgets_.insert(widget_host);
1626 RenderWidgetHostViewBase* widget_view =
1627 static_cast<RenderWidgetHostViewBase*>(
1628 view_->CreateViewForPopupWidget(widget_host));
1629 if (!widget_view)
1630 return;
1631 if (!is_fullscreen) {
1632 // Popups should not get activated.
1633 widget_view->SetPopupType(popup_type);
1635 // Save the created widget associated with the route so we can show it later.
1636 pending_widget_views_[route_id] = widget_view;
1638 #if defined(OS_MACOSX)
1639 // A RenderWidgetHostViewMac has lifetime scoped to the view. We'll retain it
1640 // to allow it to survive the trip without being hosted.
1641 base::mac::NSObjectRetain(widget_view->GetNativeView());
1642 #endif
1645 void WebContentsImpl::ShowCreatedWindow(int route_id,
1646 WindowOpenDisposition disposition,
1647 const gfx::Rect& initial_pos,
1648 bool user_gesture) {
1649 WebContentsImpl* contents = GetCreatedWindow(route_id);
1650 if (contents) {
1651 WebContentsDelegate* delegate = GetDelegate();
1652 if (delegate) {
1653 delegate->AddNewContents(
1654 this, contents, disposition, initial_pos, user_gesture, NULL);
1659 void WebContentsImpl::ShowCreatedWidget(int route_id,
1660 const gfx::Rect& initial_pos) {
1661 ShowCreatedWidget(route_id, false, initial_pos);
1664 void WebContentsImpl::ShowCreatedFullscreenWidget(int route_id) {
1665 ShowCreatedWidget(route_id, true, gfx::Rect());
1668 void WebContentsImpl::ShowCreatedWidget(int route_id,
1669 bool is_fullscreen,
1670 const gfx::Rect& initial_pos) {
1671 RenderWidgetHostViewBase* widget_host_view =
1672 static_cast<RenderWidgetHostViewBase*>(GetCreatedWidget(route_id));
1673 if (!widget_host_view)
1674 return;
1676 RenderWidgetHostView* view = NULL;
1677 BrowserPluginGuest* guest = GetBrowserPluginGuest();
1678 if (guest && guest->embedder_web_contents()) {
1679 view = guest->embedder_web_contents()->GetRenderWidgetHostView();
1680 } else {
1681 view = GetRenderWidgetHostView();
1684 if (is_fullscreen) {
1685 DCHECK_EQ(MSG_ROUTING_NONE, fullscreen_widget_routing_id_);
1686 view_->StoreFocus();
1687 fullscreen_widget_routing_id_ = route_id;
1688 if (delegate_ && delegate_->EmbedsFullscreenWidget()) {
1689 widget_host_view->InitAsChild(GetRenderWidgetHostView()->GetNativeView());
1690 delegate_->ToggleFullscreenModeForTab(this, true);
1691 } else {
1692 widget_host_view->InitAsFullscreen(view);
1694 FOR_EACH_OBSERVER(WebContentsObserver,
1695 observers_,
1696 DidShowFullscreenWidget(route_id));
1697 if (!widget_host_view->HasFocus())
1698 widget_host_view->Focus();
1699 } else {
1700 widget_host_view->InitAsPopup(view, initial_pos);
1703 RenderWidgetHostImpl* render_widget_host_impl =
1704 RenderWidgetHostImpl::From(widget_host_view->GetRenderWidgetHost());
1705 render_widget_host_impl->Init();
1706 // Only allow privileged mouse lock for fullscreen render widget, which is
1707 // used to implement Pepper Flash fullscreen.
1708 render_widget_host_impl->set_allow_privileged_mouse_lock(is_fullscreen);
1710 #if defined(OS_MACOSX)
1711 // A RenderWidgetHostViewMac has lifetime scoped to the view. Now that it's
1712 // properly embedded (or purposefully ignored) we can release the retain we
1713 // took in CreateNewWidget().
1714 base::mac::NSObjectRelease(widget_host_view->GetNativeView());
1715 #endif
1718 WebContentsImpl* WebContentsImpl::GetCreatedWindow(int route_id) {
1719 PendingContents::iterator iter = pending_contents_.find(route_id);
1721 // Certain systems can block the creation of new windows. If we didn't succeed
1722 // in creating one, just return NULL.
1723 if (iter == pending_contents_.end()) {
1724 return NULL;
1727 WebContentsImpl* new_contents = iter->second;
1728 pending_contents_.erase(route_id);
1729 RemoveDestructionObserver(new_contents);
1731 // Don't initialize the guest WebContents immediately.
1732 if (BrowserPluginGuest::IsGuest(new_contents))
1733 return new_contents;
1735 if (!new_contents->GetRenderProcessHost()->HasConnection() ||
1736 !new_contents->GetRenderViewHost()->GetView())
1737 return NULL;
1739 // TODO(brettw): It seems bogus to reach into here and initialize the host.
1740 static_cast<RenderViewHostImpl*>(new_contents->GetRenderViewHost())->Init();
1741 return new_contents;
1744 RenderWidgetHostView* WebContentsImpl::GetCreatedWidget(int route_id) {
1745 PendingWidgetViews::iterator iter = pending_widget_views_.find(route_id);
1746 if (iter == pending_widget_views_.end()) {
1747 DCHECK(false);
1748 return NULL;
1751 RenderWidgetHostView* widget_host_view = iter->second;
1752 pending_widget_views_.erase(route_id);
1754 RenderWidgetHost* widget_host = widget_host_view->GetRenderWidgetHost();
1755 if (!widget_host->GetProcess()->HasConnection()) {
1756 // The view has gone away or the renderer crashed. Nothing to do.
1757 return NULL;
1760 return widget_host_view;
1763 void WebContentsImpl::RequestMediaAccessPermission(
1764 const MediaStreamRequest& request,
1765 const MediaResponseCallback& callback) {
1766 if (delegate_) {
1767 delegate_->RequestMediaAccessPermission(this, request, callback);
1768 } else {
1769 callback.Run(MediaStreamDevices(),
1770 MEDIA_DEVICE_INVALID_STATE,
1771 scoped_ptr<MediaStreamUI>());
1775 SessionStorageNamespace* WebContentsImpl::GetSessionStorageNamespace(
1776 SiteInstance* instance) {
1777 return controller_.GetSessionStorageNamespace(instance);
1780 SessionStorageNamespaceMap WebContentsImpl::GetSessionStorageNamespaceMap() {
1781 return controller_.GetSessionStorageNamespaceMap();
1784 FrameTree* WebContentsImpl::GetFrameTree() {
1785 return &frame_tree_;
1788 AccessibilityMode WebContentsImpl::GetAccessibilityMode() const {
1789 return accessibility_mode_;
1792 void WebContentsImpl::AccessibilityEventReceived(
1793 const std::vector<AXEventNotificationDetails>& details) {
1794 FOR_EACH_OBSERVER(
1795 WebContentsObserver, observers_, AccessibilityEventReceived(details));
1798 void WebContentsImpl::OnShowValidationMessage(
1799 const gfx::Rect& anchor_in_root_view,
1800 const base::string16& main_text,
1801 const base::string16& sub_text) {
1802 if (delegate_)
1803 delegate_->ShowValidationMessage(
1804 this, anchor_in_root_view, main_text, sub_text);
1807 void WebContentsImpl::OnHideValidationMessage() {
1808 if (delegate_)
1809 delegate_->HideValidationMessage(this);
1812 void WebContentsImpl::OnMoveValidationMessage(
1813 const gfx::Rect& anchor_in_root_view) {
1814 if (delegate_)
1815 delegate_->MoveValidationMessage(this, anchor_in_root_view);
1818 void WebContentsImpl::DidSendScreenRects(RenderWidgetHostImpl* rwh) {
1819 if (browser_plugin_embedder_)
1820 browser_plugin_embedder_->DidSendScreenRects();
1823 BrowserAccessibilityManager*
1824 WebContentsImpl::GetRootBrowserAccessibilityManager() {
1825 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(GetMainFrame());
1826 return rfh ? rfh->browser_accessibility_manager() : NULL;
1829 BrowserAccessibilityManager*
1830 WebContentsImpl::GetOrCreateRootBrowserAccessibilityManager() {
1831 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(GetMainFrame());
1832 return rfh ? rfh->GetOrCreateBrowserAccessibilityManager() : NULL;
1835 void WebContentsImpl::UpdatePreferredSize(const gfx::Size& pref_size) {
1836 const gfx::Size old_size = GetPreferredSize();
1837 preferred_size_ = pref_size;
1838 OnPreferredSizeChanged(old_size);
1841 void WebContentsImpl::ResizeDueToAutoResize(const gfx::Size& new_size) {
1842 if (delegate_)
1843 delegate_->ResizeDueToAutoResize(this, new_size);
1846 WebContents* WebContentsImpl::OpenURL(const OpenURLParams& params) {
1847 if (!delegate_)
1848 return NULL;
1850 WebContents* new_contents = delegate_->OpenURLFromTab(this, params);
1851 return new_contents;
1854 bool WebContentsImpl::Send(IPC::Message* message) {
1855 if (!GetRenderViewHost()) {
1856 delete message;
1857 return false;
1860 return GetRenderViewHost()->Send(message);
1863 bool WebContentsImpl::NavigateToPendingEntry(
1864 NavigationController::ReloadType reload_type) {
1865 FrameTreeNode* node = frame_tree_.root();
1867 // If we are using --site-per-process, we should navigate in the FrameTreeNode
1868 // specified in the pending entry.
1869 NavigationEntryImpl* pending_entry =
1870 NavigationEntryImpl::FromNavigationEntry(controller_.GetPendingEntry());
1871 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) &&
1872 pending_entry->frame_tree_node_id() != -1) {
1873 node = frame_tree_.FindByID(pending_entry->frame_tree_node_id());
1876 return node->navigator()->NavigateToPendingEntry(
1877 node->current_frame_host(), reload_type);
1880 void WebContentsImpl::RenderFrameForInterstitialPageCreated(
1881 RenderFrameHost* render_frame_host) {
1882 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
1883 RenderFrameForInterstitialPageCreated(render_frame_host));
1886 void WebContentsImpl::AttachInterstitialPage(
1887 InterstitialPageImpl* interstitial_page) {
1888 DCHECK(interstitial_page);
1889 GetRenderManager()->set_interstitial_page(interstitial_page);
1891 // Cancel any visible dialogs so that they don't interfere with the
1892 // interstitial.
1893 if (dialog_manager_)
1894 dialog_manager_->CancelActiveAndPendingDialogs(this);
1896 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
1897 DidAttachInterstitialPage());
1900 void WebContentsImpl::DetachInterstitialPage() {
1901 if (ShowingInterstitialPage())
1902 GetRenderManager()->remove_interstitial_page();
1903 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
1904 DidDetachInterstitialPage());
1907 void WebContentsImpl::SetHistoryLengthAndPrune(
1908 const SiteInstance* site_instance,
1909 int history_length,
1910 int32 minimum_page_id) {
1911 // SetHistoryLengthAndPrune doesn't work when there are pending cross-site
1912 // navigations. Callers should ensure that this is the case.
1913 if (GetRenderManager()->pending_render_view_host()) {
1914 NOTREACHED();
1915 return;
1917 RenderViewHostImpl* rvh = GetRenderViewHostImpl();
1918 if (!rvh) {
1919 NOTREACHED();
1920 return;
1922 if (site_instance && rvh->GetSiteInstance() != site_instance) {
1923 NOTREACHED();
1924 return;
1926 Send(new ViewMsg_SetHistoryLengthAndPrune(GetRoutingID(),
1927 history_length,
1928 minimum_page_id));
1931 void WebContentsImpl::ReloadFocusedFrame(bool ignore_cache) {
1932 RenderFrameHost* focused_frame = GetFocusedFrame();
1933 if (!focused_frame)
1934 return;
1936 focused_frame->Send(new FrameMsg_Reload(
1937 focused_frame->GetRoutingID(), ignore_cache));
1940 void WebContentsImpl::Undo() {
1941 RenderFrameHost* focused_frame = GetFocusedFrame();
1942 if (!focused_frame)
1943 return;
1945 focused_frame->Send(new InputMsg_Undo(focused_frame->GetRoutingID()));
1946 RecordAction(base::UserMetricsAction("Undo"));
1949 void WebContentsImpl::Redo() {
1950 RenderFrameHost* focused_frame = GetFocusedFrame();
1951 if (!focused_frame)
1952 return;
1953 focused_frame->Send(new InputMsg_Redo(focused_frame->GetRoutingID()));
1954 RecordAction(base::UserMetricsAction("Redo"));
1957 void WebContentsImpl::Cut() {
1958 RenderFrameHost* focused_frame = GetFocusedFrame();
1959 if (!focused_frame)
1960 return;
1962 focused_frame->Send(new InputMsg_Cut(focused_frame->GetRoutingID()));
1963 RecordAction(base::UserMetricsAction("Cut"));
1966 void WebContentsImpl::Copy() {
1967 RenderFrameHost* focused_frame = GetFocusedFrame();
1968 if (!focused_frame)
1969 return;
1971 focused_frame->Send(new InputMsg_Copy(focused_frame->GetRoutingID()));
1972 RecordAction(base::UserMetricsAction("Copy"));
1975 void WebContentsImpl::CopyToFindPboard() {
1976 #if defined(OS_MACOSX)
1977 RenderFrameHost* focused_frame = GetFocusedFrame();
1978 if (!focused_frame)
1979 return;
1981 // Windows/Linux don't have the concept of a find pasteboard.
1982 focused_frame->Send(
1983 new InputMsg_CopyToFindPboard(focused_frame->GetRoutingID()));
1984 RecordAction(base::UserMetricsAction("CopyToFindPboard"));
1985 #endif
1988 void WebContentsImpl::Paste() {
1989 RenderFrameHost* focused_frame = GetFocusedFrame();
1990 if (!focused_frame)
1991 return;
1993 focused_frame->Send(new InputMsg_Paste(focused_frame->GetRoutingID()));
1994 RecordAction(base::UserMetricsAction("Paste"));
1997 void WebContentsImpl::PasteAndMatchStyle() {
1998 RenderFrameHost* focused_frame = GetFocusedFrame();
1999 if (!focused_frame)
2000 return;
2002 focused_frame->Send(new InputMsg_PasteAndMatchStyle(
2003 focused_frame->GetRoutingID()));
2004 RecordAction(base::UserMetricsAction("PasteAndMatchStyle"));
2007 void WebContentsImpl::Delete() {
2008 RenderFrameHost* focused_frame = GetFocusedFrame();
2009 if (!focused_frame)
2010 return;
2012 focused_frame->Send(new InputMsg_Delete(focused_frame->GetRoutingID()));
2013 RecordAction(base::UserMetricsAction("DeleteSelection"));
2016 void WebContentsImpl::SelectAll() {
2017 RenderFrameHost* focused_frame = GetFocusedFrame();
2018 if (!focused_frame)
2019 return;
2021 focused_frame->Send(new InputMsg_SelectAll(focused_frame->GetRoutingID()));
2022 RecordAction(base::UserMetricsAction("SelectAll"));
2025 void WebContentsImpl::Unselect() {
2026 RenderFrameHost* focused_frame = GetFocusedFrame();
2027 if (!focused_frame)
2028 return;
2030 focused_frame->Send(new InputMsg_Unselect(focused_frame->GetRoutingID()));
2031 RecordAction(base::UserMetricsAction("Unselect"));
2034 void WebContentsImpl::Replace(const base::string16& word) {
2035 RenderFrameHost* focused_frame = GetFocusedFrame();
2036 if (!focused_frame)
2037 return;
2039 focused_frame->Send(new InputMsg_Replace(
2040 focused_frame->GetRoutingID(), word));
2043 void WebContentsImpl::ReplaceMisspelling(const base::string16& word) {
2044 RenderFrameHost* focused_frame = GetFocusedFrame();
2045 if (!focused_frame)
2046 return;
2048 focused_frame->Send(new InputMsg_ReplaceMisspelling(
2049 focused_frame->GetRoutingID(), word));
2052 void WebContentsImpl::NotifyContextMenuClosed(
2053 const CustomContextMenuContext& context) {
2054 RenderFrameHost* focused_frame = GetFocusedFrame();
2055 if (!focused_frame)
2056 return;
2058 focused_frame->Send(new FrameMsg_ContextMenuClosed(
2059 focused_frame->GetRoutingID(), context));
2062 void WebContentsImpl::ExecuteCustomContextMenuCommand(
2063 int action, const CustomContextMenuContext& context) {
2064 RenderFrameHost* focused_frame = GetFocusedFrame();
2065 if (!focused_frame)
2066 return;
2068 focused_frame->Send(new FrameMsg_CustomContextMenuAction(
2069 focused_frame->GetRoutingID(), context, action));
2072 gfx::NativeView WebContentsImpl::GetNativeView() {
2073 return view_->GetNativeView();
2076 gfx::NativeView WebContentsImpl::GetContentNativeView() {
2077 return view_->GetContentNativeView();
2080 gfx::NativeWindow WebContentsImpl::GetTopLevelNativeWindow() {
2081 return view_->GetTopLevelNativeWindow();
2084 gfx::Rect WebContentsImpl::GetViewBounds() {
2085 return view_->GetViewBounds();
2088 gfx::Rect WebContentsImpl::GetContainerBounds() {
2089 gfx::Rect rv;
2090 view_->GetContainerBounds(&rv);
2091 return rv;
2094 DropData* WebContentsImpl::GetDropData() {
2095 return view_->GetDropData();
2098 void WebContentsImpl::Focus() {
2099 RenderWidgetHostView* const fullscreen_view =
2100 GetFullscreenRenderWidgetHostView();
2101 if (fullscreen_view)
2102 fullscreen_view->Focus();
2103 else
2104 view_->Focus();
2107 void WebContentsImpl::SetInitialFocus() {
2108 RenderWidgetHostView* const fullscreen_view =
2109 GetFullscreenRenderWidgetHostView();
2110 if (fullscreen_view)
2111 fullscreen_view->Focus();
2112 else
2113 view_->SetInitialFocus();
2116 void WebContentsImpl::StoreFocus() {
2117 if (!GetFullscreenRenderWidgetHostView())
2118 view_->StoreFocus();
2121 void WebContentsImpl::RestoreFocus() {
2122 RenderWidgetHostView* const fullscreen_view =
2123 GetFullscreenRenderWidgetHostView();
2124 if (fullscreen_view)
2125 fullscreen_view->Focus();
2126 else
2127 view_->RestoreFocus();
2130 void WebContentsImpl::FocusThroughTabTraversal(bool reverse) {
2131 if (ShowingInterstitialPage()) {
2132 GetRenderManager()->interstitial_page()->FocusThroughTabTraversal(reverse);
2133 return;
2135 RenderWidgetHostView* const fullscreen_view =
2136 GetFullscreenRenderWidgetHostView();
2137 if (fullscreen_view) {
2138 fullscreen_view->Focus();
2139 return;
2141 GetRenderViewHostImpl()->SetInitialFocus(reverse);
2144 bool WebContentsImpl::ShowingInterstitialPage() const {
2145 return GetRenderManager()->interstitial_page() != NULL;
2148 InterstitialPage* WebContentsImpl::GetInterstitialPage() const {
2149 return GetRenderManager()->interstitial_page();
2152 bool WebContentsImpl::IsSavable() {
2153 // WebKit creates Document object when MIME type is application/xhtml+xml,
2154 // so we also support this MIME type.
2155 return contents_mime_type_ == "text/html" ||
2156 contents_mime_type_ == "text/xml" ||
2157 contents_mime_type_ == "application/xhtml+xml" ||
2158 contents_mime_type_ == "text/plain" ||
2159 contents_mime_type_ == "text/css" ||
2160 net::IsSupportedJavascriptMimeType(contents_mime_type_.c_str());
2163 void WebContentsImpl::OnSavePage() {
2164 // If we can not save the page, try to download it.
2165 if (!IsSavable()) {
2166 RecordDownloadSource(INITIATED_BY_SAVE_PACKAGE_ON_NON_HTML);
2167 SaveFrame(GetURL(), Referrer());
2168 return;
2171 Stop();
2173 // Create the save package and possibly prompt the user for the name to save
2174 // the page as. The user prompt is an asynchronous operation that runs on
2175 // another thread.
2176 save_package_ = new SavePackage(this);
2177 save_package_->GetSaveInfo();
2180 // Used in automated testing to bypass prompting the user for file names.
2181 // Instead, the names and paths are hard coded rather than running them through
2182 // file name sanitation and extension / mime checking.
2183 bool WebContentsImpl::SavePage(const base::FilePath& main_file,
2184 const base::FilePath& dir_path,
2185 SavePageType save_type) {
2186 // Stop the page from navigating.
2187 Stop();
2189 save_package_ = new SavePackage(this, save_type, main_file, dir_path);
2190 return save_package_->Init(SavePackageDownloadCreatedCallback());
2193 void WebContentsImpl::SaveFrame(const GURL& url,
2194 const Referrer& referrer) {
2195 if (!GetURL().is_valid())
2196 return;
2197 bool is_main_frame = (url == GetURL());
2199 DownloadManager* dlm =
2200 BrowserContext::GetDownloadManager(GetBrowserContext());
2201 if (!dlm)
2202 return;
2203 int64 post_id = -1;
2204 if (is_main_frame) {
2205 const NavigationEntry* entry = controller_.GetLastCommittedEntry();
2206 if (entry)
2207 post_id = entry->GetPostID();
2209 scoped_ptr<DownloadUrlParameters> params(
2210 DownloadUrlParameters::FromWebContents(this, url));
2211 params->set_referrer(referrer);
2212 params->set_post_id(post_id);
2213 params->set_prefer_cache(true);
2214 if (post_id >= 0)
2215 params->set_method("POST");
2216 params->set_prompt(true);
2217 dlm->DownloadUrl(params.Pass());
2220 void WebContentsImpl::GenerateMHTML(
2221 const base::FilePath& file,
2222 const base::Callback<void(int64)>& callback) {
2223 MHTMLGenerationManager::GetInstance()->SaveMHTML(this, file, callback);
2226 const std::string& WebContentsImpl::GetContentsMimeType() const {
2227 return contents_mime_type_;
2230 bool WebContentsImpl::WillNotifyDisconnection() const {
2231 return notify_disconnection_;
2234 void WebContentsImpl::SetOverrideEncoding(const std::string& encoding) {
2235 SetEncoding(encoding);
2236 Send(new ViewMsg_SetPageEncoding(GetRoutingID(), encoding));
2239 void WebContentsImpl::ResetOverrideEncoding() {
2240 canonical_encoding_.clear();
2241 Send(new ViewMsg_ResetPageEncodingToDefault(GetRoutingID()));
2244 RendererPreferences* WebContentsImpl::GetMutableRendererPrefs() {
2245 return &renderer_preferences_;
2248 void WebContentsImpl::Close() {
2249 Close(GetRenderViewHost());
2252 void WebContentsImpl::DragSourceEndedAt(int client_x, int client_y,
2253 int screen_x, int screen_y, blink::WebDragOperation operation) {
2254 if (browser_plugin_embedder_.get())
2255 browser_plugin_embedder_->DragSourceEndedAt(client_x, client_y,
2256 screen_x, screen_y, operation);
2257 if (GetRenderViewHost())
2258 GetRenderViewHostImpl()->DragSourceEndedAt(client_x, client_y,
2259 screen_x, screen_y, operation);
2262 void WebContentsImpl::DidGetResourceResponseStart(
2263 const ResourceRequestDetails& details) {
2264 controller_.ssl_manager()->DidStartResourceResponse(details);
2266 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2267 DidGetResourceResponseStart(details));
2269 // TODO(avi): Remove. http://crbug.com/170921
2270 NotificationService::current()->Notify(
2271 NOTIFICATION_RESOURCE_RESPONSE_STARTED,
2272 Source<WebContents>(this),
2273 Details<const ResourceRequestDetails>(&details));
2276 void WebContentsImpl::DidGetRedirectForResourceRequest(
2277 RenderViewHost* render_view_host,
2278 const ResourceRedirectDetails& details) {
2279 controller_.ssl_manager()->DidReceiveResourceRedirect(details);
2281 FOR_EACH_OBSERVER(
2282 WebContentsObserver,
2283 observers_,
2284 DidGetRedirectForResourceRequest(render_view_host, details));
2286 // TODO(avi): Remove. http://crbug.com/170921
2287 NotificationService::current()->Notify(
2288 NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
2289 Source<WebContents>(this),
2290 Details<const ResourceRedirectDetails>(&details));
2293 void WebContentsImpl::SystemDragEnded() {
2294 if (GetRenderViewHost())
2295 GetRenderViewHostImpl()->DragSourceSystemDragEnded();
2296 if (delegate_)
2297 delegate_->DragEnded();
2298 if (browser_plugin_embedder_.get())
2299 browser_plugin_embedder_->SystemDragEnded();
2302 void WebContentsImpl::UserGestureDone() {
2303 OnUserGesture();
2306 void WebContentsImpl::SetClosedByUserGesture(bool value) {
2307 closed_by_user_gesture_ = value;
2310 bool WebContentsImpl::GetClosedByUserGesture() const {
2311 return closed_by_user_gesture_;
2314 void WebContentsImpl::ViewSource() {
2315 if (!delegate_)
2316 return;
2318 NavigationEntry* entry = GetController().GetLastCommittedEntry();
2319 if (!entry)
2320 return;
2322 delegate_->ViewSourceForTab(this, entry->GetURL());
2325 void WebContentsImpl::ViewFrameSource(const GURL& url,
2326 const PageState& page_state) {
2327 if (!delegate_)
2328 return;
2330 delegate_->ViewSourceForFrame(this, url, page_state);
2333 int WebContentsImpl::GetMinimumZoomPercent() const {
2334 return minimum_zoom_percent_;
2337 int WebContentsImpl::GetMaximumZoomPercent() const {
2338 return maximum_zoom_percent_;
2341 gfx::Size WebContentsImpl::GetPreferredSize() const {
2342 return capturer_count_ == 0 ? preferred_size_ : preferred_size_for_capture_;
2345 bool WebContentsImpl::GotResponseToLockMouseRequest(bool allowed) {
2346 if (GetBrowserPluginGuest())
2347 return GetBrowserPluginGuest()->LockMouse(allowed);
2349 return GetRenderViewHost() ?
2350 GetRenderViewHostImpl()->GotResponseToLockMouseRequest(allowed) : false;
2353 bool WebContentsImpl::HasOpener() const {
2354 return opener_ != NULL;
2357 void WebContentsImpl::DidChooseColorInColorChooser(SkColor color) {
2358 if (!color_chooser_info_.get())
2359 return;
2360 RenderFrameHost* rfh = RenderFrameHost::FromID(
2361 color_chooser_info_->render_process_id,
2362 color_chooser_info_->render_frame_id);
2363 if (!rfh)
2364 return;
2366 rfh->Send(new FrameMsg_DidChooseColorResponse(
2367 rfh->GetRoutingID(), color_chooser_info_->identifier, color));
2370 void WebContentsImpl::DidEndColorChooser() {
2371 if (!color_chooser_info_.get())
2372 return;
2373 RenderFrameHost* rfh = RenderFrameHost::FromID(
2374 color_chooser_info_->render_process_id,
2375 color_chooser_info_->render_frame_id);
2376 if (!rfh)
2377 return;
2379 rfh->Send(new FrameMsg_DidEndColorChooser(
2380 rfh->GetRoutingID(), color_chooser_info_->identifier));
2381 color_chooser_info_.reset();
2384 int WebContentsImpl::DownloadImage(const GURL& url,
2385 bool is_favicon,
2386 uint32_t max_bitmap_size,
2387 const ImageDownloadCallback& callback) {
2388 int id = StartDownload(GetMainFrame(), url, is_favicon, max_bitmap_size);
2389 image_download_map_[id] = callback;
2390 return id;
2393 bool WebContentsImpl::IsSubframe() const {
2394 return is_subframe_;
2397 void WebContentsImpl::Find(int request_id,
2398 const base::string16& search_text,
2399 const blink::WebFindOptions& options) {
2400 Send(new ViewMsg_Find(GetRoutingID(), request_id, search_text, options));
2403 void WebContentsImpl::StopFinding(StopFindAction action) {
2404 Send(new ViewMsg_StopFinding(GetRoutingID(), action));
2407 void WebContentsImpl::InsertCSS(const std::string& css) {
2408 GetMainFrame()->Send(new FrameMsg_CSSInsertRequest(
2409 GetMainFrame()->GetRoutingID(), css));
2412 bool WebContentsImpl::WasRecentlyAudible() {
2413 return audio_stream_monitor_.WasRecentlyAudible();
2416 bool WebContentsImpl::FocusLocationBarByDefault() {
2417 NavigationEntry* entry = controller_.GetVisibleEntry();
2418 if (entry && entry->GetURL() == GURL(url::kAboutBlankURL))
2419 return true;
2420 return delegate_ && delegate_->ShouldFocusLocationBarByDefault(this);
2423 void WebContentsImpl::SetFocusToLocationBar(bool select_all) {
2424 if (delegate_)
2425 delegate_->SetFocusToLocationBar(select_all);
2428 void WebContentsImpl::DidStartProvisionalLoad(
2429 RenderFrameHostImpl* render_frame_host,
2430 const GURL& validated_url,
2431 bool is_error_page,
2432 bool is_iframe_srcdoc) {
2433 // Notify observers about the start of the provisional load.
2434 FOR_EACH_OBSERVER(
2435 WebContentsObserver,
2436 observers_,
2437 DidStartProvisionalLoadForFrame(
2438 render_frame_host, validated_url, is_error_page, is_iframe_srcdoc));
2440 if (!render_frame_host->GetParent()) {
2441 FOR_EACH_OBSERVER(
2442 WebContentsObserver,
2443 observers_,
2444 ProvisionalChangeToMainFrameUrl(validated_url,
2445 render_frame_host));
2449 void WebContentsImpl::DidStartNavigationTransition(
2450 RenderFrameHostImpl* render_frame_host) {
2451 #if defined(OS_ANDROID)
2452 int render_frame_id = render_frame_host->GetRoutingID();
2453 GetWebContentsAndroid()->DidStartNavigationTransitionForFrame(
2454 render_frame_id);
2455 #endif
2458 void WebContentsImpl::DidFailProvisionalLoadWithError(
2459 RenderFrameHostImpl* render_frame_host,
2460 const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) {
2461 GURL validated_url(params.url);
2462 FOR_EACH_OBSERVER(WebContentsObserver,
2463 observers_,
2464 DidFailProvisionalLoad(render_frame_host,
2465 validated_url,
2466 params.error_code,
2467 params.error_description));
2470 void WebContentsImpl::DidFailLoadWithError(
2471 RenderFrameHostImpl* render_frame_host,
2472 const GURL& url,
2473 int error_code,
2474 const base::string16& error_description) {
2475 FOR_EACH_OBSERVER(
2476 WebContentsObserver,
2477 observers_,
2478 DidFailLoad(render_frame_host, url, error_code, error_description));
2481 void WebContentsImpl::NotifyChangedNavigationState(
2482 InvalidateTypes changed_flags) {
2483 NotifyNavigationStateChanged(changed_flags);
2486 void WebContentsImpl::AboutToNavigateRenderFrame(
2487 RenderFrameHostImpl* render_frame_host) {
2488 // Notify observers that we will navigate in this RenderView.
2489 RenderViewHost* render_view_host = render_frame_host->render_view_host();
2490 FOR_EACH_OBSERVER(
2491 WebContentsObserver,
2492 observers_,
2493 AboutToNavigateRenderView(render_view_host));
2496 void WebContentsImpl::DidStartNavigationToPendingEntry(
2497 RenderFrameHostImpl* render_frame_host,
2498 const GURL& url,
2499 NavigationController::ReloadType reload_type) {
2500 // Notify observers about navigation.
2501 FOR_EACH_OBSERVER(
2502 WebContentsObserver,
2503 observers_,
2504 DidStartNavigationToPendingEntry(url, reload_type));
2507 void WebContentsImpl::RequestOpenURL(RenderFrameHostImpl* render_frame_host,
2508 const OpenURLParams& params) {
2509 int source_render_frame_id = render_frame_host->GetRoutingID();
2510 WebContents* new_contents = OpenURL(params);
2512 if (new_contents) {
2513 // Notify observers.
2514 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2515 DidOpenRequestedURL(new_contents,
2516 params.url,
2517 params.referrer,
2518 params.disposition,
2519 params.transition,
2520 source_render_frame_id));
2524 bool WebContentsImpl::ShouldPreserveAbortedURLs() {
2525 if (!delegate_)
2526 return false;
2527 return delegate_->ShouldPreserveAbortedURLs(this);
2530 void WebContentsImpl::DidRedirectProvisionalLoad(
2531 RenderFrameHostImpl* render_frame_host,
2532 const GURL& validated_target_url) {
2533 // Notify observers about the provisional change in the main frame URL.
2534 FOR_EACH_OBSERVER(
2535 WebContentsObserver,
2536 observers_,
2537 ProvisionalChangeToMainFrameUrl(validated_target_url,
2538 render_frame_host));
2541 void WebContentsImpl::DidCommitProvisionalLoad(
2542 RenderFrameHostImpl* render_frame_host,
2543 const GURL& url,
2544 PageTransition transition_type) {
2545 // Notify observers about the commit of the provisional load.
2546 FOR_EACH_OBSERVER(WebContentsObserver,
2547 observers_,
2548 DidCommitProvisionalLoadForFrame(
2549 render_frame_host, url, transition_type));
2552 void WebContentsImpl::DidNavigateMainFramePreCommit(
2553 bool navigation_is_within_page) {
2554 // Ensure fullscreen mode is exited before committing the navigation to a
2555 // different page. The next page will not start out assuming it is in
2556 // fullscreen mode.
2557 if (navigation_is_within_page) {
2558 // No page change? Then, the renderer and browser can remain in fullscreen.
2559 return;
2561 if (IsFullscreenForCurrentTab())
2562 GetRenderViewHost()->ExitFullscreen();
2563 DCHECK(!IsFullscreenForCurrentTab());
2566 void WebContentsImpl::DidNavigateMainFramePostCommit(
2567 const LoadCommittedDetails& details,
2568 const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
2569 if (details.is_navigation_to_different_page()) {
2570 // Clear the status bubble. This is a workaround for a bug where WebKit
2571 // doesn't let us know that the cursor left an element during a
2572 // transition (this is also why the mouse cursor remains as a hand after
2573 // clicking on a link); see bugs 1184641 and 980803. We don't want to
2574 // clear the bubble when a user navigates to a named anchor in the same
2575 // page.
2576 UpdateTargetURL(details.entry->GetPageID(), GURL());
2579 if (!details.is_in_page) {
2580 // Once the main frame is navigated, we're no longer considered to have
2581 // displayed insecure content.
2582 displayed_insecure_content_ = false;
2583 SSLManager::NotifySSLInternalStateChanged(
2584 GetController().GetBrowserContext());
2587 // Notify observers about navigation.
2588 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2589 DidNavigateMainFrame(details, params));
2591 if (delegate_)
2592 delegate_->DidNavigateMainFramePostCommit(this);
2593 view_->SetOverscrollControllerEnabled(CanOverscrollContent());
2596 void WebContentsImpl::DidNavigateAnyFramePostCommit(
2597 RenderFrameHostImpl* render_frame_host,
2598 const LoadCommittedDetails& details,
2599 const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
2600 // Now that something has committed, we don't need to track whether the
2601 // initial page has been accessed.
2602 has_accessed_initial_document_ = false;
2604 // If we navigate off the page, close all JavaScript dialogs.
2605 if (dialog_manager_ && !details.is_in_page)
2606 dialog_manager_->CancelActiveAndPendingDialogs(this);
2608 // Notify observers about navigation.
2609 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2610 DidNavigateAnyFrame(details, params));
2613 void WebContentsImpl::SetMainFrameMimeType(const std::string& mime_type) {
2614 contents_mime_type_ = mime_type;
2617 bool WebContentsImpl::CanOverscrollContent() const {
2618 // Disable overscroll when touch emulation is on. See crbug.com/369938.
2619 if (force_disable_overscroll_content_)
2620 return false;
2622 if (delegate_)
2623 return delegate_->CanOverscrollContent();
2625 return false;
2628 void WebContentsImpl::OnThemeColorChanged(SkColor theme_color) {
2629 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2630 DidChangeThemeColor(theme_color));
2633 void WebContentsImpl::OnDidLoadResourceFromMemoryCache(
2634 const GURL& url,
2635 const std::string& security_info,
2636 const std::string& http_method,
2637 const std::string& mime_type,
2638 ResourceType resource_type) {
2639 base::StatsCounter cache("WebKit.CacheHit");
2640 cache.Increment();
2642 // Send out a notification that we loaded a resource from our memory cache.
2643 int cert_id = 0;
2644 net::CertStatus cert_status = 0;
2645 int security_bits = -1;
2646 int connection_status = 0;
2647 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
2648 DeserializeSecurityInfo(security_info, &cert_id, &cert_status,
2649 &security_bits, &connection_status,
2650 &signed_certificate_timestamp_ids);
2651 // TODO(alcutter,eranm): Pass signed_certificate_timestamp_ids into details
2652 LoadFromMemoryCacheDetails details(
2653 url, GetRenderProcessHost()->GetID(), cert_id, cert_status, http_method,
2654 mime_type, resource_type);
2656 controller_.ssl_manager()->DidLoadFromMemoryCache(details);
2658 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2659 DidLoadResourceFromMemoryCache(details));
2661 if (url.is_valid() && url.SchemeIsHTTPOrHTTPS()) {
2662 scoped_refptr<net::URLRequestContextGetter> request_context(
2663 resource_type == RESOURCE_TYPE_MEDIA ?
2664 GetBrowserContext()->GetMediaRequestContextForRenderProcess(
2665 GetRenderProcessHost()->GetID()) :
2666 GetBrowserContext()->GetRequestContextForRenderProcess(
2667 GetRenderProcessHost()->GetID()));
2668 BrowserThread::PostTask(
2669 BrowserThread::IO,
2670 FROM_HERE,
2671 base::Bind(&NotifyCacheOnIO, request_context, url, http_method));
2675 void WebContentsImpl::OnDidDisplayInsecureContent() {
2676 RecordAction(base::UserMetricsAction("SSL.DisplayedInsecureContent"));
2677 displayed_insecure_content_ = true;
2678 SSLManager::NotifySSLInternalStateChanged(
2679 GetController().GetBrowserContext());
2682 void WebContentsImpl::OnDidRunInsecureContent(
2683 const std::string& security_origin, const GURL& target_url) {
2684 LOG(WARNING) << security_origin << " ran insecure content from "
2685 << target_url.possibly_invalid_spec();
2686 RecordAction(base::UserMetricsAction("SSL.RanInsecureContent"));
2687 if (EndsWith(security_origin, kDotGoogleDotCom, false))
2688 RecordAction(base::UserMetricsAction("SSL.RanInsecureContentGoogle"));
2689 controller_.ssl_manager()->DidRunInsecureContent(security_origin);
2690 displayed_insecure_content_ = true;
2691 SSLManager::NotifySSLInternalStateChanged(
2692 GetController().GetBrowserContext());
2695 void WebContentsImpl::OnDocumentLoadedInFrame() {
2696 CHECK(render_frame_message_source_);
2697 CHECK(!render_view_message_source_);
2698 RenderFrameHostImpl* rfh =
2699 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2700 FOR_EACH_OBSERVER(
2701 WebContentsObserver, observers_, DocumentLoadedInFrame(rfh));
2704 void WebContentsImpl::OnDidFinishLoad(
2705 const GURL& url) {
2706 if (!render_frame_message_source_) {
2707 RecordAction(base::UserMetricsAction("BadMessageTerminate_RVD2"));
2708 GetRenderProcessHost()->ReceivedBadMessage();
2709 return;
2712 GURL validated_url(url);
2713 RenderProcessHost* render_process_host =
2714 render_frame_message_source_->GetProcess();
2715 render_process_host->FilterURL(false, &validated_url);
2717 RenderFrameHostImpl* rfh =
2718 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2719 FOR_EACH_OBSERVER(
2720 WebContentsObserver, observers_, DidFinishLoad(rfh, validated_url));
2723 void WebContentsImpl::OnDidStartLoading(bool to_different_document) {
2724 RenderFrameHostImpl* rfh =
2725 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2726 int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id();
2728 // It is possible to get multiple calls to OnDidStartLoading that don't have
2729 // corresponding calls to OnDidStopLoading:
2730 // - With "swappedout://" URLs, this happens when a RenderView gets swapped
2731 // out for a cross-process navigation, and it turns into a placeholder for
2732 // one being rendered in a different process.
2733 // - Also, there might be more than one RenderFrameHost sharing the same
2734 // FrameTreeNode (and thus sharing its ID) each sending a start.
2735 // - But in the future, once clamy@ moves navigation network requests to the
2736 // browser process, there's a good chance that callbacks about starting and
2737 // stopping will all be handled by the browser. When that happens, there
2738 // should no longer be a start/stop call imbalance. TODO(avi): When this
2739 // future arrives, update this code to not allow this case.
2740 DCHECK_GE(loading_frames_in_progress_, 0);
2741 if (loading_progresses_.find(render_frame_id) == loading_progresses_.end()) {
2742 if (loading_frames_in_progress_ == 0)
2743 DidStartLoading(rfh, to_different_document);
2744 ++loading_frames_in_progress_;
2747 loading_progresses_[render_frame_id] = kMinimumLoadingProgress;
2748 SendLoadProgressChanged();
2751 void WebContentsImpl::OnDidStopLoading() {
2752 RenderFrameHostImpl* rfh =
2753 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2754 int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id();
2756 if (loading_progresses_.find(render_frame_id) != loading_progresses_.end()) {
2757 // Load stopped while we were still tracking load. Make sure we update
2758 // progress based on this frame's completion.
2759 loading_progresses_[render_frame_id] = 1.0;
2760 SendLoadProgressChanged();
2761 // Then we clean-up our states.
2762 if (loading_total_progress_ == 1.0)
2763 ResetLoadProgressState();
2766 // TODO(japhet): This should be a DCHECK, but the pdf plugin sometimes
2767 // calls DidStopLoading() without a matching DidStartLoading().
2768 if (loading_frames_in_progress_ == 0)
2769 return;
2770 --loading_frames_in_progress_;
2771 if (loading_frames_in_progress_ == 0)
2772 DidStopLoading(rfh);
2775 void WebContentsImpl::OnDidChangeLoadProgress(double load_progress) {
2776 RenderFrameHostImpl* rfh =
2777 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2778 int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id();
2780 loading_progresses_[render_frame_id] = load_progress;
2782 // We notify progress change immediately for the first and last updates.
2783 // Also, since the message loop may be pretty busy when a page is loaded, it
2784 // might not execute a posted task in a timely manner so we make sure to
2785 // immediately send progress report if enough time has passed.
2786 base::TimeDelta min_delay =
2787 base::TimeDelta::FromMilliseconds(kMinimumDelayBetweenLoadingUpdatesMS);
2788 if (load_progress == 1.0 || loading_last_progress_update_.is_null() ||
2789 base::TimeTicks::Now() - loading_last_progress_update_ > min_delay) {
2790 // If there is a pending task to send progress, it is now obsolete.
2791 loading_weak_factory_.InvalidateWeakPtrs();
2792 SendLoadProgressChanged();
2793 if (loading_total_progress_ == 1.0)
2794 ResetLoadProgressState();
2795 return;
2798 if (loading_weak_factory_.HasWeakPtrs())
2799 return;
2801 base::MessageLoop::current()->PostDelayedTask(
2802 FROM_HERE,
2803 base::Bind(&WebContentsImpl::SendLoadProgressChanged,
2804 loading_weak_factory_.GetWeakPtr()),
2805 min_delay);
2808 void WebContentsImpl::OnGoToEntryAtOffset(int offset) {
2809 if (!delegate_ || delegate_->OnGoToEntryOffset(offset))
2810 controller_.GoToOffset(offset);
2813 void WebContentsImpl::OnUpdateZoomLimits(int minimum_percent,
2814 int maximum_percent) {
2815 minimum_zoom_percent_ = minimum_percent;
2816 maximum_zoom_percent_ = maximum_percent;
2819 void WebContentsImpl::OnEnumerateDirectory(int request_id,
2820 const base::FilePath& path) {
2821 if (!delegate_)
2822 return;
2824 ChildProcessSecurityPolicyImpl* policy =
2825 ChildProcessSecurityPolicyImpl::GetInstance();
2826 if (policy->CanReadFile(GetRenderProcessHost()->GetID(), path))
2827 delegate_->EnumerateDirectory(this, request_id, path);
2830 void WebContentsImpl::OnRegisterProtocolHandler(const std::string& protocol,
2831 const GURL& url,
2832 const base::string16& title,
2833 bool user_gesture) {
2834 if (!delegate_)
2835 return;
2837 ChildProcessSecurityPolicyImpl* policy =
2838 ChildProcessSecurityPolicyImpl::GetInstance();
2839 if (policy->IsPseudoScheme(protocol))
2840 return;
2842 delegate_->RegisterProtocolHandler(this, protocol, url, user_gesture);
2845 void WebContentsImpl::OnUnregisterProtocolHandler(const std::string& protocol,
2846 const GURL& url,
2847 bool user_gesture) {
2848 if (!delegate_)
2849 return;
2851 ChildProcessSecurityPolicyImpl* policy =
2852 ChildProcessSecurityPolicyImpl::GetInstance();
2853 if (policy->IsPseudoScheme(protocol))
2854 return;
2856 delegate_->UnregisterProtocolHandler(this, protocol, url, user_gesture);
2859 void WebContentsImpl::OnFindReply(int request_id,
2860 int number_of_matches,
2861 const gfx::Rect& selection_rect,
2862 int active_match_ordinal,
2863 bool final_update) {
2864 if (delegate_) {
2865 delegate_->FindReply(this, request_id, number_of_matches, selection_rect,
2866 active_match_ordinal, final_update);
2870 #if defined(OS_ANDROID)
2871 void WebContentsImpl::OnFindMatchRectsReply(
2872 int version,
2873 const std::vector<gfx::RectF>& rects,
2874 const gfx::RectF& active_rect) {
2875 if (delegate_)
2876 delegate_->FindMatchRectsReply(this, version, rects, active_rect);
2879 void WebContentsImpl::OnOpenDateTimeDialog(
2880 const ViewHostMsg_DateTimeDialogValue_Params& value) {
2881 date_time_chooser_->ShowDialog(ContentViewCore::FromWebContents(this),
2882 GetRenderViewHost(),
2883 value.dialog_type,
2884 value.dialog_value,
2885 value.minimum,
2886 value.maximum,
2887 value.step,
2888 value.suggestions);
2891 #endif
2893 void WebContentsImpl::OnPepperPluginHung(int plugin_child_id,
2894 const base::FilePath& path,
2895 bool is_hung) {
2896 UMA_HISTOGRAM_COUNTS("Pepper.PluginHung", 1);
2898 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2899 PluginHungStatusChanged(plugin_child_id, path, is_hung));
2902 void WebContentsImpl::OnPluginCrashed(const base::FilePath& plugin_path,
2903 base::ProcessId plugin_pid) {
2904 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2905 PluginCrashed(plugin_path, plugin_pid));
2908 void WebContentsImpl::OnDomOperationResponse(const std::string& json_string,
2909 int automation_id) {
2910 DomOperationNotificationDetails details(json_string, automation_id);
2911 NotificationService::current()->Notify(
2912 NOTIFICATION_DOM_OPERATION_RESPONSE,
2913 Source<WebContents>(this),
2914 Details<DomOperationNotificationDetails>(&details));
2917 void WebContentsImpl::OnAppCacheAccessed(const GURL& manifest_url,
2918 bool blocked_by_policy) {
2919 // Notify observers about navigation.
2920 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2921 AppCacheAccessed(manifest_url, blocked_by_policy));
2924 void WebContentsImpl::OnOpenColorChooser(
2925 int color_chooser_id,
2926 SkColor color,
2927 const std::vector<ColorSuggestion>& suggestions) {
2928 ColorChooser* new_color_chooser = delegate_ ?
2929 delegate_->OpenColorChooser(this, color, suggestions) :
2930 NULL;
2931 if (!new_color_chooser)
2932 return;
2933 if (color_chooser_info_.get())
2934 color_chooser_info_->chooser->End();
2936 color_chooser_info_.reset(new ColorChooserInfo(
2937 render_frame_message_source_->GetProcess()->GetID(),
2938 render_frame_message_source_->GetRoutingID(),
2939 new_color_chooser,
2940 color_chooser_id));
2943 void WebContentsImpl::OnEndColorChooser(int color_chooser_id) {
2944 if (color_chooser_info_ &&
2945 color_chooser_id == color_chooser_info_->identifier)
2946 color_chooser_info_->chooser->End();
2949 void WebContentsImpl::OnSetSelectedColorInColorChooser(int color_chooser_id,
2950 SkColor color) {
2951 if (color_chooser_info_ &&
2952 color_chooser_id == color_chooser_info_->identifier)
2953 color_chooser_info_->chooser->SetSelectedColor(color);
2956 // This exists for render views that don't have a WebUI, but do have WebUI
2957 // bindings enabled.
2958 void WebContentsImpl::OnWebUISend(const GURL& source_url,
2959 const std::string& name,
2960 const base::ListValue& args) {
2961 if (delegate_)
2962 delegate_->WebUISend(this, source_url, name, args);
2965 #if defined(ENABLE_PLUGINS)
2966 void WebContentsImpl::OnRequestPpapiBrokerPermission(
2967 int routing_id,
2968 const GURL& url,
2969 const base::FilePath& plugin_path) {
2970 if (!delegate_) {
2971 OnPpapiBrokerPermissionResult(routing_id, false);
2972 return;
2975 if (!delegate_->RequestPpapiBrokerPermission(
2976 this, url, plugin_path,
2977 base::Bind(&WebContentsImpl::OnPpapiBrokerPermissionResult,
2978 base::Unretained(this), routing_id))) {
2979 NOTIMPLEMENTED();
2980 OnPpapiBrokerPermissionResult(routing_id, false);
2984 void WebContentsImpl::OnPpapiBrokerPermissionResult(int routing_id,
2985 bool result) {
2986 Send(new ViewMsg_PpapiBrokerPermissionResult(routing_id, result));
2989 void WebContentsImpl::OnBrowserPluginMessage(const IPC::Message& message) {
2990 // This creates a BrowserPluginEmbedder, which handles all the BrowserPlugin
2991 // specific messages for this WebContents. This means that any message from
2992 // a BrowserPlugin prior to this will be ignored.
2993 // For more info, see comment above classes BrowserPluginEmbedder and
2994 // BrowserPluginGuest.
2995 CHECK(!browser_plugin_embedder_.get());
2996 browser_plugin_embedder_.reset(BrowserPluginEmbedder::Create(this));
2997 browser_plugin_embedder_->OnMessageReceived(message);
2999 #endif
3001 void WebContentsImpl::OnDidDownloadImage(
3002 int id,
3003 int http_status_code,
3004 const GURL& image_url,
3005 const std::vector<SkBitmap>& bitmaps,
3006 const std::vector<gfx::Size>& original_bitmap_sizes) {
3007 if (bitmaps.size() != original_bitmap_sizes.size())
3008 return;
3010 ImageDownloadMap::iterator iter = image_download_map_.find(id);
3011 if (iter == image_download_map_.end()) {
3012 // Currently WebContents notifies us of ANY downloads so that it is
3013 // possible to get here.
3014 return;
3016 if (!iter->second.is_null()) {
3017 iter->second.Run(
3018 id, http_status_code, image_url, bitmaps, original_bitmap_sizes);
3020 image_download_map_.erase(id);
3023 void WebContentsImpl::OnUpdateFaviconURL(
3024 const std::vector<FaviconURL>& candidates) {
3025 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3026 DidUpdateFaviconURL(candidates));
3029 void WebContentsImpl::CreateAudioPowerSaveBlocker() {
3030 // ChromeOS has its own way of handling power save blocks for media.
3031 #if !defined(OS_CHROMEOS)
3032 DCHECK(!audio_power_save_blocker_);
3033 audio_power_save_blocker_ = PowerSaveBlocker::Create(
3034 PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, "Playing Audio");
3035 #endif
3038 void WebContentsImpl::CreateVideoPowerSaveBlocker() {
3039 // ChromeOS has its own way of handling power save blocks for media.
3040 #if !defined(OS_CHROMEOS)
3041 DCHECK(!video_power_save_blocker_);
3042 DCHECK(!active_video_players_.empty());
3043 video_power_save_blocker_ = PowerSaveBlocker::Create(
3044 PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, "Playing Video");
3045 #if defined(OS_ANDROID)
3046 static_cast<PowerSaveBlockerImpl*>(video_power_save_blocker_.get())
3047 ->InitDisplaySleepBlocker(GetView()->GetNativeView());
3048 #endif
3049 #endif
3052 void WebContentsImpl::MaybeReleasePowerSaveBlockers() {
3053 // If there are no more audio players and we don't have audio stream
3054 // monitoring, release the audio power save blocker here instead of during
3055 // NotifyNavigationStateChanged().
3056 if (active_audio_players_.empty() &&
3057 !AudioStreamMonitor::monitoring_available()) {
3058 audio_power_save_blocker_.reset();
3061 // If there are no more video players, clear the video power save blocker.
3062 if (active_video_players_.empty())
3063 video_power_save_blocker_.reset();
3066 void WebContentsImpl::OnMediaPlayingNotification(int64 player_cookie,
3067 bool has_video,
3068 bool has_audio) {
3069 if (has_audio) {
3070 AddMediaPlayerEntry(player_cookie, &active_audio_players_);
3072 // If we don't have audio stream monitoring, allocate the audio power save
3073 // blocker here instead of during NotifyNavigationStateChanged().
3074 if (!audio_power_save_blocker_ &&
3075 !AudioStreamMonitor::monitoring_available()) {
3076 CreateAudioPowerSaveBlocker();
3080 if (has_video) {
3081 AddMediaPlayerEntry(player_cookie, &active_video_players_);
3083 // If we're not hidden and have just created a player, create a blocker.
3084 if (!video_power_save_blocker_ && !IsHidden())
3085 CreateVideoPowerSaveBlocker();
3089 void WebContentsImpl::OnMediaPausedNotification(int64 player_cookie) {
3090 RemoveMediaPlayerEntry(player_cookie, &active_audio_players_);
3091 RemoveMediaPlayerEntry(player_cookie, &active_video_players_);
3092 MaybeReleasePowerSaveBlockers();
3095 void WebContentsImpl::OnFirstVisuallyNonEmptyPaint() {
3096 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3097 DidFirstVisuallyNonEmptyPaint());
3100 void WebContentsImpl::DidChangeVisibleSSLState() {
3101 if (delegate_)
3102 delegate_->VisibleSSLStateChanged(this);
3105 void WebContentsImpl::NotifyBeforeFormRepostWarningShow() {
3106 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3107 BeforeFormRepostWarningShow());
3110 void WebContentsImpl::ActivateAndShowRepostFormWarningDialog() {
3111 Activate();
3112 if (delegate_)
3113 delegate_->ShowRepostFormWarningDialog(this);
3116 bool WebContentsImpl::HasAccessedInitialDocument() {
3117 return has_accessed_initial_document_;
3120 // Notifies the RenderWidgetHost instance about the fact that the page is
3121 // loading, or done loading.
3122 void WebContentsImpl::SetIsLoading(RenderViewHost* render_view_host,
3123 bool is_loading,
3124 bool to_different_document,
3125 LoadNotificationDetails* details) {
3126 if (is_loading == is_loading_)
3127 return;
3129 if (!is_loading) {
3130 load_state_ = net::LoadStateWithParam(net::LOAD_STATE_IDLE,
3131 base::string16());
3132 load_state_host_.clear();
3133 upload_size_ = 0;
3134 upload_position_ = 0;
3137 GetRenderManager()->SetIsLoading(is_loading);
3139 is_loading_ = is_loading;
3140 waiting_for_response_ = is_loading;
3141 is_load_to_different_document_ = to_different_document;
3143 if (delegate_)
3144 delegate_->LoadingStateChanged(this, to_different_document);
3145 NotifyNavigationStateChanged(INVALIDATE_TYPE_LOAD);
3147 std::string url = (details ? details->url.possibly_invalid_spec() : "NULL");
3148 if (is_loading) {
3149 TRACE_EVENT_ASYNC_BEGIN1("browser,navigation", "WebContentsImpl Loading",
3150 this, "URL", url);
3151 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3152 DidStartLoading(render_view_host));
3153 } else {
3154 TRACE_EVENT_ASYNC_END1("browser,navigation", "WebContentsImpl Loading",
3155 this, "URL", url);
3156 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3157 DidStopLoading(render_view_host));
3160 // TODO(avi): Remove. http://crbug.com/170921
3161 int type = is_loading ? NOTIFICATION_LOAD_START : NOTIFICATION_LOAD_STOP;
3162 NotificationDetails det = NotificationService::NoDetails();
3163 if (details)
3164 det = Details<LoadNotificationDetails>(details);
3165 NotificationService::current()->Notify(
3166 type, Source<NavigationController>(&controller_), det);
3169 void WebContentsImpl::SelectRange(const gfx::Point& start,
3170 const gfx::Point& end) {
3171 RenderFrameHost* focused_frame = GetFocusedFrame();
3172 if (!focused_frame)
3173 return;
3175 focused_frame->Send(
3176 new InputMsg_SelectRange(focused_frame->GetRoutingID(), start, end));
3179 void WebContentsImpl::UpdateMaxPageIDIfNecessary(RenderViewHost* rvh) {
3180 // If we are creating a RVH for a restored controller, then we need to make
3181 // sure the RenderView starts with a next_page_id_ larger than the number
3182 // of restored entries. This must be called before the RenderView starts
3183 // navigating (to avoid a race between the browser updating max_page_id and
3184 // the renderer updating next_page_id_). Because of this, we only call this
3185 // from CreateRenderView and allow that to notify the RenderView for us.
3186 int max_restored_page_id = controller_.GetMaxRestoredPageID();
3187 if (max_restored_page_id >
3188 GetMaxPageIDForSiteInstance(rvh->GetSiteInstance()))
3189 UpdateMaxPageIDForSiteInstance(rvh->GetSiteInstance(),
3190 max_restored_page_id);
3193 bool WebContentsImpl::UpdateTitleForEntry(NavigationEntryImpl* entry,
3194 const base::string16& title) {
3195 // For file URLs without a title, use the pathname instead. In the case of a
3196 // synthesized title, we don't want the update to count toward the "one set
3197 // per page of the title to history."
3198 base::string16 final_title;
3199 bool explicit_set;
3200 if (entry && entry->GetURL().SchemeIsFile() && title.empty()) {
3201 final_title = base::UTF8ToUTF16(entry->GetURL().ExtractFileName());
3202 explicit_set = false; // Don't count synthetic titles toward the set limit.
3203 } else {
3204 base::TrimWhitespace(title, base::TRIM_ALL, &final_title);
3205 explicit_set = true;
3208 // If a page is created via window.open and never navigated,
3209 // there will be no navigation entry. In this situation,
3210 // |page_title_when_no_navigation_entry_| will be used for page title.
3211 if (entry) {
3212 if (final_title == entry->GetTitle())
3213 return false; // Nothing changed, don't bother.
3215 entry->SetTitle(final_title);
3216 } else {
3217 if (page_title_when_no_navigation_entry_ == final_title)
3218 return false; // Nothing changed, don't bother.
3220 page_title_when_no_navigation_entry_ = final_title;
3223 // Lastly, set the title for the view.
3224 view_->SetPageTitle(final_title);
3226 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3227 TitleWasSet(entry, explicit_set));
3229 // TODO(avi): Remove. http://crbug.com/170921
3230 std::pair<NavigationEntry*, bool> details =
3231 std::make_pair(entry, explicit_set);
3232 NotificationService::current()->Notify(
3233 NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
3234 Source<WebContents>(this),
3235 Details<std::pair<NavigationEntry*, bool> >(&details));
3237 return true;
3240 void WebContentsImpl::SendLoadProgressChanged() {
3241 loading_last_progress_update_ = base::TimeTicks::Now();
3242 double progress = 0.0;
3243 int frame_count = 0;
3245 for (LoadingProgressMap::iterator it = loading_progresses_.begin();
3246 it != loading_progresses_.end();
3247 ++it) {
3248 progress += it->second;
3249 ++frame_count;
3251 if (frame_count == 0)
3252 return;
3253 progress /= frame_count;
3254 DCHECK(progress <= 1.0);
3256 if (progress <= loading_total_progress_)
3257 return;
3258 loading_total_progress_ = progress;
3260 if (delegate_)
3261 delegate_->LoadProgressChanged(this, progress);
3264 void WebContentsImpl::ResetLoadProgressState() {
3265 loading_progresses_.clear();
3266 loading_total_progress_ = 0.0;
3267 loading_weak_factory_.InvalidateWeakPtrs();
3268 loading_last_progress_update_ = base::TimeTicks();
3271 void WebContentsImpl::NotifyViewSwapped(RenderViewHost* old_host,
3272 RenderViewHost* new_host) {
3273 // After sending out a swap notification, we need to send a disconnect
3274 // notification so that clients that pick up a pointer to |this| can NULL the
3275 // pointer. See Bug 1230284.
3276 notify_disconnection_ = true;
3277 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3278 RenderViewHostChanged(old_host, new_host));
3280 // TODO(avi): Remove. http://crbug.com/170921
3281 std::pair<RenderViewHost*, RenderViewHost*> details =
3282 std::make_pair(old_host, new_host);
3283 NotificationService::current()->Notify(
3284 NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
3285 Source<WebContents>(this),
3286 Details<std::pair<RenderViewHost*, RenderViewHost*> >(&details));
3288 // Ensure that the associated embedder gets cleared after a RenderViewHost
3289 // gets swapped, so we don't reuse the same embedder next time a
3290 // RenderViewHost is attached to this WebContents.
3291 RemoveBrowserPluginEmbedder();
3294 void WebContentsImpl::NotifyFrameSwapped(RenderFrameHost* old_host,
3295 RenderFrameHost* new_host) {
3296 FOR_EACH_OBSERVER(WebContentsObserver,
3297 observers_,
3298 RenderFrameHostChanged(old_host, new_host));
3301 // TODO(avi): Remove this entire function because this notification is already
3302 // covered by two observer functions. http://crbug.com/170921
3303 void WebContentsImpl::NotifyDisconnected() {
3304 if (!notify_disconnection_)
3305 return;
3307 notify_disconnection_ = false;
3308 NotificationService::current()->Notify(
3309 NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
3310 Source<WebContents>(this),
3311 NotificationService::NoDetails());
3314 void WebContentsImpl::NotifyNavigationEntryCommitted(
3315 const LoadCommittedDetails& load_details) {
3316 FOR_EACH_OBSERVER(
3317 WebContentsObserver, observers_, NavigationEntryCommitted(load_details));
3320 bool WebContentsImpl::OnMessageReceived(RenderFrameHost* render_frame_host,
3321 const IPC::Message& message) {
3322 return OnMessageReceived(NULL, render_frame_host, message);
3325 const GURL& WebContentsImpl::GetMainFrameLastCommittedURL() const {
3326 return GetLastCommittedURL();
3329 void WebContentsImpl::RenderFrameCreated(RenderFrameHost* render_frame_host) {
3330 // Note this is only for subframes, the notification for the main frame
3331 // happens in RenderViewCreated.
3332 FOR_EACH_OBSERVER(WebContentsObserver,
3333 observers_,
3334 RenderFrameCreated(render_frame_host));
3335 SetAccessibilityModeOnFrame(accessibility_mode_, render_frame_host);
3338 void WebContentsImpl::RenderFrameDeleted(RenderFrameHost* render_frame_host) {
3339 ClearPowerSaveBlockers(render_frame_host);
3340 FOR_EACH_OBSERVER(WebContentsObserver,
3341 observers_,
3342 RenderFrameDeleted(render_frame_host));
3345 void WebContentsImpl::WorkerCrashed(RenderFrameHost* render_frame_host) {
3346 if (delegate_)
3347 delegate_->WorkerCrashed(this);
3350 void WebContentsImpl::ShowContextMenu(RenderFrameHost* render_frame_host,
3351 const ContextMenuParams& params) {
3352 ContextMenuParams context_menu_params(params);
3353 // Allow WebContentsDelegates to handle the context menu operation first.
3354 if (GetBrowserPluginGuest()) {
3355 WebContentsViewGuest* view_guest =
3356 static_cast<WebContentsViewGuest*>(GetView());
3357 context_menu_params = view_guest->ConvertContextMenuParams(params);
3359 if (delegate_ && delegate_->HandleContextMenu(context_menu_params))
3360 return;
3362 render_view_host_delegate_view_->ShowContextMenu(render_frame_host,
3363 context_menu_params);
3366 void WebContentsImpl::RunJavaScriptMessage(
3367 RenderFrameHost* render_frame_host,
3368 const base::string16& message,
3369 const base::string16& default_prompt,
3370 const GURL& frame_url,
3371 JavaScriptMessageType javascript_message_type,
3372 IPC::Message* reply_msg) {
3373 // Suppress JavaScript dialogs when requested. Also suppress messages when
3374 // showing an interstitial as it's shown over the previous page and we don't
3375 // want the hidden page's dialogs to interfere with the interstitial.
3376 bool suppress_this_message =
3377 static_cast<RenderViewHostImpl*>(render_frame_host->GetRenderViewHost())->
3378 IsSwappedOut() ||
3379 ShowingInterstitialPage() ||
3380 !delegate_ ||
3381 delegate_->ShouldSuppressDialogs() ||
3382 !delegate_->GetJavaScriptDialogManager();
3384 if (!suppress_this_message) {
3385 std::string accept_lang = GetContentClient()->browser()->
3386 GetAcceptLangs(GetBrowserContext());
3387 dialog_manager_ = delegate_->GetJavaScriptDialogManager();
3388 dialog_manager_->RunJavaScriptDialog(
3389 this,
3390 frame_url.GetOrigin(),
3391 accept_lang,
3392 javascript_message_type,
3393 message,
3394 default_prompt,
3395 base::Bind(&WebContentsImpl::OnDialogClosed,
3396 base::Unretained(this),
3397 render_frame_host->GetProcess()->GetID(),
3398 render_frame_host->GetRoutingID(),
3399 reply_msg,
3400 false),
3401 &suppress_this_message);
3404 if (suppress_this_message) {
3405 // If we are suppressing messages, just reply as if the user immediately
3406 // pressed "Cancel", passing true to |dialog_was_suppressed|.
3407 OnDialogClosed(render_frame_host->GetProcess()->GetID(),
3408 render_frame_host->GetRoutingID(), reply_msg,
3409 true, false, base::string16());
3412 // OnDialogClosed (two lines up) may have caused deletion of this object (see
3413 // http://crbug.com/288961 ). The only safe thing to do here is return.
3416 void WebContentsImpl::RunBeforeUnloadConfirm(
3417 RenderFrameHost* render_frame_host,
3418 const base::string16& message,
3419 bool is_reload,
3420 IPC::Message* reply_msg) {
3421 RenderFrameHostImpl* rfhi =
3422 static_cast<RenderFrameHostImpl*>(render_frame_host);
3423 RenderViewHostImpl* rvhi =
3424 static_cast<RenderViewHostImpl*>(render_frame_host->GetRenderViewHost());
3425 if (delegate_)
3426 delegate_->WillRunBeforeUnloadConfirm();
3428 bool suppress_this_message =
3429 rvhi->rvh_state() != RenderViewHostImpl::STATE_DEFAULT ||
3430 !delegate_ ||
3431 delegate_->ShouldSuppressDialogs() ||
3432 !delegate_->GetJavaScriptDialogManager();
3433 if (suppress_this_message) {
3434 rfhi->JavaScriptDialogClosed(reply_msg, true, base::string16(), true);
3435 return;
3438 is_showing_before_unload_dialog_ = true;
3439 dialog_manager_ = delegate_->GetJavaScriptDialogManager();
3440 dialog_manager_->RunBeforeUnloadDialog(
3441 this, message, is_reload,
3442 base::Bind(&WebContentsImpl::OnDialogClosed, base::Unretained(this),
3443 render_frame_host->GetProcess()->GetID(),
3444 render_frame_host->GetRoutingID(), reply_msg,
3445 false));
3448 WebContents* WebContentsImpl::GetAsWebContents() {
3449 return this;
3452 bool WebContentsImpl::IsNeverVisible() {
3453 if (!delegate_)
3454 return false;
3455 return delegate_->IsNeverVisible(this);
3458 #if defined(OS_WIN)
3459 gfx::NativeViewAccessible WebContentsImpl::GetParentNativeViewAccessible() {
3460 return accessible_parent_;
3462 #endif
3464 RenderViewHostDelegateView* WebContentsImpl::GetDelegateView() {
3465 return render_view_host_delegate_view_;
3468 RendererPreferences WebContentsImpl::GetRendererPrefs(
3469 BrowserContext* browser_context) const {
3470 return renderer_preferences_;
3473 gfx::Rect WebContentsImpl::GetRootWindowResizerRect() const {
3474 if (delegate_)
3475 return delegate_->GetRootWindowResizerRect();
3476 return gfx::Rect();
3479 void WebContentsImpl::RemoveBrowserPluginEmbedder() {
3480 if (browser_plugin_embedder_)
3481 browser_plugin_embedder_.reset();
3484 void WebContentsImpl::RenderViewCreated(RenderViewHost* render_view_host) {
3485 // Don't send notifications if we are just creating a swapped-out RVH for
3486 // the opener chain. These won't be used for view-source or WebUI, so it's
3487 // ok to return early.
3488 if (static_cast<RenderViewHostImpl*>(render_view_host)->IsSwappedOut())
3489 return;
3491 if (delegate_)
3492 view_->SetOverscrollControllerEnabled(CanOverscrollContent());
3494 NotificationService::current()->Notify(
3495 NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
3496 Source<WebContents>(this),
3497 Details<RenderViewHost>(render_view_host));
3499 // When we're creating views, we're still doing initial setup, so we always
3500 // use the pending Web UI rather than any possibly existing committed one.
3501 if (GetRenderManager()->pending_web_ui())
3502 GetRenderManager()->pending_web_ui()->RenderViewCreated(render_view_host);
3504 NavigationEntry* entry = controller_.GetPendingEntry();
3505 if (entry && entry->IsViewSourceMode()) {
3506 // Put the renderer in view source mode.
3507 render_view_host->Send(
3508 new ViewMsg_EnableViewSourceMode(render_view_host->GetRoutingID()));
3511 view_->RenderViewCreated(render_view_host);
3513 FOR_EACH_OBSERVER(
3514 WebContentsObserver, observers_, RenderViewCreated(render_view_host));
3516 // We tell the observers now instead of when the main RenderFrameHostImpl is
3517 // constructed because otherwise it would be too early (i.e. IPCs sent to the
3518 // frame would be dropped because it's not created yet).
3519 RenderFrameHost* main_frame = render_view_host->GetMainFrame();
3520 FOR_EACH_OBSERVER(
3521 WebContentsObserver, observers_, RenderFrameCreated(main_frame));
3522 SetAccessibilityModeOnFrame(accessibility_mode_, main_frame);
3525 void WebContentsImpl::RenderViewReady(RenderViewHost* rvh) {
3526 if (rvh != GetRenderViewHost()) {
3527 // Don't notify the world, since this came from a renderer in the
3528 // background.
3529 return;
3532 notify_disconnection_ = true;
3533 // TODO(avi): Remove. http://crbug.com/170921
3534 NotificationService::current()->Notify(
3535 NOTIFICATION_WEB_CONTENTS_CONNECTED,
3536 Source<WebContents>(this),
3537 NotificationService::NoDetails());
3539 bool was_crashed = IsCrashed();
3540 SetIsCrashed(base::TERMINATION_STATUS_STILL_RUNNING, 0);
3542 // Restore the focus to the tab (otherwise the focus will be on the top
3543 // window).
3544 if (was_crashed && !FocusLocationBarByDefault() &&
3545 (!delegate_ || delegate_->ShouldFocusPageAfterCrash())) {
3546 view_->Focus();
3549 FOR_EACH_OBSERVER(WebContentsObserver, observers_, RenderViewReady());
3552 void WebContentsImpl::RenderViewTerminated(RenderViewHost* rvh,
3553 base::TerminationStatus status,
3554 int error_code) {
3555 if (rvh != GetRenderViewHost()) {
3556 // The pending page's RenderViewHost is gone.
3557 return;
3560 // Ensure fullscreen mode is exited in the |delegate_| since a crashed
3561 // renderer may not have made a clean exit.
3562 if (IsFullscreenForCurrentTab())
3563 ToggleFullscreenMode(false);
3565 // Cancel any visible dialogs so they are not left dangling over the sad tab.
3566 if (dialog_manager_)
3567 dialog_manager_->CancelActiveAndPendingDialogs(this);
3569 if (delegate_)
3570 delegate_->HideValidationMessage(this);
3572 SetIsLoading(rvh, false, true, NULL);
3573 NotifyDisconnected();
3574 SetIsCrashed(status, error_code);
3576 // Reset the loading progress. TODO(avi): What does it mean to have a
3577 // "renderer crash" when there is more than one renderer process serving a
3578 // webpage? Once this function is called at a more granular frame level, we
3579 // probably will need to more granularly reset the state here.
3580 ResetLoadProgressState();
3581 loading_frames_in_progress_ = 0;
3583 FOR_EACH_OBSERVER(WebContentsObserver,
3584 observers_,
3585 RenderProcessGone(GetCrashedStatus()));
3588 void WebContentsImpl::RenderViewDeleted(RenderViewHost* rvh) {
3589 FOR_EACH_OBSERVER(WebContentsObserver, observers_, RenderViewDeleted(rvh));
3592 void WebContentsImpl::UpdateState(RenderViewHost* rvh,
3593 int32 page_id,
3594 const PageState& page_state) {
3595 // Ensure that this state update comes from either the active RVH or one of
3596 // the swapped out RVHs. We don't expect to hear from any other RVHs.
3597 // TODO(nasko): This should go through RenderFrameHost.
3598 // TODO(creis): We can't update state for cross-process subframes until we
3599 // have FrameNavigationEntries. Once we do, this should be a DCHECK.
3600 if (rvh != GetRenderViewHost() &&
3601 !GetRenderManager()->IsRVHOnSwappedOutList(
3602 static_cast<RenderViewHostImpl*>(rvh)))
3603 return;
3605 // We must be prepared to handle state updates for any page, these occur
3606 // when the user is scrolling and entering form data, as well as when we're
3607 // leaving a page, in which case our state may have already been moved to
3608 // the next page. The navigation controller will look up the appropriate
3609 // NavigationEntry and update it when it is notified via the delegate.
3611 int entry_index = controller_.GetEntryIndexWithPageID(
3612 rvh->GetSiteInstance(), page_id);
3613 if (entry_index < 0)
3614 return;
3615 NavigationEntry* entry = controller_.GetEntryAtIndex(entry_index);
3617 if (page_state == entry->GetPageState())
3618 return; // Nothing to update.
3619 entry->SetPageState(page_state);
3620 controller_.NotifyEntryChanged(entry, entry_index);
3623 void WebContentsImpl::UpdateTargetURL(int32 page_id, const GURL& url) {
3624 if (delegate_)
3625 delegate_->UpdateTargetURL(this, page_id, url);
3628 void WebContentsImpl::Close(RenderViewHost* rvh) {
3629 #if defined(OS_MACOSX)
3630 // The UI may be in an event-tracking loop, such as between the
3631 // mouse-down and mouse-up in text selection or a button click.
3632 // Defer the close until after tracking is complete, so that we
3633 // don't free objects out from under the UI.
3634 // TODO(shess): This could get more fine-grained. For instance,
3635 // closing a tab in another window while selecting text in the
3636 // current window's Omnibox should be just fine.
3637 if (view_->IsEventTracking()) {
3638 view_->CloseTabAfterEventTracking();
3639 return;
3641 #endif
3643 // Ignore this if it comes from a RenderViewHost that we aren't showing.
3644 if (delegate_ && rvh == GetRenderViewHost())
3645 delegate_->CloseContents(this);
3648 void WebContentsImpl::SwappedOut(RenderFrameHost* rfh) {
3649 if (delegate_ && rfh->GetRenderViewHost() == GetRenderViewHost())
3650 delegate_->SwappedOut(this);
3653 void WebContentsImpl::DidDeferAfterResponseStarted(
3654 const TransitionLayerData& transition_data) {
3655 #if defined(OS_ANDROID)
3656 GetWebContentsAndroid()->DidDeferAfterResponseStarted(transition_data);
3657 #endif
3660 bool WebContentsImpl::WillHandleDeferAfterResponseStarted() {
3661 #if defined(OS_ANDROID)
3662 return GetWebContentsAndroid()->WillHandleDeferAfterResponseStarted();
3663 #else
3664 return false;
3665 #endif
3668 void WebContentsImpl::RequestMove(const gfx::Rect& new_bounds) {
3669 if (delegate_ && delegate_->IsPopupOrPanel(this))
3670 delegate_->MoveContents(this, new_bounds);
3673 void WebContentsImpl::DidStartLoading(RenderFrameHost* render_frame_host,
3674 bool to_different_document) {
3675 SetIsLoading(render_frame_host->GetRenderViewHost(), true,
3676 to_different_document, NULL);
3679 void WebContentsImpl::DidStopLoading(RenderFrameHost* render_frame_host) {
3680 scoped_ptr<LoadNotificationDetails> details;
3682 // Use the last committed entry rather than the active one, in case a
3683 // pending entry has been created.
3684 NavigationEntry* entry = controller_.GetLastCommittedEntry();
3685 Navigator* navigator = frame_tree_.root()->navigator();
3687 // An entry may not exist for a stop when loading an initial blank page or
3688 // if an iframe injected by script into a blank page finishes loading.
3689 if (entry) {
3690 base::TimeDelta elapsed =
3691 base::TimeTicks::Now() - navigator->GetCurrentLoadStart();
3693 details.reset(new LoadNotificationDetails(
3694 entry->GetVirtualURL(),
3695 entry->GetTransitionType(),
3696 elapsed,
3697 &controller_,
3698 controller_.GetCurrentEntryIndex()));
3701 SetIsLoading(render_frame_host->GetRenderViewHost(), false, true,
3702 details.get());
3705 void WebContentsImpl::DidCancelLoading() {
3706 controller_.DiscardNonCommittedEntries();
3708 // Update the URL display.
3709 NotifyNavigationStateChanged(INVALIDATE_TYPE_URL);
3712 void WebContentsImpl::DidAccessInitialDocument() {
3713 has_accessed_initial_document_ = true;
3715 // We may have left a failed browser-initiated navigation in the address bar
3716 // to let the user edit it and try again. Clear it now that content might
3717 // show up underneath it.
3718 if (!IsLoading() && controller_.GetPendingEntry())
3719 controller_.DiscardPendingEntry();
3721 // Update the URL display.
3722 NotifyNavigationStateChanged(INVALIDATE_TYPE_URL);
3725 void WebContentsImpl::DidDisownOpener(RenderFrameHost* render_frame_host) {
3726 // No action is necessary if the opener has already been cleared.
3727 if (!opener_)
3728 return;
3730 // Clear our opener so that future cross-process navigations don't have an
3731 // opener assigned.
3732 RemoveDestructionObserver(opener_);
3733 opener_ = NULL;
3735 // Notify all swapped out RenderViewHosts for this tab. This is important
3736 // in case we go back to them, or if another window in those processes tries
3737 // to access window.opener.
3738 GetRenderManager()->DidDisownOpener(render_frame_host);
3741 void WebContentsImpl::DocumentOnLoadCompleted(
3742 RenderFrameHost* render_frame_host) {
3743 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3744 DocumentOnLoadCompletedInMainFrame());
3746 // TODO(avi): Remove. http://crbug.com/170921
3747 NotificationService::current()->Notify(
3748 NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
3749 Source<WebContents>(this),
3750 NotificationService::NoDetails());
3753 void WebContentsImpl::UpdateTitle(RenderFrameHost* render_frame_host,
3754 int32 page_id,
3755 const base::string16& title,
3756 base::i18n::TextDirection title_direction) {
3757 RenderViewHost* rvh = render_frame_host->GetRenderViewHost();
3759 // If we have a title, that's a pretty good indication that we've started
3760 // getting useful data.
3761 SetNotWaitingForResponse();
3763 // Try to find the navigation entry, which might not be the current one.
3764 // For example, it might be from a pending RVH for the pending entry.
3765 NavigationEntryImpl* entry = controller_.GetEntryWithPageID(
3766 rvh->GetSiteInstance(), page_id);
3768 // We can handle title updates when we don't have an entry in
3769 // UpdateTitleForEntry, but only if the update is from the current RVH.
3770 // TODO(avi): Change to make decisions based on the RenderFrameHost.
3771 if (!entry && rvh != GetRenderViewHost())
3772 return;
3774 // TODO(evan): make use of title_direction.
3775 // http://code.google.com/p/chromium/issues/detail?id=27094
3776 if (!UpdateTitleForEntry(entry, title))
3777 return;
3779 // Broadcast notifications when the UI should be updated.
3780 if (entry == controller_.GetEntryAtOffset(0))
3781 NotifyNavigationStateChanged(INVALIDATE_TYPE_TITLE);
3784 void WebContentsImpl::UpdateEncoding(RenderFrameHost* render_frame_host,
3785 const std::string& encoding) {
3786 SetEncoding(encoding);
3789 void WebContentsImpl::DocumentAvailableInMainFrame(
3790 RenderViewHost* render_view_host) {
3791 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3792 DocumentAvailableInMainFrame());
3794 void WebContentsImpl::RouteCloseEvent(RenderViewHost* rvh) {
3795 // Tell the active RenderViewHost to run unload handlers and close, as long
3796 // as the request came from a RenderViewHost in the same BrowsingInstance.
3797 // In most cases, we receive this from a swapped out RenderViewHost.
3798 // It is possible to receive it from one that has just been swapped in,
3799 // in which case we might as well deliver the message anyway.
3800 if (rvh->GetSiteInstance()->IsRelatedSiteInstance(GetSiteInstance()))
3801 GetRenderViewHost()->ClosePage();
3804 void WebContentsImpl::RouteMessageEvent(
3805 RenderViewHost* rvh,
3806 const ViewMsg_PostMessage_Params& params) {
3807 // Only deliver the message to the active RenderViewHost if the request
3808 // came from a RenderViewHost in the same BrowsingInstance or if this
3809 // WebContents is dedicated to a browser plugin guest.
3810 // Note: This check means that an embedder could theoretically receive a
3811 // postMessage from anyone (not just its own guests). However, this is
3812 // probably not a risk for apps since other pages won't have references
3813 // to App windows.
3814 if (!rvh->GetSiteInstance()->IsRelatedSiteInstance(GetSiteInstance()) &&
3815 !GetBrowserPluginGuest() && !GetBrowserPluginEmbedder())
3816 return;
3818 ViewMsg_PostMessage_Params new_params(params);
3820 if (!params.message_port_ids.empty()) {
3821 MessagePortMessageFilter* message_port_message_filter =
3822 static_cast<RenderProcessHostImpl*>(GetRenderProcessHost())
3823 ->message_port_message_filter();
3824 message_port_message_filter->UpdateMessagePortsWithNewRoutes(
3825 params.message_port_ids,
3826 &new_params.new_routing_ids);
3829 // If there is a source_routing_id, translate it to the routing ID for
3830 // the equivalent swapped out RVH in the target process. If we need
3831 // to create a swapped out RVH for the source tab, we create its opener
3832 // chain as well, since those will also be accessible to the target page.
3833 if (new_params.source_routing_id != MSG_ROUTING_NONE) {
3834 // Try to look up the WebContents for the source page.
3835 WebContentsImpl* source_contents = NULL;
3836 RenderViewHostImpl* source_rvh = RenderViewHostImpl::FromID(
3837 rvh->GetProcess()->GetID(), params.source_routing_id);
3838 if (source_rvh) {
3839 source_contents = static_cast<WebContentsImpl*>(
3840 source_rvh->GetDelegate()->GetAsWebContents());
3843 if (source_contents) {
3844 if (GetBrowserPluginGuest()) {
3845 // We create a swapped out RenderView for the embedder in the guest's
3846 // render process but we intentionally do not expose the embedder's
3847 // opener chain to it.
3848 new_params.source_routing_id =
3849 source_contents->CreateSwappedOutRenderView(GetSiteInstance());
3850 } else {
3851 new_params.source_routing_id =
3852 source_contents->CreateOpenerRenderViews(GetSiteInstance());
3854 } else {
3855 // We couldn't find it, so don't pass a source frame.
3856 new_params.source_routing_id = MSG_ROUTING_NONE;
3860 // In most cases, we receive this from a swapped out RenderViewHost.
3861 // It is possible to receive it from one that has just been swapped in,
3862 // in which case we might as well deliver the message anyway.
3863 Send(new ViewMsg_PostMessageEvent(GetRoutingID(), new_params));
3866 bool WebContentsImpl::AddMessageToConsole(int32 level,
3867 const base::string16& message,
3868 int32 line_no,
3869 const base::string16& source_id) {
3870 if (!delegate_)
3871 return false;
3872 return delegate_->AddMessageToConsole(this, level, message, line_no,
3873 source_id);
3876 WebPreferences WebContentsImpl::ComputeWebkitPrefs() {
3877 // We want to base the page config off of the actual URL, rather than the
3878 // virtual URL.
3879 // TODO(nasko): Investigate how to remove the GetActiveEntry usage here,
3880 // as it is deprecated and can be out of sync with GetRenderViewHost().
3881 GURL url = controller_.GetActiveEntry()
3882 ? controller_.GetActiveEntry()->GetURL() : GURL::EmptyGURL();
3884 return GetRenderManager()->current_host()->ComputeWebkitPrefs(url);
3887 int WebContentsImpl::CreateSwappedOutRenderView(
3888 SiteInstance* instance) {
3889 return GetRenderManager()->CreateRenderFrame(
3890 instance, MSG_ROUTING_NONE, true, true, true);
3893 void WebContentsImpl::OnUserGesture() {
3894 // Notify observers.
3895 FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidGetUserGesture());
3897 ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
3898 if (rdh) // NULL in unittests.
3899 rdh->OnUserGesture(this);
3902 void WebContentsImpl::OnIgnoredUIEvent() {
3903 // Notify observers.
3904 FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidGetIgnoredUIEvent());
3907 void WebContentsImpl::RendererUnresponsive(RenderViewHost* rvh,
3908 bool is_during_beforeunload,
3909 bool is_during_unload) {
3910 // Don't show hung renderer dialog for a swapped out RVH.
3911 if (rvh != GetRenderViewHost())
3912 return;
3914 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(rvh);
3916 // Ignore renderer unresponsive event if debugger is attached to the tab
3917 // since the event may be a result of the renderer sitting on a breakpoint.
3918 // See http://crbug.com/65458
3919 if (DevToolsAgentHost::IsDebuggerAttached(this))
3920 return;
3922 if (is_during_beforeunload || is_during_unload) {
3923 // Hang occurred while firing the beforeunload/unload handler.
3924 // Pretend the handler fired so tab closing continues as if it had.
3925 rvhi->set_sudden_termination_allowed(true);
3927 if (!GetRenderManager()->ShouldCloseTabOnUnresponsiveRenderer())
3928 return;
3930 // If the tab hangs in the beforeunload/unload handler there's really
3931 // nothing we can do to recover. If the hang is in the beforeunload handler,
3932 // pretend the beforeunload listeners have all fired and allow the delegate
3933 // to continue closing; the user will not have the option of cancelling the
3934 // close. Otherwise, pretend the unload listeners have all fired and close
3935 // the tab.
3936 bool close = true;
3937 if (is_during_beforeunload && delegate_) {
3938 delegate_->BeforeUnloadFired(this, true, &close);
3940 if (close)
3941 Close(rvh);
3942 return;
3945 if (!GetRenderViewHostImpl() || !GetRenderViewHostImpl()->IsRenderViewLive())
3946 return;
3948 if (delegate_)
3949 delegate_->RendererUnresponsive(this);
3952 void WebContentsImpl::RendererResponsive(RenderViewHost* render_view_host) {
3953 if (delegate_)
3954 delegate_->RendererResponsive(this);
3957 void WebContentsImpl::LoadStateChanged(
3958 const GURL& url,
3959 const net::LoadStateWithParam& load_state,
3960 uint64 upload_position,
3961 uint64 upload_size) {
3962 load_state_ = load_state;
3963 upload_position_ = upload_position;
3964 upload_size_ = upload_size;
3965 load_state_host_ = net::IDNToUnicode(url.host(),
3966 GetContentClient()->browser()->GetAcceptLangs(
3967 GetBrowserContext()));
3968 if (load_state_.state == net::LOAD_STATE_READING_RESPONSE)
3969 SetNotWaitingForResponse();
3970 if (IsLoading()) {
3971 NotifyNavigationStateChanged(static_cast<InvalidateTypes>(
3972 INVALIDATE_TYPE_LOAD | INVALIDATE_TYPE_TAB));
3976 void WebContentsImpl::BeforeUnloadFiredFromRenderManager(
3977 bool proceed, const base::TimeTicks& proceed_time,
3978 bool* proceed_to_fire_unload) {
3979 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3980 BeforeUnloadFired(proceed_time));
3981 if (delegate_)
3982 delegate_->BeforeUnloadFired(this, proceed, proceed_to_fire_unload);
3983 // Note: |this| might be deleted at this point.
3986 void WebContentsImpl::RenderProcessGoneFromRenderManager(
3987 RenderViewHost* render_view_host) {
3988 DCHECK(crashed_status_ != base::TERMINATION_STATUS_STILL_RUNNING);
3989 RenderViewTerminated(render_view_host, crashed_status_, crashed_error_code_);
3992 void WebContentsImpl::UpdateRenderViewSizeForRenderManager() {
3993 // TODO(brettw) this is a hack. See WebContentsView::SizeContents.
3994 gfx::Size size = GetSizeForNewRenderView();
3995 // 0x0 isn't a valid window size (minimal window size is 1x1) but it may be
3996 // here during container initialization and normal window size will be set
3997 // later. In case of tab duplication this resizing to 0x0 prevents setting
3998 // normal size later so just ignore it.
3999 if (!size.IsEmpty())
4000 view_->SizeContents(size);
4003 void WebContentsImpl::CancelModalDialogsForRenderManager() {
4004 // We need to cancel modal dialogs when doing a process swap, since the load
4005 // deferrer would prevent us from swapping out.
4006 if (dialog_manager_)
4007 dialog_manager_->CancelActiveAndPendingDialogs(this);
4010 void WebContentsImpl::NotifySwappedFromRenderManager(RenderFrameHost* old_host,
4011 RenderFrameHost* new_host,
4012 bool is_main_frame) {
4013 if (is_main_frame) {
4014 NotifyViewSwapped(old_host ? old_host->GetRenderViewHost() : NULL,
4015 new_host->GetRenderViewHost());
4017 // Make sure the visible RVH reflects the new delegate's preferences.
4018 if (delegate_)
4019 view_->SetOverscrollControllerEnabled(CanOverscrollContent());
4021 view_->RenderViewSwappedIn(new_host->GetRenderViewHost());
4024 NotifyFrameSwapped(old_host, new_host);
4027 int WebContentsImpl::CreateOpenerRenderViewsForRenderManager(
4028 SiteInstance* instance) {
4029 if (!opener_)
4030 return MSG_ROUTING_NONE;
4032 // Recursively create RenderViews for anything else in the opener chain.
4033 return opener_->CreateOpenerRenderViews(instance);
4036 int WebContentsImpl::CreateOpenerRenderViews(SiteInstance* instance) {
4037 int opener_route_id = MSG_ROUTING_NONE;
4039 // If this tab has an opener, ensure it has a RenderView in the given
4040 // SiteInstance as well.
4041 if (opener_)
4042 opener_route_id = opener_->CreateOpenerRenderViews(instance);
4044 // If any of the renderers (current, pending, or swapped out) for this
4045 // WebContents has the same SiteInstance, use it.
4046 if (GetRenderManager()->current_host()->GetSiteInstance() == instance)
4047 return GetRenderManager()->current_host()->GetRoutingID();
4049 if (GetRenderManager()->pending_render_view_host() &&
4050 GetRenderManager()->pending_render_view_host()->GetSiteInstance() ==
4051 instance)
4052 return GetRenderManager()->pending_render_view_host()->GetRoutingID();
4054 RenderViewHostImpl* rvh = GetRenderManager()->GetSwappedOutRenderViewHost(
4055 instance);
4056 if (rvh)
4057 return rvh->GetRoutingID();
4059 // Create a swapped out RenderView in the given SiteInstance if none exists,
4060 // setting its opener to the given route_id. Return the new view's route_id.
4061 return GetRenderManager()->CreateRenderFrame(
4062 instance, opener_route_id, true, true, true);
4065 NavigationControllerImpl& WebContentsImpl::GetControllerForRenderManager() {
4066 return GetController();
4069 WebUIImpl* WebContentsImpl::CreateWebUIForRenderManager(const GURL& url) {
4070 return static_cast<WebUIImpl*>(CreateWebUI(url));
4073 NavigationEntry*
4074 WebContentsImpl::GetLastCommittedNavigationEntryForRenderManager() {
4075 return controller_.GetLastCommittedEntry();
4078 bool WebContentsImpl::CreateRenderViewForRenderManager(
4079 RenderViewHost* render_view_host,
4080 int opener_route_id,
4081 int proxy_routing_id,
4082 bool for_main_frame_navigation) {
4083 TRACE_EVENT0("browser,navigation",
4084 "WebContentsImpl::CreateRenderViewForRenderManager");
4085 // Can be NULL during tests.
4086 RenderWidgetHostViewBase* rwh_view;
4087 // TODO(kenrb): RenderWidgetHostViewChildFrame special casing is temporary
4088 // until RenderWidgetHost is attached to RenderFrameHost. We need to special
4089 // case this because RWH is still a base class of RenderViewHost, and child
4090 // frame RWHVs are unique in that they do not have their own WebContents.
4091 if (!for_main_frame_navigation) {
4092 RenderWidgetHostViewChildFrame* rwh_view_child =
4093 new RenderWidgetHostViewChildFrame(render_view_host);
4094 rwh_view = rwh_view_child;
4095 } else {
4096 rwh_view = view_->CreateViewForWidget(render_view_host);
4099 // Now that the RenderView has been created, we need to tell it its size.
4100 if (rwh_view)
4101 rwh_view->SetSize(GetSizeForNewRenderView());
4103 // Make sure we use the correct starting page_id in the new RenderView.
4104 UpdateMaxPageIDIfNecessary(render_view_host);
4105 int32 max_page_id =
4106 GetMaxPageIDForSiteInstance(render_view_host->GetSiteInstance());
4108 if (!static_cast<RenderViewHostImpl*>(
4109 render_view_host)->CreateRenderView(base::string16(),
4110 opener_route_id,
4111 proxy_routing_id,
4112 max_page_id,
4113 created_with_opener_)) {
4114 return false;
4117 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
4118 // Force a ViewMsg_Resize to be sent, needed to make plugins show up on
4119 // linux. See crbug.com/83941.
4120 if (rwh_view) {
4121 if (RenderWidgetHost* render_widget_host = rwh_view->GetRenderWidgetHost())
4122 render_widget_host->WasResized();
4124 #endif
4126 return true;
4129 bool WebContentsImpl::CreateRenderFrameForRenderManager(
4130 RenderFrameHost* render_frame_host,
4131 int parent_routing_id) {
4132 TRACE_EVENT0("browser,navigation",
4133 "WebContentsImpl::CreateRenderFrameForRenderManager");
4135 RenderFrameHostImpl* rfh =
4136 static_cast<RenderFrameHostImpl*>(render_frame_host);
4137 if (!rfh->CreateRenderFrame(parent_routing_id))
4138 return false;
4140 // TODO(nasko): When RenderWidgetHost is owned by RenderFrameHost, the passed
4141 // RenderFrameHost will have to be associated with the appropriate
4142 // RenderWidgetHostView or a new one should be created here.
4144 return true;
4147 #if defined(OS_ANDROID)
4149 base::android::ScopedJavaLocalRef<jobject>
4150 WebContentsImpl::GetJavaWebContents() {
4151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4152 return GetWebContentsAndroid()->GetJavaObject();
4155 WebContentsAndroid* WebContentsImpl::GetWebContentsAndroid() {
4156 WebContentsAndroid* web_contents_android =
4157 static_cast<WebContentsAndroid*>(GetUserData(kWebContentsAndroidKey));
4158 if (!web_contents_android) {
4159 web_contents_android = new WebContentsAndroid(this);
4160 SetUserData(kWebContentsAndroidKey, web_contents_android);
4162 return web_contents_android;
4165 bool WebContentsImpl::CreateRenderViewForInitialEmptyDocument() {
4166 return CreateRenderViewForRenderManager(GetRenderViewHost(),
4167 MSG_ROUTING_NONE,
4168 MSG_ROUTING_NONE,
4169 true);
4172 #elif defined(OS_MACOSX)
4174 void WebContentsImpl::SetAllowOtherViews(bool allow) {
4175 view_->SetAllowOtherViews(allow);
4178 bool WebContentsImpl::GetAllowOtherViews() {
4179 return view_->GetAllowOtherViews();
4182 #endif
4184 void WebContentsImpl::OnDialogClosed(int render_process_id,
4185 int render_frame_id,
4186 IPC::Message* reply_msg,
4187 bool dialog_was_suppressed,
4188 bool success,
4189 const base::string16& user_input) {
4190 RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID(render_process_id,
4191 render_frame_id);
4192 last_dialog_suppressed_ = dialog_was_suppressed;
4194 if (is_showing_before_unload_dialog_ && !success) {
4195 // If a beforeunload dialog is canceled, we need to stop the throbber from
4196 // spinning, since we forced it to start spinning in Navigate.
4197 if (rfh)
4198 DidStopLoading(rfh);
4199 controller_.DiscardNonCommittedEntries();
4201 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
4202 BeforeUnloadDialogCancelled());
4205 is_showing_before_unload_dialog_ = false;
4206 if (rfh) {
4207 rfh->JavaScriptDialogClosed(reply_msg, success, user_input,
4208 dialog_was_suppressed);
4209 } else {
4210 // Don't leak the sync IPC reply if the RFH or process is gone.
4211 delete reply_msg;
4215 void WebContentsImpl::SetEncoding(const std::string& encoding) {
4216 if (encoding == last_reported_encoding_)
4217 return;
4218 last_reported_encoding_ = encoding;
4220 canonical_encoding_ = GetContentClient()->browser()->
4221 GetCanonicalEncodingNameByAliasName(encoding);
4224 void WebContentsImpl::CreateViewAndSetSizeForRVH(RenderViewHost* rvh) {
4225 RenderWidgetHostViewBase* rwh_view = view_->CreateViewForWidget(rvh);
4226 // Can be NULL during tests.
4227 if (rwh_view)
4228 rwh_view->SetSize(GetContainerBounds().size());
4231 bool WebContentsImpl::IsHidden() {
4232 return capturer_count_ == 0 && !should_normally_be_visible_;
4235 RenderFrameHostManager* WebContentsImpl::GetRenderManager() const {
4236 return frame_tree_.root()->render_manager();
4239 RenderViewHostImpl* WebContentsImpl::GetRenderViewHostImpl() {
4240 return static_cast<RenderViewHostImpl*>(GetRenderViewHost());
4243 BrowserPluginGuest* WebContentsImpl::GetBrowserPluginGuest() const {
4244 return browser_plugin_guest_.get();
4247 void WebContentsImpl::SetBrowserPluginGuest(BrowserPluginGuest* guest) {
4248 CHECK(!browser_plugin_guest_);
4249 browser_plugin_guest_.reset(guest);
4252 BrowserPluginEmbedder* WebContentsImpl::GetBrowserPluginEmbedder() const {
4253 return browser_plugin_embedder_.get();
4256 void WebContentsImpl::ClearPowerSaveBlockers(
4257 RenderFrameHost* render_frame_host) {
4258 RemoveAllMediaPlayerEntries(render_frame_host, &active_audio_players_);
4259 RemoveAllMediaPlayerEntries(render_frame_host, &active_video_players_);
4260 MaybeReleasePowerSaveBlockers();
4263 void WebContentsImpl::ClearAllPowerSaveBlockers() {
4264 active_audio_players_.clear();
4265 active_video_players_.clear();
4266 audio_power_save_blocker_.reset();
4267 video_power_save_blocker_.reset();
4270 gfx::Size WebContentsImpl::GetSizeForNewRenderView() {
4271 gfx::Size size;
4272 if (delegate_)
4273 size = delegate_->GetSizeForNewRenderView(this);
4274 if (size.IsEmpty())
4275 size = GetContainerBounds().size();
4276 return size;
4279 void WebContentsImpl::OnFrameRemoved(RenderFrameHost* render_frame_host) {
4280 FOR_EACH_OBSERVER(
4281 WebContentsObserver, observers_, FrameDetached(render_frame_host));
4284 void WebContentsImpl::OnPreferredSizeChanged(const gfx::Size& old_size) {
4285 if (!delegate_)
4286 return;
4287 const gfx::Size new_size = GetPreferredSize();
4288 if (new_size != old_size)
4289 delegate_->UpdatePreferredSize(this, new_size);
4292 void WebContentsImpl::AddMediaPlayerEntry(int64 player_cookie,
4293 ActiveMediaPlayerMap* player_map) {
4294 const uintptr_t key =
4295 reinterpret_cast<uintptr_t>(render_frame_message_source_);
4296 DCHECK(std::find((*player_map)[key].begin(),
4297 (*player_map)[key].end(),
4298 player_cookie) == (*player_map)[key].end());
4299 (*player_map)[key].push_back(player_cookie);
4302 void WebContentsImpl::RemoveMediaPlayerEntry(int64 player_cookie,
4303 ActiveMediaPlayerMap* player_map) {
4304 const uintptr_t key =
4305 reinterpret_cast<uintptr_t>(render_frame_message_source_);
4306 ActiveMediaPlayerMap::iterator it = player_map->find(key);
4307 if (it == player_map->end())
4308 return;
4310 // Remove the player.
4311 PlayerList::iterator player_it =
4312 std::find(it->second.begin(), it->second.end(), player_cookie);
4313 if (player_it != it->second.end())
4314 it->second.erase(player_it);
4316 // If there are no players left, remove the map entry.
4317 if (it->second.empty())
4318 player_map->erase(it);
4321 void WebContentsImpl::RemoveAllMediaPlayerEntries(
4322 RenderFrameHost* render_frame_host,
4323 ActiveMediaPlayerMap* player_map) {
4324 ActiveMediaPlayerMap::iterator it =
4325 player_map->find(reinterpret_cast<uintptr_t>(render_frame_host));
4326 if (it == player_map->end())
4327 return;
4328 player_map->erase(it);
4331 void WebContentsImpl::ResumeResponseDeferredAtStart() {
4332 FrameTreeNode* node = frame_tree_.root();
4333 node->render_manager()->ResumeResponseDeferredAtStart();
4336 void WebContentsImpl::SetForceDisableOverscrollContent(bool force_disable) {
4337 force_disable_overscroll_content_ = force_disable;
4338 if (view_)
4339 view_->SetOverscrollControllerEnabled(CanOverscrollContent());
4342 } // namespace content