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.
4
5 #include "content/browser/web_contents/web_contents_impl.h"
6
7 #include <utility>
8
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/browser_plugin/browser_plugin_embedder.h"
22 #include "content/browser/browser_plugin/browser_plugin_guest.h"
23 #include "content/browser/child_process_security_policy_impl.h"
24 #include "content/browser/devtools/render_view_devtools_agent_host.h"
25 #include "content/browser/dom_storage/dom_storage_context_wrapper.h"
26 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
27 #include "content/browser/download/download_stats.h"
28 #include "content/browser/download/mhtml_generation_manager.h"
29 #include "content/browser/download/save_package.h"
30 #include "content/browser/frame_host/cross_process_frame_connector.h"
31 #include "content/browser/frame_host/interstitial_page_impl.h"
32 #include "content/browser/frame_host/navigation_entry_impl.h"
33 #include "content/browser/frame_host/navigator_impl.h"
34 #include "content/browser/frame_host/render_frame_host_impl.h"
35 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
36 #include "content/browser/geolocation/geolocation_dispatcher_host.h"
37 #include "content/browser/host_zoom_map_impl.h"
38 #include "content/browser/loader/resource_dispatcher_host_impl.h"
39 #include "content/browser/media/midi_dispatcher_host.h"
40 #include "content/browser/message_port_message_filter.h"
41 #include "content/browser/message_port_service.h"
42 #include "content/browser/power_save_blocker_impl.h"
43 #include "content/browser/renderer_host/render_process_host_impl.h"
44 #include "content/browser/renderer_host/render_view_host_delegate_view.h"
45 #include "content/browser/renderer_host/render_view_host_impl.h"
46 #include "content/browser/renderer_host/render_widget_host_impl.h"
47 #include "content/browser/renderer_host/render_widget_host_view_base.h"
48 #include "content/browser/screen_orientation/screen_orientation_dispatcher_host.h"
49 #include "content/browser/site_instance_impl.h"
50 #include "content/browser/web_contents/web_contents_view_guest.h"
51 #include "content/browser/webui/generic_handler.h"
52 #include "content/browser/webui/web_ui_controller_factory_registry.h"
53 #include "content/browser/webui/web_ui_impl.h"
54 #include "content/common/browser_plugin/browser_plugin_constants.h"
55 #include "content/common/browser_plugin/browser_plugin_messages.h"
56 #include "content/common/frame_messages.h"
57 #include "content/common/image_messages.h"
58 #include "content/common/input_messages.h"
59 #include "content/common/ssl_status_serialization.h"
60 #include "content/common/view_messages.h"
61 #include "content/public/browser/ax_event_notification_details.h"
62 #include "content/public/browser/browser_context.h"
63 #include "content/public/browser/browser_plugin_guest_manager.h"
64 #include "content/public/browser/content_browser_client.h"
65 #include "content/public/browser/devtools_agent_host.h"
66 #include "content/public/browser/download_manager.h"
67 #include "content/public/browser/download_url_parameters.h"
68 #include "content/public/browser/invalidate_type.h"
69 #include "content/public/browser/javascript_dialog_manager.h"
70 #include "content/public/browser/load_from_memory_cache_details.h"
71 #include "content/public/browser/load_notification_details.h"
72 #include "content/public/browser/navigation_details.h"
73 #include "content/public/browser/notification_details.h"
74 #include "content/public/browser/notification_service.h"
75 #include "content/public/browser/resource_request_details.h"
76 #include "content/public/browser/storage_partition.h"
77 #include "content/public/browser/user_metrics.h"
78 #include "content/public/browser/web_contents_delegate.h"
79 #include "content/public/browser/web_contents_observer.h"
80 #include "content/public/common/bindings_policy.h"
81 #include "content/public/common/content_constants.h"
82 #include "content/public/common/content_switches.h"
83 #include "content/public/common/page_zoom.h"
84 #include "content/public/common/result_codes.h"
85 #include "content/public/common/url_constants.h"
86 #include "content/public/common/url_utils.h"
87 #include "net/base/mime_util.h"
88 #include "net/base/net_util.h"
89 #include "net/http/http_cache.h"
90 #include "net/http/http_transaction_factory.h"
91 #include "net/url_request/url_request_context.h"
92 #include "net/url_request/url_request_context_getter.h"
93 #include "ui/base/layout.h"
94 #include "ui/gfx/display.h"
95 #include "ui/gfx/screen.h"
96 #include "ui/gl/gl_switches.h"
97 #include "webkit/common/webpreferences.h"
98
99 #if defined(OS_ANDROID)
100 #include "content/browser/android/date_time_chooser_android.h"
101 #include "content/browser/media/android/browser_media_player_manager.h"
102 #include "content/browser/web_contents/web_contents_android.h"
103 #include "content/public/browser/android/content_view_core.h"
104 #endif
105
106 #if defined(OS_MACOSX)
107 #include "base/mac/foundation_util.h"
108 #endif
109
110 // Cross-Site Navigations
111 //
112 // If a WebContentsImpl is told to navigate to a different web site (as
113 // determined by SiteInstance), it will replace its current RenderViewHost with
114 // a new RenderViewHost dedicated to the new SiteInstance. This works as
115 // follows:
116 //
117 // - RVHM::Navigate determines whether the destination is cross-site, and if so,
118 // it creates a pending_render_view_host_.
119 // - The pending RVH is "suspended," so that no navigation messages are sent to
120 // its renderer until the beforeunload JavaScript handler has a chance to
121 // run in the current RVH.
122 // - The pending RVH tells CrossSiteRequestManager (a thread-safe singleton)
123 // that it has a pending cross-site request. We will check this on the IO
124 // thread when deciding how to handle the response.
125 // - The current RVH runs its beforeunload handler. If it returns false, we
126 // cancel all the pending logic. Otherwise we allow the pending RVH to send
127 // the navigation request to its renderer.
128 // - ResourceDispatcherHost receives a ResourceRequest on the IO thread for the
129 // main resource load on the pending RVH. It creates a
130 // CrossSiteResourceHandler to check whether a process swap is needed when
131 // the request is ready to commit.
132 // - When RDH receives a response, the BufferedResourceHandler determines
133 // whether it is a download. If so, it sends a message to the new renderer
134 // causing it to cancel the request, and the download proceeds. For now, the
135 // pending RVH remains until the next DidNavigate event for this
136 // WebContentsImpl. This isn't ideal, but it doesn't affect any functionality.
137 // - After RDH receives a response and determines that it is safe and not a
138 // download, the CrossSiteResourceHandler checks whether a process swap is
139 // needed (either because CrossSiteRequestManager has state for it or because
140 // a transfer was needed for a redirect).
141 // - If so, CrossSiteResourceHandler pauses the response to first run the old
142 // page's unload handler. It does this by asynchronously calling the
143 // OnCrossSiteResponse method of RenderFrameHostManager on the UI thread,
144 // which sends a SwapOut message to the current RVH.
145 // - Once the unload handler is finished, RVHM::SwappedOut checks if a transfer
146 // to a new process is needed, based on the stored pending_nav_params_. (This
147 // is independent of whether we started out with a cross-process navigation.)
148 // - If not, it just tells the ResourceDispatcherHost to resume the response
149 // to its current RenderViewHost.
150 // - If so, it cancels the current pending RenderViewHost and sets up a new
151 // navigation using RequestTransferURL. When the transferred request
152 // arrives in the ResourceDispatcherHost, we transfer the response and
153 // resume it.
154 // - The pending renderer sends a FrameNavigate message that invokes the
155 // DidNavigate method. This replaces the current RVH with the
156 // pending RVH.
157 // - The previous renderer is kept swapped out in RenderFrameHostManager in case
158 // the user goes back. The process only stays live if another tab is using
159 // it, but if so, the existing frame relationships will be maintained.
160
161 namespace content {
162 namespace {
163
164 const int kMinimumDelayBetweenLoadingUpdatesMS = 100;
165
166 // This matches what Blink's ProgressTracker has traditionally used for a
167 // minimum progress value.
168 const double kMinimumLoadingProgress = 0.1;
169
170 const char kDotGoogleDotCom[] = ".google.com";
171
172 #if defined(OS_ANDROID)
173 const char kWebContentsAndroidKey[] = "web_contents_android";
174 #endif // OS_ANDROID
175
176 base::LazyInstance<std::vector<WebContentsImpl::CreatedCallback> >
177 g_created_callbacks = LAZY_INSTANCE_INITIALIZER;
178
StartDownload(content::RenderFrameHost * rfh,const GURL & url,bool is_favicon,uint32_t max_bitmap_size)179 static int StartDownload(content::RenderFrameHost* rfh,
180 const GURL& url,
181 bool is_favicon,
182 uint32_t max_bitmap_size) {
183 static int g_next_image_download_id = 0;
184 rfh->Send(new ImageMsg_DownloadImage(rfh->GetRoutingID(),
185 ++g_next_image_download_id,
186 url,
187 is_favicon,
188 max_bitmap_size));
189 return g_next_image_download_id;
190 }
191
NotifyCacheOnIO(scoped_refptr<net::URLRequestContextGetter> request_context,const GURL & url,const std::string & http_method)192 void NotifyCacheOnIO(
193 scoped_refptr<net::URLRequestContextGetter> request_context,
194 const GURL& url,
195 const std::string& http_method) {
196 request_context->GetURLRequestContext()->http_transaction_factory()->
197 GetCache()->OnExternalCacheHit(url, http_method);
198 }
199
200 // Helper function for retrieving all the sites in a frame tree.
CollectSites(BrowserContext * context,std::set<GURL> * sites,FrameTreeNode * node)201 bool CollectSites(BrowserContext* context,
202 std::set<GURL>* sites,
203 FrameTreeNode* node) {
204 sites->insert(SiteInstance::GetSiteForURL(context, node->current_url()));
205 return true;
206 }
207
ForEachFrameInternal(const base::Callback<void (RenderFrameHost *)> & on_frame,FrameTreeNode * node)208 bool ForEachFrameInternal(
209 const base::Callback<void(RenderFrameHost*)>& on_frame,
210 FrameTreeNode* node) {
211 on_frame.Run(node->current_frame_host());
212 return true;
213 }
214
SendToAllFramesInternal(IPC::Message * message,RenderFrameHost * rfh)215 void SendToAllFramesInternal(IPC::Message* message, RenderFrameHost* rfh) {
216 IPC::Message* message_copy = new IPC::Message(*message);
217 message_copy->set_routing_id(rfh->GetRoutingID());
218 rfh->Send(message_copy);
219 }
220
AddRenderWidgetHostViewToSet(std::set<RenderWidgetHostView * > * set,RenderFrameHost * rfh)221 void AddRenderWidgetHostViewToSet(std::set<RenderWidgetHostView*>* set,
222 RenderFrameHost* rfh) {
223 RenderWidgetHostView* rwhv = static_cast<RenderFrameHostImpl*>(rfh)
224 ->frame_tree_node()
225 ->render_manager()
226 ->GetRenderWidgetHostView();
227 set->insert(rwhv);
228 }
229
230 } // namespace
231
Create(const WebContents::CreateParams & params)232 WebContents* WebContents::Create(const WebContents::CreateParams& params) {
233 return WebContentsImpl::CreateWithOpener(
234 params, static_cast<WebContentsImpl*>(params.opener));
235 }
236
CreateWithSessionStorage(const WebContents::CreateParams & params,const SessionStorageNamespaceMap & session_storage_namespace_map)237 WebContents* WebContents::CreateWithSessionStorage(
238 const WebContents::CreateParams& params,
239 const SessionStorageNamespaceMap& session_storage_namespace_map) {
240 WebContentsImpl* new_contents = new WebContentsImpl(
241 params.browser_context, NULL);
242
243 for (SessionStorageNamespaceMap::const_iterator it =
244 session_storage_namespace_map.begin();
245 it != session_storage_namespace_map.end();
246 ++it) {
247 new_contents->GetController()
248 .SetSessionStorageNamespace(it->first, it->second.get());
249 }
250
251 new_contents->Init(params);
252 return new_contents;
253 }
254
AddCreatedCallback(const CreatedCallback & callback)255 void WebContentsImpl::AddCreatedCallback(const CreatedCallback& callback) {
256 g_created_callbacks.Get().push_back(callback);
257 }
258
RemoveCreatedCallback(const CreatedCallback & callback)259 void WebContentsImpl::RemoveCreatedCallback(const CreatedCallback& callback) {
260 for (size_t i = 0; i < g_created_callbacks.Get().size(); ++i) {
261 if (g_created_callbacks.Get().at(i).Equals(callback)) {
262 g_created_callbacks.Get().erase(g_created_callbacks.Get().begin() + i);
263 return;
264 }
265 }
266 }
267
FromRenderViewHost(const RenderViewHost * rvh)268 WebContents* WebContents::FromRenderViewHost(const RenderViewHost* rvh) {
269 return rvh->GetDelegate()->GetAsWebContents();
270 }
271
FromRenderFrameHost(RenderFrameHost * rfh)272 WebContents* WebContents::FromRenderFrameHost(RenderFrameHost* rfh) {
273 RenderFrameHostImpl* rfh_impl = static_cast<RenderFrameHostImpl*>(rfh);
274 if (!rfh_impl)
275 return NULL;
276 return rfh_impl->delegate()->GetAsWebContents();
277 }
278
279 // WebContentsImpl::DestructionObserver ----------------------------------------
280
281 class WebContentsImpl::DestructionObserver : public WebContentsObserver {
282 public:
DestructionObserver(WebContentsImpl * owner,WebContents * watched_contents)283 DestructionObserver(WebContentsImpl* owner, WebContents* watched_contents)
284 : WebContentsObserver(watched_contents),
285 owner_(owner) {
286 }
287
288 // WebContentsObserver:
WebContentsDestroyed()289 virtual void WebContentsDestroyed() OVERRIDE {
290 owner_->OnWebContentsDestroyed(
291 static_cast<WebContentsImpl*>(web_contents()));
292 }
293
294 private:
295 WebContentsImpl* owner_;
296
297 DISALLOW_COPY_AND_ASSIGN(DestructionObserver);
298 };
299
ColorChooserInfo(int render_process_id,int render_frame_id,ColorChooser * chooser,int identifier)300 WebContentsImpl::ColorChooserInfo::ColorChooserInfo(int render_process_id,
301 int render_frame_id,
302 ColorChooser* chooser,
303 int identifier)
304 : render_process_id(render_process_id),
305 render_frame_id(render_frame_id),
306 chooser(chooser),
307 identifier(identifier) {
308 }
309
~ColorChooserInfo()310 WebContentsImpl::ColorChooserInfo::~ColorChooserInfo() {
311 }
312
313 // WebContentsImpl -------------------------------------------------------------
314
WebContentsImpl(BrowserContext * browser_context,WebContentsImpl * opener)315 WebContentsImpl::WebContentsImpl(
316 BrowserContext* browser_context,
317 WebContentsImpl* opener)
318 : delegate_(NULL),
319 controller_(this, browser_context),
320 render_view_host_delegate_view_(NULL),
321 opener_(opener),
322 created_with_opener_(!!opener),
323 #if defined(OS_WIN)
324 accessible_parent_(NULL),
325 #endif
326 frame_tree_(new NavigatorImpl(&controller_, this),
327 this, this, this, this),
328 is_loading_(false),
329 is_load_to_different_document_(false),
330 crashed_status_(base::TERMINATION_STATUS_STILL_RUNNING),
331 crashed_error_code_(0),
332 waiting_for_response_(false),
333 load_state_(net::LOAD_STATE_IDLE, base::string16()),
334 loading_total_progress_(0.0),
335 loading_weak_factory_(this),
336 loading_frames_in_progress_(0),
337 upload_size_(0),
338 upload_position_(0),
339 displayed_insecure_content_(false),
340 has_accessed_initial_document_(false),
341 capturer_count_(0),
342 should_normally_be_visible_(true),
343 is_being_destroyed_(false),
344 notify_disconnection_(false),
345 dialog_manager_(NULL),
346 is_showing_before_unload_dialog_(false),
347 last_active_time_(base::TimeTicks::Now()),
348 closed_by_user_gesture_(false),
349 minimum_zoom_percent_(static_cast<int>(kMinimumZoomFactor * 100)),
350 maximum_zoom_percent_(static_cast<int>(kMaximumZoomFactor * 100)),
351 totalPinchGestureAmount_(0),
352 currentPinchZoomStepDelta_(0),
353 render_view_message_source_(NULL),
354 fullscreen_widget_routing_id_(MSG_ROUTING_NONE),
355 is_subframe_(false),
356 touch_emulation_enabled_(false),
357 last_dialog_suppressed_(false) {
358 for (size_t i = 0; i < g_created_callbacks.Get().size(); i++)
359 g_created_callbacks.Get().at(i).Run(this);
360 frame_tree_.SetFrameRemoveListener(
361 base::Bind(&WebContentsImpl::OnFrameRemoved,
362 base::Unretained(this)));
363 }
364
~WebContentsImpl()365 WebContentsImpl::~WebContentsImpl() {
366 is_being_destroyed_ = true;
367
368 // Delete all RFH pending shutdown, which will lead the corresponding RVH to
369 // shutdown and be deleted as well.
370 frame_tree_.ForEach(
371 base::Bind(&RenderFrameHostManager::ClearRFHsPendingShutdown));
372
373 ClearAllPowerSaveBlockers();
374
375 for (std::set<RenderWidgetHostImpl*>::iterator iter =
376 created_widgets_.begin(); iter != created_widgets_.end(); ++iter) {
377 (*iter)->DetachDelegate();
378 }
379 created_widgets_.clear();
380
381 // Clear out any JavaScript state.
382 if (dialog_manager_)
383 dialog_manager_->WebContentsDestroyed(this);
384
385 if (color_chooser_info_.get())
386 color_chooser_info_->chooser->End();
387
388 NotifyDisconnected();
389
390 // Notify any observer that have a reference on this WebContents.
391 NotificationService::current()->Notify(
392 NOTIFICATION_WEB_CONTENTS_DESTROYED,
393 Source<WebContents>(this),
394 NotificationService::NoDetails());
395
396 // Destroy all frame tree nodes except for the root; this notifies observers.
397 frame_tree_.ResetForMainFrameSwap();
398 GetRenderManager()->ResetProxyHosts();
399
400 // Manually call the observer methods for the root frame tree node.
401 RenderFrameHostManager* root = GetRenderManager();
402 if (root->pending_frame_host()) {
403 FOR_EACH_OBSERVER(WebContentsObserver,
404 observers_,
405 RenderFrameDeleted(root->pending_frame_host()));
406 }
407 FOR_EACH_OBSERVER(WebContentsObserver,
408 observers_,
409 RenderFrameDeleted(root->current_frame_host()));
410
411 if (root->pending_render_view_host()) {
412 FOR_EACH_OBSERVER(WebContentsObserver,
413 observers_,
414 RenderViewDeleted(root->pending_render_view_host()));
415 }
416
417 FOR_EACH_OBSERVER(WebContentsObserver,
418 observers_,
419 RenderViewDeleted(root->current_host()));
420
421 FOR_EACH_OBSERVER(WebContentsObserver,
422 observers_,
423 WebContentsDestroyed());
424
425 FOR_EACH_OBSERVER(WebContentsObserver,
426 observers_,
427 ResetWebContents());
428
429 SetDelegate(NULL);
430
431 STLDeleteContainerPairSecondPointers(destruction_observers_.begin(),
432 destruction_observers_.end());
433 }
434
CreateWithOpener(const WebContents::CreateParams & params,WebContentsImpl * opener)435 WebContentsImpl* WebContentsImpl::CreateWithOpener(
436 const WebContents::CreateParams& params,
437 WebContentsImpl* opener) {
438 TRACE_EVENT0("browser", "WebContentsImpl::CreateWithOpener");
439 WebContentsImpl* new_contents = new WebContentsImpl(
440 params.browser_context, params.opener_suppressed ? NULL : opener);
441
442 if (params.guest_instance_id) {
443 scoped_ptr<base::DictionaryValue> extra_params;
444 if (params.guest_extra_params)
445 extra_params.reset(params.guest_extra_params->DeepCopy());
446 // This makes |new_contents| act as a guest.
447 // For more info, see comment above class BrowserPluginGuest.
448 BrowserPluginGuest::Create(params.guest_instance_id,
449 params.site_instance,
450 new_contents,
451 extra_params.Pass(),
452 opener ? opener->GetBrowserPluginGuest() : NULL);
453 // We are instantiating a WebContents for browser plugin. Set its subframe
454 // bit to true.
455 new_contents->is_subframe_ = true;
456 }
457 new_contents->Init(params);
458 return new_contents;
459 }
460
GetRenderManagerForTesting()461 RenderFrameHostManager* WebContentsImpl::GetRenderManagerForTesting() {
462 return GetRenderManager();
463 }
464
OnMessageReceived(RenderViewHost * render_view_host,const IPC::Message & message)465 bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host,
466 const IPC::Message& message) {
467 return OnMessageReceived(render_view_host, NULL, message);
468 }
469
OnMessageReceived(RenderViewHost * render_view_host,RenderFrameHost * render_frame_host,const IPC::Message & message)470 bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host,
471 RenderFrameHost* render_frame_host,
472 const IPC::Message& message) {
473 DCHECK(render_view_host || render_frame_host);
474 if (GetWebUI() &&
475 static_cast<WebUIImpl*>(GetWebUI())->OnMessageReceived(message)) {
476 return true;
477 }
478
479 ObserverListBase<WebContentsObserver>::Iterator it(observers_);
480 WebContentsObserver* observer;
481 if (render_frame_host) {
482 while ((observer = it.GetNext()) != NULL)
483 if (observer->OnMessageReceived(message, render_frame_host))
484 return true;
485 } else {
486 while ((observer = it.GetNext()) != NULL)
487 if (observer->OnMessageReceived(message))
488 return true;
489 }
490
491 // Message handlers should be aware of which
492 // RenderViewHost/RenderFrameHost sent the message, which is temporarily
493 // stored in render_(view|frame)_message_source_.
494 if (render_frame_host) {
495 if (RenderViewDevToolsAgentHost::DispatchIPCMessage(
496 render_frame_host->GetRenderViewHost(), message))
497 return true;
498 render_frame_message_source_ = render_frame_host;
499 } else {
500 if (RenderViewDevToolsAgentHost::DispatchIPCMessage(
501 render_view_host, message))
502 return true;
503 render_view_message_source_ = render_view_host;
504 }
505
506 bool handled = true;
507 IPC_BEGIN_MESSAGE_MAP(WebContentsImpl, message)
508 IPC_MESSAGE_HANDLER(FrameHostMsg_PepperPluginHung, OnPepperPluginHung)
509 IPC_MESSAGE_HANDLER(FrameHostMsg_PluginCrashed, OnPluginCrashed)
510 IPC_MESSAGE_HANDLER(FrameHostMsg_DomOperationResponse,
511 OnDomOperationResponse)
512 IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeThemeColor,
513 OnThemeColorChanged)
514 IPC_MESSAGE_HANDLER(FrameHostMsg_DidFinishDocumentLoad,
515 OnDocumentLoadedInFrame)
516 IPC_MESSAGE_HANDLER(FrameHostMsg_DidFinishLoad, OnDidFinishLoad)
517 IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartLoading, OnDidStartLoading)
518 IPC_MESSAGE_HANDLER(FrameHostMsg_DidStopLoading, OnDidStopLoading)
519 IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeLoadProgress,
520 OnDidChangeLoadProgress)
521 IPC_MESSAGE_HANDLER(FrameHostMsg_OpenColorChooser, OnOpenColorChooser)
522 IPC_MESSAGE_HANDLER(FrameHostMsg_EndColorChooser, OnEndColorChooser)
523 IPC_MESSAGE_HANDLER(FrameHostMsg_SetSelectedColorInColorChooser,
524 OnSetSelectedColorInColorChooser)
525 IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPlayingNotification,
526 OnMediaPlayingNotification)
527 IPC_MESSAGE_HANDLER(FrameHostMsg_MediaPausedNotification,
528 OnMediaPausedNotification)
529 IPC_MESSAGE_HANDLER(ViewHostMsg_DidLoadResourceFromMemoryCache,
530 OnDidLoadResourceFromMemoryCache)
531 IPC_MESSAGE_HANDLER(ViewHostMsg_DidDisplayInsecureContent,
532 OnDidDisplayInsecureContent)
533 IPC_MESSAGE_HANDLER(ViewHostMsg_DidRunInsecureContent,
534 OnDidRunInsecureContent)
535 IPC_MESSAGE_HANDLER(ViewHostMsg_GoToEntryAtOffset, OnGoToEntryAtOffset)
536 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateZoomLimits, OnUpdateZoomLimits)
537 IPC_MESSAGE_HANDLER(ViewHostMsg_EnumerateDirectory, OnEnumerateDirectory)
538 IPC_MESSAGE_HANDLER(ViewHostMsg_RegisterProtocolHandler,
539 OnRegisterProtocolHandler)
540 IPC_MESSAGE_HANDLER(ViewHostMsg_Find_Reply, OnFindReply)
541 IPC_MESSAGE_HANDLER(ViewHostMsg_AppCacheAccessed, OnAppCacheAccessed)
542 IPC_MESSAGE_HANDLER(ViewHostMsg_WebUISend, OnWebUISend)
543 IPC_MESSAGE_HANDLER(ViewHostMsg_RequestPpapiBrokerPermission,
544 OnRequestPpapiBrokerPermission)
545 IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginHostMsg_Attach,
546 OnBrowserPluginMessage(message))
547 IPC_MESSAGE_HANDLER(ImageHostMsg_DidDownloadImage, OnDidDownloadImage)
548 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFaviconURL, OnUpdateFaviconURL)
549 IPC_MESSAGE_HANDLER(ViewHostMsg_DidFirstVisuallyNonEmptyPaint,
550 OnFirstVisuallyNonEmptyPaint)
551 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowValidationMessage,
552 OnShowValidationMessage)
553 IPC_MESSAGE_HANDLER(ViewHostMsg_HideValidationMessage,
554 OnHideValidationMessage)
555 IPC_MESSAGE_HANDLER(ViewHostMsg_MoveValidationMessage,
556 OnMoveValidationMessage)
557 #if defined(OS_ANDROID)
558 IPC_MESSAGE_HANDLER(ViewHostMsg_FindMatchRects_Reply,
559 OnFindMatchRectsReply)
560 IPC_MESSAGE_HANDLER(ViewHostMsg_OpenDateTimeDialog,
561 OnOpenDateTimeDialog)
562 #endif
563 IPC_MESSAGE_UNHANDLED(handled = false)
564 IPC_END_MESSAGE_MAP()
565 render_view_message_source_ = NULL;
566 render_frame_message_source_ = NULL;
567
568 return handled;
569 }
570
RunFileChooser(RenderViewHost * render_view_host,const FileChooserParams & params)571 void WebContentsImpl::RunFileChooser(
572 RenderViewHost* render_view_host,
573 const FileChooserParams& params) {
574 if (delegate_)
575 delegate_->RunFileChooser(this, params);
576 }
577
GetController()578 NavigationControllerImpl& WebContentsImpl::GetController() {
579 return controller_;
580 }
581
GetController() const582 const NavigationControllerImpl& WebContentsImpl::GetController() const {
583 return controller_;
584 }
585
GetBrowserContext() const586 BrowserContext* WebContentsImpl::GetBrowserContext() const {
587 return controller_.GetBrowserContext();
588 }
589
GetURL() const590 const GURL& WebContentsImpl::GetURL() const {
591 // We may not have a navigation entry yet.
592 NavigationEntry* entry = controller_.GetVisibleEntry();
593 return entry ? entry->GetVirtualURL() : GURL::EmptyGURL();
594 }
595
GetVisibleURL() const596 const GURL& WebContentsImpl::GetVisibleURL() const {
597 // We may not have a navigation entry yet.
598 NavigationEntry* entry = controller_.GetVisibleEntry();
599 return entry ? entry->GetVirtualURL() : GURL::EmptyGURL();
600 }
601
GetLastCommittedURL() const602 const GURL& WebContentsImpl::GetLastCommittedURL() const {
603 // We may not have a navigation entry yet.
604 NavigationEntry* entry = controller_.GetLastCommittedEntry();
605 return entry ? entry->GetVirtualURL() : GURL::EmptyGURL();
606 }
607
GetDelegate()608 WebContentsDelegate* WebContentsImpl::GetDelegate() {
609 return delegate_;
610 }
611
SetDelegate(WebContentsDelegate * delegate)612 void WebContentsImpl::SetDelegate(WebContentsDelegate* delegate) {
613 // TODO(cbentzel): remove this debugging code?
614 if (delegate == delegate_)
615 return;
616 if (delegate_)
617 delegate_->Detach(this);
618 delegate_ = delegate;
619 if (delegate_) {
620 delegate_->Attach(this);
621 // Ensure the visible RVH reflects the new delegate's preferences.
622 if (view_)
623 view_->SetOverscrollControllerEnabled(CanOverscrollContent());
624 }
625 }
626
GetRenderProcessHost() const627 RenderProcessHost* WebContentsImpl::GetRenderProcessHost() const {
628 RenderViewHostImpl* host = GetRenderManager()->current_host();
629 return host ? host->GetProcess() : NULL;
630 }
631
GetMainFrame()632 RenderFrameHost* WebContentsImpl::GetMainFrame() {
633 return frame_tree_.root()->current_frame_host();
634 }
635
GetFocusedFrame()636 RenderFrameHost* WebContentsImpl::GetFocusedFrame() {
637 if (!frame_tree_.GetFocusedFrame())
638 return NULL;
639 return frame_tree_.GetFocusedFrame()->current_frame_host();
640 }
641
ForEachFrame(const base::Callback<void (RenderFrameHost *)> & on_frame)642 void WebContentsImpl::ForEachFrame(
643 const base::Callback<void(RenderFrameHost*)>& on_frame) {
644 frame_tree_.ForEach(base::Bind(&ForEachFrameInternal, on_frame));
645 }
646
SendToAllFrames(IPC::Message * message)647 void WebContentsImpl::SendToAllFrames(IPC::Message* message) {
648 ForEachFrame(base::Bind(&SendToAllFramesInternal, message));
649 delete message;
650 }
651
GetRenderViewHost() const652 RenderViewHost* WebContentsImpl::GetRenderViewHost() const {
653 return GetRenderManager()->current_host();
654 }
655
GetRoutingID() const656 int WebContentsImpl::GetRoutingID() const {
657 if (!GetRenderViewHost())
658 return MSG_ROUTING_NONE;
659
660 return GetRenderViewHost()->GetRoutingID();
661 }
662
GetFullscreenWidgetRoutingID() const663 int WebContentsImpl::GetFullscreenWidgetRoutingID() const {
664 return fullscreen_widget_routing_id_;
665 }
666
GetRenderWidgetHostView() const667 RenderWidgetHostView* WebContentsImpl::GetRenderWidgetHostView() const {
668 return GetRenderManager()->GetRenderWidgetHostView();
669 }
670
GetFullscreenRenderWidgetHostView() const671 RenderWidgetHostView* WebContentsImpl::GetFullscreenRenderWidgetHostView()
672 const {
673 RenderWidgetHost* const widget_host =
674 RenderWidgetHostImpl::FromID(GetRenderProcessHost()->GetID(),
675 GetFullscreenWidgetRoutingID());
676 return widget_host ? widget_host->GetView() : NULL;
677 }
678
GetView() const679 WebContentsView* WebContentsImpl::GetView() const {
680 return view_.get();
681 }
682
CreateWebUI(const GURL & url)683 WebUI* WebContentsImpl::CreateWebUI(const GURL& url) {
684 WebUIImpl* web_ui = new WebUIImpl(this);
685 WebUIController* controller = WebUIControllerFactoryRegistry::GetInstance()->
686 CreateWebUIControllerForURL(web_ui, url);
687 if (controller) {
688 web_ui->AddMessageHandler(new GenericHandler());
689 web_ui->SetController(controller);
690 return web_ui;
691 }
692
693 delete web_ui;
694 return NULL;
695 }
696
GetWebUI() const697 WebUI* WebContentsImpl::GetWebUI() const {
698 return GetRenderManager()->web_ui() ? GetRenderManager()->web_ui()
699 : GetRenderManager()->pending_web_ui();
700 }
701
GetCommittedWebUI() const702 WebUI* WebContentsImpl::GetCommittedWebUI() const {
703 return GetRenderManager()->web_ui();
704 }
705
SetUserAgentOverride(const std::string & override)706 void WebContentsImpl::SetUserAgentOverride(const std::string& override) {
707 if (GetUserAgentOverride() == override)
708 return;
709
710 renderer_preferences_.user_agent_override = override;
711
712 // Send the new override string to the renderer.
713 RenderViewHost* host = GetRenderViewHost();
714 if (host)
715 host->SyncRendererPrefs();
716
717 // Reload the page if a load is currently in progress to avoid having
718 // different parts of the page loaded using different user agents.
719 NavigationEntry* entry = controller_.GetVisibleEntry();
720 if (is_loading_ && entry != NULL && entry->GetIsOverridingUserAgent())
721 controller_.ReloadIgnoringCache(true);
722
723 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
724 UserAgentOverrideSet(override));
725 }
726
GetUserAgentOverride() const727 const std::string& WebContentsImpl::GetUserAgentOverride() const {
728 return renderer_preferences_.user_agent_override;
729 }
730
731 #if defined(OS_WIN)
SetParentNativeViewAccessible(gfx::NativeViewAccessible accessible_parent)732 void WebContentsImpl::SetParentNativeViewAccessible(
733 gfx::NativeViewAccessible accessible_parent) {
734 accessible_parent_ = accessible_parent;
735 if (GetRenderViewHost())
736 GetRenderViewHostImpl()->SetParentNativeViewAccessible(accessible_parent);
737 }
738 #endif
739
GetTitle() const740 const base::string16& WebContentsImpl::GetTitle() const {
741 // Transient entries take precedence. They are used for interstitial pages
742 // that are shown on top of existing pages.
743 NavigationEntry* entry = controller_.GetTransientEntry();
744 std::string accept_languages =
745 GetContentClient()->browser()->GetAcceptLangs(
746 GetBrowserContext());
747 if (entry) {
748 return entry->GetTitleForDisplay(accept_languages);
749 }
750 WebUI* our_web_ui = GetRenderManager()->pending_web_ui() ?
751 GetRenderManager()->pending_web_ui() : GetRenderManager()->web_ui();
752 if (our_web_ui) {
753 // Don't override the title in view source mode.
754 entry = controller_.GetVisibleEntry();
755 if (!(entry && entry->IsViewSourceMode())) {
756 // Give the Web UI the chance to override our title.
757 const base::string16& title = our_web_ui->GetOverriddenTitle();
758 if (!title.empty())
759 return title;
760 }
761 }
762
763 // We use the title for the last committed entry rather than a pending
764 // navigation entry. For example, when the user types in a URL, we want to
765 // keep the old page's title until the new load has committed and we get a new
766 // title.
767 entry = controller_.GetLastCommittedEntry();
768
769 // We make an exception for initial navigations.
770 if (controller_.IsInitialNavigation()) {
771 // We only want to use the title from the visible entry in one of two cases:
772 // 1. There's already a committed entry for an initial navigation, in which
773 // case we are doing a history navigation in a new tab (e.g., Ctrl+Back).
774 // 2. The pending entry has been explicitly assigned a title to display.
775 //
776 // If there's no last committed entry and no assigned title, we should fall
777 // back to |page_title_when_no_navigation_entry_| rather than showing the
778 // URL.
779 if (entry ||
780 (controller_.GetVisibleEntry() &&
781 !controller_.GetVisibleEntry()->GetTitle().empty())) {
782 entry = controller_.GetVisibleEntry();
783 }
784 }
785
786 if (entry) {
787 return entry->GetTitleForDisplay(accept_languages);
788 }
789
790 // |page_title_when_no_navigation_entry_| is finally used
791 // if no title cannot be retrieved.
792 return page_title_when_no_navigation_entry_;
793 }
794
GetMaxPageID()795 int32 WebContentsImpl::GetMaxPageID() {
796 return GetMaxPageIDForSiteInstance(GetSiteInstance());
797 }
798
GetMaxPageIDForSiteInstance(SiteInstance * site_instance)799 int32 WebContentsImpl::GetMaxPageIDForSiteInstance(
800 SiteInstance* site_instance) {
801 if (max_page_ids_.find(site_instance->GetId()) == max_page_ids_.end())
802 max_page_ids_[site_instance->GetId()] = -1;
803
804 return max_page_ids_[site_instance->GetId()];
805 }
806
UpdateMaxPageID(int32 page_id)807 void WebContentsImpl::UpdateMaxPageID(int32 page_id) {
808 UpdateMaxPageIDForSiteInstance(GetSiteInstance(), page_id);
809 }
810
UpdateMaxPageIDForSiteInstance(SiteInstance * site_instance,int32 page_id)811 void WebContentsImpl::UpdateMaxPageIDForSiteInstance(
812 SiteInstance* site_instance, int32 page_id) {
813 if (GetMaxPageIDForSiteInstance(site_instance) < page_id)
814 max_page_ids_[site_instance->GetId()] = page_id;
815 }
816
CopyMaxPageIDsFrom(WebContents * web_contents)817 void WebContentsImpl::CopyMaxPageIDsFrom(WebContents* web_contents) {
818 WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents);
819 max_page_ids_ = contents->max_page_ids_;
820 }
821
GetSiteInstance() const822 SiteInstance* WebContentsImpl::GetSiteInstance() const {
823 return GetRenderManager()->current_host()->GetSiteInstance();
824 }
825
GetPendingSiteInstance() const826 SiteInstance* WebContentsImpl::GetPendingSiteInstance() const {
827 RenderViewHost* dest_rvh = GetRenderManager()->pending_render_view_host() ?
828 GetRenderManager()->pending_render_view_host() :
829 GetRenderManager()->current_host();
830 return dest_rvh->GetSiteInstance();
831 }
832
IsLoading() const833 bool WebContentsImpl::IsLoading() const {
834 return is_loading_;
835 }
836
IsLoadingToDifferentDocument() const837 bool WebContentsImpl::IsLoadingToDifferentDocument() const {
838 return is_loading_ && is_load_to_different_document_;
839 }
840
IsWaitingForResponse() const841 bool WebContentsImpl::IsWaitingForResponse() const {
842 return waiting_for_response_ && is_load_to_different_document_;
843 }
844
GetLoadState() const845 const net::LoadStateWithParam& WebContentsImpl::GetLoadState() const {
846 return load_state_;
847 }
848
GetLoadStateHost() const849 const base::string16& WebContentsImpl::GetLoadStateHost() const {
850 return load_state_host_;
851 }
852
GetUploadSize() const853 uint64 WebContentsImpl::GetUploadSize() const {
854 return upload_size_;
855 }
856
GetUploadPosition() const857 uint64 WebContentsImpl::GetUploadPosition() const {
858 return upload_position_;
859 }
860
GetSitesInTab() const861 std::set<GURL> WebContentsImpl::GetSitesInTab() const {
862 std::set<GURL> sites;
863 frame_tree_.ForEach(base::Bind(&CollectSites,
864 base::Unretained(GetBrowserContext()),
865 base::Unretained(&sites)));
866 return sites;
867 }
868
GetEncoding() const869 const std::string& WebContentsImpl::GetEncoding() const {
870 return canonical_encoding_;
871 }
872
DisplayedInsecureContent() const873 bool WebContentsImpl::DisplayedInsecureContent() const {
874 return displayed_insecure_content_;
875 }
876
IncrementCapturerCount(const gfx::Size & capture_size)877 void WebContentsImpl::IncrementCapturerCount(const gfx::Size& capture_size) {
878 DCHECK(!is_being_destroyed_);
879 ++capturer_count_;
880 DVLOG(1) << "There are now " << capturer_count_
881 << " capturing(s) of WebContentsImpl@" << this;
882
883 // Note: This provides a hint to upstream code to size the views optimally
884 // for quality (e.g., to avoid scaling).
885 if (!capture_size.IsEmpty() && preferred_size_for_capture_.IsEmpty()) {
886 preferred_size_for_capture_ = capture_size;
887 OnPreferredSizeChanged(preferred_size_);
888 }
889 }
890
DecrementCapturerCount()891 void WebContentsImpl::DecrementCapturerCount() {
892 --capturer_count_;
893 DVLOG(1) << "There are now " << capturer_count_
894 << " capturing(s) of WebContentsImpl@" << this;
895 DCHECK_LE(0, capturer_count_);
896
897 if (is_being_destroyed_)
898 return;
899
900 if (capturer_count_ == 0) {
901 const gfx::Size old_size = preferred_size_for_capture_;
902 preferred_size_for_capture_ = gfx::Size();
903 OnPreferredSizeChanged(old_size);
904 }
905
906 if (IsHidden()) {
907 DVLOG(1) << "Executing delayed WasHidden().";
908 WasHidden();
909 }
910 }
911
GetCapturerCount() const912 int WebContentsImpl::GetCapturerCount() const {
913 return capturer_count_;
914 }
915
IsCrashed() const916 bool WebContentsImpl::IsCrashed() const {
917 return (crashed_status_ == base::TERMINATION_STATUS_PROCESS_CRASHED ||
918 crashed_status_ == base::TERMINATION_STATUS_ABNORMAL_TERMINATION ||
919 crashed_status_ == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
920 }
921
SetIsCrashed(base::TerminationStatus status,int error_code)922 void WebContentsImpl::SetIsCrashed(base::TerminationStatus status,
923 int error_code) {
924 if (status == crashed_status_)
925 return;
926
927 crashed_status_ = status;
928 crashed_error_code_ = error_code;
929 NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
930 }
931
GetCrashedStatus() const932 base::TerminationStatus WebContentsImpl::GetCrashedStatus() const {
933 return crashed_status_;
934 }
935
IsBeingDestroyed() const936 bool WebContentsImpl::IsBeingDestroyed() const {
937 return is_being_destroyed_;
938 }
939
NotifyNavigationStateChanged(unsigned changed_flags)940 void WebContentsImpl::NotifyNavigationStateChanged(unsigned changed_flags) {
941 if (delegate_)
942 delegate_->NavigationStateChanged(this, changed_flags);
943 }
944
GetLastActiveTime() const945 base::TimeTicks WebContentsImpl::GetLastActiveTime() const {
946 return last_active_time_;
947 }
948
WasShown()949 void WebContentsImpl::WasShown() {
950 controller_.SetActive(true);
951
952 std::set<RenderWidgetHostView*> widgets = GetRenderWidgetHostViewsInTree();
953 for (std::set<RenderWidgetHostView*>::iterator iter = widgets.begin();
954 iter != widgets.end();
955 iter++) {
956 if (*iter) {
957 (*iter)->Show();
958 #if defined(OS_MACOSX)
959 (*iter)->SetActive(true);
960 #endif
961 }
962 }
963
964 last_active_time_ = base::TimeTicks::Now();
965
966 // The resize rect might have changed while this was inactive -- send the new
967 // one to make sure it's up to date.
968 RenderViewHostImpl* rvh =
969 static_cast<RenderViewHostImpl*>(GetRenderViewHost());
970 if (rvh) {
971 rvh->ResizeRectChanged(GetRootWindowResizerRect());
972 }
973
974 FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasShown());
975
976 should_normally_be_visible_ = true;
977 }
978
WasHidden()979 void WebContentsImpl::WasHidden() {
980 // If there are entities capturing screenshots or video (e.g., mirroring),
981 // don't activate the "disable rendering" optimization.
982 if (capturer_count_ == 0) {
983 // |GetRenderViewHost()| can be NULL if the user middle clicks a link to
984 // open a tab in the background, then closes the tab before selecting it.
985 // This is because closing the tab calls WebContentsImpl::Destroy(), which
986 // removes the |GetRenderViewHost()|; then when we actually destroy the
987 // window, OnWindowPosChanged() notices and calls WasHidden() (which
988 // calls us).
989 std::set<RenderWidgetHostView*> widgets = GetRenderWidgetHostViewsInTree();
990 for (std::set<RenderWidgetHostView*>::iterator iter = widgets.begin();
991 iter != widgets.end();
992 iter++) {
993 if (*iter)
994 (*iter)->Hide();
995 }
996 }
997
998 FOR_EACH_OBSERVER(WebContentsObserver, observers_, WasHidden());
999
1000 should_normally_be_visible_ = false;
1001 }
1002
NeedToFireBeforeUnload()1003 bool WebContentsImpl::NeedToFireBeforeUnload() {
1004 // TODO(creis): Should we fire even for interstitial pages?
1005 return WillNotifyDisconnection() &&
1006 !ShowingInterstitialPage() &&
1007 !static_cast<RenderViewHostImpl*>(
1008 GetRenderViewHost())->SuddenTerminationAllowed();
1009 }
1010
DispatchBeforeUnload(bool for_cross_site_transition)1011 void WebContentsImpl::DispatchBeforeUnload(bool for_cross_site_transition) {
1012 static_cast<RenderFrameHostImpl*>(GetMainFrame())->DispatchBeforeUnload(
1013 for_cross_site_transition);
1014 }
1015
Stop()1016 void WebContentsImpl::Stop() {
1017 GetRenderManager()->Stop();
1018 FOR_EACH_OBSERVER(WebContentsObserver, observers_, NavigationStopped());
1019 }
1020
Clone()1021 WebContents* WebContentsImpl::Clone() {
1022 // We use our current SiteInstance since the cloned entry will use it anyway.
1023 // We pass our own opener so that the cloned page can access it if it was
1024 // before.
1025 CreateParams create_params(GetBrowserContext(), GetSiteInstance());
1026 create_params.initial_size = GetContainerBounds().size();
1027 WebContentsImpl* tc = CreateWithOpener(create_params, opener_);
1028 tc->GetController().CopyStateFrom(controller_);
1029 FOR_EACH_OBSERVER(WebContentsObserver,
1030 observers_,
1031 DidCloneToNewWebContents(this, tc));
1032 return tc;
1033 }
1034
Observe(int type,const NotificationSource & source,const NotificationDetails & details)1035 void WebContentsImpl::Observe(int type,
1036 const NotificationSource& source,
1037 const NotificationDetails& details) {
1038 switch (type) {
1039 case NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: {
1040 RenderWidgetHost* host = Source<RenderWidgetHost>(source).ptr();
1041 for (PendingWidgetViews::iterator i = pending_widget_views_.begin();
1042 i != pending_widget_views_.end(); ++i) {
1043 if (host->GetView() == i->second) {
1044 pending_widget_views_.erase(i);
1045 break;
1046 }
1047 }
1048 break;
1049 }
1050 default:
1051 NOTREACHED();
1052 }
1053 }
1054
GetWebContents()1055 WebContents* WebContentsImpl::GetWebContents() {
1056 return this;
1057 }
1058
Init(const WebContents::CreateParams & params)1059 void WebContentsImpl::Init(const WebContents::CreateParams& params) {
1060 // This is set before initializing the render manager since
1061 // RenderFrameHostManager::Init calls back into us via its delegate to ask if
1062 // it should be hidden.
1063 should_normally_be_visible_ = !params.initially_hidden;
1064
1065 GetRenderManager()->Init(
1066 params.browser_context, params.site_instance, params.routing_id,
1067 params.main_frame_routing_id);
1068
1069 WebContentsViewDelegate* delegate =
1070 GetContentClient()->browser()->GetWebContentsViewDelegate(this);
1071
1072 if (browser_plugin_guest_) {
1073 scoped_ptr<WebContentsView> platform_view(CreateWebContentsView(
1074 this, delegate, &render_view_host_delegate_view_));
1075
1076 WebContentsViewGuest* rv = new WebContentsViewGuest(
1077 this, browser_plugin_guest_.get(), platform_view.Pass(),
1078 render_view_host_delegate_view_);
1079 render_view_host_delegate_view_ = rv;
1080 view_.reset(rv);
1081 } else {
1082 // Regular WebContentsView.
1083 view_.reset(CreateWebContentsView(
1084 this, delegate, &render_view_host_delegate_view_));
1085 }
1086 CHECK(render_view_host_delegate_view_);
1087 CHECK(view_.get());
1088
1089 gfx::Size initial_size = params.initial_size;
1090 view_->CreateView(initial_size, params.context);
1091
1092 // Listen for whether our opener gets destroyed.
1093 if (opener_)
1094 AddDestructionObserver(opener_);
1095
1096 registrar_.Add(this,
1097 NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
1098 NotificationService::AllBrowserContextsAndSources());
1099
1100 geolocation_dispatcher_host_.reset(new GeolocationDispatcherHost(this));
1101 midi_dispatcher_host_.reset(new MidiDispatcherHost(this));
1102
1103 screen_orientation_dispatcher_host_.reset(
1104 new ScreenOrientationDispatcherHost(this));
1105
1106 #if defined(OS_ANDROID)
1107 date_time_chooser_.reset(new DateTimeChooserAndroid());
1108 #endif
1109 }
1110
OnWebContentsDestroyed(WebContentsImpl * web_contents)1111 void WebContentsImpl::OnWebContentsDestroyed(WebContentsImpl* web_contents) {
1112 RemoveDestructionObserver(web_contents);
1113
1114 // Clear the opener if it has been closed.
1115 if (web_contents == opener_) {
1116 opener_ = NULL;
1117 return;
1118 }
1119 // Clear a pending contents that has been closed before being shown.
1120 for (PendingContents::iterator iter = pending_contents_.begin();
1121 iter != pending_contents_.end();
1122 ++iter) {
1123 if (iter->second != web_contents)
1124 continue;
1125 pending_contents_.erase(iter);
1126 return;
1127 }
1128 NOTREACHED();
1129 }
1130
AddDestructionObserver(WebContentsImpl * web_contents)1131 void WebContentsImpl::AddDestructionObserver(WebContentsImpl* web_contents) {
1132 if (!ContainsKey(destruction_observers_, web_contents)) {
1133 destruction_observers_[web_contents] =
1134 new DestructionObserver(this, web_contents);
1135 }
1136 }
1137
RemoveDestructionObserver(WebContentsImpl * web_contents)1138 void WebContentsImpl::RemoveDestructionObserver(WebContentsImpl* web_contents) {
1139 DestructionObservers::iterator iter =
1140 destruction_observers_.find(web_contents);
1141 if (iter != destruction_observers_.end()) {
1142 delete destruction_observers_[web_contents];
1143 destruction_observers_.erase(iter);
1144 }
1145 }
1146
AddObserver(WebContentsObserver * observer)1147 void WebContentsImpl::AddObserver(WebContentsObserver* observer) {
1148 observers_.AddObserver(observer);
1149 }
1150
RemoveObserver(WebContentsObserver * observer)1151 void WebContentsImpl::RemoveObserver(WebContentsObserver* observer) {
1152 observers_.RemoveObserver(observer);
1153 }
1154
1155 std::set<RenderWidgetHostView*>
GetRenderWidgetHostViewsInTree()1156 WebContentsImpl::GetRenderWidgetHostViewsInTree() {
1157 std::set<RenderWidgetHostView*> set;
1158 if (ShowingInterstitialPage()) {
1159 set.insert(GetRenderWidgetHostView());
1160 } else {
1161 ForEachFrame(
1162 base::Bind(&AddRenderWidgetHostViewToSet, base::Unretained(&set)));
1163 }
1164 return set;
1165 }
1166
Activate()1167 void WebContentsImpl::Activate() {
1168 if (delegate_)
1169 delegate_->ActivateContents(this);
1170 }
1171
Deactivate()1172 void WebContentsImpl::Deactivate() {
1173 if (delegate_)
1174 delegate_->DeactivateContents(this);
1175 }
1176
LostCapture()1177 void WebContentsImpl::LostCapture() {
1178 if (delegate_)
1179 delegate_->LostCapture();
1180 }
1181
RenderWidgetDeleted(RenderWidgetHostImpl * render_widget_host)1182 void WebContentsImpl::RenderWidgetDeleted(
1183 RenderWidgetHostImpl* render_widget_host) {
1184 if (is_being_destroyed_) {
1185 // |created_widgets_| might have been destroyed.
1186 return;
1187 }
1188
1189 std::set<RenderWidgetHostImpl*>::iterator iter =
1190 created_widgets_.find(render_widget_host);
1191 if (iter != created_widgets_.end())
1192 created_widgets_.erase(iter);
1193
1194 if (render_widget_host &&
1195 render_widget_host->GetRoutingID() == fullscreen_widget_routing_id_) {
1196 if (delegate_ && delegate_->EmbedsFullscreenWidget())
1197 delegate_->ToggleFullscreenModeForTab(this, false);
1198 FOR_EACH_OBSERVER(WebContentsObserver,
1199 observers_,
1200 DidDestroyFullscreenWidget(
1201 fullscreen_widget_routing_id_));
1202 fullscreen_widget_routing_id_ = MSG_ROUTING_NONE;
1203 }
1204 }
1205
PreHandleKeyboardEvent(const NativeWebKeyboardEvent & event,bool * is_keyboard_shortcut)1206 bool WebContentsImpl::PreHandleKeyboardEvent(
1207 const NativeWebKeyboardEvent& event,
1208 bool* is_keyboard_shortcut) {
1209 return delegate_ &&
1210 delegate_->PreHandleKeyboardEvent(this, event, is_keyboard_shortcut);
1211 }
1212
HandleKeyboardEvent(const NativeWebKeyboardEvent & event)1213 void WebContentsImpl::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
1214 if (delegate_)
1215 delegate_->HandleKeyboardEvent(this, event);
1216 }
1217
HandleWheelEvent(const blink::WebMouseWheelEvent & event)1218 bool WebContentsImpl::HandleWheelEvent(
1219 const blink::WebMouseWheelEvent& event) {
1220 #if !defined(OS_MACOSX)
1221 // On platforms other than Mac, control+mousewheel changes zoom. On Mac, this
1222 // isn't done for two reasons:
1223 // -the OS already has a gesture to do this through pinch-zoom
1224 // -if a user starts an inertial scroll, let's go, and presses control
1225 // (i.e. control+tab) then the OS's buffered scroll events will come in
1226 // with control key set which isn't what the user wants
1227 if (delegate_ &&
1228 event.wheelTicksY &&
1229 (event.modifiers & blink::WebInputEvent::ControlKey) &&
1230 // Avoid adjusting the zoom in response to two-finger-scrolling touchpad
1231 // gestures, which are regrettably easy to trigger accidentally.
1232 !event.hasPreciseScrollingDeltas) {
1233 delegate_->ContentsZoomChange(event.wheelTicksY > 0);
1234 return true;
1235 }
1236 #endif
1237 return false;
1238 }
1239
PreHandleGestureEvent(const blink::WebGestureEvent & event)1240 bool WebContentsImpl::PreHandleGestureEvent(
1241 const blink::WebGestureEvent& event) {
1242 return delegate_ && delegate_->PreHandleGestureEvent(this, event);
1243 }
1244
HandleGestureEvent(const blink::WebGestureEvent & event)1245 bool WebContentsImpl::HandleGestureEvent(
1246 const blink::WebGestureEvent& event) {
1247 // Some platforms (eg. Mac) send GesturePinch events for trackpad pinch-zoom.
1248 // Use them to implement browser zoom, as for HandleWheelEvent above.
1249 if (event.type == blink::WebInputEvent::GesturePinchUpdate &&
1250 event.sourceDevice == blink::WebGestureDeviceTouchpad) {
1251 // The scale difference necessary to trigger a zoom action. Derived from
1252 // experimentation to find a value that feels reasonable.
1253 const float kZoomStepValue = 0.6f;
1254
1255 // Find the (absolute) thresholds on either side of the current zoom factor,
1256 // then convert those to actual numbers to trigger a zoom in or out.
1257 // This logic deliberately makes the range around the starting zoom value
1258 // for the gesture twice as large as the other ranges (i.e., the notches are
1259 // at ..., -3*step, -2*step, -step, step, 2*step, 3*step, ... but not at 0)
1260 // so that it's easier to get back to your starting point than it is to
1261 // overshoot.
1262 float nextStep = (abs(currentPinchZoomStepDelta_) + 1) * kZoomStepValue;
1263 float backStep = abs(currentPinchZoomStepDelta_) * kZoomStepValue;
1264 float zoomInThreshold = (currentPinchZoomStepDelta_ >= 0) ? nextStep
1265 : -backStep;
1266 float zoomOutThreshold = (currentPinchZoomStepDelta_ <= 0) ? -nextStep
1267 : backStep;
1268
1269 totalPinchGestureAmount_ += (event.data.pinchUpdate.scale - 1.0);
1270 if (totalPinchGestureAmount_ > zoomInThreshold) {
1271 currentPinchZoomStepDelta_++;
1272 if (delegate_)
1273 delegate_->ContentsZoomChange(true);
1274 } else if (totalPinchGestureAmount_ < zoomOutThreshold) {
1275 currentPinchZoomStepDelta_--;
1276 if (delegate_)
1277 delegate_->ContentsZoomChange(false);
1278 }
1279 return true;
1280 }
1281
1282 return false;
1283 }
1284
1285 #if defined(OS_WIN)
GetParentNativeViewAccessible()1286 gfx::NativeViewAccessible WebContentsImpl::GetParentNativeViewAccessible() {
1287 return accessible_parent_;
1288 }
1289 #endif
1290
HandleMouseDown()1291 void WebContentsImpl::HandleMouseDown() {
1292 if (delegate_)
1293 delegate_->HandleMouseDown();
1294 }
1295
HandleMouseUp()1296 void WebContentsImpl::HandleMouseUp() {
1297 if (delegate_)
1298 delegate_->HandleMouseUp();
1299 }
1300
HandlePointerActivate()1301 void WebContentsImpl::HandlePointerActivate() {
1302 if (delegate_)
1303 delegate_->HandlePointerActivate();
1304 }
1305
HandleGestureBegin()1306 void WebContentsImpl::HandleGestureBegin() {
1307 if (delegate_)
1308 delegate_->HandleGestureBegin();
1309 }
1310
HandleGestureEnd()1311 void WebContentsImpl::HandleGestureEnd() {
1312 if (delegate_)
1313 delegate_->HandleGestureEnd();
1314 }
1315
ToggleFullscreenMode(bool enter_fullscreen)1316 void WebContentsImpl::ToggleFullscreenMode(bool enter_fullscreen) {
1317 // This method is being called to enter or leave renderer-initiated fullscreen
1318 // mode. Either way, make sure any existing fullscreen widget is shut down
1319 // first.
1320 RenderWidgetHostView* const widget_view = GetFullscreenRenderWidgetHostView();
1321 if (widget_view)
1322 RenderWidgetHostImpl::From(widget_view->GetRenderWidgetHost())->Shutdown();
1323
1324 if (delegate_)
1325 delegate_->ToggleFullscreenModeForTab(this, enter_fullscreen);
1326
1327 FOR_EACH_OBSERVER(WebContentsObserver,
1328 observers_,
1329 DidToggleFullscreenModeForTab(IsFullscreenForCurrentTab()));
1330 }
1331
IsFullscreenForCurrentTab() const1332 bool WebContentsImpl::IsFullscreenForCurrentTab() const {
1333 return delegate_ ? delegate_->IsFullscreenForTabOrPending(this) : false;
1334 }
1335
RequestToLockMouse(bool user_gesture,bool last_unlocked_by_target)1336 void WebContentsImpl::RequestToLockMouse(bool user_gesture,
1337 bool last_unlocked_by_target) {
1338 if (delegate_) {
1339 delegate_->RequestToLockMouse(this, user_gesture, last_unlocked_by_target);
1340 } else {
1341 GotResponseToLockMouseRequest(false);
1342 }
1343 }
1344
LostMouseLock()1345 void WebContentsImpl::LostMouseLock() {
1346 if (delegate_)
1347 delegate_->LostMouseLock();
1348 }
1349
CreateNewWindow(int render_process_id,int route_id,int main_frame_route_id,const ViewHostMsg_CreateWindow_Params & params,SessionStorageNamespace * session_storage_namespace)1350 void WebContentsImpl::CreateNewWindow(
1351 int render_process_id,
1352 int route_id,
1353 int main_frame_route_id,
1354 const ViewHostMsg_CreateWindow_Params& params,
1355 SessionStorageNamespace* session_storage_namespace) {
1356 // We usually create the new window in the same BrowsingInstance (group of
1357 // script-related windows), by passing in the current SiteInstance. However,
1358 // if the opener is being suppressed (in a non-guest), we create a new
1359 // SiteInstance in its own BrowsingInstance.
1360 bool is_guest = BrowserPluginGuest::IsGuest(this);
1361
1362 // If the opener is to be suppressed, the new window can be in any process.
1363 // Since routing ids are process specific, we must not have one passed in
1364 // as argument here.
1365 DCHECK(!params.opener_suppressed || route_id == MSG_ROUTING_NONE);
1366
1367 scoped_refptr<SiteInstance> site_instance =
1368 params.opener_suppressed && !is_guest ?
1369 SiteInstance::CreateForURL(GetBrowserContext(), params.target_url) :
1370 GetSiteInstance();
1371
1372 // A message to create a new window can only come from the active process for
1373 // this WebContentsImpl instance. If any other process sends the request,
1374 // it is invalid and the process must be terminated.
1375 if (GetRenderProcessHost()->GetID() != render_process_id) {
1376 base::ProcessHandle process_handle =
1377 RenderProcessHost::FromID(render_process_id)->GetHandle();
1378 if (process_handle != base::kNullProcessHandle) {
1379 RecordAction(
1380 base::UserMetricsAction("Terminate_ProcessMismatch_CreateNewWindow"));
1381 base::KillProcess(process_handle, content::RESULT_CODE_KILLED, false);
1382 }
1383 return;
1384 }
1385
1386 // We must assign the SessionStorageNamespace before calling Init().
1387 //
1388 // http://crbug.com/142685
1389 const std::string& partition_id =
1390 GetContentClient()->browser()->
1391 GetStoragePartitionIdForSite(GetBrowserContext(),
1392 site_instance->GetSiteURL());
1393 StoragePartition* partition = BrowserContext::GetStoragePartition(
1394 GetBrowserContext(), site_instance.get());
1395 DOMStorageContextWrapper* dom_storage_context =
1396 static_cast<DOMStorageContextWrapper*>(partition->GetDOMStorageContext());
1397 SessionStorageNamespaceImpl* session_storage_namespace_impl =
1398 static_cast<SessionStorageNamespaceImpl*>(session_storage_namespace);
1399 CHECK(session_storage_namespace_impl->IsFromContext(dom_storage_context));
1400
1401 if (delegate_ &&
1402 !delegate_->ShouldCreateWebContents(this,
1403 route_id,
1404 params.window_container_type,
1405 params.frame_name,
1406 params.target_url,
1407 partition_id,
1408 session_storage_namespace)) {
1409 if (route_id != MSG_ROUTING_NONE &&
1410 !RenderViewHost::FromID(render_process_id, route_id)) {
1411 // If the embedder didn't create a WebContents for this route, we need to
1412 // delete the RenderView that had already been created.
1413 Send(new ViewMsg_Close(route_id));
1414 }
1415 GetRenderViewHost()->GetProcess()->ResumeRequestsForView(route_id);
1416 GetRenderViewHost()->GetProcess()->ResumeRequestsForView(
1417 main_frame_route_id);
1418 return;
1419 }
1420
1421 // Create the new web contents. This will automatically create the new
1422 // WebContentsView. In the future, we may want to create the view separately.
1423 CreateParams create_params(GetBrowserContext(), site_instance.get());
1424 create_params.routing_id = route_id;
1425 create_params.main_frame_routing_id = main_frame_route_id;
1426 create_params.opener = this;
1427 create_params.opener_suppressed = params.opener_suppressed;
1428 if (params.disposition == NEW_BACKGROUND_TAB)
1429 create_params.initially_hidden = true;
1430
1431 if (!is_guest) {
1432 create_params.context = view_->GetNativeView();
1433 create_params.initial_size = GetContainerBounds().size();
1434 } else {
1435 create_params.guest_instance_id =
1436 GetBrowserContext()->GetGuestManager()->GetNextInstanceID();
1437 }
1438 WebContentsImpl* new_contents = static_cast<WebContentsImpl*>(
1439 WebContents::Create(create_params));
1440 new_contents->GetController().SetSessionStorageNamespace(
1441 partition_id,
1442 session_storage_namespace);
1443 new_contents->RenderViewCreated(new_contents->GetRenderViewHost());
1444
1445 // Save the window for later if we're not suppressing the opener (since it
1446 // will be shown immediately).
1447 if (!params.opener_suppressed) {
1448 if (!is_guest) {
1449 WebContentsView* new_view = new_contents->view_.get();
1450
1451 // TODO(brettw): It seems bogus that we have to call this function on the
1452 // newly created object and give it one of its own member variables.
1453 new_view->CreateViewForWidget(new_contents->GetRenderViewHost());
1454 }
1455 // Save the created window associated with the route so we can show it
1456 // later.
1457 DCHECK_NE(MSG_ROUTING_NONE, route_id);
1458 pending_contents_[route_id] = new_contents;
1459 AddDestructionObserver(new_contents);
1460 }
1461
1462 if (delegate_) {
1463 delegate_->WebContentsCreated(
1464 this, params.opener_render_frame_id, params.frame_name,
1465 params.target_url, new_contents);
1466 }
1467
1468 if (params.opener_suppressed) {
1469 // When the opener is suppressed, the original renderer cannot access the
1470 // new window. As a result, we need to show and navigate the window here.
1471 bool was_blocked = false;
1472 if (delegate_) {
1473 gfx::Rect initial_pos;
1474 delegate_->AddNewContents(
1475 this, new_contents, params.disposition, initial_pos,
1476 params.user_gesture, &was_blocked);
1477 }
1478 if (!was_blocked) {
1479 OpenURLParams open_params(params.target_url,
1480 Referrer(),
1481 CURRENT_TAB,
1482 PAGE_TRANSITION_LINK,
1483 true /* is_renderer_initiated */);
1484 open_params.user_gesture = params.user_gesture;
1485 new_contents->OpenURL(open_params);
1486 }
1487 }
1488 }
1489
CreateNewWidget(int render_process_id,int route_id,blink::WebPopupType popup_type)1490 void WebContentsImpl::CreateNewWidget(int render_process_id,
1491 int route_id,
1492 blink::WebPopupType popup_type) {
1493 CreateNewWidget(render_process_id, route_id, false, popup_type);
1494 }
1495
CreateNewFullscreenWidget(int render_process_id,int route_id)1496 void WebContentsImpl::CreateNewFullscreenWidget(int render_process_id,
1497 int route_id) {
1498 CreateNewWidget(render_process_id, route_id, true, blink::WebPopupTypeNone);
1499 }
1500
CreateNewWidget(int render_process_id,int route_id,bool is_fullscreen,blink::WebPopupType popup_type)1501 void WebContentsImpl::CreateNewWidget(int render_process_id,
1502 int route_id,
1503 bool is_fullscreen,
1504 blink::WebPopupType popup_type) {
1505 RenderProcessHost* process = GetRenderProcessHost();
1506 // A message to create a new widget can only come from the active process for
1507 // this WebContentsImpl instance. If any other process sends the request,
1508 // it is invalid and the process must be terminated.
1509 if (process->GetID() != render_process_id) {
1510 base::ProcessHandle process_handle =
1511 RenderProcessHost::FromID(render_process_id)->GetHandle();
1512 if (process_handle != base::kNullProcessHandle) {
1513 RecordAction(
1514 base::UserMetricsAction("Terminate_ProcessMismatch_CreateNewWidget"));
1515 base::KillProcess(process_handle, content::RESULT_CODE_KILLED, false);
1516 }
1517 return;
1518 }
1519
1520 RenderWidgetHostImpl* widget_host =
1521 new RenderWidgetHostImpl(this, process, route_id, IsHidden());
1522 created_widgets_.insert(widget_host);
1523
1524 RenderWidgetHostViewBase* widget_view =
1525 static_cast<RenderWidgetHostViewBase*>(
1526 view_->CreateViewForPopupWidget(widget_host));
1527 if (!widget_view)
1528 return;
1529 if (!is_fullscreen) {
1530 // Popups should not get activated.
1531 widget_view->SetPopupType(popup_type);
1532 }
1533 // Save the created widget associated with the route so we can show it later.
1534 pending_widget_views_[route_id] = widget_view;
1535
1536 #if defined(OS_MACOSX)
1537 // A RenderWidgetHostViewMac has lifetime scoped to the view. We'll retain it
1538 // to allow it to survive the trip without being hosted.
1539 base::mac::NSObjectRetain(widget_view->GetNativeView());
1540 #endif
1541 }
1542
ShowCreatedWindow(int route_id,WindowOpenDisposition disposition,const gfx::Rect & initial_pos,bool user_gesture)1543 void WebContentsImpl::ShowCreatedWindow(int route_id,
1544 WindowOpenDisposition disposition,
1545 const gfx::Rect& initial_pos,
1546 bool user_gesture) {
1547 WebContentsImpl* contents = GetCreatedWindow(route_id);
1548 if (contents) {
1549 WebContentsDelegate* delegate = GetDelegate();
1550 if (delegate) {
1551 delegate->AddNewContents(
1552 this, contents, disposition, initial_pos, user_gesture, NULL);
1553 }
1554 }
1555 }
1556
ShowCreatedWidget(int route_id,const gfx::Rect & initial_pos)1557 void WebContentsImpl::ShowCreatedWidget(int route_id,
1558 const gfx::Rect& initial_pos) {
1559 ShowCreatedWidget(route_id, false, initial_pos);
1560 }
1561
ShowCreatedFullscreenWidget(int route_id)1562 void WebContentsImpl::ShowCreatedFullscreenWidget(int route_id) {
1563 ShowCreatedWidget(route_id, true, gfx::Rect());
1564 }
1565
ShowCreatedWidget(int route_id,bool is_fullscreen,const gfx::Rect & initial_pos)1566 void WebContentsImpl::ShowCreatedWidget(int route_id,
1567 bool is_fullscreen,
1568 const gfx::Rect& initial_pos) {
1569 RenderWidgetHostViewBase* widget_host_view =
1570 static_cast<RenderWidgetHostViewBase*>(GetCreatedWidget(route_id));
1571 if (!widget_host_view)
1572 return;
1573
1574 RenderWidgetHostView* view = NULL;
1575 BrowserPluginGuest* guest = GetBrowserPluginGuest();
1576 if (guest && guest->embedder_web_contents()) {
1577 view = guest->embedder_web_contents()->GetRenderWidgetHostView();
1578 } else {
1579 view = GetRenderWidgetHostView();
1580 }
1581
1582 if (is_fullscreen) {
1583 DCHECK_EQ(MSG_ROUTING_NONE, fullscreen_widget_routing_id_);
1584 fullscreen_widget_routing_id_ = route_id;
1585 if (delegate_ && delegate_->EmbedsFullscreenWidget()) {
1586 widget_host_view->InitAsChild(GetRenderWidgetHostView()->GetNativeView());
1587 delegate_->ToggleFullscreenModeForTab(this, true);
1588 } else {
1589 widget_host_view->InitAsFullscreen(view);
1590 }
1591 FOR_EACH_OBSERVER(WebContentsObserver,
1592 observers_,
1593 DidShowFullscreenWidget(route_id));
1594 if (!widget_host_view->HasFocus())
1595 widget_host_view->Focus();
1596 } else {
1597 widget_host_view->InitAsPopup(view, initial_pos);
1598 }
1599
1600 RenderWidgetHostImpl* render_widget_host_impl =
1601 RenderWidgetHostImpl::From(widget_host_view->GetRenderWidgetHost());
1602 render_widget_host_impl->Init();
1603 // Only allow privileged mouse lock for fullscreen render widget, which is
1604 // used to implement Pepper Flash fullscreen.
1605 render_widget_host_impl->set_allow_privileged_mouse_lock(is_fullscreen);
1606
1607 #if defined(OS_MACOSX)
1608 // A RenderWidgetHostViewMac has lifetime scoped to the view. Now that it's
1609 // properly embedded (or purposefully ignored) we can release the retain we
1610 // took in CreateNewWidget().
1611 base::mac::NSObjectRelease(widget_host_view->GetNativeView());
1612 #endif
1613 }
1614
GetCreatedWindow(int route_id)1615 WebContentsImpl* WebContentsImpl::GetCreatedWindow(int route_id) {
1616 PendingContents::iterator iter = pending_contents_.find(route_id);
1617
1618 // Certain systems can block the creation of new windows. If we didn't succeed
1619 // in creating one, just return NULL.
1620 if (iter == pending_contents_.end()) {
1621 return NULL;
1622 }
1623
1624 WebContentsImpl* new_contents = iter->second;
1625 pending_contents_.erase(route_id);
1626 RemoveDestructionObserver(new_contents);
1627
1628 // Don't initialize the guest WebContents immediately.
1629 if (BrowserPluginGuest::IsGuest(new_contents))
1630 return new_contents;
1631
1632 if (!new_contents->GetRenderProcessHost()->HasConnection() ||
1633 !new_contents->GetRenderViewHost()->GetView())
1634 return NULL;
1635
1636 // TODO(brettw): It seems bogus to reach into here and initialize the host.
1637 static_cast<RenderViewHostImpl*>(new_contents->GetRenderViewHost())->Init();
1638 return new_contents;
1639 }
1640
GetCreatedWidget(int route_id)1641 RenderWidgetHostView* WebContentsImpl::GetCreatedWidget(int route_id) {
1642 PendingWidgetViews::iterator iter = pending_widget_views_.find(route_id);
1643 if (iter == pending_widget_views_.end()) {
1644 DCHECK(false);
1645 return NULL;
1646 }
1647
1648 RenderWidgetHostView* widget_host_view = iter->second;
1649 pending_widget_views_.erase(route_id);
1650
1651 RenderWidgetHost* widget_host = widget_host_view->GetRenderWidgetHost();
1652 if (!widget_host->GetProcess()->HasConnection()) {
1653 // The view has gone away or the renderer crashed. Nothing to do.
1654 return NULL;
1655 }
1656
1657 return widget_host_view;
1658 }
1659
RequestMediaAccessPermission(const MediaStreamRequest & request,const MediaResponseCallback & callback)1660 void WebContentsImpl::RequestMediaAccessPermission(
1661 const MediaStreamRequest& request,
1662 const MediaResponseCallback& callback) {
1663 if (delegate_) {
1664 delegate_->RequestMediaAccessPermission(this, request, callback);
1665 } else {
1666 callback.Run(MediaStreamDevices(),
1667 MEDIA_DEVICE_INVALID_STATE,
1668 scoped_ptr<MediaStreamUI>());
1669 }
1670 }
1671
GetSessionStorageNamespace(SiteInstance * instance)1672 SessionStorageNamespace* WebContentsImpl::GetSessionStorageNamespace(
1673 SiteInstance* instance) {
1674 return controller_.GetSessionStorageNamespace(instance);
1675 }
1676
GetSessionStorageNamespaceMap()1677 SessionStorageNamespaceMap WebContentsImpl::GetSessionStorageNamespaceMap() {
1678 return controller_.GetSessionStorageNamespaceMap();
1679 }
1680
GetFrameTree()1681 FrameTree* WebContentsImpl::GetFrameTree() {
1682 return &frame_tree_;
1683 }
1684
AccessibilityEventReceived(const std::vector<AXEventNotificationDetails> & details)1685 void WebContentsImpl::AccessibilityEventReceived(
1686 const std::vector<AXEventNotificationDetails>& details) {
1687 FOR_EACH_OBSERVER(
1688 WebContentsObserver, observers_, AccessibilityEventReceived(details));
1689 }
1690
OnShowValidationMessage(const gfx::Rect & anchor_in_root_view,const base::string16 & main_text,const base::string16 & sub_text)1691 void WebContentsImpl::OnShowValidationMessage(
1692 const gfx::Rect& anchor_in_root_view,
1693 const base::string16& main_text,
1694 const base::string16& sub_text) {
1695 if (delegate_)
1696 delegate_->ShowValidationMessage(
1697 this, anchor_in_root_view, main_text, sub_text);
1698 }
1699
OnHideValidationMessage()1700 void WebContentsImpl::OnHideValidationMessage() {
1701 if (delegate_)
1702 delegate_->HideValidationMessage(this);
1703 }
1704
OnMoveValidationMessage(const gfx::Rect & anchor_in_root_view)1705 void WebContentsImpl::OnMoveValidationMessage(
1706 const gfx::Rect& anchor_in_root_view) {
1707 if (delegate_)
1708 delegate_->MoveValidationMessage(this, anchor_in_root_view);
1709 }
1710
DidSendScreenRects(RenderWidgetHostImpl * rwh)1711 void WebContentsImpl::DidSendScreenRects(RenderWidgetHostImpl* rwh) {
1712 if (browser_plugin_embedder_)
1713 browser_plugin_embedder_->DidSendScreenRects();
1714 }
1715
OnTouchEmulationEnabled(bool enabled)1716 void WebContentsImpl::OnTouchEmulationEnabled(bool enabled) {
1717 touch_emulation_enabled_ = enabled;
1718 if (view_)
1719 view_->SetOverscrollControllerEnabled(CanOverscrollContent());
1720 }
1721
UpdatePreferredSize(const gfx::Size & pref_size)1722 void WebContentsImpl::UpdatePreferredSize(const gfx::Size& pref_size) {
1723 const gfx::Size old_size = GetPreferredSize();
1724 preferred_size_ = pref_size;
1725 OnPreferredSizeChanged(old_size);
1726 }
1727
ResizeDueToAutoResize(const gfx::Size & new_size)1728 void WebContentsImpl::ResizeDueToAutoResize(const gfx::Size& new_size) {
1729 if (delegate_)
1730 delegate_->ResizeDueToAutoResize(this, new_size);
1731 }
1732
OpenURL(const OpenURLParams & params)1733 WebContents* WebContentsImpl::OpenURL(const OpenURLParams& params) {
1734 if (!delegate_)
1735 return NULL;
1736
1737 WebContents* new_contents = delegate_->OpenURLFromTab(this, params);
1738 return new_contents;
1739 }
1740
Send(IPC::Message * message)1741 bool WebContentsImpl::Send(IPC::Message* message) {
1742 if (!GetRenderViewHost()) {
1743 delete message;
1744 return false;
1745 }
1746
1747 return GetRenderViewHost()->Send(message);
1748 }
1749
NavigateToPendingEntry(NavigationController::ReloadType reload_type)1750 bool WebContentsImpl::NavigateToPendingEntry(
1751 NavigationController::ReloadType reload_type) {
1752 FrameTreeNode* node = frame_tree_.root();
1753
1754 // If we are using --site-per-process, we should navigate in the FrameTreeNode
1755 // specified in the pending entry.
1756 NavigationEntryImpl* pending_entry =
1757 NavigationEntryImpl::FromNavigationEntry(controller_.GetPendingEntry());
1758 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) &&
1759 pending_entry->frame_tree_node_id() != -1) {
1760 node = frame_tree_.FindByID(pending_entry->frame_tree_node_id());
1761 }
1762
1763 return node->navigator()->NavigateToPendingEntry(
1764 node->current_frame_host(), reload_type);
1765 }
1766
RenderFrameForInterstitialPageCreated(RenderFrameHost * render_frame_host)1767 void WebContentsImpl::RenderFrameForInterstitialPageCreated(
1768 RenderFrameHost* render_frame_host) {
1769 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
1770 RenderFrameForInterstitialPageCreated(render_frame_host));
1771 }
1772
AttachInterstitialPage(InterstitialPageImpl * interstitial_page)1773 void WebContentsImpl::AttachInterstitialPage(
1774 InterstitialPageImpl* interstitial_page) {
1775 DCHECK(interstitial_page);
1776 GetRenderManager()->set_interstitial_page(interstitial_page);
1777
1778 // Cancel any visible dialogs so that they don't interfere with the
1779 // interstitial.
1780 if (dialog_manager_)
1781 dialog_manager_->CancelActiveAndPendingDialogs(this);
1782
1783 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
1784 DidAttachInterstitialPage());
1785 }
1786
DetachInterstitialPage()1787 void WebContentsImpl::DetachInterstitialPage() {
1788 if (ShowingInterstitialPage())
1789 GetRenderManager()->remove_interstitial_page();
1790 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
1791 DidDetachInterstitialPage());
1792 }
1793
SetHistoryLengthAndPrune(const SiteInstance * site_instance,int history_length,int32 minimum_page_id)1794 void WebContentsImpl::SetHistoryLengthAndPrune(
1795 const SiteInstance* site_instance,
1796 int history_length,
1797 int32 minimum_page_id) {
1798 // SetHistoryLengthAndPrune doesn't work when there are pending cross-site
1799 // navigations. Callers should ensure that this is the case.
1800 if (GetRenderManager()->pending_render_view_host()) {
1801 NOTREACHED();
1802 return;
1803 }
1804 RenderViewHostImpl* rvh = GetRenderViewHostImpl();
1805 if (!rvh) {
1806 NOTREACHED();
1807 return;
1808 }
1809 if (site_instance && rvh->GetSiteInstance() != site_instance) {
1810 NOTREACHED();
1811 return;
1812 }
1813 Send(new ViewMsg_SetHistoryLengthAndPrune(GetRoutingID(),
1814 history_length,
1815 minimum_page_id));
1816 }
1817
ReloadFocusedFrame(bool ignore_cache)1818 void WebContentsImpl::ReloadFocusedFrame(bool ignore_cache) {
1819 RenderFrameHost* focused_frame = GetFocusedFrame();
1820 if (!focused_frame)
1821 return;
1822
1823 focused_frame->Send(new FrameMsg_Reload(
1824 focused_frame->GetRoutingID(), ignore_cache));
1825 }
1826
Undo()1827 void WebContentsImpl::Undo() {
1828 RenderFrameHost* focused_frame = GetFocusedFrame();
1829 if (!focused_frame)
1830 return;
1831
1832 focused_frame->Send(new InputMsg_Undo(focused_frame->GetRoutingID()));
1833 RecordAction(base::UserMetricsAction("Undo"));
1834 }
1835
Redo()1836 void WebContentsImpl::Redo() {
1837 RenderFrameHost* focused_frame = GetFocusedFrame();
1838 if (!focused_frame)
1839 return;
1840 focused_frame->Send(new InputMsg_Redo(focused_frame->GetRoutingID()));
1841 RecordAction(base::UserMetricsAction("Redo"));
1842 }
1843
Cut()1844 void WebContentsImpl::Cut() {
1845 RenderFrameHost* focused_frame = GetFocusedFrame();
1846 if (!focused_frame)
1847 return;
1848
1849 focused_frame->Send(new InputMsg_Cut(focused_frame->GetRoutingID()));
1850 RecordAction(base::UserMetricsAction("Cut"));
1851 }
1852
Copy()1853 void WebContentsImpl::Copy() {
1854 RenderFrameHost* focused_frame = GetFocusedFrame();
1855 if (!focused_frame)
1856 return;
1857
1858 focused_frame->Send(new InputMsg_Copy(focused_frame->GetRoutingID()));
1859 RecordAction(base::UserMetricsAction("Copy"));
1860 }
1861
CopyToFindPboard()1862 void WebContentsImpl::CopyToFindPboard() {
1863 #if defined(OS_MACOSX)
1864 RenderFrameHost* focused_frame = GetFocusedFrame();
1865 if (!focused_frame)
1866 return;
1867
1868 // Windows/Linux don't have the concept of a find pasteboard.
1869 focused_frame->Send(
1870 new InputMsg_CopyToFindPboard(focused_frame->GetRoutingID()));
1871 RecordAction(base::UserMetricsAction("CopyToFindPboard"));
1872 #endif
1873 }
1874
Paste()1875 void WebContentsImpl::Paste() {
1876 RenderFrameHost* focused_frame = GetFocusedFrame();
1877 if (!focused_frame)
1878 return;
1879
1880 focused_frame->Send(new InputMsg_Paste(focused_frame->GetRoutingID()));
1881 RecordAction(base::UserMetricsAction("Paste"));
1882 }
1883
PasteAndMatchStyle()1884 void WebContentsImpl::PasteAndMatchStyle() {
1885 RenderFrameHost* focused_frame = GetFocusedFrame();
1886 if (!focused_frame)
1887 return;
1888
1889 focused_frame->Send(new InputMsg_PasteAndMatchStyle(
1890 focused_frame->GetRoutingID()));
1891 RecordAction(base::UserMetricsAction("PasteAndMatchStyle"));
1892 }
1893
Delete()1894 void WebContentsImpl::Delete() {
1895 RenderFrameHost* focused_frame = GetFocusedFrame();
1896 if (!focused_frame)
1897 return;
1898
1899 focused_frame->Send(new InputMsg_Delete(focused_frame->GetRoutingID()));
1900 RecordAction(base::UserMetricsAction("DeleteSelection"));
1901 }
1902
SelectAll()1903 void WebContentsImpl::SelectAll() {
1904 RenderFrameHost* focused_frame = GetFocusedFrame();
1905 if (!focused_frame)
1906 return;
1907
1908 focused_frame->Send(new InputMsg_SelectAll(focused_frame->GetRoutingID()));
1909 RecordAction(base::UserMetricsAction("SelectAll"));
1910 }
1911
Unselect()1912 void WebContentsImpl::Unselect() {
1913 RenderFrameHost* focused_frame = GetFocusedFrame();
1914 if (!focused_frame)
1915 return;
1916
1917 focused_frame->Send(new InputMsg_Unselect(focused_frame->GetRoutingID()));
1918 RecordAction(base::UserMetricsAction("Unselect"));
1919 }
1920
Replace(const base::string16 & word)1921 void WebContentsImpl::Replace(const base::string16& word) {
1922 RenderFrameHost* focused_frame = GetFocusedFrame();
1923 if (!focused_frame)
1924 return;
1925
1926 focused_frame->Send(new InputMsg_Replace(
1927 focused_frame->GetRoutingID(), word));
1928 }
1929
ReplaceMisspelling(const base::string16 & word)1930 void WebContentsImpl::ReplaceMisspelling(const base::string16& word) {
1931 RenderFrameHost* focused_frame = GetFocusedFrame();
1932 if (!focused_frame)
1933 return;
1934
1935 focused_frame->Send(new InputMsg_ReplaceMisspelling(
1936 focused_frame->GetRoutingID(), word));
1937 }
1938
NotifyContextMenuClosed(const CustomContextMenuContext & context)1939 void WebContentsImpl::NotifyContextMenuClosed(
1940 const CustomContextMenuContext& context) {
1941 RenderFrameHost* focused_frame = GetFocusedFrame();
1942 if (!focused_frame)
1943 return;
1944
1945 focused_frame->Send(new FrameMsg_ContextMenuClosed(
1946 focused_frame->GetRoutingID(), context));
1947 }
1948
ExecuteCustomContextMenuCommand(int action,const CustomContextMenuContext & context)1949 void WebContentsImpl::ExecuteCustomContextMenuCommand(
1950 int action, const CustomContextMenuContext& context) {
1951 RenderFrameHost* focused_frame = GetFocusedFrame();
1952 if (!focused_frame)
1953 return;
1954
1955 focused_frame->Send(new FrameMsg_CustomContextMenuAction(
1956 focused_frame->GetRoutingID(), context, action));
1957 }
1958
GetNativeView()1959 gfx::NativeView WebContentsImpl::GetNativeView() {
1960 return view_->GetNativeView();
1961 }
1962
GetContentNativeView()1963 gfx::NativeView WebContentsImpl::GetContentNativeView() {
1964 return view_->GetContentNativeView();
1965 }
1966
GetTopLevelNativeWindow()1967 gfx::NativeWindow WebContentsImpl::GetTopLevelNativeWindow() {
1968 return view_->GetTopLevelNativeWindow();
1969 }
1970
GetViewBounds()1971 gfx::Rect WebContentsImpl::GetViewBounds() {
1972 return view_->GetViewBounds();
1973 }
1974
GetContainerBounds()1975 gfx::Rect WebContentsImpl::GetContainerBounds() {
1976 gfx::Rect rv;
1977 view_->GetContainerBounds(&rv);
1978 return rv;
1979 }
1980
GetDropData()1981 DropData* WebContentsImpl::GetDropData() {
1982 return view_->GetDropData();
1983 }
1984
Focus()1985 void WebContentsImpl::Focus() {
1986 view_->Focus();
1987 }
1988
SetInitialFocus()1989 void WebContentsImpl::SetInitialFocus() {
1990 view_->SetInitialFocus();
1991 }
1992
StoreFocus()1993 void WebContentsImpl::StoreFocus() {
1994 view_->StoreFocus();
1995 }
1996
RestoreFocus()1997 void WebContentsImpl::RestoreFocus() {
1998 view_->RestoreFocus();
1999 }
2000
FocusThroughTabTraversal(bool reverse)2001 void WebContentsImpl::FocusThroughTabTraversal(bool reverse) {
2002 if (ShowingInterstitialPage()) {
2003 GetRenderManager()->interstitial_page()->FocusThroughTabTraversal(reverse);
2004 return;
2005 }
2006 GetRenderViewHostImpl()->SetInitialFocus(reverse);
2007 }
2008
ShowingInterstitialPage() const2009 bool WebContentsImpl::ShowingInterstitialPage() const {
2010 return GetRenderManager()->interstitial_page() != NULL;
2011 }
2012
GetInterstitialPage() const2013 InterstitialPage* WebContentsImpl::GetInterstitialPage() const {
2014 return GetRenderManager()->interstitial_page();
2015 }
2016
IsSavable()2017 bool WebContentsImpl::IsSavable() {
2018 // WebKit creates Document object when MIME type is application/xhtml+xml,
2019 // so we also support this MIME type.
2020 return contents_mime_type_ == "text/html" ||
2021 contents_mime_type_ == "text/xml" ||
2022 contents_mime_type_ == "application/xhtml+xml" ||
2023 contents_mime_type_ == "text/plain" ||
2024 contents_mime_type_ == "text/css" ||
2025 net::IsSupportedJavascriptMimeType(contents_mime_type_.c_str());
2026 }
2027
OnSavePage()2028 void WebContentsImpl::OnSavePage() {
2029 // If we can not save the page, try to download it.
2030 if (!IsSavable()) {
2031 RecordDownloadSource(INITIATED_BY_SAVE_PACKAGE_ON_NON_HTML);
2032 SaveFrame(GetURL(), Referrer());
2033 return;
2034 }
2035
2036 Stop();
2037
2038 // Create the save package and possibly prompt the user for the name to save
2039 // the page as. The user prompt is an asynchronous operation that runs on
2040 // another thread.
2041 save_package_ = new SavePackage(this);
2042 save_package_->GetSaveInfo();
2043 }
2044
2045 // Used in automated testing to bypass prompting the user for file names.
2046 // Instead, the names and paths are hard coded rather than running them through
2047 // file name sanitation and extension / mime checking.
SavePage(const base::FilePath & main_file,const base::FilePath & dir_path,SavePageType save_type)2048 bool WebContentsImpl::SavePage(const base::FilePath& main_file,
2049 const base::FilePath& dir_path,
2050 SavePageType save_type) {
2051 // Stop the page from navigating.
2052 Stop();
2053
2054 save_package_ = new SavePackage(this, save_type, main_file, dir_path);
2055 return save_package_->Init(SavePackageDownloadCreatedCallback());
2056 }
2057
SaveFrame(const GURL & url,const Referrer & referrer)2058 void WebContentsImpl::SaveFrame(const GURL& url,
2059 const Referrer& referrer) {
2060 if (!GetURL().is_valid())
2061 return;
2062 bool is_main_frame = (url == GetURL());
2063
2064 DownloadManager* dlm =
2065 BrowserContext::GetDownloadManager(GetBrowserContext());
2066 if (!dlm)
2067 return;
2068 int64 post_id = -1;
2069 if (is_main_frame) {
2070 const NavigationEntry* entry = controller_.GetLastCommittedEntry();
2071 if (entry)
2072 post_id = entry->GetPostID();
2073 }
2074 scoped_ptr<DownloadUrlParameters> params(
2075 DownloadUrlParameters::FromWebContents(this, url));
2076 params->set_referrer(referrer);
2077 params->set_post_id(post_id);
2078 params->set_prefer_cache(true);
2079 if (post_id >= 0)
2080 params->set_method("POST");
2081 params->set_prompt(true);
2082 dlm->DownloadUrl(params.Pass());
2083 }
2084
GenerateMHTML(const base::FilePath & file,const base::Callback<void (int64)> & callback)2085 void WebContentsImpl::GenerateMHTML(
2086 const base::FilePath& file,
2087 const base::Callback<void(int64)>& callback) {
2088 MHTMLGenerationManager::GetInstance()->SaveMHTML(this, file, callback);
2089 }
2090
GetContentsMimeType() const2091 const std::string& WebContentsImpl::GetContentsMimeType() const {
2092 return contents_mime_type_;
2093 }
2094
WillNotifyDisconnection() const2095 bool WebContentsImpl::WillNotifyDisconnection() const {
2096 return notify_disconnection_;
2097 }
2098
SetOverrideEncoding(const std::string & encoding)2099 void WebContentsImpl::SetOverrideEncoding(const std::string& encoding) {
2100 SetEncoding(encoding);
2101 Send(new ViewMsg_SetPageEncoding(GetRoutingID(), encoding));
2102 }
2103
ResetOverrideEncoding()2104 void WebContentsImpl::ResetOverrideEncoding() {
2105 canonical_encoding_.clear();
2106 Send(new ViewMsg_ResetPageEncodingToDefault(GetRoutingID()));
2107 }
2108
GetMutableRendererPrefs()2109 RendererPreferences* WebContentsImpl::GetMutableRendererPrefs() {
2110 return &renderer_preferences_;
2111 }
2112
Close()2113 void WebContentsImpl::Close() {
2114 Close(GetRenderViewHost());
2115 }
2116
DragSourceEndedAt(int client_x,int client_y,int screen_x,int screen_y,blink::WebDragOperation operation)2117 void WebContentsImpl::DragSourceEndedAt(int client_x, int client_y,
2118 int screen_x, int screen_y, blink::WebDragOperation operation) {
2119 if (browser_plugin_embedder_.get())
2120 browser_plugin_embedder_->DragSourceEndedAt(client_x, client_y,
2121 screen_x, screen_y, operation);
2122 if (GetRenderViewHost())
2123 GetRenderViewHostImpl()->DragSourceEndedAt(client_x, client_y,
2124 screen_x, screen_y, operation);
2125 }
2126
DidGetResourceResponseStart(const ResourceRequestDetails & details)2127 void WebContentsImpl::DidGetResourceResponseStart(
2128 const ResourceRequestDetails& details) {
2129 controller_.ssl_manager()->DidStartResourceResponse(details);
2130
2131 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2132 DidGetResourceResponseStart(details));
2133
2134 // TODO(avi): Remove. http://crbug.com/170921
2135 NotificationService::current()->Notify(
2136 NOTIFICATION_RESOURCE_RESPONSE_STARTED,
2137 Source<WebContents>(this),
2138 Details<const ResourceRequestDetails>(&details));
2139 }
2140
DidGetRedirectForResourceRequest(RenderViewHost * render_view_host,const ResourceRedirectDetails & details)2141 void WebContentsImpl::DidGetRedirectForResourceRequest(
2142 RenderViewHost* render_view_host,
2143 const ResourceRedirectDetails& details) {
2144 controller_.ssl_manager()->DidReceiveResourceRedirect(details);
2145
2146 FOR_EACH_OBSERVER(
2147 WebContentsObserver,
2148 observers_,
2149 DidGetRedirectForResourceRequest(render_view_host, details));
2150
2151 // TODO(avi): Remove. http://crbug.com/170921
2152 NotificationService::current()->Notify(
2153 NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
2154 Source<WebContents>(this),
2155 Details<const ResourceRedirectDetails>(&details));
2156 }
2157
SystemDragEnded()2158 void WebContentsImpl::SystemDragEnded() {
2159 if (GetRenderViewHost())
2160 GetRenderViewHostImpl()->DragSourceSystemDragEnded();
2161 if (delegate_)
2162 delegate_->DragEnded();
2163 if (browser_plugin_embedder_.get())
2164 browser_plugin_embedder_->SystemDragEnded();
2165 }
2166
UserGestureDone()2167 void WebContentsImpl::UserGestureDone() {
2168 OnUserGesture();
2169 }
2170
SetClosedByUserGesture(bool value)2171 void WebContentsImpl::SetClosedByUserGesture(bool value) {
2172 closed_by_user_gesture_ = value;
2173 }
2174
GetClosedByUserGesture() const2175 bool WebContentsImpl::GetClosedByUserGesture() const {
2176 return closed_by_user_gesture_;
2177 }
2178
GetZoomPercent(bool * enable_increment,bool * enable_decrement) const2179 int WebContentsImpl::GetZoomPercent(bool* enable_increment,
2180 bool* enable_decrement) const {
2181 *enable_decrement = *enable_increment = false;
2182 // Calculate the zoom percent from the factor. Round up to the nearest whole
2183 // number.
2184 int percent = static_cast<int>(
2185 ZoomLevelToZoomFactor(HostZoomMap::GetZoomLevel(this)) * 100 + 0.5);
2186 *enable_decrement = percent > minimum_zoom_percent_;
2187 *enable_increment = percent < maximum_zoom_percent_;
2188 return percent;
2189 }
2190
ViewSource()2191 void WebContentsImpl::ViewSource() {
2192 if (!delegate_)
2193 return;
2194
2195 NavigationEntry* entry = GetController().GetLastCommittedEntry();
2196 if (!entry)
2197 return;
2198
2199 delegate_->ViewSourceForTab(this, entry->GetURL());
2200 }
2201
ViewFrameSource(const GURL & url,const PageState & page_state)2202 void WebContentsImpl::ViewFrameSource(const GURL& url,
2203 const PageState& page_state) {
2204 if (!delegate_)
2205 return;
2206
2207 delegate_->ViewSourceForFrame(this, url, page_state);
2208 }
2209
GetMinimumZoomPercent() const2210 int WebContentsImpl::GetMinimumZoomPercent() const {
2211 return minimum_zoom_percent_;
2212 }
2213
GetMaximumZoomPercent() const2214 int WebContentsImpl::GetMaximumZoomPercent() const {
2215 return maximum_zoom_percent_;
2216 }
2217
GetPreferredSize() const2218 gfx::Size WebContentsImpl::GetPreferredSize() const {
2219 return capturer_count_ == 0 ? preferred_size_ : preferred_size_for_capture_;
2220 }
2221
GotResponseToLockMouseRequest(bool allowed)2222 bool WebContentsImpl::GotResponseToLockMouseRequest(bool allowed) {
2223 if (GetBrowserPluginGuest())
2224 return GetBrowserPluginGuest()->LockMouse(allowed);
2225
2226 return GetRenderViewHost() ?
2227 GetRenderViewHostImpl()->GotResponseToLockMouseRequest(allowed) : false;
2228 }
2229
HasOpener() const2230 bool WebContentsImpl::HasOpener() const {
2231 return opener_ != NULL;
2232 }
2233
DidChooseColorInColorChooser(SkColor color)2234 void WebContentsImpl::DidChooseColorInColorChooser(SkColor color) {
2235 if (!color_chooser_info_.get())
2236 return;
2237 RenderFrameHost* rfh = RenderFrameHost::FromID(
2238 color_chooser_info_->render_process_id,
2239 color_chooser_info_->render_frame_id);
2240 if (!rfh)
2241 return;
2242
2243 rfh->Send(new FrameMsg_DidChooseColorResponse(
2244 rfh->GetRoutingID(), color_chooser_info_->identifier, color));
2245 }
2246
DidEndColorChooser()2247 void WebContentsImpl::DidEndColorChooser() {
2248 if (!color_chooser_info_.get())
2249 return;
2250 RenderFrameHost* rfh = RenderFrameHost::FromID(
2251 color_chooser_info_->render_process_id,
2252 color_chooser_info_->render_frame_id);
2253 if (!rfh)
2254 return;
2255
2256 rfh->Send(new FrameMsg_DidEndColorChooser(
2257 rfh->GetRoutingID(), color_chooser_info_->identifier));
2258 color_chooser_info_.reset();
2259 }
2260
DownloadImage(const GURL & url,bool is_favicon,uint32_t max_bitmap_size,const ImageDownloadCallback & callback)2261 int WebContentsImpl::DownloadImage(const GURL& url,
2262 bool is_favicon,
2263 uint32_t max_bitmap_size,
2264 const ImageDownloadCallback& callback) {
2265 int id = StartDownload(GetMainFrame(), url, is_favicon, max_bitmap_size);
2266 image_download_map_[id] = callback;
2267 return id;
2268 }
2269
IsSubframe() const2270 bool WebContentsImpl::IsSubframe() const {
2271 return is_subframe_;
2272 }
2273
Find(int request_id,const base::string16 & search_text,const blink::WebFindOptions & options)2274 void WebContentsImpl::Find(int request_id,
2275 const base::string16& search_text,
2276 const blink::WebFindOptions& options) {
2277 Send(new ViewMsg_Find(GetRoutingID(), request_id, search_text, options));
2278 }
2279
StopFinding(StopFindAction action)2280 void WebContentsImpl::StopFinding(StopFindAction action) {
2281 Send(new ViewMsg_StopFinding(GetRoutingID(), action));
2282 }
2283
InsertCSS(const std::string & css)2284 void WebContentsImpl::InsertCSS(const std::string& css) {
2285 GetMainFrame()->Send(new FrameMsg_CSSInsertRequest(
2286 GetMainFrame()->GetRoutingID(), css));
2287 }
2288
FocusLocationBarByDefault()2289 bool WebContentsImpl::FocusLocationBarByDefault() {
2290 NavigationEntry* entry = controller_.GetVisibleEntry();
2291 if (entry && entry->GetURL() == GURL(url::kAboutBlankURL))
2292 return true;
2293 return delegate_ && delegate_->ShouldFocusLocationBarByDefault(this);
2294 }
2295
SetFocusToLocationBar(bool select_all)2296 void WebContentsImpl::SetFocusToLocationBar(bool select_all) {
2297 if (delegate_)
2298 delegate_->SetFocusToLocationBar(select_all);
2299 }
2300
DidStartProvisionalLoad(RenderFrameHostImpl * render_frame_host,int parent_routing_id,const GURL & validated_url,bool is_error_page,bool is_iframe_srcdoc)2301 void WebContentsImpl::DidStartProvisionalLoad(
2302 RenderFrameHostImpl* render_frame_host,
2303 int parent_routing_id,
2304 const GURL& validated_url,
2305 bool is_error_page,
2306 bool is_iframe_srcdoc) {
2307 bool is_main_frame = render_frame_host->frame_tree_node()->IsMainFrame();
2308
2309 // Notify observers about the start of the provisional load.
2310 int render_frame_id = render_frame_host->GetRoutingID();
2311 RenderViewHost* render_view_host = render_frame_host->render_view_host();
2312 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2313 DidStartProvisionalLoadForFrame(
2314 render_frame_id, parent_routing_id, is_main_frame,
2315 validated_url, is_error_page, is_iframe_srcdoc,
2316 render_view_host));
2317
2318 if (is_main_frame) {
2319 FOR_EACH_OBSERVER(
2320 WebContentsObserver,
2321 observers_,
2322 ProvisionalChangeToMainFrameUrl(validated_url,
2323 render_frame_host));
2324 }
2325 }
2326
DidFailProvisionalLoadWithError(RenderFrameHostImpl * render_frame_host,const FrameHostMsg_DidFailProvisionalLoadWithError_Params & params)2327 void WebContentsImpl::DidFailProvisionalLoadWithError(
2328 RenderFrameHostImpl* render_frame_host,
2329 const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) {
2330 GURL validated_url(params.url);
2331 int render_frame_id = render_frame_host->GetRoutingID();
2332 bool is_main_frame = render_frame_host->frame_tree_node()->IsMainFrame();
2333 RenderViewHost* render_view_host = render_frame_host->render_view_host();
2334 FOR_EACH_OBSERVER(
2335 WebContentsObserver,
2336 observers_,
2337 DidFailProvisionalLoad(render_frame_id,
2338 params.frame_unique_name,
2339 is_main_frame,
2340 validated_url,
2341 params.error_code,
2342 params.error_description,
2343 render_view_host));
2344 }
2345
DidFailLoadWithError(RenderFrameHostImpl * render_frame_host,const GURL & url,int error_code,const base::string16 & error_description)2346 void WebContentsImpl::DidFailLoadWithError(
2347 RenderFrameHostImpl* render_frame_host,
2348 const GURL& url,
2349 int error_code,
2350 const base::string16& error_description) {
2351 int render_frame_id = render_frame_host->GetRoutingID();
2352 bool is_main_frame = render_frame_host->frame_tree_node()->IsMainFrame();
2353 RenderViewHost* render_view_host = render_frame_host->render_view_host();
2354 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2355 DidFailLoad(render_frame_id, url, is_main_frame, error_code,
2356 error_description, render_view_host));
2357 }
2358
NotifyChangedNavigationState(InvalidateTypes changed_flags)2359 void WebContentsImpl::NotifyChangedNavigationState(
2360 InvalidateTypes changed_flags) {
2361 NotifyNavigationStateChanged(changed_flags);
2362 }
2363
AboutToNavigateRenderFrame(RenderFrameHostImpl * render_frame_host)2364 void WebContentsImpl::AboutToNavigateRenderFrame(
2365 RenderFrameHostImpl* render_frame_host) {
2366 // Notify observers that we will navigate in this RenderView.
2367 RenderViewHost* render_view_host = render_frame_host->render_view_host();
2368 FOR_EACH_OBSERVER(
2369 WebContentsObserver,
2370 observers_,
2371 AboutToNavigateRenderView(render_view_host));
2372 }
2373
DidStartNavigationToPendingEntry(RenderFrameHostImpl * render_frame_host,const GURL & url,NavigationController::ReloadType reload_type)2374 void WebContentsImpl::DidStartNavigationToPendingEntry(
2375 RenderFrameHostImpl* render_frame_host,
2376 const GURL& url,
2377 NavigationController::ReloadType reload_type) {
2378 // Notify observers about navigation.
2379 FOR_EACH_OBSERVER(
2380 WebContentsObserver,
2381 observers_,
2382 DidStartNavigationToPendingEntry(url, reload_type));
2383 }
2384
RequestOpenURL(RenderFrameHostImpl * render_frame_host,const OpenURLParams & params)2385 void WebContentsImpl::RequestOpenURL(RenderFrameHostImpl* render_frame_host,
2386 const OpenURLParams& params) {
2387 int source_render_frame_id = render_frame_host->GetRoutingID();
2388 WebContents* new_contents = OpenURL(params);
2389
2390 if (new_contents) {
2391 // Notify observers.
2392 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2393 DidOpenRequestedURL(new_contents,
2394 params.url,
2395 params.referrer,
2396 params.disposition,
2397 params.transition,
2398 source_render_frame_id));
2399 }
2400 }
2401
ShouldPreserveAbortedURLs()2402 bool WebContentsImpl::ShouldPreserveAbortedURLs() {
2403 if (!delegate_)
2404 return false;
2405 return delegate_->ShouldPreserveAbortedURLs(this);
2406 }
2407
DidRedirectProvisionalLoad(RenderFrameHostImpl * render_frame_host,const GURL & validated_target_url)2408 void WebContentsImpl::DidRedirectProvisionalLoad(
2409 RenderFrameHostImpl* render_frame_host,
2410 const GURL& validated_target_url) {
2411 // Notify observers about the provisional change in the main frame URL.
2412 FOR_EACH_OBSERVER(
2413 WebContentsObserver,
2414 observers_,
2415 ProvisionalChangeToMainFrameUrl(validated_target_url,
2416 render_frame_host));
2417 }
2418
DidCommitProvisionalLoad(RenderFrameHostImpl * render_frame_host,const base::string16 & frame_unique_name,bool is_main_frame,const GURL & url,PageTransition transition_type)2419 void WebContentsImpl::DidCommitProvisionalLoad(
2420 RenderFrameHostImpl* render_frame_host,
2421 const base::string16& frame_unique_name,
2422 bool is_main_frame,
2423 const GURL& url,
2424 PageTransition transition_type) {
2425 int render_frame_id = render_frame_host->GetRoutingID();
2426 RenderViewHost* render_view_host = render_frame_host->render_view_host();
2427 // Notify observers about the commit of the provisional load.
2428 FOR_EACH_OBSERVER(
2429 WebContentsObserver,
2430 observers_,
2431 DidCommitProvisionalLoadForFrame(render_frame_id,
2432 frame_unique_name,
2433 is_main_frame,
2434 url,
2435 transition_type,
2436 render_view_host));
2437 }
2438
DidNavigateMainFramePreCommit(const FrameHostMsg_DidCommitProvisionalLoad_Params & params)2439 void WebContentsImpl::DidNavigateMainFramePreCommit(
2440 const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
2441 // Ensure fullscreen mode is exited before committing the navigation to a
2442 // different page. The next page will not start out assuming it is in
2443 // fullscreen mode.
2444 if (controller_.IsURLInPageNavigation(params.url,
2445 params.was_within_same_page,
2446 NAVIGATION_TYPE_UNKNOWN)) {
2447 // No page change? Then, the renderer and browser can remain in fullscreen.
2448 return;
2449 }
2450 if (IsFullscreenForCurrentTab())
2451 GetRenderViewHost()->ExitFullscreen();
2452 DCHECK(!IsFullscreenForCurrentTab());
2453 }
2454
DidNavigateMainFramePostCommit(const LoadCommittedDetails & details,const FrameHostMsg_DidCommitProvisionalLoad_Params & params)2455 void WebContentsImpl::DidNavigateMainFramePostCommit(
2456 const LoadCommittedDetails& details,
2457 const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
2458 if (details.is_navigation_to_different_page()) {
2459 // Clear the status bubble. This is a workaround for a bug where WebKit
2460 // doesn't let us know that the cursor left an element during a
2461 // transition (this is also why the mouse cursor remains as a hand after
2462 // clicking on a link); see bugs 1184641 and 980803. We don't want to
2463 // clear the bubble when a user navigates to a named anchor in the same
2464 // page.
2465 UpdateTargetURL(details.entry->GetPageID(), GURL());
2466 }
2467
2468 if (!details.is_in_page) {
2469 // Once the main frame is navigated, we're no longer considered to have
2470 // displayed insecure content.
2471 displayed_insecure_content_ = false;
2472 SSLManager::NotifySSLInternalStateChanged(
2473 GetController().GetBrowserContext());
2474 }
2475
2476 // Notify observers about navigation.
2477 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2478 DidNavigateMainFrame(details, params));
2479
2480 if (delegate_)
2481 delegate_->DidNavigateMainFramePostCommit(this);
2482 view_->SetOverscrollControllerEnabled(CanOverscrollContent());
2483 }
2484
DidNavigateAnyFramePostCommit(RenderFrameHostImpl * render_frame_host,const LoadCommittedDetails & details,const FrameHostMsg_DidCommitProvisionalLoad_Params & params)2485 void WebContentsImpl::DidNavigateAnyFramePostCommit(
2486 RenderFrameHostImpl* render_frame_host,
2487 const LoadCommittedDetails& details,
2488 const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
2489 // Now that something has committed, we don't need to track whether the
2490 // initial page has been accessed.
2491 has_accessed_initial_document_ = false;
2492
2493 // If we navigate off the page, close all JavaScript dialogs.
2494 if (dialog_manager_ && !details.is_in_page)
2495 dialog_manager_->CancelActiveAndPendingDialogs(this);
2496
2497 // Notify observers about navigation.
2498 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2499 DidNavigateAnyFrame(details, params));
2500 }
2501
SetMainFrameMimeType(const std::string & mime_type)2502 void WebContentsImpl::SetMainFrameMimeType(const std::string& mime_type) {
2503 contents_mime_type_ = mime_type;
2504 }
2505
CanOverscrollContent() const2506 bool WebContentsImpl::CanOverscrollContent() const {
2507 // Disable overscroll when touch emulation is on. See crbug.com/369938.
2508 if (touch_emulation_enabled_)
2509 return false;
2510
2511 if (delegate_)
2512 return delegate_->CanOverscrollContent();
2513
2514 return false;
2515 }
2516
OnThemeColorChanged(SkColor theme_color)2517 void WebContentsImpl::OnThemeColorChanged(SkColor theme_color) {
2518 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2519 DidChangeThemeColor(theme_color));
2520 }
2521
OnDidLoadResourceFromMemoryCache(const GURL & url,const std::string & security_info,const std::string & http_method,const std::string & mime_type,ResourceType::Type resource_type)2522 void WebContentsImpl::OnDidLoadResourceFromMemoryCache(
2523 const GURL& url,
2524 const std::string& security_info,
2525 const std::string& http_method,
2526 const std::string& mime_type,
2527 ResourceType::Type resource_type) {
2528 base::StatsCounter cache("WebKit.CacheHit");
2529 cache.Increment();
2530
2531 // Send out a notification that we loaded a resource from our memory cache.
2532 int cert_id = 0;
2533 net::CertStatus cert_status = 0;
2534 int security_bits = -1;
2535 int connection_status = 0;
2536 SignedCertificateTimestampIDStatusList signed_certificate_timestamp_ids;
2537 DeserializeSecurityInfo(security_info, &cert_id, &cert_status,
2538 &security_bits, &connection_status,
2539 &signed_certificate_timestamp_ids);
2540 // TODO(alcutter,eranm): Pass signed_certificate_timestamp_ids into details
2541 LoadFromMemoryCacheDetails details(
2542 url, GetRenderProcessHost()->GetID(), cert_id, cert_status, http_method,
2543 mime_type, resource_type);
2544
2545 controller_.ssl_manager()->DidLoadFromMemoryCache(details);
2546
2547 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2548 DidLoadResourceFromMemoryCache(details));
2549
2550 if (url.is_valid() && url.SchemeIsHTTPOrHTTPS()) {
2551 scoped_refptr<net::URLRequestContextGetter> request_context(
2552 resource_type == ResourceType::MEDIA ?
2553 GetBrowserContext()->GetMediaRequestContextForRenderProcess(
2554 GetRenderProcessHost()->GetID()) :
2555 GetBrowserContext()->GetRequestContextForRenderProcess(
2556 GetRenderProcessHost()->GetID()));
2557 BrowserThread::PostTask(
2558 BrowserThread::IO,
2559 FROM_HERE,
2560 base::Bind(&NotifyCacheOnIO, request_context, url, http_method));
2561 }
2562 }
2563
OnDidDisplayInsecureContent()2564 void WebContentsImpl::OnDidDisplayInsecureContent() {
2565 RecordAction(base::UserMetricsAction("SSL.DisplayedInsecureContent"));
2566 displayed_insecure_content_ = true;
2567 SSLManager::NotifySSLInternalStateChanged(
2568 GetController().GetBrowserContext());
2569 }
2570
OnDidRunInsecureContent(const std::string & security_origin,const GURL & target_url)2571 void WebContentsImpl::OnDidRunInsecureContent(
2572 const std::string& security_origin, const GURL& target_url) {
2573 LOG(WARNING) << security_origin << " ran insecure content from "
2574 << target_url.possibly_invalid_spec();
2575 RecordAction(base::UserMetricsAction("SSL.RanInsecureContent"));
2576 if (EndsWith(security_origin, kDotGoogleDotCom, false))
2577 RecordAction(base::UserMetricsAction("SSL.RanInsecureContentGoogle"));
2578 controller_.ssl_manager()->DidRunInsecureContent(security_origin);
2579 displayed_insecure_content_ = true;
2580 SSLManager::NotifySSLInternalStateChanged(
2581 GetController().GetBrowserContext());
2582 }
2583
OnDocumentLoadedInFrame()2584 void WebContentsImpl::OnDocumentLoadedInFrame() {
2585 CHECK(render_frame_message_source_);
2586 CHECK(!render_view_message_source_);
2587 RenderFrameHostImpl* rfh =
2588 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2589
2590 int render_frame_id = rfh->GetRoutingID();
2591 RenderViewHost* render_view_host = rfh->render_view_host();
2592 FOR_EACH_OBSERVER(WebContentsObserver,
2593 observers_,
2594 DocumentLoadedInFrame(render_frame_id, render_view_host));
2595 }
2596
OnDidFinishLoad(const GURL & url)2597 void WebContentsImpl::OnDidFinishLoad(
2598 const GURL& url) {
2599 if (!render_frame_message_source_) {
2600 RecordAction(base::UserMetricsAction("BadMessageTerminate_RVD2"));
2601 GetRenderProcessHost()->ReceivedBadMessage();
2602 return;
2603 }
2604
2605 GURL validated_url(url);
2606 RenderProcessHost* render_process_host =
2607 render_frame_message_source_->GetProcess();
2608 render_process_host->FilterURL(false, &validated_url);
2609
2610 RenderFrameHostImpl* rfh =
2611 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2612 int render_frame_id = rfh->GetRoutingID();
2613 RenderViewHost* render_view_host = rfh->render_view_host();
2614 bool is_main_frame = rfh->frame_tree_node()->IsMainFrame();
2615 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2616 DidFinishLoad(render_frame_id, validated_url,
2617 is_main_frame, render_view_host));
2618 }
2619
OnDidStartLoading(bool to_different_document)2620 void WebContentsImpl::OnDidStartLoading(bool to_different_document) {
2621 RenderFrameHostImpl* rfh =
2622 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2623 int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id();
2624
2625 // It is possible to get multiple calls to OnDidStartLoading that don't have
2626 // corresponding calls to OnDidStopLoading:
2627 // - With "swappedout://" URLs, this happens when a RenderView gets swapped
2628 // out for a cross-process navigation, and it turns into a placeholder for
2629 // one being rendered in a different process.
2630 // - Also, there might be more than one RenderFrameHost sharing the same
2631 // FrameTreeNode (and thus sharing its ID) each sending a start.
2632 // - But in the future, once clamy@ moves navigation network requests to the
2633 // browser process, there's a good chance that callbacks about starting and
2634 // stopping will all be handled by the browser. When that happens, there
2635 // should no longer be a start/stop call imbalance. TODO(avi): When this
2636 // future arrives, update this code to not allow this case.
2637 DCHECK_GE(loading_frames_in_progress_, 0);
2638 if (loading_progresses_.find(render_frame_id) == loading_progresses_.end()) {
2639 if (loading_frames_in_progress_ == 0)
2640 DidStartLoading(rfh, to_different_document);
2641 ++loading_frames_in_progress_;
2642 }
2643
2644 loading_progresses_[render_frame_id] = kMinimumLoadingProgress;
2645 SendLoadProgressChanged();
2646 }
2647
OnDidStopLoading()2648 void WebContentsImpl::OnDidStopLoading() {
2649 RenderFrameHostImpl* rfh =
2650 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2651 int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id();
2652
2653 if (loading_progresses_.find(render_frame_id) != loading_progresses_.end()) {
2654 // Load stopped while we were still tracking load. Make sure we update
2655 // progress based on this frame's completion.
2656 loading_progresses_[render_frame_id] = 1.0;
2657 SendLoadProgressChanged();
2658 // Then we clean-up our states.
2659 if (loading_total_progress_ == 1.0)
2660 ResetLoadProgressState();
2661 }
2662
2663 // TODO(japhet): This should be a DCHECK, but the pdf plugin sometimes
2664 // calls DidStopLoading() without a matching DidStartLoading().
2665 if (loading_frames_in_progress_ == 0)
2666 return;
2667 --loading_frames_in_progress_;
2668 if (loading_frames_in_progress_ == 0)
2669 DidStopLoading(rfh);
2670 }
2671
OnDidChangeLoadProgress(double load_progress)2672 void WebContentsImpl::OnDidChangeLoadProgress(double load_progress) {
2673 RenderFrameHostImpl* rfh =
2674 static_cast<RenderFrameHostImpl*>(render_frame_message_source_);
2675 int64 render_frame_id = rfh->frame_tree_node()->frame_tree_node_id();
2676
2677 loading_progresses_[render_frame_id] = load_progress;
2678
2679 // We notify progress change immediately for the first and last updates.
2680 // Also, since the message loop may be pretty busy when a page is loaded, it
2681 // might not execute a posted task in a timely manner so we make sure to
2682 // immediately send progress report if enough time has passed.
2683 base::TimeDelta min_delay =
2684 base::TimeDelta::FromMilliseconds(kMinimumDelayBetweenLoadingUpdatesMS);
2685 if (load_progress == 1.0 || loading_last_progress_update_.is_null() ||
2686 base::TimeTicks::Now() - loading_last_progress_update_ > min_delay) {
2687 // If there is a pending task to send progress, it is now obsolete.
2688 loading_weak_factory_.InvalidateWeakPtrs();
2689 SendLoadProgressChanged();
2690 if (loading_total_progress_ == 1.0)
2691 ResetLoadProgressState();
2692 return;
2693 }
2694
2695 if (loading_weak_factory_.HasWeakPtrs())
2696 return;
2697
2698 base::MessageLoop::current()->PostDelayedTask(
2699 FROM_HERE,
2700 base::Bind(&WebContentsImpl::SendLoadProgressChanged,
2701 loading_weak_factory_.GetWeakPtr()),
2702 min_delay);
2703 }
2704
OnGoToEntryAtOffset(int offset)2705 void WebContentsImpl::OnGoToEntryAtOffset(int offset) {
2706 if (!delegate_ || delegate_->OnGoToEntryOffset(offset))
2707 controller_.GoToOffset(offset);
2708 }
2709
OnUpdateZoomLimits(int minimum_percent,int maximum_percent)2710 void WebContentsImpl::OnUpdateZoomLimits(int minimum_percent,
2711 int maximum_percent) {
2712 minimum_zoom_percent_ = minimum_percent;
2713 maximum_zoom_percent_ = maximum_percent;
2714 }
2715
OnEnumerateDirectory(int request_id,const base::FilePath & path)2716 void WebContentsImpl::OnEnumerateDirectory(int request_id,
2717 const base::FilePath& path) {
2718 if (!delegate_)
2719 return;
2720
2721 ChildProcessSecurityPolicyImpl* policy =
2722 ChildProcessSecurityPolicyImpl::GetInstance();
2723 if (policy->CanReadFile(GetRenderProcessHost()->GetID(), path))
2724 delegate_->EnumerateDirectory(this, request_id, path);
2725 }
2726
OnRegisterProtocolHandler(const std::string & protocol,const GURL & url,const base::string16 & title,bool user_gesture)2727 void WebContentsImpl::OnRegisterProtocolHandler(const std::string& protocol,
2728 const GURL& url,
2729 const base::string16& title,
2730 bool user_gesture) {
2731 if (!delegate_)
2732 return;
2733
2734 ChildProcessSecurityPolicyImpl* policy =
2735 ChildProcessSecurityPolicyImpl::GetInstance();
2736 if (policy->IsPseudoScheme(protocol))
2737 return;
2738
2739 delegate_->RegisterProtocolHandler(this, protocol, url, user_gesture);
2740 }
2741
OnFindReply(int request_id,int number_of_matches,const gfx::Rect & selection_rect,int active_match_ordinal,bool final_update)2742 void WebContentsImpl::OnFindReply(int request_id,
2743 int number_of_matches,
2744 const gfx::Rect& selection_rect,
2745 int active_match_ordinal,
2746 bool final_update) {
2747 if (delegate_) {
2748 delegate_->FindReply(this, request_id, number_of_matches, selection_rect,
2749 active_match_ordinal, final_update);
2750 }
2751 }
2752
2753 #if defined(OS_ANDROID)
OnFindMatchRectsReply(int version,const std::vector<gfx::RectF> & rects,const gfx::RectF & active_rect)2754 void WebContentsImpl::OnFindMatchRectsReply(
2755 int version,
2756 const std::vector<gfx::RectF>& rects,
2757 const gfx::RectF& active_rect) {
2758 if (delegate_)
2759 delegate_->FindMatchRectsReply(this, version, rects, active_rect);
2760 }
2761
OnOpenDateTimeDialog(const ViewHostMsg_DateTimeDialogValue_Params & value)2762 void WebContentsImpl::OnOpenDateTimeDialog(
2763 const ViewHostMsg_DateTimeDialogValue_Params& value) {
2764 date_time_chooser_->ShowDialog(ContentViewCore::FromWebContents(this),
2765 GetRenderViewHost(),
2766 value.dialog_type,
2767 value.dialog_value,
2768 value.minimum,
2769 value.maximum,
2770 value.step,
2771 value.suggestions);
2772 }
2773
2774 #endif
2775
OnPepperPluginHung(int plugin_child_id,const base::FilePath & path,bool is_hung)2776 void WebContentsImpl::OnPepperPluginHung(int plugin_child_id,
2777 const base::FilePath& path,
2778 bool is_hung) {
2779 UMA_HISTOGRAM_COUNTS("Pepper.PluginHung", 1);
2780
2781 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2782 PluginHungStatusChanged(plugin_child_id, path, is_hung));
2783 }
2784
OnPluginCrashed(const base::FilePath & plugin_path,base::ProcessId plugin_pid)2785 void WebContentsImpl::OnPluginCrashed(const base::FilePath& plugin_path,
2786 base::ProcessId plugin_pid) {
2787 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2788 PluginCrashed(plugin_path, plugin_pid));
2789 }
2790
OnDomOperationResponse(const std::string & json_string,int automation_id)2791 void WebContentsImpl::OnDomOperationResponse(const std::string& json_string,
2792 int automation_id) {
2793 DomOperationNotificationDetails details(json_string, automation_id);
2794 NotificationService::current()->Notify(
2795 NOTIFICATION_DOM_OPERATION_RESPONSE,
2796 Source<WebContents>(this),
2797 Details<DomOperationNotificationDetails>(&details));
2798 }
2799
OnAppCacheAccessed(const GURL & manifest_url,bool blocked_by_policy)2800 void WebContentsImpl::OnAppCacheAccessed(const GURL& manifest_url,
2801 bool blocked_by_policy) {
2802 // Notify observers about navigation.
2803 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2804 AppCacheAccessed(manifest_url, blocked_by_policy));
2805 }
2806
OnOpenColorChooser(int color_chooser_id,SkColor color,const std::vector<ColorSuggestion> & suggestions)2807 void WebContentsImpl::OnOpenColorChooser(
2808 int color_chooser_id,
2809 SkColor color,
2810 const std::vector<ColorSuggestion>& suggestions) {
2811 ColorChooser* new_color_chooser = delegate_ ?
2812 delegate_->OpenColorChooser(this, color, suggestions) :
2813 NULL;
2814 if (!new_color_chooser)
2815 return;
2816 if (color_chooser_info_.get())
2817 color_chooser_info_->chooser->End();
2818
2819 color_chooser_info_.reset(new ColorChooserInfo(
2820 render_frame_message_source_->GetProcess()->GetID(),
2821 render_frame_message_source_->GetRoutingID(),
2822 new_color_chooser,
2823 color_chooser_id));
2824 }
2825
OnEndColorChooser(int color_chooser_id)2826 void WebContentsImpl::OnEndColorChooser(int color_chooser_id) {
2827 if (color_chooser_info_ &&
2828 color_chooser_id == color_chooser_info_->identifier)
2829 color_chooser_info_->chooser->End();
2830 }
2831
OnSetSelectedColorInColorChooser(int color_chooser_id,SkColor color)2832 void WebContentsImpl::OnSetSelectedColorInColorChooser(int color_chooser_id,
2833 SkColor color) {
2834 if (color_chooser_info_ &&
2835 color_chooser_id == color_chooser_info_->identifier)
2836 color_chooser_info_->chooser->SetSelectedColor(color);
2837 }
2838
2839 // This exists for render views that don't have a WebUI, but do have WebUI
2840 // bindings enabled.
OnWebUISend(const GURL & source_url,const std::string & name,const base::ListValue & args)2841 void WebContentsImpl::OnWebUISend(const GURL& source_url,
2842 const std::string& name,
2843 const base::ListValue& args) {
2844 if (delegate_)
2845 delegate_->WebUISend(this, source_url, name, args);
2846 }
2847
OnRequestPpapiBrokerPermission(int routing_id,const GURL & url,const base::FilePath & plugin_path)2848 void WebContentsImpl::OnRequestPpapiBrokerPermission(
2849 int routing_id,
2850 const GURL& url,
2851 const base::FilePath& plugin_path) {
2852 if (!delegate_) {
2853 OnPpapiBrokerPermissionResult(routing_id, false);
2854 return;
2855 }
2856
2857 if (!delegate_->RequestPpapiBrokerPermission(
2858 this, url, plugin_path,
2859 base::Bind(&WebContentsImpl::OnPpapiBrokerPermissionResult,
2860 base::Unretained(this), routing_id))) {
2861 NOTIMPLEMENTED();
2862 OnPpapiBrokerPermissionResult(routing_id, false);
2863 }
2864 }
2865
OnPpapiBrokerPermissionResult(int routing_id,bool result)2866 void WebContentsImpl::OnPpapiBrokerPermissionResult(int routing_id,
2867 bool result) {
2868 Send(new ViewMsg_PpapiBrokerPermissionResult(routing_id, result));
2869 }
2870
OnBrowserPluginMessage(const IPC::Message & message)2871 void WebContentsImpl::OnBrowserPluginMessage(const IPC::Message& message) {
2872 // This creates a BrowserPluginEmbedder, which handles all the BrowserPlugin
2873 // specific messages for this WebContents. This means that any message from
2874 // a BrowserPlugin prior to this will be ignored.
2875 // For more info, see comment above classes BrowserPluginEmbedder and
2876 // BrowserPluginGuest.
2877 CHECK(!browser_plugin_embedder_.get());
2878 browser_plugin_embedder_.reset(BrowserPluginEmbedder::Create(this));
2879 browser_plugin_embedder_->OnMessageReceived(message);
2880 }
2881
OnDidDownloadImage(int id,int http_status_code,const GURL & image_url,const std::vector<SkBitmap> & bitmaps,const std::vector<gfx::Size> & original_bitmap_sizes)2882 void WebContentsImpl::OnDidDownloadImage(
2883 int id,
2884 int http_status_code,
2885 const GURL& image_url,
2886 const std::vector<SkBitmap>& bitmaps,
2887 const std::vector<gfx::Size>& original_bitmap_sizes) {
2888 if (bitmaps.size() != original_bitmap_sizes.size())
2889 return;
2890
2891 ImageDownloadMap::iterator iter = image_download_map_.find(id);
2892 if (iter == image_download_map_.end()) {
2893 // Currently WebContents notifies us of ANY downloads so that it is
2894 // possible to get here.
2895 return;
2896 }
2897 if (!iter->second.is_null()) {
2898 iter->second.Run(
2899 id, http_status_code, image_url, bitmaps, original_bitmap_sizes);
2900 }
2901 image_download_map_.erase(id);
2902 }
2903
OnUpdateFaviconURL(const std::vector<FaviconURL> & candidates)2904 void WebContentsImpl::OnUpdateFaviconURL(
2905 const std::vector<FaviconURL>& candidates) {
2906 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2907 DidUpdateFaviconURL(candidates));
2908 }
2909
OnMediaPlayingNotification(int64 player_cookie,bool has_video,bool has_audio)2910 void WebContentsImpl::OnMediaPlayingNotification(int64 player_cookie,
2911 bool has_video,
2912 bool has_audio) {
2913 // Chrome OS does its own detection of audio and video.
2914 #if !defined(OS_CHROMEOS)
2915 scoped_ptr<PowerSaveBlocker> blocker;
2916 if (has_video) {
2917 blocker = PowerSaveBlocker::Create(
2918 PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, "Playing video");
2919 #if defined(OS_ANDROID)
2920 static_cast<PowerSaveBlockerImpl*>(blocker.get())
2921 ->InitDisplaySleepBlocker(GetView()->GetNativeView());
2922 #endif
2923 } else if (has_audio) {
2924 blocker = PowerSaveBlocker::Create(
2925 PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, "Playing audio");
2926 }
2927
2928 if (blocker) {
2929 power_save_blockers_[render_frame_message_source_][player_cookie] =
2930 blocker.release();
2931 }
2932 #endif // !defined(OS_CHROMEOS)
2933 }
2934
OnMediaPausedNotification(int64 player_cookie)2935 void WebContentsImpl::OnMediaPausedNotification(int64 player_cookie) {
2936 // Chrome OS does its own detection of audio and video.
2937 #if !defined(OS_CHROMEOS)
2938 delete power_save_blockers_[render_frame_message_source_][player_cookie];
2939 power_save_blockers_[render_frame_message_source_].erase(player_cookie);
2940 #endif // !defined(OS_CHROMEOS)
2941 }
2942
OnFirstVisuallyNonEmptyPaint()2943 void WebContentsImpl::OnFirstVisuallyNonEmptyPaint() {
2944 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2945 DidFirstVisuallyNonEmptyPaint());
2946 }
2947
DidChangeVisibleSSLState()2948 void WebContentsImpl::DidChangeVisibleSSLState() {
2949 if (delegate_)
2950 delegate_->VisibleSSLStateChanged(this);
2951 }
2952
NotifyBeforeFormRepostWarningShow()2953 void WebContentsImpl::NotifyBeforeFormRepostWarningShow() {
2954 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
2955 BeforeFormRepostWarningShow());
2956 }
2957
2958
ActivateAndShowRepostFormWarningDialog()2959 void WebContentsImpl::ActivateAndShowRepostFormWarningDialog() {
2960 Activate();
2961 if (delegate_)
2962 delegate_->ShowRepostFormWarningDialog(this);
2963 }
2964
HasAccessedInitialDocument()2965 bool WebContentsImpl::HasAccessedInitialDocument() {
2966 return has_accessed_initial_document_;
2967 }
2968
2969 // Notifies the RenderWidgetHost instance about the fact that the page is
2970 // loading, or done loading.
SetIsLoading(RenderViewHost * render_view_host,bool is_loading,bool to_different_document,LoadNotificationDetails * details)2971 void WebContentsImpl::SetIsLoading(RenderViewHost* render_view_host,
2972 bool is_loading,
2973 bool to_different_document,
2974 LoadNotificationDetails* details) {
2975 if (is_loading == is_loading_)
2976 return;
2977
2978 if (!is_loading) {
2979 load_state_ = net::LoadStateWithParam(net::LOAD_STATE_IDLE,
2980 base::string16());
2981 load_state_host_.clear();
2982 upload_size_ = 0;
2983 upload_position_ = 0;
2984 }
2985
2986 GetRenderManager()->SetIsLoading(is_loading);
2987
2988 is_loading_ = is_loading;
2989 waiting_for_response_ = is_loading;
2990 is_load_to_different_document_ = to_different_document;
2991
2992 if (delegate_)
2993 delegate_->LoadingStateChanged(this, to_different_document);
2994 NotifyNavigationStateChanged(INVALIDATE_TYPE_LOAD);
2995
2996 std::string url = (details ? details->url.possibly_invalid_spec() : "NULL");
2997 if (is_loading) {
2998 TRACE_EVENT_ASYNC_BEGIN1("browser", "WebContentsImpl Loading", this,
2999 "URL", url);
3000 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3001 DidStartLoading(render_view_host));
3002 } else {
3003 TRACE_EVENT_ASYNC_END1("browser", "WebContentsImpl Loading", this,
3004 "URL", url);
3005 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3006 DidStopLoading(render_view_host));
3007 }
3008
3009 // TODO(avi): Remove. http://crbug.com/170921
3010 int type = is_loading ? NOTIFICATION_LOAD_START : NOTIFICATION_LOAD_STOP;
3011 NotificationDetails det = NotificationService::NoDetails();
3012 if (details)
3013 det = Details<LoadNotificationDetails>(details);
3014 NotificationService::current()->Notify(
3015 type, Source<NavigationController>(&controller_), det);
3016 }
3017
SelectRange(const gfx::Point & start,const gfx::Point & end)3018 void WebContentsImpl::SelectRange(const gfx::Point& start,
3019 const gfx::Point& end) {
3020 RenderFrameHost* focused_frame = GetFocusedFrame();
3021 if (!focused_frame)
3022 return;
3023
3024 focused_frame->Send(
3025 new InputMsg_SelectRange(focused_frame->GetRoutingID(), start, end));
3026 }
3027
UpdateMaxPageIDIfNecessary(RenderViewHost * rvh)3028 void WebContentsImpl::UpdateMaxPageIDIfNecessary(RenderViewHost* rvh) {
3029 // If we are creating a RVH for a restored controller, then we need to make
3030 // sure the RenderView starts with a next_page_id_ larger than the number
3031 // of restored entries. This must be called before the RenderView starts
3032 // navigating (to avoid a race between the browser updating max_page_id and
3033 // the renderer updating next_page_id_). Because of this, we only call this
3034 // from CreateRenderView and allow that to notify the RenderView for us.
3035 int max_restored_page_id = controller_.GetMaxRestoredPageID();
3036 if (max_restored_page_id >
3037 GetMaxPageIDForSiteInstance(rvh->GetSiteInstance()))
3038 UpdateMaxPageIDForSiteInstance(rvh->GetSiteInstance(),
3039 max_restored_page_id);
3040 }
3041
UpdateTitleForEntry(NavigationEntryImpl * entry,const base::string16 & title)3042 bool WebContentsImpl::UpdateTitleForEntry(NavigationEntryImpl* entry,
3043 const base::string16& title) {
3044 // For file URLs without a title, use the pathname instead. In the case of a
3045 // synthesized title, we don't want the update to count toward the "one set
3046 // per page of the title to history."
3047 base::string16 final_title;
3048 bool explicit_set;
3049 if (entry && entry->GetURL().SchemeIsFile() && title.empty()) {
3050 final_title = base::UTF8ToUTF16(entry->GetURL().ExtractFileName());
3051 explicit_set = false; // Don't count synthetic titles toward the set limit.
3052 } else {
3053 base::TrimWhitespace(title, base::TRIM_ALL, &final_title);
3054 explicit_set = true;
3055 }
3056
3057 // If a page is created via window.open and never navigated,
3058 // there will be no navigation entry. In this situation,
3059 // |page_title_when_no_navigation_entry_| will be used for page title.
3060 if (entry) {
3061 if (final_title == entry->GetTitle())
3062 return false; // Nothing changed, don't bother.
3063
3064 entry->SetTitle(final_title);
3065 } else {
3066 if (page_title_when_no_navigation_entry_ == final_title)
3067 return false; // Nothing changed, don't bother.
3068
3069 page_title_when_no_navigation_entry_ = final_title;
3070 }
3071
3072 // Lastly, set the title for the view.
3073 view_->SetPageTitle(final_title);
3074
3075 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3076 TitleWasSet(entry, explicit_set));
3077
3078 // TODO(avi): Remove. http://crbug.com/170921
3079 std::pair<NavigationEntry*, bool> details =
3080 std::make_pair(entry, explicit_set);
3081 NotificationService::current()->Notify(
3082 NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
3083 Source<WebContents>(this),
3084 Details<std::pair<NavigationEntry*, bool> >(&details));
3085
3086 return true;
3087 }
3088
SendLoadProgressChanged()3089 void WebContentsImpl::SendLoadProgressChanged() {
3090 loading_last_progress_update_ = base::TimeTicks::Now();
3091 double progress = 0.0;
3092 int frame_count = 0;
3093
3094 for (LoadingProgressMap::iterator it = loading_progresses_.begin();
3095 it != loading_progresses_.end();
3096 ++it) {
3097 progress += it->second;
3098 ++frame_count;
3099 }
3100 if (frame_count == 0)
3101 return;
3102 progress /= frame_count;
3103 DCHECK(progress <= 1.0);
3104
3105 if (progress <= loading_total_progress_)
3106 return;
3107 loading_total_progress_ = progress;
3108
3109 if (delegate_)
3110 delegate_->LoadProgressChanged(this, progress);
3111 }
3112
ResetLoadProgressState()3113 void WebContentsImpl::ResetLoadProgressState() {
3114 loading_progresses_.clear();
3115 loading_total_progress_ = 0.0;
3116 loading_weak_factory_.InvalidateWeakPtrs();
3117 loading_last_progress_update_ = base::TimeTicks();
3118 }
3119
NotifySwapped(RenderViewHost * old_host,RenderViewHost * new_host)3120 void WebContentsImpl::NotifySwapped(RenderViewHost* old_host,
3121 RenderViewHost* new_host) {
3122 // After sending out a swap notification, we need to send a disconnect
3123 // notification so that clients that pick up a pointer to |this| can NULL the
3124 // pointer. See Bug 1230284.
3125 notify_disconnection_ = true;
3126 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3127 RenderViewHostChanged(old_host, new_host));
3128
3129 // TODO(avi): Remove. http://crbug.com/170921
3130 std::pair<RenderViewHost*, RenderViewHost*> details =
3131 std::make_pair(old_host, new_host);
3132 NotificationService::current()->Notify(
3133 NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
3134 Source<WebContents>(this),
3135 Details<std::pair<RenderViewHost*, RenderViewHost*> >(&details));
3136
3137 // Ensure that the associated embedder gets cleared after a RenderViewHost
3138 // gets swapped, so we don't reuse the same embedder next time a
3139 // RenderViewHost is attached to this WebContents.
3140 RemoveBrowserPluginEmbedder();
3141 }
3142
3143 // TODO(avi): Remove this entire function because this notification is already
3144 // covered by two observer functions. http://crbug.com/170921
NotifyDisconnected()3145 void WebContentsImpl::NotifyDisconnected() {
3146 if (!notify_disconnection_)
3147 return;
3148
3149 notify_disconnection_ = false;
3150 NotificationService::current()->Notify(
3151 NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
3152 Source<WebContents>(this),
3153 NotificationService::NoDetails());
3154 }
3155
NotifyNavigationEntryCommitted(const LoadCommittedDetails & load_details)3156 void WebContentsImpl::NotifyNavigationEntryCommitted(
3157 const LoadCommittedDetails& load_details) {
3158 FOR_EACH_OBSERVER(
3159 WebContentsObserver, observers_, NavigationEntryCommitted(load_details));
3160 }
3161
OnMessageReceived(RenderFrameHost * render_frame_host,const IPC::Message & message)3162 bool WebContentsImpl::OnMessageReceived(RenderFrameHost* render_frame_host,
3163 const IPC::Message& message) {
3164 return OnMessageReceived(NULL, render_frame_host, message);
3165 }
3166
GetMainFrameLastCommittedURL() const3167 const GURL& WebContentsImpl::GetMainFrameLastCommittedURL() const {
3168 return GetLastCommittedURL();
3169 }
3170
RenderFrameCreated(RenderFrameHost * render_frame_host)3171 void WebContentsImpl::RenderFrameCreated(RenderFrameHost* render_frame_host) {
3172 // Note this is only for subframes, the notification for the main frame
3173 // happens in RenderViewCreated.
3174 FOR_EACH_OBSERVER(WebContentsObserver,
3175 observers_,
3176 RenderFrameCreated(render_frame_host));
3177 }
3178
RenderFrameDeleted(RenderFrameHost * render_frame_host)3179 void WebContentsImpl::RenderFrameDeleted(RenderFrameHost* render_frame_host) {
3180 ClearPowerSaveBlockers(render_frame_host);
3181 FOR_EACH_OBSERVER(WebContentsObserver,
3182 observers_,
3183 RenderFrameDeleted(render_frame_host));
3184 }
3185
WorkerCrashed(RenderFrameHost * render_frame_host)3186 void WebContentsImpl::WorkerCrashed(RenderFrameHost* render_frame_host) {
3187 if (delegate_)
3188 delegate_->WorkerCrashed(this);
3189 }
3190
ShowContextMenu(RenderFrameHost * render_frame_host,const ContextMenuParams & params)3191 void WebContentsImpl::ShowContextMenu(RenderFrameHost* render_frame_host,
3192 const ContextMenuParams& params) {
3193 ContextMenuParams context_menu_params(params);
3194 // Allow WebContentsDelegates to handle the context menu operation first.
3195 if (GetBrowserPluginGuest()) {
3196 WebContentsViewGuest* view_guest =
3197 static_cast<WebContentsViewGuest*>(GetView());
3198 context_menu_params = view_guest->ConvertContextMenuParams(params);
3199 }
3200 if (delegate_ && delegate_->HandleContextMenu(context_menu_params))
3201 return;
3202
3203 render_view_host_delegate_view_->ShowContextMenu(render_frame_host,
3204 context_menu_params);
3205 }
3206
RunJavaScriptMessage(RenderFrameHost * render_frame_host,const base::string16 & message,const base::string16 & default_prompt,const GURL & frame_url,JavaScriptMessageType javascript_message_type,IPC::Message * reply_msg)3207 void WebContentsImpl::RunJavaScriptMessage(
3208 RenderFrameHost* render_frame_host,
3209 const base::string16& message,
3210 const base::string16& default_prompt,
3211 const GURL& frame_url,
3212 JavaScriptMessageType javascript_message_type,
3213 IPC::Message* reply_msg) {
3214 // Suppress JavaScript dialogs when requested. Also suppress messages when
3215 // showing an interstitial as it's shown over the previous page and we don't
3216 // want the hidden page's dialogs to interfere with the interstitial.
3217 bool suppress_this_message =
3218 static_cast<RenderViewHostImpl*>(render_frame_host->GetRenderViewHost())->
3219 IsSwappedOut() ||
3220 ShowingInterstitialPage() ||
3221 !delegate_ ||
3222 delegate_->ShouldSuppressDialogs() ||
3223 !delegate_->GetJavaScriptDialogManager();
3224
3225 if (!suppress_this_message) {
3226 std::string accept_lang = GetContentClient()->browser()->
3227 GetAcceptLangs(GetBrowserContext());
3228 dialog_manager_ = delegate_->GetJavaScriptDialogManager();
3229 dialog_manager_->RunJavaScriptDialog(
3230 this,
3231 frame_url.GetOrigin(),
3232 accept_lang,
3233 javascript_message_type,
3234 message,
3235 default_prompt,
3236 base::Bind(&WebContentsImpl::OnDialogClosed,
3237 base::Unretained(this),
3238 render_frame_host->GetProcess()->GetID(),
3239 render_frame_host->GetRoutingID(),
3240 reply_msg,
3241 false),
3242 &suppress_this_message);
3243 }
3244
3245 if (suppress_this_message) {
3246 // If we are suppressing messages, just reply as if the user immediately
3247 // pressed "Cancel", passing true to |dialog_was_suppressed|.
3248 OnDialogClosed(render_frame_host->GetProcess()->GetID(),
3249 render_frame_host->GetRoutingID(), reply_msg,
3250 true, false, base::string16());
3251 }
3252
3253 // OnDialogClosed (two lines up) may have caused deletion of this object (see
3254 // http://crbug.com/288961 ). The only safe thing to do here is return.
3255 }
3256
RunBeforeUnloadConfirm(RenderFrameHost * render_frame_host,const base::string16 & message,bool is_reload,IPC::Message * reply_msg)3257 void WebContentsImpl::RunBeforeUnloadConfirm(
3258 RenderFrameHost* render_frame_host,
3259 const base::string16& message,
3260 bool is_reload,
3261 IPC::Message* reply_msg) {
3262 RenderFrameHostImpl* rfhi =
3263 static_cast<RenderFrameHostImpl*>(render_frame_host);
3264 RenderViewHostImpl* rvhi =
3265 static_cast<RenderViewHostImpl*>(render_frame_host->GetRenderViewHost());
3266 if (delegate_)
3267 delegate_->WillRunBeforeUnloadConfirm();
3268
3269 bool suppress_this_message =
3270 rvhi->rvh_state() != RenderViewHostImpl::STATE_DEFAULT ||
3271 !delegate_ ||
3272 delegate_->ShouldSuppressDialogs() ||
3273 !delegate_->GetJavaScriptDialogManager();
3274 if (suppress_this_message) {
3275 rfhi->JavaScriptDialogClosed(reply_msg, true, base::string16(), true);
3276 return;
3277 }
3278
3279 is_showing_before_unload_dialog_ = true;
3280 dialog_manager_ = delegate_->GetJavaScriptDialogManager();
3281 dialog_manager_->RunBeforeUnloadDialog(
3282 this, message, is_reload,
3283 base::Bind(&WebContentsImpl::OnDialogClosed, base::Unretained(this),
3284 render_frame_host->GetProcess()->GetID(),
3285 render_frame_host->GetRoutingID(), reply_msg,
3286 false));
3287 }
3288
GetAsWebContents()3289 WebContents* WebContentsImpl::GetAsWebContents() {
3290 return this;
3291 }
3292
IsNeverVisible()3293 bool WebContentsImpl::IsNeverVisible() {
3294 if (!delegate_)
3295 return false;
3296 return delegate_->IsNeverVisible(this);
3297 }
3298
GetDelegateView()3299 RenderViewHostDelegateView* WebContentsImpl::GetDelegateView() {
3300 return render_view_host_delegate_view_;
3301 }
3302
GetRendererPrefs(BrowserContext * browser_context) const3303 RendererPreferences WebContentsImpl::GetRendererPrefs(
3304 BrowserContext* browser_context) const {
3305 return renderer_preferences_;
3306 }
3307
GetRootWindowResizerRect() const3308 gfx::Rect WebContentsImpl::GetRootWindowResizerRect() const {
3309 if (delegate_)
3310 return delegate_->GetRootWindowResizerRect();
3311 return gfx::Rect();
3312 }
3313
RemoveBrowserPluginEmbedder()3314 void WebContentsImpl::RemoveBrowserPluginEmbedder() {
3315 if (browser_plugin_embedder_)
3316 browser_plugin_embedder_.reset();
3317 }
3318
RenderViewCreated(RenderViewHost * render_view_host)3319 void WebContentsImpl::RenderViewCreated(RenderViewHost* render_view_host) {
3320 // Don't send notifications if we are just creating a swapped-out RVH for
3321 // the opener chain. These won't be used for view-source or WebUI, so it's
3322 // ok to return early.
3323 if (static_cast<RenderViewHostImpl*>(render_view_host)->IsSwappedOut())
3324 return;
3325
3326 if (delegate_)
3327 view_->SetOverscrollControllerEnabled(CanOverscrollContent());
3328
3329 NotificationService::current()->Notify(
3330 NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
3331 Source<WebContents>(this),
3332 Details<RenderViewHost>(render_view_host));
3333
3334 // When we're creating views, we're still doing initial setup, so we always
3335 // use the pending Web UI rather than any possibly existing committed one.
3336 if (GetRenderManager()->pending_web_ui())
3337 GetRenderManager()->pending_web_ui()->RenderViewCreated(render_view_host);
3338
3339 NavigationEntry* entry = controller_.GetPendingEntry();
3340 if (entry && entry->IsViewSourceMode()) {
3341 // Put the renderer in view source mode.
3342 render_view_host->Send(
3343 new ViewMsg_EnableViewSourceMode(render_view_host->GetRoutingID()));
3344 }
3345
3346 view_->RenderViewCreated(render_view_host);
3347
3348 FOR_EACH_OBSERVER(
3349 WebContentsObserver, observers_, RenderViewCreated(render_view_host));
3350
3351 // We tell the observers now instead of when the main RenderFrameHostImpl is
3352 // constructed because otherwise it would be too early (i.e. IPCs sent to the
3353 // frame would be dropped because it's not created yet).
3354 RenderFrameHost* main_frame = render_view_host->GetMainFrame();
3355 FOR_EACH_OBSERVER(
3356 WebContentsObserver, observers_, RenderFrameCreated(main_frame));
3357 }
3358
RenderViewReady(RenderViewHost * rvh)3359 void WebContentsImpl::RenderViewReady(RenderViewHost* rvh) {
3360 if (rvh != GetRenderViewHost()) {
3361 // Don't notify the world, since this came from a renderer in the
3362 // background.
3363 return;
3364 }
3365
3366 notify_disconnection_ = true;
3367 // TODO(avi): Remove. http://crbug.com/170921
3368 NotificationService::current()->Notify(
3369 NOTIFICATION_WEB_CONTENTS_CONNECTED,
3370 Source<WebContents>(this),
3371 NotificationService::NoDetails());
3372
3373 bool was_crashed = IsCrashed();
3374 SetIsCrashed(base::TERMINATION_STATUS_STILL_RUNNING, 0);
3375
3376 // Restore the focus to the tab (otherwise the focus will be on the top
3377 // window).
3378 if (was_crashed && !FocusLocationBarByDefault() &&
3379 (!delegate_ || delegate_->ShouldFocusPageAfterCrash())) {
3380 view_->Focus();
3381 }
3382
3383 FOR_EACH_OBSERVER(WebContentsObserver, observers_, RenderViewReady());
3384 }
3385
RenderViewTerminated(RenderViewHost * rvh,base::TerminationStatus status,int error_code)3386 void WebContentsImpl::RenderViewTerminated(RenderViewHost* rvh,
3387 base::TerminationStatus status,
3388 int error_code) {
3389 if (rvh != GetRenderViewHost()) {
3390 // The pending page's RenderViewHost is gone.
3391 return;
3392 }
3393
3394 // Ensure fullscreen mode is exited in the |delegate_| since a crashed
3395 // renderer may not have made a clean exit.
3396 if (IsFullscreenForCurrentTab())
3397 ToggleFullscreenMode(false);
3398
3399 // Cancel any visible dialogs so they are not left dangling over the sad tab.
3400 if (dialog_manager_)
3401 dialog_manager_->CancelActiveAndPendingDialogs(this);
3402
3403 if (delegate_)
3404 delegate_->HideValidationMessage(this);
3405
3406 SetIsLoading(rvh, false, true, NULL);
3407 NotifyDisconnected();
3408 SetIsCrashed(status, error_code);
3409
3410 // Reset the loading progress. TODO(avi): What does it mean to have a
3411 // "renderer crash" when there is more than one renderer process serving a
3412 // webpage? Once this function is called at a more granular frame level, we
3413 // probably will need to more granularly reset the state here.
3414 ResetLoadProgressState();
3415 loading_frames_in_progress_ = 0;
3416
3417 FOR_EACH_OBSERVER(WebContentsObserver,
3418 observers_,
3419 RenderProcessGone(GetCrashedStatus()));
3420 }
3421
RenderViewDeleted(RenderViewHost * rvh)3422 void WebContentsImpl::RenderViewDeleted(RenderViewHost* rvh) {
3423 FOR_EACH_OBSERVER(WebContentsObserver, observers_, RenderViewDeleted(rvh));
3424 }
3425
UpdateState(RenderViewHost * rvh,int32 page_id,const PageState & page_state)3426 void WebContentsImpl::UpdateState(RenderViewHost* rvh,
3427 int32 page_id,
3428 const PageState& page_state) {
3429 // Ensure that this state update comes from either the active RVH or one of
3430 // the swapped out RVHs. We don't expect to hear from any other RVHs.
3431 // TODO(nasko): This should go through RenderFrameHost.
3432 // TODO(creis): We can't update state for cross-process subframes until we
3433 // have FrameNavigationEntries. Once we do, this should be a DCHECK.
3434 if (rvh != GetRenderViewHost() &&
3435 !GetRenderManager()->IsRVHOnSwappedOutList(
3436 static_cast<RenderViewHostImpl*>(rvh)))
3437 return;
3438
3439 // We must be prepared to handle state updates for any page, these occur
3440 // when the user is scrolling and entering form data, as well as when we're
3441 // leaving a page, in which case our state may have already been moved to
3442 // the next page. The navigation controller will look up the appropriate
3443 // NavigationEntry and update it when it is notified via the delegate.
3444
3445 int entry_index = controller_.GetEntryIndexWithPageID(
3446 rvh->GetSiteInstance(), page_id);
3447 if (entry_index < 0)
3448 return;
3449 NavigationEntry* entry = controller_.GetEntryAtIndex(entry_index);
3450
3451 if (page_state == entry->GetPageState())
3452 return; // Nothing to update.
3453 entry->SetPageState(page_state);
3454 controller_.NotifyEntryChanged(entry, entry_index);
3455 }
3456
UpdateTargetURL(int32 page_id,const GURL & url)3457 void WebContentsImpl::UpdateTargetURL(int32 page_id, const GURL& url) {
3458 if (delegate_)
3459 delegate_->UpdateTargetURL(this, page_id, url);
3460 }
3461
Close(RenderViewHost * rvh)3462 void WebContentsImpl::Close(RenderViewHost* rvh) {
3463 #if defined(OS_MACOSX)
3464 // The UI may be in an event-tracking loop, such as between the
3465 // mouse-down and mouse-up in text selection or a button click.
3466 // Defer the close until after tracking is complete, so that we
3467 // don't free objects out from under the UI.
3468 // TODO(shess): This could get more fine-grained. For instance,
3469 // closing a tab in another window while selecting text in the
3470 // current window's Omnibox should be just fine.
3471 if (view_->IsEventTracking()) {
3472 view_->CloseTabAfterEventTracking();
3473 return;
3474 }
3475 #endif
3476
3477 // Ignore this if it comes from a RenderViewHost that we aren't showing.
3478 if (delegate_ && rvh == GetRenderViewHost())
3479 delegate_->CloseContents(this);
3480 }
3481
SwappedOut(RenderFrameHost * rfh)3482 void WebContentsImpl::SwappedOut(RenderFrameHost* rfh) {
3483 if (delegate_ && rfh->GetRenderViewHost() == GetRenderViewHost())
3484 delegate_->SwappedOut(this);
3485 }
3486
RequestMove(const gfx::Rect & new_bounds)3487 void WebContentsImpl::RequestMove(const gfx::Rect& new_bounds) {
3488 if (delegate_ && delegate_->IsPopupOrPanel(this))
3489 delegate_->MoveContents(this, new_bounds);
3490 }
3491
DidStartLoading(RenderFrameHost * render_frame_host,bool to_different_document)3492 void WebContentsImpl::DidStartLoading(RenderFrameHost* render_frame_host,
3493 bool to_different_document) {
3494 SetIsLoading(render_frame_host->GetRenderViewHost(), true,
3495 to_different_document, NULL);
3496 }
3497
DidStopLoading(RenderFrameHost * render_frame_host)3498 void WebContentsImpl::DidStopLoading(RenderFrameHost* render_frame_host) {
3499 scoped_ptr<LoadNotificationDetails> details;
3500
3501 // Use the last committed entry rather than the active one, in case a
3502 // pending entry has been created.
3503 NavigationEntry* entry = controller_.GetLastCommittedEntry();
3504 Navigator* navigator = frame_tree_.root()->navigator();
3505
3506 // An entry may not exist for a stop when loading an initial blank page or
3507 // if an iframe injected by script into a blank page finishes loading.
3508 if (entry) {
3509 base::TimeDelta elapsed =
3510 base::TimeTicks::Now() - navigator->GetCurrentLoadStart();
3511
3512 details.reset(new LoadNotificationDetails(
3513 entry->GetVirtualURL(),
3514 entry->GetTransitionType(),
3515 elapsed,
3516 &controller_,
3517 controller_.GetCurrentEntryIndex()));
3518 }
3519
3520 SetIsLoading(render_frame_host->GetRenderViewHost(), false, true,
3521 details.get());
3522 }
3523
DidCancelLoading()3524 void WebContentsImpl::DidCancelLoading() {
3525 controller_.DiscardNonCommittedEntries();
3526
3527 // Update the URL display.
3528 NotifyNavigationStateChanged(INVALIDATE_TYPE_URL);
3529 }
3530
DidAccessInitialDocument()3531 void WebContentsImpl::DidAccessInitialDocument() {
3532 has_accessed_initial_document_ = true;
3533
3534 // We may have left a failed browser-initiated navigation in the address bar
3535 // to let the user edit it and try again. Clear it now that content might
3536 // show up underneath it.
3537 if (!IsLoading() && controller_.GetPendingEntry())
3538 controller_.DiscardPendingEntry();
3539
3540 // Update the URL display.
3541 NotifyNavigationStateChanged(content::INVALIDATE_TYPE_URL);
3542 }
3543
DidDisownOpener(RenderFrameHost * render_frame_host)3544 void WebContentsImpl::DidDisownOpener(RenderFrameHost* render_frame_host) {
3545 if (opener_) {
3546 // Clear our opener so that future cross-process navigations don't have an
3547 // opener assigned.
3548 RemoveDestructionObserver(opener_);
3549 opener_ = NULL;
3550 }
3551
3552 // Notify all swapped out RenderViewHosts for this tab. This is important
3553 // in case we go back to them, or if another window in those processes tries
3554 // to access window.opener.
3555 GetRenderManager()->DidDisownOpener(render_frame_host->GetRenderViewHost());
3556 }
3557
DocumentOnLoadCompleted(RenderFrameHost * render_frame_host)3558 void WebContentsImpl::DocumentOnLoadCompleted(
3559 RenderFrameHost* render_frame_host) {
3560 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3561 DocumentOnLoadCompletedInMainFrame());
3562
3563 // TODO(avi): Remove. http://crbug.com/170921
3564 NotificationService::current()->Notify(
3565 NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
3566 Source<WebContents>(this),
3567 NotificationService::NoDetails());
3568 }
3569
UpdateTitle(RenderFrameHost * render_frame_host,int32 page_id,const base::string16 & title,base::i18n::TextDirection title_direction)3570 void WebContentsImpl::UpdateTitle(RenderFrameHost* render_frame_host,
3571 int32 page_id,
3572 const base::string16& title,
3573 base::i18n::TextDirection title_direction) {
3574 RenderViewHost* rvh = render_frame_host->GetRenderViewHost();
3575
3576 // If we have a title, that's a pretty good indication that we've started
3577 // getting useful data.
3578 SetNotWaitingForResponse();
3579
3580 // Try to find the navigation entry, which might not be the current one.
3581 // For example, it might be from a pending RVH for the pending entry.
3582 NavigationEntryImpl* entry = controller_.GetEntryWithPageID(
3583 rvh->GetSiteInstance(), page_id);
3584
3585 // We can handle title updates when we don't have an entry in
3586 // UpdateTitleForEntry, but only if the update is from the current RVH.
3587 // TODO(avi): Change to make decisions based on the RenderFrameHost.
3588 if (!entry && rvh != GetRenderViewHost())
3589 return;
3590
3591 // TODO(evan): make use of title_direction.
3592 // http://code.google.com/p/chromium/issues/detail?id=27094
3593 if (!UpdateTitleForEntry(entry, title))
3594 return;
3595
3596 // Broadcast notifications when the UI should be updated.
3597 if (entry == controller_.GetEntryAtOffset(0))
3598 NotifyNavigationStateChanged(INVALIDATE_TYPE_TITLE);
3599 }
3600
UpdateEncoding(RenderFrameHost * render_frame_host,const std::string & encoding)3601 void WebContentsImpl::UpdateEncoding(RenderFrameHost* render_frame_host,
3602 const std::string& encoding) {
3603 SetEncoding(encoding);
3604 }
3605
DocumentAvailableInMainFrame(RenderViewHost * render_view_host)3606 void WebContentsImpl::DocumentAvailableInMainFrame(
3607 RenderViewHost* render_view_host) {
3608 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3609 DocumentAvailableInMainFrame());
3610 }
RouteCloseEvent(RenderViewHost * rvh)3611 void WebContentsImpl::RouteCloseEvent(RenderViewHost* rvh) {
3612 // Tell the active RenderViewHost to run unload handlers and close, as long
3613 // as the request came from a RenderViewHost in the same BrowsingInstance.
3614 // In most cases, we receive this from a swapped out RenderViewHost.
3615 // It is possible to receive it from one that has just been swapped in,
3616 // in which case we might as well deliver the message anyway.
3617 if (rvh->GetSiteInstance()->IsRelatedSiteInstance(GetSiteInstance()))
3618 GetRenderViewHost()->ClosePage();
3619 }
3620
RouteMessageEvent(RenderViewHost * rvh,const ViewMsg_PostMessage_Params & params)3621 void WebContentsImpl::RouteMessageEvent(
3622 RenderViewHost* rvh,
3623 const ViewMsg_PostMessage_Params& params) {
3624 // Only deliver the message to the active RenderViewHost if the request
3625 // came from a RenderViewHost in the same BrowsingInstance or if this
3626 // WebContents is dedicated to a browser plugin guest.
3627 // Note: This check means that an embedder could theoretically receive a
3628 // postMessage from anyone (not just its own guests). However, this is
3629 // probably not a risk for apps since other pages won't have references
3630 // to App windows.
3631 if (!rvh->GetSiteInstance()->IsRelatedSiteInstance(GetSiteInstance()) &&
3632 !GetBrowserPluginGuest() && !GetBrowserPluginEmbedder())
3633 return;
3634
3635 ViewMsg_PostMessage_Params new_params(params);
3636
3637 if (!params.message_port_ids.empty()) {
3638 MessagePortMessageFilter* message_port_message_filter =
3639 static_cast<RenderProcessHostImpl*>(GetRenderProcessHost())
3640 ->message_port_message_filter();
3641 message_port_message_filter->UpdateMessagePortsWithNewRoutes(
3642 params.message_port_ids,
3643 &new_params.new_routing_ids);
3644 }
3645
3646 // If there is a source_routing_id, translate it to the routing ID for
3647 // the equivalent swapped out RVH in the target process. If we need
3648 // to create a swapped out RVH for the source tab, we create its opener
3649 // chain as well, since those will also be accessible to the target page.
3650 if (new_params.source_routing_id != MSG_ROUTING_NONE) {
3651 // Try to look up the WebContents for the source page.
3652 WebContentsImpl* source_contents = NULL;
3653 RenderViewHostImpl* source_rvh = RenderViewHostImpl::FromID(
3654 rvh->GetProcess()->GetID(), params.source_routing_id);
3655 if (source_rvh) {
3656 source_contents = static_cast<WebContentsImpl*>(
3657 source_rvh->GetDelegate()->GetAsWebContents());
3658 }
3659
3660 if (source_contents) {
3661 if (GetBrowserPluginGuest()) {
3662 // We create a swapped out RenderView for the embedder in the guest's
3663 // render process but we intentionally do not expose the embedder's
3664 // opener chain to it.
3665 new_params.source_routing_id =
3666 source_contents->CreateSwappedOutRenderView(GetSiteInstance());
3667 } else {
3668 new_params.source_routing_id =
3669 source_contents->CreateOpenerRenderViews(GetSiteInstance());
3670 }
3671 } else {
3672 // We couldn't find it, so don't pass a source frame.
3673 new_params.source_routing_id = MSG_ROUTING_NONE;
3674 }
3675 }
3676
3677 // In most cases, we receive this from a swapped out RenderViewHost.
3678 // It is possible to receive it from one that has just been swapped in,
3679 // in which case we might as well deliver the message anyway.
3680 Send(new ViewMsg_PostMessageEvent(GetRoutingID(), new_params));
3681 }
3682
AddMessageToConsole(int32 level,const base::string16 & message,int32 line_no,const base::string16 & source_id)3683 bool WebContentsImpl::AddMessageToConsole(int32 level,
3684 const base::string16& message,
3685 int32 line_no,
3686 const base::string16& source_id) {
3687 if (!delegate_)
3688 return false;
3689 return delegate_->AddMessageToConsole(this, level, message, line_no,
3690 source_id);
3691 }
3692
GetWebkitPrefs()3693 WebPreferences WebContentsImpl::GetWebkitPrefs() {
3694 // We want to base the page config off of the actual URL, rather than the
3695 // virtual URL.
3696 // TODO(nasko): Investigate how to remove the GetActiveEntry usage here,
3697 // as it is deprecated and can be out of sync with GetRenderViewHost().
3698 GURL url = controller_.GetActiveEntry()
3699 ? controller_.GetActiveEntry()->GetURL() : GURL::EmptyGURL();
3700
3701 return GetRenderManager()->current_host()->GetWebkitPrefs(url);
3702 }
3703
CreateSwappedOutRenderView(SiteInstance * instance)3704 int WebContentsImpl::CreateSwappedOutRenderView(
3705 SiteInstance* instance) {
3706 return GetRenderManager()->CreateRenderFrame(instance, MSG_ROUTING_NONE,
3707 true, true);
3708 }
3709
OnUserGesture()3710 void WebContentsImpl::OnUserGesture() {
3711 // Notify observers.
3712 FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidGetUserGesture());
3713
3714 ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get();
3715 if (rdh) // NULL in unittests.
3716 rdh->OnUserGesture(this);
3717 }
3718
OnIgnoredUIEvent()3719 void WebContentsImpl::OnIgnoredUIEvent() {
3720 // Notify observers.
3721 FOR_EACH_OBSERVER(WebContentsObserver, observers_, DidGetIgnoredUIEvent());
3722 }
3723
RendererUnresponsive(RenderViewHost * rvh,bool is_during_beforeunload,bool is_during_unload)3724 void WebContentsImpl::RendererUnresponsive(RenderViewHost* rvh,
3725 bool is_during_beforeunload,
3726 bool is_during_unload) {
3727 // Don't show hung renderer dialog for a swapped out RVH.
3728 if (rvh != GetRenderViewHost())
3729 return;
3730
3731 RenderViewHostImpl* rvhi = static_cast<RenderViewHostImpl*>(rvh);
3732
3733 // Ignore renderer unresponsive event if debugger is attached to the tab
3734 // since the event may be a result of the renderer sitting on a breakpoint.
3735 // See http://crbug.com/65458
3736 if (DevToolsAgentHost::IsDebuggerAttached(this))
3737 return;
3738
3739 if (is_during_beforeunload || is_during_unload) {
3740 // Hang occurred while firing the beforeunload/unload handler.
3741 // Pretend the handler fired so tab closing continues as if it had.
3742 rvhi->set_sudden_termination_allowed(true);
3743
3744 if (!GetRenderManager()->ShouldCloseTabOnUnresponsiveRenderer())
3745 return;
3746
3747 // If the tab hangs in the beforeunload/unload handler there's really
3748 // nothing we can do to recover. If the hang is in the beforeunload handler,
3749 // pretend the beforeunload listeners have all fired and allow the delegate
3750 // to continue closing; the user will not have the option of cancelling the
3751 // close. Otherwise, pretend the unload listeners have all fired and close
3752 // the tab.
3753 bool close = true;
3754 if (is_during_beforeunload && delegate_) {
3755 delegate_->BeforeUnloadFired(this, true, &close);
3756 }
3757 if (close)
3758 Close(rvh);
3759 return;
3760 }
3761
3762 if (!GetRenderViewHostImpl() || !GetRenderViewHostImpl()->IsRenderViewLive())
3763 return;
3764
3765 if (delegate_)
3766 delegate_->RendererUnresponsive(this);
3767 }
3768
RendererResponsive(RenderViewHost * render_view_host)3769 void WebContentsImpl::RendererResponsive(RenderViewHost* render_view_host) {
3770 if (delegate_)
3771 delegate_->RendererResponsive(this);
3772 }
3773
LoadStateChanged(const GURL & url,const net::LoadStateWithParam & load_state,uint64 upload_position,uint64 upload_size)3774 void WebContentsImpl::LoadStateChanged(
3775 const GURL& url,
3776 const net::LoadStateWithParam& load_state,
3777 uint64 upload_position,
3778 uint64 upload_size) {
3779 load_state_ = load_state;
3780 upload_position_ = upload_position;
3781 upload_size_ = upload_size;
3782 load_state_host_ = net::IDNToUnicode(url.host(),
3783 GetContentClient()->browser()->GetAcceptLangs(
3784 GetBrowserContext()));
3785 if (load_state_.state == net::LOAD_STATE_READING_RESPONSE)
3786 SetNotWaitingForResponse();
3787 if (IsLoading()) {
3788 NotifyNavigationStateChanged(INVALIDATE_TYPE_LOAD | INVALIDATE_TYPE_TAB);
3789 }
3790 }
3791
BeforeUnloadFiredFromRenderManager(bool proceed,const base::TimeTicks & proceed_time,bool * proceed_to_fire_unload)3792 void WebContentsImpl::BeforeUnloadFiredFromRenderManager(
3793 bool proceed, const base::TimeTicks& proceed_time,
3794 bool* proceed_to_fire_unload) {
3795 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
3796 BeforeUnloadFired(proceed_time));
3797 if (delegate_)
3798 delegate_->BeforeUnloadFired(this, proceed, proceed_to_fire_unload);
3799 // Note: |this| might be deleted at this point.
3800 }
3801
RenderProcessGoneFromRenderManager(RenderViewHost * render_view_host)3802 void WebContentsImpl::RenderProcessGoneFromRenderManager(
3803 RenderViewHost* render_view_host) {
3804 DCHECK(crashed_status_ != base::TERMINATION_STATUS_STILL_RUNNING);
3805 RenderViewTerminated(render_view_host, crashed_status_, crashed_error_code_);
3806 }
3807
UpdateRenderViewSizeForRenderManager()3808 void WebContentsImpl::UpdateRenderViewSizeForRenderManager() {
3809 // TODO(brettw) this is a hack. See WebContentsView::SizeContents.
3810 gfx::Size size = GetSizeForNewRenderView();
3811 // 0x0 isn't a valid window size (minimal window size is 1x1) but it may be
3812 // here during container initialization and normal window size will be set
3813 // later. In case of tab duplication this resizing to 0x0 prevents setting
3814 // normal size later so just ignore it.
3815 if (!size.IsEmpty())
3816 view_->SizeContents(size);
3817 }
3818
CancelModalDialogsForRenderManager()3819 void WebContentsImpl::CancelModalDialogsForRenderManager() {
3820 // We need to cancel modal dialogs when doing a process swap, since the load
3821 // deferrer would prevent us from swapping out.
3822 if (dialog_manager_)
3823 dialog_manager_->CancelActiveAndPendingDialogs(this);
3824 }
3825
NotifySwappedFromRenderManager(RenderViewHost * old_host,RenderViewHost * new_host)3826 void WebContentsImpl::NotifySwappedFromRenderManager(RenderViewHost* old_host,
3827 RenderViewHost* new_host) {
3828 NotifySwapped(old_host, new_host);
3829
3830 // Make sure the visible RVH reflects the new delegate's preferences.
3831 if (delegate_)
3832 view_->SetOverscrollControllerEnabled(CanOverscrollContent());
3833
3834 view_->RenderViewSwappedIn(new_host);
3835 }
3836
CreateOpenerRenderViewsForRenderManager(SiteInstance * instance)3837 int WebContentsImpl::CreateOpenerRenderViewsForRenderManager(
3838 SiteInstance* instance) {
3839 if (!opener_)
3840 return MSG_ROUTING_NONE;
3841
3842 // Recursively create RenderViews for anything else in the opener chain.
3843 return opener_->CreateOpenerRenderViews(instance);
3844 }
3845
CreateOpenerRenderViews(SiteInstance * instance)3846 int WebContentsImpl::CreateOpenerRenderViews(SiteInstance* instance) {
3847 int opener_route_id = MSG_ROUTING_NONE;
3848
3849 // If this tab has an opener, ensure it has a RenderView in the given
3850 // SiteInstance as well.
3851 if (opener_)
3852 opener_route_id = opener_->CreateOpenerRenderViews(instance);
3853
3854 // If any of the renderers (current, pending, or swapped out) for this
3855 // WebContents has the same SiteInstance, use it.
3856 if (GetRenderManager()->current_host()->GetSiteInstance() == instance)
3857 return GetRenderManager()->current_host()->GetRoutingID();
3858
3859 if (GetRenderManager()->pending_render_view_host() &&
3860 GetRenderManager()->pending_render_view_host()->GetSiteInstance() ==
3861 instance)
3862 return GetRenderManager()->pending_render_view_host()->GetRoutingID();
3863
3864 RenderViewHostImpl* rvh = GetRenderManager()->GetSwappedOutRenderViewHost(
3865 instance);
3866 if (rvh)
3867 return rvh->GetRoutingID();
3868
3869 // Create a swapped out RenderView in the given SiteInstance if none exists,
3870 // setting its opener to the given route_id. Return the new view's route_id.
3871 return GetRenderManager()->CreateRenderFrame(instance, opener_route_id,
3872 true, true);
3873 }
3874
GetControllerForRenderManager()3875 NavigationControllerImpl& WebContentsImpl::GetControllerForRenderManager() {
3876 return GetController();
3877 }
3878
CreateWebUIForRenderManager(const GURL & url)3879 WebUIImpl* WebContentsImpl::CreateWebUIForRenderManager(const GURL& url) {
3880 return static_cast<WebUIImpl*>(CreateWebUI(url));
3881 }
3882
3883 NavigationEntry*
GetLastCommittedNavigationEntryForRenderManager()3884 WebContentsImpl::GetLastCommittedNavigationEntryForRenderManager() {
3885 return controller_.GetLastCommittedEntry();
3886 }
3887
CreateRenderViewForRenderManager(RenderViewHost * render_view_host,int opener_route_id,int proxy_routing_id,bool for_main_frame)3888 bool WebContentsImpl::CreateRenderViewForRenderManager(
3889 RenderViewHost* render_view_host,
3890 int opener_route_id,
3891 int proxy_routing_id,
3892 bool for_main_frame) {
3893 TRACE_EVENT0("browser", "WebContentsImpl::CreateRenderViewForRenderManager");
3894 // Can be NULL during tests.
3895 RenderWidgetHostViewBase* rwh_view;
3896 // TODO(kenrb): RenderWidgetHostViewChildFrame special casing is temporary
3897 // until RenderWidgetHost is attached to RenderFrameHost. We need to special
3898 // case this because RWH is still a base class of RenderViewHost, and child
3899 // frame RWHVs are unique in that they do not have their own WebContents.
3900 if (!for_main_frame) {
3901 RenderWidgetHostViewChildFrame* rwh_view_child =
3902 new RenderWidgetHostViewChildFrame(render_view_host);
3903 rwh_view = rwh_view_child;
3904 } else {
3905 rwh_view = view_->CreateViewForWidget(render_view_host);
3906 }
3907
3908 // Now that the RenderView has been created, we need to tell it its size.
3909 if (rwh_view)
3910 rwh_view->SetSize(GetSizeForNewRenderView());
3911
3912 // Make sure we use the correct starting page_id in the new RenderView.
3913 UpdateMaxPageIDIfNecessary(render_view_host);
3914 int32 max_page_id =
3915 GetMaxPageIDForSiteInstance(render_view_host->GetSiteInstance());
3916
3917 if (!static_cast<RenderViewHostImpl*>(
3918 render_view_host)->CreateRenderView(base::string16(),
3919 opener_route_id,
3920 proxy_routing_id,
3921 max_page_id,
3922 created_with_opener_)) {
3923 return false;
3924 }
3925
3926 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
3927 // Force a ViewMsg_Resize to be sent, needed to make plugins show up on
3928 // linux. See crbug.com/83941.
3929 if (rwh_view) {
3930 if (RenderWidgetHost* render_widget_host = rwh_view->GetRenderWidgetHost())
3931 render_widget_host->WasResized();
3932 }
3933 #endif
3934
3935 return true;
3936 }
3937
3938 #if defined(OS_ANDROID)
3939
3940 base::android::ScopedJavaLocalRef<jobject>
GetJavaWebContents()3941 WebContentsImpl::GetJavaWebContents() {
3942 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3943
3944 WebContentsAndroid* web_contents_android =
3945 static_cast<WebContentsAndroid*>(GetUserData(kWebContentsAndroidKey));
3946 if (!web_contents_android) {
3947 web_contents_android = new WebContentsAndroid(this);
3948 SetUserData(kWebContentsAndroidKey, web_contents_android);
3949 }
3950 return web_contents_android->GetJavaObject();
3951 }
3952
CreateRenderViewForInitialEmptyDocument()3953 bool WebContentsImpl::CreateRenderViewForInitialEmptyDocument() {
3954 return CreateRenderViewForRenderManager(GetRenderViewHost(),
3955 MSG_ROUTING_NONE,
3956 MSG_ROUTING_NONE,
3957 true);
3958 }
3959
3960 #elif defined(OS_MACOSX)
3961
SetAllowOverlappingViews(bool overlapping)3962 void WebContentsImpl::SetAllowOverlappingViews(bool overlapping) {
3963 view_->SetAllowOverlappingViews(overlapping);
3964 }
3965
GetAllowOverlappingViews()3966 bool WebContentsImpl::GetAllowOverlappingViews() {
3967 return view_->GetAllowOverlappingViews();
3968 }
3969
SetOverlayView(WebContents * overlay,const gfx::Point & offset)3970 void WebContentsImpl::SetOverlayView(WebContents* overlay,
3971 const gfx::Point& offset) {
3972 view_->SetOverlayView(static_cast<WebContentsImpl*>(overlay)->GetView(),
3973 offset);
3974 }
3975
RemoveOverlayView()3976 void WebContentsImpl::RemoveOverlayView() {
3977 view_->RemoveOverlayView();
3978 }
3979
3980 #endif
3981
OnDialogClosed(int render_process_id,int render_frame_id,IPC::Message * reply_msg,bool dialog_was_suppressed,bool success,const base::string16 & user_input)3982 void WebContentsImpl::OnDialogClosed(int render_process_id,
3983 int render_frame_id,
3984 IPC::Message* reply_msg,
3985 bool dialog_was_suppressed,
3986 bool success,
3987 const base::string16& user_input) {
3988 RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID(render_process_id,
3989 render_frame_id);
3990 last_dialog_suppressed_ = dialog_was_suppressed;
3991
3992 if (is_showing_before_unload_dialog_ && !success) {
3993 // If a beforeunload dialog is canceled, we need to stop the throbber from
3994 // spinning, since we forced it to start spinning in Navigate.
3995 if (rfh)
3996 DidStopLoading(rfh);
3997 controller_.DiscardNonCommittedEntries();
3998
3999 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
4000 BeforeUnloadDialogCancelled());
4001 }
4002
4003 is_showing_before_unload_dialog_ = false;
4004 if (rfh) {
4005 rfh->JavaScriptDialogClosed(reply_msg, success, user_input,
4006 dialog_was_suppressed);
4007 } else {
4008 // Don't leak the sync IPC reply if the RFH or process is gone.
4009 delete reply_msg;
4010 }
4011 }
4012
SetEncoding(const std::string & encoding)4013 void WebContentsImpl::SetEncoding(const std::string& encoding) {
4014 if (encoding == last_reported_encoding_)
4015 return;
4016 last_reported_encoding_ = encoding;
4017
4018 canonical_encoding_ = GetContentClient()->browser()->
4019 GetCanonicalEncodingNameByAliasName(encoding);
4020 }
4021
CreateViewAndSetSizeForRVH(RenderViewHost * rvh)4022 void WebContentsImpl::CreateViewAndSetSizeForRVH(RenderViewHost* rvh) {
4023 RenderWidgetHostViewBase* rwh_view = view_->CreateViewForWidget(rvh);
4024 // Can be NULL during tests.
4025 if (rwh_view)
4026 rwh_view->SetSize(GetContainerBounds().size());
4027 }
4028
IsHidden()4029 bool WebContentsImpl::IsHidden() {
4030 return capturer_count_ == 0 && !should_normally_be_visible_;
4031 }
4032
GetRenderManager() const4033 RenderFrameHostManager* WebContentsImpl::GetRenderManager() const {
4034 return frame_tree_.root()->render_manager();
4035 }
4036
GetRenderViewHostImpl()4037 RenderViewHostImpl* WebContentsImpl::GetRenderViewHostImpl() {
4038 return static_cast<RenderViewHostImpl*>(GetRenderViewHost());
4039 }
4040
GetBrowserPluginGuest() const4041 BrowserPluginGuest* WebContentsImpl::GetBrowserPluginGuest() const {
4042 return browser_plugin_guest_.get();
4043 }
4044
SetBrowserPluginGuest(BrowserPluginGuest * guest)4045 void WebContentsImpl::SetBrowserPluginGuest(BrowserPluginGuest* guest) {
4046 CHECK(!browser_plugin_guest_);
4047 browser_plugin_guest_.reset(guest);
4048 }
4049
GetBrowserPluginEmbedder() const4050 BrowserPluginEmbedder* WebContentsImpl::GetBrowserPluginEmbedder() const {
4051 return browser_plugin_embedder_.get();
4052 }
4053
ClearPowerSaveBlockers(RenderFrameHost * render_frame_host)4054 void WebContentsImpl::ClearPowerSaveBlockers(
4055 RenderFrameHost* render_frame_host) {
4056 STLDeleteValues(&power_save_blockers_[render_frame_host]);
4057 power_save_blockers_.erase(render_frame_host);
4058 }
4059
ClearAllPowerSaveBlockers()4060 void WebContentsImpl::ClearAllPowerSaveBlockers() {
4061 for (PowerSaveBlockerMap::iterator i(power_save_blockers_.begin());
4062 i != power_save_blockers_.end(); ++i)
4063 STLDeleteValues(&power_save_blockers_[i->first]);
4064 power_save_blockers_.clear();
4065 }
4066
GetSizeForNewRenderView()4067 gfx::Size WebContentsImpl::GetSizeForNewRenderView() {
4068 gfx::Size size;
4069 if (delegate_)
4070 size = delegate_->GetSizeForNewRenderView(this);
4071 if (size.IsEmpty())
4072 size = GetContainerBounds().size();
4073 return size;
4074 }
4075
OnFrameRemoved(RenderViewHostImpl * render_view_host,int frame_routing_id)4076 void WebContentsImpl::OnFrameRemoved(
4077 RenderViewHostImpl* render_view_host,
4078 int frame_routing_id) {
4079 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
4080 FrameDetached(render_view_host, frame_routing_id));
4081 }
4082
OnPreferredSizeChanged(const gfx::Size & old_size)4083 void WebContentsImpl::OnPreferredSizeChanged(const gfx::Size& old_size) {
4084 if (!delegate_)
4085 return;
4086 const gfx::Size new_size = GetPreferredSize();
4087 if (new_size != old_size)
4088 delegate_->UpdatePreferredSize(this, new_size);
4089 }
4090
4091 } // namespace content
4092