render_frame_impl.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
1// Copyright 2013 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/renderer/render_frame_impl.h" 6 7#include <map> 8#include <string> 9 10#include "base/auto_reset.h" 11#include "base/command_line.h" 12#include "base/debug/alias.h" 13#include "base/debug/asan_invalid_access.h" 14#include "base/debug/dump_without_crashing.h" 15#include "base/i18n/char_iterator.h" 16#include "base/metrics/histogram.h" 17#include "base/process/kill.h" 18#include "base/process/process.h" 19#include "base/strings/string16.h" 20#include "base/strings/utf_string_conversions.h" 21#include "base/time/time.h" 22#include "content/child/appcache/appcache_dispatcher.h" 23#include "content/child/plugin_messages.h" 24#include "content/child/quota_dispatcher.h" 25#include "content/child/request_extra_data.h" 26#include "content/child/service_worker/service_worker_network_provider.h" 27#include "content/child/service_worker/web_service_worker_provider_impl.h" 28#include "content/child/web_socket_stream_handle_impl.h" 29#include "content/child/web_url_request_util.h" 30#include "content/child/webmessageportchannel_impl.h" 31#include "content/child/websocket_bridge.h" 32#include "content/child/weburlresponse_extradata_impl.h" 33#include "content/common/clipboard_messages.h" 34#include "content/common/frame_messages.h" 35#include "content/common/input_messages.h" 36#include "content/common/service_worker/service_worker_types.h" 37#include "content/common/socket_stream_handle_data.h" 38#include "content/common/swapped_out_messages.h" 39#include "content/common/view_messages.h" 40#include "content/public/common/bindings_policy.h" 41#include "content/public/common/content_constants.h" 42#include "content/public/common/content_switches.h" 43#include "content/public/common/context_menu_params.h" 44#include "content/public/common/url_constants.h" 45#include "content/public/common/url_utils.h" 46#include "content/public/renderer/content_renderer_client.h" 47#include "content/public/renderer/context_menu_client.h" 48#include "content/public/renderer/document_state.h" 49#include "content/public/renderer/navigation_state.h" 50#include "content/public/renderer/render_frame_observer.h" 51#include "content/renderer/accessibility/renderer_accessibility.h" 52#include "content/renderer/accessibility/renderer_accessibility_complete.h" 53#include "content/renderer/accessibility/renderer_accessibility_focus_only.h" 54#include "content/renderer/browser_plugin/browser_plugin.h" 55#include "content/renderer/browser_plugin/browser_plugin_manager.h" 56#include "content/renderer/child_frame_compositing_helper.h" 57#include "content/renderer/context_menu_params_builder.h" 58#include "content/renderer/devtools/devtools_agent.h" 59#include "content/renderer/dom_automation_controller.h" 60#include "content/renderer/dom_utils.h" 61#include "content/renderer/geolocation_dispatcher.h" 62#include "content/renderer/history_controller.h" 63#include "content/renderer/history_serialization.h" 64#include "content/renderer/image_loading_helper.h" 65#include "content/renderer/ime_event_guard.h" 66#include "content/renderer/internal_document_state_data.h" 67#include "content/renderer/media/audio_renderer_mixer_manager.h" 68#include "content/renderer/media/media_stream_dispatcher.h" 69#include "content/renderer/media/media_stream_impl.h" 70#include "content/renderer/media/media_stream_renderer_factory.h" 71#include "content/renderer/media/midi_dispatcher.h" 72#include "content/renderer/media/render_media_log.h" 73#include "content/renderer/media/webcontentdecryptionmodule_impl.h" 74#include "content/renderer/media/webmediaplayer_impl.h" 75#include "content/renderer/media/webmediaplayer_ms.h" 76#include "content/renderer/media/webmediaplayer_params.h" 77#include "content/renderer/notification_permission_dispatcher.h" 78#include "content/renderer/notification_provider.h" 79#include "content/renderer/npapi/plugin_channel_host.h" 80#include "content/renderer/push_messaging_dispatcher.h" 81#include "content/renderer/render_frame_proxy.h" 82#include "content/renderer/render_process.h" 83#include "content/renderer/render_thread_impl.h" 84#include "content/renderer/render_view_impl.h" 85#include "content/renderer/render_widget_fullscreen_pepper.h" 86#include "content/renderer/renderer_webapplicationcachehost_impl.h" 87#include "content/renderer/renderer_webcolorchooser_impl.h" 88#include "content/renderer/screen_orientation/screen_orientation_dispatcher.h" 89#include "content/renderer/shared_worker_repository.h" 90#include "content/renderer/v8_value_converter_impl.h" 91#include "content/renderer/websharedworker_proxy.h" 92#include "media/base/audio_renderer_mixer_input.h" 93#include "net/base/data_url.h" 94#include "net/base/net_errors.h" 95#include "net/base/registry_controlled_domains/registry_controlled_domain.h" 96#include "net/http/http_util.h" 97#include "third_party/WebKit/public/platform/WebStorageQuotaCallbacks.h" 98#include "third_party/WebKit/public/platform/WebString.h" 99#include "third_party/WebKit/public/platform/WebURL.h" 100#include "third_party/WebKit/public/platform/WebURLError.h" 101#include "third_party/WebKit/public/platform/WebURLResponse.h" 102#include "third_party/WebKit/public/platform/WebVector.h" 103#include "third_party/WebKit/public/web/WebColorSuggestion.h" 104#include "third_party/WebKit/public/web/WebDocument.h" 105#include "third_party/WebKit/public/web/WebGlyphCache.h" 106#include "third_party/WebKit/public/web/WebLocalFrame.h" 107#include "third_party/WebKit/public/web/WebMediaStreamRegistry.h" 108#include "third_party/WebKit/public/web/WebNavigationPolicy.h" 109#include "third_party/WebKit/public/web/WebPlugin.h" 110#include "third_party/WebKit/public/web/WebPluginParams.h" 111#include "third_party/WebKit/public/web/WebRange.h" 112#include "third_party/WebKit/public/web/WebScriptSource.h" 113#include "third_party/WebKit/public/web/WebSearchableFormData.h" 114#include "third_party/WebKit/public/web/WebSecurityOrigin.h" 115#include "third_party/WebKit/public/web/WebSecurityPolicy.h" 116#include "third_party/WebKit/public/web/WebSurroundingText.h" 117#include "third_party/WebKit/public/web/WebUserGestureIndicator.h" 118#include "third_party/WebKit/public/web/WebView.h" 119 120#if defined(ENABLE_PLUGINS) 121#include "content/renderer/npapi/webplugin_impl.h" 122#include "content/renderer/pepper/pepper_browser_connection.h" 123#include "content/renderer/pepper/pepper_plugin_instance_impl.h" 124#include "content/renderer/pepper/pepper_webplugin_impl.h" 125#include "content/renderer/pepper/plugin_module.h" 126#endif 127 128#if defined(ENABLE_WEBRTC) 129#include "content/renderer/media/rtc_peer_connection_handler.h" 130#endif 131 132#if defined(OS_ANDROID) 133#include <cpu-features.h> 134 135#include "content/common/gpu/client/context_provider_command_buffer.h" 136#include "content/renderer/android/synchronous_compositor_factory.h" 137#include "content/renderer/java/gin_java_bridge_dispatcher.h" 138#include "content/renderer/media/android/renderer_media_player_manager.h" 139#include "content/renderer/media/android/stream_texture_factory_impl.h" 140#include "content/renderer/media/android/webmediaplayer_android.h" 141#endif 142 143#if defined(ENABLE_BROWSER_CDMS) 144#include "content/renderer/media/crypto/renderer_cdm_manager.h" 145#endif 146 147using blink::WebContextMenuData; 148using blink::WebData; 149using blink::WebDataSource; 150using blink::WebDocument; 151using blink::WebElement; 152using blink::WebExternalPopupMenu; 153using blink::WebExternalPopupMenuClient; 154using blink::WebFrame; 155using blink::WebHistoryItem; 156using blink::WebHTTPBody; 157using blink::WebLocalFrame; 158using blink::WebMediaPlayer; 159using blink::WebMediaPlayerClient; 160using blink::WebNavigationPolicy; 161using blink::WebNavigationType; 162using blink::WebNode; 163using blink::WebPluginParams; 164using blink::WebPopupMenuInfo; 165using blink::WebRange; 166using blink::WebReferrerPolicy; 167using blink::WebScriptSource; 168using blink::WebSearchableFormData; 169using blink::WebSecurityOrigin; 170using blink::WebSecurityPolicy; 171using blink::WebServiceWorkerProvider; 172using blink::WebStorageQuotaCallbacks; 173using blink::WebString; 174using blink::WebURL; 175using blink::WebURLError; 176using blink::WebURLRequest; 177using blink::WebURLResponse; 178using blink::WebUserGestureIndicator; 179using blink::WebVector; 180using blink::WebView; 181using base::Time; 182using base::TimeDelta; 183 184namespace content { 185 186namespace { 187 188const char kDefaultAcceptHeader[] = 189 "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/" 190 "*;q=0.8"; 191const char kAcceptHeader[] = "Accept"; 192 193const size_t kExtraCharsBeforeAndAfterSelection = 100; 194 195typedef std::map<int, RenderFrameImpl*> RoutingIDFrameMap; 196static base::LazyInstance<RoutingIDFrameMap> g_routing_id_frame_map = 197 LAZY_INSTANCE_INITIALIZER; 198 199typedef std::map<blink::WebFrame*, RenderFrameImpl*> FrameMap; 200base::LazyInstance<FrameMap> g_frame_map = LAZY_INSTANCE_INITIALIZER; 201 202int64 ExtractPostId(const WebHistoryItem& item) { 203 if (item.isNull()) 204 return -1; 205 206 if (item.httpBody().isNull()) 207 return -1; 208 209 return item.httpBody().identifier(); 210} 211 212WebURLResponseExtraDataImpl* GetExtraDataFromResponse( 213 const WebURLResponse& response) { 214 return static_cast<WebURLResponseExtraDataImpl*>(response.extraData()); 215} 216 217void GetRedirectChain(WebDataSource* ds, std::vector<GURL>* result) { 218 // Replace any occurrences of swappedout:// with about:blank. 219 const WebURL& blank_url = GURL(url::kAboutBlankURL); 220 WebVector<WebURL> urls; 221 ds->redirectChain(urls); 222 result->reserve(urls.size()); 223 for (size_t i = 0; i < urls.size(); ++i) { 224 if (urls[i] != GURL(kSwappedOutURL)) 225 result->push_back(urls[i]); 226 else 227 result->push_back(blank_url); 228 } 229} 230 231// Returns the original request url. If there is no redirect, the original 232// url is the same as ds->request()->url(). If the WebDataSource belongs to a 233// frame was loaded by loadData, the original url will be ds->unreachableURL() 234static GURL GetOriginalRequestURL(WebDataSource* ds) { 235 // WebDataSource has unreachable URL means that the frame is loaded through 236 // blink::WebFrame::loadData(), and the base URL will be in the redirect 237 // chain. However, we never visited the baseURL. So in this case, we should 238 // use the unreachable URL as the original URL. 239 if (ds->hasUnreachableURL()) 240 return ds->unreachableURL(); 241 242 std::vector<GURL> redirects; 243 GetRedirectChain(ds, &redirects); 244 if (!redirects.empty()) 245 return redirects.at(0); 246 247 return ds->originalRequest().url(); 248} 249 250NOINLINE static void CrashIntentionally() { 251 // NOTE(shess): Crash directly rather than using NOTREACHED() so 252 // that the signature is easier to triage in crash reports. 253 volatile int* zero = NULL; 254 *zero = 0; 255} 256 257#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN) 258NOINLINE static void MaybeTriggerAsanError(const GURL& url) { 259 // NOTE(rogerm): We intentionally perform an invalid heap access here in 260 // order to trigger an Address Sanitizer (ASAN) error report. 261 const char kCrashDomain[] = "crash"; 262 const char kHeapOverflow[] = "/heap-overflow"; 263 const char kHeapUnderflow[] = "/heap-underflow"; 264 const char kUseAfterFree[] = "/use-after-free"; 265#if defined(SYZYASAN) 266 const char kCorruptHeapBlock[] = "/corrupt-heap-block"; 267 const char kCorruptHeap[] = "/corrupt-heap"; 268#endif 269 270 if (!url.DomainIs(kCrashDomain, sizeof(kCrashDomain) - 1)) 271 return; 272 273 if (!url.has_path()) 274 return; 275 276 std::string crash_type(url.path()); 277 if (crash_type == kHeapOverflow) { 278 base::debug::AsanHeapOverflow(); 279 } else if (crash_type == kHeapUnderflow ) { 280 base::debug::AsanHeapUnderflow(); 281 } else if (crash_type == kUseAfterFree) { 282 base::debug::AsanHeapUseAfterFree(); 283#if defined(SYZYASAN) 284 } else if (crash_type == kCorruptHeapBlock) { 285 base::debug::AsanCorruptHeapBlock(); 286 } else if (crash_type == kCorruptHeap) { 287 base::debug::AsanCorruptHeap(); 288#endif 289 } 290} 291#endif // ADDRESS_SANITIZER || SYZYASAN 292 293static void MaybeHandleDebugURL(const GURL& url) { 294 if (!url.SchemeIs(kChromeUIScheme)) 295 return; 296 if (url == GURL(kChromeUICrashURL)) { 297 CrashIntentionally(); 298 } else if (url == GURL(kChromeUIDumpURL)) { 299 // This URL will only correctly create a crash dump file if content is 300 // hosted in a process that has correctly called 301 // base::debug::SetDumpWithoutCrashingFunction. Refer to the documentation 302 // of base::debug::DumpWithoutCrashing for more details. 303 base::debug::DumpWithoutCrashing(); 304 } else if (url == GURL(kChromeUIKillURL)) { 305 base::KillProcess(base::GetCurrentProcessHandle(), 1, false); 306 } else if (url == GURL(kChromeUIHangURL)) { 307 for (;;) { 308 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); 309 } 310 } else if (url == GURL(kChromeUIShorthangURL)) { 311 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(20)); 312 } 313 314#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN) 315 MaybeTriggerAsanError(url); 316#endif // ADDRESS_SANITIZER || SYZYASAN 317} 318 319// Returns false unless this is a top-level navigation. 320static bool IsTopLevelNavigation(WebFrame* frame) { 321 return frame->parent() == NULL; 322} 323 324// Returns false unless this is a top-level navigation that crosses origins. 325static bool IsNonLocalTopLevelNavigation(const GURL& url, 326 WebFrame* frame, 327 WebNavigationType type, 328 bool is_form_post) { 329 if (!IsTopLevelNavigation(frame)) 330 return false; 331 332 // Navigations initiated within Webkit are not sent out to the external host 333 // in the following cases. 334 // 1. The url scheme is not http/https 335 // 2. The origin of the url and the opener is the same in which case the 336 // opener relationship is maintained. 337 // 3. Reloads/form submits/back forward navigations 338 if (!url.SchemeIs(url::kHttpScheme) && !url.SchemeIs(url::kHttpsScheme)) 339 return false; 340 341 if (type != blink::WebNavigationTypeReload && 342 type != blink::WebNavigationTypeBackForward && !is_form_post) { 343 // The opener relationship between the new window and the parent allows the 344 // new window to script the parent and vice versa. This is not allowed if 345 // the origins of the two domains are different. This can be treated as a 346 // top level navigation and routed back to the host. 347 blink::WebFrame* opener = frame->opener(); 348 if (!opener) 349 return true; 350 351 if (url.GetOrigin() != GURL(opener->document().url()).GetOrigin()) 352 return true; 353 } 354 return false; 355} 356 357} // namespace 358 359static RenderFrameImpl* (*g_create_render_frame_impl)(RenderViewImpl*, int32) = 360 NULL; 361 362// static 363RenderFrameImpl* RenderFrameImpl::Create(RenderViewImpl* render_view, 364 int32 routing_id) { 365 DCHECK(routing_id != MSG_ROUTING_NONE); 366 367 if (g_create_render_frame_impl) 368 return g_create_render_frame_impl(render_view, routing_id); 369 else 370 return new RenderFrameImpl(render_view, routing_id); 371} 372 373// static 374RenderFrameImpl* RenderFrameImpl::FromRoutingID(int32 routing_id) { 375 RoutingIDFrameMap::iterator iter = 376 g_routing_id_frame_map.Get().find(routing_id); 377 if (iter != g_routing_id_frame_map.Get().end()) 378 return iter->second; 379 return NULL; 380} 381 382// static 383void RenderFrameImpl::CreateFrame(int routing_id, int parent_routing_id) { 384 // TODO(nasko): For now, this message is only sent for subframes, as the 385 // top level frame is created when the RenderView is created through the 386 // ViewMsg_New IPC. 387 CHECK_NE(MSG_ROUTING_NONE, parent_routing_id); 388 389 RenderFrameProxy* proxy = RenderFrameProxy::FromRoutingID(parent_routing_id); 390 391 // If the browser is sending a valid parent routing id, it should already be 392 // created and registered. 393 CHECK(proxy); 394 blink::WebRemoteFrame* parent_web_frame = proxy->web_frame(); 395 396 // Create the RenderFrame and WebLocalFrame, linking the two. 397 RenderFrameImpl* render_frame = 398 RenderFrameImpl::Create(proxy->render_view(), routing_id); 399 blink::WebLocalFrame* web_frame = 400 parent_web_frame->createLocalChild("", render_frame); 401 render_frame->SetWebFrame(web_frame); 402 render_frame->Initialize(); 403} 404 405// static 406RenderFrame* RenderFrame::FromWebFrame(blink::WebFrame* web_frame) { 407 return RenderFrameImpl::FromWebFrame(web_frame); 408} 409 410// static 411RenderFrameImpl* RenderFrameImpl::FromWebFrame(blink::WebFrame* web_frame) { 412 FrameMap::iterator iter = g_frame_map.Get().find(web_frame); 413 if (iter != g_frame_map.Get().end()) 414 return iter->second; 415 return NULL; 416} 417 418// static 419void RenderFrameImpl::InstallCreateHook( 420 RenderFrameImpl* (*create_render_frame_impl)(RenderViewImpl*, int32)) { 421 CHECK(!g_create_render_frame_impl); 422 g_create_render_frame_impl = create_render_frame_impl; 423} 424 425// RenderFrameImpl ---------------------------------------------------------- 426RenderFrameImpl::RenderFrameImpl(RenderViewImpl* render_view, int routing_id) 427 : frame_(NULL), 428 render_view_(render_view->AsWeakPtr()), 429 routing_id_(routing_id), 430 is_swapped_out_(false), 431 render_frame_proxy_(NULL), 432 is_detaching_(false), 433 cookie_jar_(this), 434 selection_text_offset_(0), 435 selection_range_(gfx::Range::InvalidRange()), 436 handling_select_range_(false), 437 notification_permission_dispatcher_(NULL), 438 notification_provider_(NULL), 439 web_user_media_client_(NULL), 440 midi_dispatcher_(NULL), 441#if defined(OS_ANDROID) 442 media_player_manager_(NULL), 443#endif 444#if defined(ENABLE_BROWSER_CDMS) 445 cdm_manager_(NULL), 446#endif 447#if defined(VIDEO_HOLE) 448 contains_media_player_(false), 449#endif 450 geolocation_dispatcher_(NULL), 451 push_messaging_dispatcher_(NULL), 452 screen_orientation_dispatcher_(NULL), 453 accessibility_mode_(AccessibilityModeOff), 454 renderer_accessibility_(NULL), 455 weak_factory_(this) { 456 std::pair<RoutingIDFrameMap::iterator, bool> result = 457 g_routing_id_frame_map.Get().insert(std::make_pair(routing_id_, this)); 458 CHECK(result.second) << "Inserting a duplicate item."; 459 460 RenderThread::Get()->AddRoute(routing_id_, this); 461 462 render_view_->RegisterRenderFrame(this); 463 464#if defined(OS_ANDROID) 465 new GinJavaBridgeDispatcher(this); 466#endif 467 468#if defined(ENABLE_NOTIFICATIONS) 469 notification_provider_ = new NotificationProvider(this); 470#endif 471} 472 473RenderFrameImpl::~RenderFrameImpl() { 474 FOR_EACH_OBSERVER(RenderFrameObserver, observers_, RenderFrameGone()); 475 FOR_EACH_OBSERVER(RenderFrameObserver, observers_, OnDestruct()); 476 477#if defined(VIDEO_HOLE) 478 if (contains_media_player_) 479 render_view_->UnregisterVideoHoleFrame(this); 480#endif 481 482 render_view_->UnregisterRenderFrame(this); 483 g_routing_id_frame_map.Get().erase(routing_id_); 484 RenderThread::Get()->RemoveRoute(routing_id_); 485} 486 487void RenderFrameImpl::SetWebFrame(blink::WebLocalFrame* web_frame) { 488 DCHECK(!frame_); 489 490 std::pair<FrameMap::iterator, bool> result = g_frame_map.Get().insert( 491 std::make_pair(web_frame, this)); 492 CHECK(result.second) << "Inserting a duplicate item."; 493 494 frame_ = web_frame; 495} 496 497void RenderFrameImpl::Initialize() { 498#if defined(ENABLE_PLUGINS) 499 new PepperBrowserConnection(this); 500#endif 501 new SharedWorkerRepository(this); 502 503 if (!frame_->parent()) 504 new ImageLoadingHelper(this); 505 506 // We delay calling this until we have the WebFrame so that any observer or 507 // embedder can call GetWebFrame on any RenderFrame. 508 GetContentClient()->renderer()->RenderFrameCreated(this); 509} 510 511RenderWidget* RenderFrameImpl::GetRenderWidget() { 512 return render_view_.get(); 513} 514 515#if defined(ENABLE_PLUGINS) 516void RenderFrameImpl::PepperPluginCreated(RendererPpapiHost* host) { 517 FOR_EACH_OBSERVER(RenderFrameObserver, observers_, 518 DidCreatePepperPlugin(host)); 519} 520 521void RenderFrameImpl::PepperDidChangeCursor( 522 PepperPluginInstanceImpl* instance, 523 const blink::WebCursorInfo& cursor) { 524 // Update the cursor appearance immediately if the requesting plugin is the 525 // one which receives the last mouse event. Otherwise, the new cursor won't be 526 // picked up until the plugin gets the next input event. That is bad if, e.g., 527 // the plugin would like to set an invisible cursor when there isn't any user 528 // input for a while. 529 if (instance == render_view_->pepper_last_mouse_event_target()) 530 GetRenderWidget()->didChangeCursor(cursor); 531} 532 533void RenderFrameImpl::PepperDidReceiveMouseEvent( 534 PepperPluginInstanceImpl* instance) { 535 render_view_->set_pepper_last_mouse_event_target(instance); 536} 537 538void RenderFrameImpl::PepperTextInputTypeChanged( 539 PepperPluginInstanceImpl* instance) { 540 if (instance != render_view_->focused_pepper_plugin()) 541 return; 542 543 GetRenderWidget()->UpdateTextInputState( 544 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME); 545 if (renderer_accessibility()) 546 renderer_accessibility()->FocusedNodeChanged(WebNode()); 547} 548 549void RenderFrameImpl::PepperCaretPositionChanged( 550 PepperPluginInstanceImpl* instance) { 551 if (instance != render_view_->focused_pepper_plugin()) 552 return; 553 GetRenderWidget()->UpdateSelectionBounds(); 554} 555 556void RenderFrameImpl::PepperCancelComposition( 557 PepperPluginInstanceImpl* instance) { 558 if (instance != render_view_->focused_pepper_plugin()) 559 return; 560 Send(new InputHostMsg_ImeCancelComposition(render_view_->GetRoutingID()));; 561#if defined(OS_MACOSX) || defined(USE_AURA) 562 GetRenderWidget()->UpdateCompositionInfo(true); 563#endif 564} 565 566void RenderFrameImpl::PepperSelectionChanged( 567 PepperPluginInstanceImpl* instance) { 568 if (instance != render_view_->focused_pepper_plugin()) 569 return; 570 SyncSelectionIfRequired(); 571} 572 573RenderWidgetFullscreenPepper* RenderFrameImpl::CreatePepperFullscreenContainer( 574 PepperPluginInstanceImpl* plugin) { 575 GURL active_url; 576 if (render_view_->webview() && render_view_->webview()->mainFrame()) 577 active_url = GURL(render_view_->webview()->mainFrame()->document().url()); 578 RenderWidgetFullscreenPepper* widget = RenderWidgetFullscreenPepper::Create( 579 GetRenderWidget()->routing_id(), plugin, active_url, 580 GetRenderWidget()->screenInfo()); 581 widget->show(blink::WebNavigationPolicyIgnore); 582 return widget; 583} 584 585bool RenderFrameImpl::IsPepperAcceptingCompositionEvents() const { 586 if (!render_view_->focused_pepper_plugin()) 587 return false; 588 return render_view_->focused_pepper_plugin()-> 589 IsPluginAcceptingCompositionEvents(); 590} 591 592void RenderFrameImpl::PluginCrashed(const base::FilePath& plugin_path, 593 base::ProcessId plugin_pid) { 594 // TODO(jam): dispatch this IPC in RenderFrameHost and switch to use 595 // routing_id_ as a result. 596 Send(new FrameHostMsg_PluginCrashed(routing_id_, plugin_path, plugin_pid)); 597} 598 599void RenderFrameImpl::SimulateImeSetComposition( 600 const base::string16& text, 601 const std::vector<blink::WebCompositionUnderline>& underlines, 602 int selection_start, 603 int selection_end) { 604 render_view_->OnImeSetComposition( 605 text, underlines, selection_start, selection_end); 606} 607 608void RenderFrameImpl::SimulateImeConfirmComposition( 609 const base::string16& text, 610 const gfx::Range& replacement_range) { 611 render_view_->OnImeConfirmComposition(text, replacement_range, false); 612} 613 614 615void RenderFrameImpl::OnImeSetComposition( 616 const base::string16& text, 617 const std::vector<blink::WebCompositionUnderline>& underlines, 618 int selection_start, 619 int selection_end) { 620 // When a PPAPI plugin has focus, we bypass WebKit. 621 if (!IsPepperAcceptingCompositionEvents()) { 622 pepper_composition_text_ = text; 623 } else { 624 // TODO(kinaba) currently all composition events are sent directly to 625 // plugins. Use DOM event mechanism after WebKit is made aware about 626 // plugins that support composition. 627 // The code below mimics the behavior of WebCore::Editor::setComposition. 628 629 // Empty -> nonempty: composition started. 630 if (pepper_composition_text_.empty() && !text.empty()) { 631 render_view_->focused_pepper_plugin()->HandleCompositionStart( 632 base::string16()); 633 } 634 // Nonempty -> empty: composition canceled. 635 if (!pepper_composition_text_.empty() && text.empty()) { 636 render_view_->focused_pepper_plugin()->HandleCompositionEnd( 637 base::string16()); 638 } 639 pepper_composition_text_ = text; 640 // Nonempty: composition is ongoing. 641 if (!pepper_composition_text_.empty()) { 642 render_view_->focused_pepper_plugin()->HandleCompositionUpdate( 643 pepper_composition_text_, underlines, selection_start, 644 selection_end); 645 } 646 } 647} 648 649void RenderFrameImpl::OnImeConfirmComposition( 650 const base::string16& text, 651 const gfx::Range& replacement_range, 652 bool keep_selection) { 653 // When a PPAPI plugin has focus, we bypass WebKit. 654 // Here, text.empty() has a special meaning. It means to commit the last 655 // update of composition text (see 656 // RenderWidgetHost::ImeConfirmComposition()). 657 const base::string16& last_text = text.empty() ? pepper_composition_text_ 658 : text; 659 660 // last_text is empty only when both text and pepper_composition_text_ is. 661 // Ignore it. 662 if (last_text.empty()) 663 return; 664 665 if (!IsPepperAcceptingCompositionEvents()) { 666 base::i18n::UTF16CharIterator iterator(&last_text); 667 int32 i = 0; 668 while (iterator.Advance()) { 669 blink::WebKeyboardEvent char_event; 670 char_event.type = blink::WebInputEvent::Char; 671 char_event.timeStampSeconds = base::Time::Now().ToDoubleT(); 672 char_event.modifiers = 0; 673 char_event.windowsKeyCode = last_text[i]; 674 char_event.nativeKeyCode = last_text[i]; 675 676 const int32 char_start = i; 677 for (; i < iterator.array_pos(); ++i) { 678 char_event.text[i - char_start] = last_text[i]; 679 char_event.unmodifiedText[i - char_start] = last_text[i]; 680 } 681 682 if (GetRenderWidget()->webwidget()) 683 GetRenderWidget()->webwidget()->handleInputEvent(char_event); 684 } 685 } else { 686 // Mimics the order of events sent by WebKit. 687 // See WebCore::Editor::setComposition() for the corresponding code. 688 render_view_->focused_pepper_plugin()->HandleCompositionEnd(last_text); 689 render_view_->focused_pepper_plugin()->HandleTextInput(last_text); 690 } 691 pepper_composition_text_.clear(); 692} 693 694#endif // ENABLE_PLUGINS 695 696MediaStreamDispatcher* RenderFrameImpl::GetMediaStreamDispatcher() { 697 if (!web_user_media_client_) 698 InitializeUserMediaClient(); 699 return web_user_media_client_ ? 700 web_user_media_client_->media_stream_dispatcher() : NULL; 701} 702 703bool RenderFrameImpl::Send(IPC::Message* message) { 704 if (is_detaching_) { 705 delete message; 706 return false; 707 } 708 if (frame_->parent() == NULL && 709 (is_swapped_out_ || render_view_->is_swapped_out())) { 710 if (!SwappedOutMessages::CanSendWhileSwappedOut(message)) { 711 delete message; 712 return false; 713 } 714 715 // In most cases, send IPCs through the proxy when swapped out. In some 716 // calls the associated RenderViewImpl routing id is used to send 717 // messages, so don't use the proxy. 718 if (render_frame_proxy_ && message->routing_id() == routing_id_) 719 return render_frame_proxy_->Send(message); 720 } 721 722 return RenderThread::Get()->Send(message); 723} 724 725bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) { 726 // TODO(kenrb): document() should not be null, but as a transitional step 727 // we have RenderFrameProxy 'wrapping' a RenderFrameImpl, passing messages 728 // to this method. This happens for a top-level remote frame, where a 729 // document-less RenderFrame is replaced by a RenderFrameProxy but kept 730 // around and is still able to receive messages. 731 if (!frame_->document().isNull()) 732 GetContentClient()->SetActiveURL(frame_->document().url()); 733 734 ObserverListBase<RenderFrameObserver>::Iterator it(observers_); 735 RenderFrameObserver* observer; 736 while ((observer = it.GetNext()) != NULL) { 737 if (observer->OnMessageReceived(msg)) 738 return true; 739 } 740 741 bool handled = true; 742 IPC_BEGIN_MESSAGE_MAP(RenderFrameImpl, msg) 743 IPC_MESSAGE_HANDLER(FrameMsg_Navigate, OnNavigate) 744 IPC_MESSAGE_HANDLER(FrameMsg_BeforeUnload, OnBeforeUnload) 745 IPC_MESSAGE_HANDLER(FrameMsg_SwapOut, OnSwapOut) 746 IPC_MESSAGE_HANDLER(FrameMsg_Stop, OnStop) 747 IPC_MESSAGE_HANDLER(FrameMsg_ContextMenuClosed, OnContextMenuClosed) 748 IPC_MESSAGE_HANDLER(FrameMsg_CustomContextMenuAction, 749 OnCustomContextMenuAction) 750 IPC_MESSAGE_HANDLER(InputMsg_Undo, OnUndo) 751 IPC_MESSAGE_HANDLER(InputMsg_Redo, OnRedo) 752 IPC_MESSAGE_HANDLER(InputMsg_Cut, OnCut) 753 IPC_MESSAGE_HANDLER(InputMsg_Copy, OnCopy) 754 IPC_MESSAGE_HANDLER(InputMsg_Paste, OnPaste) 755 IPC_MESSAGE_HANDLER(InputMsg_PasteAndMatchStyle, OnPasteAndMatchStyle) 756 IPC_MESSAGE_HANDLER(InputMsg_Delete, OnDelete) 757 IPC_MESSAGE_HANDLER(InputMsg_SelectAll, OnSelectAll) 758 IPC_MESSAGE_HANDLER(InputMsg_SelectRange, OnSelectRange) 759 IPC_MESSAGE_HANDLER(InputMsg_Unselect, OnUnselect) 760 IPC_MESSAGE_HANDLER(InputMsg_Replace, OnReplace) 761 IPC_MESSAGE_HANDLER(InputMsg_ReplaceMisspelling, OnReplaceMisspelling) 762 IPC_MESSAGE_HANDLER(InputMsg_ExtendSelectionAndDelete, 763 OnExtendSelectionAndDelete) 764 IPC_MESSAGE_HANDLER(InputMsg_SetCompositionFromExistingText, 765 OnSetCompositionFromExistingText) 766 IPC_MESSAGE_HANDLER(FrameMsg_CSSInsertRequest, OnCSSInsertRequest) 767 IPC_MESSAGE_HANDLER(FrameMsg_JavaScriptExecuteRequest, 768 OnJavaScriptExecuteRequest) 769 IPC_MESSAGE_HANDLER(FrameMsg_SetEditableSelectionOffsets, 770 OnSetEditableSelectionOffsets) 771 IPC_MESSAGE_HANDLER(FrameMsg_SetupTransitionView, OnSetupTransitionView) 772 IPC_MESSAGE_HANDLER(FrameMsg_BeginExitTransition, OnBeginExitTransition) 773 IPC_MESSAGE_HANDLER(FrameMsg_Reload, OnReload) 774 IPC_MESSAGE_HANDLER(FrameMsg_TextSurroundingSelectionRequest, 775 OnTextSurroundingSelectionRequest) 776 IPC_MESSAGE_HANDLER(FrameMsg_AddStyleSheetByURL, 777 OnAddStyleSheetByURL) 778 IPC_MESSAGE_HANDLER(FrameMsg_SetAccessibilityMode, 779 OnSetAccessibilityMode) 780#if defined(OS_MACOSX) 781 IPC_MESSAGE_HANDLER(InputMsg_CopyToFindPboard, OnCopyToFindPboard) 782#endif 783 IPC_END_MESSAGE_MAP() 784 785 return handled; 786} 787 788void RenderFrameImpl::OnNavigate(const FrameMsg_Navigate_Params& params) { 789 MaybeHandleDebugURL(params.url); 790 if (!render_view_->webview()) 791 return; 792 793 FOR_EACH_OBSERVER( 794 RenderViewObserver, render_view_->observers_, Navigate(params.url)); 795 796 bool is_reload = RenderViewImpl::IsReload(params); 797 WebURLRequest::CachePolicy cache_policy = 798 WebURLRequest::UseProtocolCachePolicy; 799 800 // If this is a stale back/forward (due to a recent navigation the browser 801 // didn't know about), ignore it. 802 if (render_view_->IsBackForwardToStaleEntry(params, is_reload)) 803 return; 804 805 // Swap this renderer back in if necessary. 806 if (render_view_->is_swapped_out_ && 807 GetWebFrame() == render_view_->webview()->mainFrame()) { 808 // We marked the view as hidden when swapping the view out, so be sure to 809 // reset the visibility state before navigating to the new URL. 810 render_view_->webview()->setVisibilityState( 811 render_view_->visibilityState(), false); 812 813 // If this is an attempt to reload while we are swapped out, we should not 814 // reload swappedout://, but the previous page, which is stored in 815 // params.state. Setting is_reload to false will treat this like a back 816 // navigation to accomplish that. 817 is_reload = false; 818 cache_policy = WebURLRequest::ReloadIgnoringCacheData; 819 820 // We refresh timezone when a view is swapped in since timezone 821 // can get out of sync when the system timezone is updated while 822 // the view is swapped out. 823 RenderThreadImpl::NotifyTimezoneChange(); 824 825 render_view_->SetSwappedOut(false); 826 is_swapped_out_ = false; 827 } 828 829 if (params.should_clear_history_list) { 830 CHECK_EQ(params.pending_history_list_offset, -1); 831 CHECK_EQ(params.current_history_list_offset, -1); 832 CHECK_EQ(params.current_history_list_length, 0); 833 } 834 render_view_->history_list_offset_ = params.current_history_list_offset; 835 render_view_->history_list_length_ = params.current_history_list_length; 836 if (render_view_->history_list_length_ >= 0) { 837 render_view_->history_page_ids_.resize( 838 render_view_->history_list_length_, -1); 839 } 840 if (params.pending_history_list_offset >= 0 && 841 params.pending_history_list_offset < render_view_->history_list_length_) { 842 render_view_->history_page_ids_[params.pending_history_list_offset] = 843 params.page_id; 844 } 845 846 GetContentClient()->SetActiveURL(params.url); 847 848 WebFrame* frame = frame_; 849 if (!params.frame_to_navigate.empty()) { 850 // TODO(nasko): Move this lookup to the browser process. 851 frame = render_view_->webview()->findFrameByName( 852 WebString::fromUTF8(params.frame_to_navigate)); 853 CHECK(frame) << "Invalid frame name passed: " << params.frame_to_navigate; 854 } 855 856 if (is_reload && !render_view_->history_controller()->GetCurrentEntry()) { 857 // We cannot reload if we do not have any history state. This happens, for 858 // example, when recovering from a crash. 859 is_reload = false; 860 cache_policy = WebURLRequest::ReloadIgnoringCacheData; 861 } 862 863 render_view_->pending_navigation_params_.reset( 864 new FrameMsg_Navigate_Params(params)); 865 866 // If we are reloading, then WebKit will use the history state of the current 867 // page, so we should just ignore any given history state. Otherwise, if we 868 // have history state, then we need to navigate to it, which corresponds to a 869 // back/forward navigation event. 870 if (is_reload) { 871 bool reload_original_url = 872 (params.navigation_type == 873 FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL); 874 bool ignore_cache = (params.navigation_type == 875 FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE); 876 877 if (reload_original_url) 878 frame->reloadWithOverrideURL(params.url, true); 879 else 880 frame->reload(ignore_cache); 881 } else if (params.page_state.IsValid()) { 882 // We must know the page ID of the page we are navigating back to. 883 DCHECK_NE(params.page_id, -1); 884 scoped_ptr<HistoryEntry> entry = 885 PageStateToHistoryEntry(params.page_state); 886 if (entry) { 887 // Ensure we didn't save the swapped out URL in UpdateState, since the 888 // browser should never be telling us to navigate to swappedout://. 889 CHECK(entry->root().urlString() != WebString::fromUTF8(kSwappedOutURL)); 890 render_view_->history_controller()->GoToEntry(entry.Pass(), cache_policy); 891 } 892 } else if (!params.base_url_for_data_url.is_empty()) { 893 // A loadData request with a specified base URL. 894 std::string mime_type, charset, data; 895 if (net::DataURL::Parse(params.url, &mime_type, &charset, &data)) { 896 frame->loadData( 897 WebData(data.c_str(), data.length()), 898 WebString::fromUTF8(mime_type), 899 WebString::fromUTF8(charset), 900 params.base_url_for_data_url, 901 params.history_url_for_data_url, 902 false); 903 } else { 904 CHECK(false) << 905 "Invalid URL passed: " << params.url.possibly_invalid_spec(); 906 } 907 } else { 908 // Navigate to the given URL. 909 WebURLRequest request(params.url); 910 911 // A session history navigation should have been accompanied by state. 912 CHECK_EQ(params.page_id, -1); 913 914 if (frame->isViewSourceModeEnabled()) 915 request.setCachePolicy(WebURLRequest::ReturnCacheDataElseLoad); 916 917 if (params.referrer.url.is_valid()) { 918 WebString referrer = WebSecurityPolicy::generateReferrerHeader( 919 params.referrer.policy, 920 params.url, 921 WebString::fromUTF8(params.referrer.url.spec())); 922 if (!referrer.isEmpty()) 923 request.setHTTPReferrer(referrer, params.referrer.policy); 924 } 925 926 if (!params.extra_headers.empty()) { 927 for (net::HttpUtil::HeadersIterator i(params.extra_headers.begin(), 928 params.extra_headers.end(), "\n"); 929 i.GetNext(); ) { 930 request.addHTTPHeaderField(WebString::fromUTF8(i.name()), 931 WebString::fromUTF8(i.values())); 932 } 933 } 934 935 if (params.is_post) { 936 request.setHTTPMethod(WebString::fromUTF8("POST")); 937 938 // Set post data. 939 WebHTTPBody http_body; 940 http_body.initialize(); 941 const char* data = NULL; 942 if (params.browser_initiated_post_data.size()) { 943 data = reinterpret_cast<const char*>( 944 ¶ms.browser_initiated_post_data.front()); 945 } 946 http_body.appendData( 947 WebData(data, params.browser_initiated_post_data.size())); 948 request.setHTTPBody(http_body); 949 } 950 951 // Record this before starting the load, we need a lower bound of this time 952 // to sanitize the navigationStart override set below. 953 base::TimeTicks renderer_navigation_start = base::TimeTicks::Now(); 954 frame->loadRequest(request); 955 956 // The browser provides the navigation_start time to bootstrap the 957 // Navigation Timing information for the browser-initiated navigations. In 958 // case of cross-process navigations, this carries over the time of 959 // finishing the onbeforeunload handler of the previous page. 960 DCHECK(!params.browser_navigation_start.is_null()); 961 if (frame->provisionalDataSource()) { 962 // |browser_navigation_start| is likely before this process existed, so we 963 // can't use InterProcessTimeTicksConverter. We need at least to ensure 964 // that the browser-side navigation start we set is not later than the one 965 // on the renderer side. 966 base::TimeTicks navigation_start = std::min( 967 params.browser_navigation_start, renderer_navigation_start); 968 double navigation_start_seconds = 969 (navigation_start - base::TimeTicks()).InSecondsF(); 970 frame->provisionalDataSource()->setNavigationStartTime( 971 navigation_start_seconds); 972 } 973 } 974 975 // In case LoadRequest failed before DidCreateDataSource was called. 976 render_view_->pending_navigation_params_.reset(); 977} 978 979void RenderFrameImpl::BindServiceRegistry( 980 mojo::ScopedMessagePipeHandle service_provider_handle) { 981 service_registry_.BindRemoteServiceProvider(service_provider_handle.Pass()); 982} 983 984void RenderFrameImpl::OnBeforeUnload() { 985 // TODO(creis): Right now, this is only called on the main frame. Make the 986 // browser process send dispatchBeforeUnloadEvent to every frame that needs 987 // it. 988 CHECK(!frame_->parent()); 989 990 base::TimeTicks before_unload_start_time = base::TimeTicks::Now(); 991 bool proceed = frame_->dispatchBeforeUnloadEvent(); 992 base::TimeTicks before_unload_end_time = base::TimeTicks::Now(); 993 Send(new FrameHostMsg_BeforeUnload_ACK(routing_id_, proceed, 994 before_unload_start_time, 995 before_unload_end_time)); 996} 997 998void RenderFrameImpl::OnSwapOut(int proxy_routing_id) { 999 RenderFrameProxy* proxy = NULL; 1000 bool is_site_per_process = 1001 CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess); 1002 bool is_main_frame = !frame_->parent(); 1003 1004 // Only run unload if we're not swapped out yet, but send the ack either way. 1005 if (!is_swapped_out_ || !render_view_->is_swapped_out_) { 1006 // Swap this RenderFrame out so the frame can navigate to a page rendered by 1007 // a different process. This involves running the unload handler and 1008 // clearing the page. We also allow this process to exit if there are no 1009 // other active RenderFrames in it. 1010 1011 // Send an UpdateState message before we get swapped out. Create the 1012 // RenderFrameProxy as well so its routing id is registered for receiving 1013 // IPC messages. 1014 render_view_->SyncNavigationState(); 1015 proxy = RenderFrameProxy::CreateProxyToReplaceFrame(this, 1016 proxy_routing_id); 1017 1018 // Synchronously run the unload handler before sending the ACK. 1019 // TODO(creis): Call dispatchUnloadEvent unconditionally here to support 1020 // unload on subframes as well. 1021 if (is_main_frame) 1022 frame_->dispatchUnloadEvent(); 1023 1024 // Swap out and stop sending any IPC messages that are not ACKs. 1025 // TODO(nasko): Do we need RenderFrameImpl::is_swapped_out_ anymore? 1026 if (is_main_frame) 1027 render_view_->SetSwappedOut(true); 1028 is_swapped_out_ = true; 1029 1030 // Now that we're swapped out and filtering IPC messages, stop loading to 1031 // ensure that no other in-progress navigation continues. We do this here 1032 // to avoid sending a DidStopLoading message to the browser process. 1033 // TODO(creis): Should we be stopping all frames here and using 1034 // StopAltErrorPageFetcher with RenderView::OnStop, or just stopping this 1035 // frame? 1036 OnStop(); 1037 1038 // Let subframes know that the frame is now rendered remotely, for the 1039 // purposes of compositing and input events. 1040 if (!is_main_frame) 1041 frame_->setIsRemote(true); 1042 1043 // Replace the page with a blank dummy URL. The unload handler will not be 1044 // run a second time, thanks to a check in FrameLoader::stopLoading. 1045 // TODO(creis): Need to add a better way to do this that avoids running the 1046 // beforeunload handler. For now, we just run it a second time silently. 1047 if (!is_site_per_process || is_main_frame) 1048 render_view_->NavigateToSwappedOutURL(frame_); 1049 1050 // Let WebKit know that this view is hidden so it can drop resources and 1051 // stop compositing. 1052 // TODO(creis): Support this for subframes as well. 1053 if (is_main_frame) { 1054 render_view_->webview()->setVisibilityState( 1055 blink::WebPageVisibilityStateHidden, false); 1056 } 1057 } 1058 1059 // It is now safe to show modal dialogs again. 1060 // TODO(creis): Deal with modal dialogs from subframes. 1061 if (is_main_frame) 1062 render_view_->suppress_dialogs_until_swap_out_ = false; 1063 1064 Send(new FrameHostMsg_SwapOut_ACK(routing_id_)); 1065 1066 // Now that all of the cleanup is complete and the browser side is notified, 1067 // start using the RenderFrameProxy, if one is created. 1068 if (proxy) { 1069 if (!is_main_frame) { 1070 frame_->swap(proxy->web_frame()); 1071 if (is_site_per_process) { 1072 // TODO(nasko): delete the frame here, since we've replaced it with a 1073 // proxy. 1074 } 1075 } else { 1076 set_render_frame_proxy(proxy); 1077 } 1078 } 1079 1080 // Safe to exit if no one else is using the process. 1081 if (is_main_frame) 1082 render_view_->WasSwappedOut(); 1083} 1084 1085void RenderFrameImpl::OnContextMenuClosed( 1086 const CustomContextMenuContext& custom_context) { 1087 if (custom_context.request_id) { 1088 // External request, should be in our map. 1089 ContextMenuClient* client = 1090 pending_context_menus_.Lookup(custom_context.request_id); 1091 if (client) { 1092 client->OnMenuClosed(custom_context.request_id); 1093 pending_context_menus_.Remove(custom_context.request_id); 1094 } 1095 } else { 1096 if (custom_context.link_followed.is_valid()) { 1097 frame_->sendPings( 1098 DomUtils::ExtractParentAnchorNode(context_menu_node_), 1099 custom_context.link_followed); 1100 } 1101 // Internal request, forward to WebKit. 1102 context_menu_node_.reset(); 1103 } 1104} 1105 1106void RenderFrameImpl::OnCustomContextMenuAction( 1107 const CustomContextMenuContext& custom_context, 1108 unsigned action) { 1109 if (custom_context.request_id) { 1110 // External context menu request, look in our map. 1111 ContextMenuClient* client = 1112 pending_context_menus_.Lookup(custom_context.request_id); 1113 if (client) 1114 client->OnMenuAction(custom_context.request_id, action); 1115 } else { 1116 // Internal request, forward to WebKit. 1117 render_view_->webview()->performCustomContextMenuAction(action); 1118 } 1119} 1120 1121void RenderFrameImpl::OnUndo() { 1122 frame_->executeCommand(WebString::fromUTF8("Undo"), GetFocusedElement()); 1123} 1124 1125void RenderFrameImpl::OnRedo() { 1126 frame_->executeCommand(WebString::fromUTF8("Redo"), GetFocusedElement()); 1127} 1128 1129void RenderFrameImpl::OnCut() { 1130 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1131 frame_->executeCommand(WebString::fromUTF8("Cut"), GetFocusedElement()); 1132} 1133 1134void RenderFrameImpl::OnCopy() { 1135 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1136 WebNode current_node = context_menu_node_.isNull() ? 1137 GetFocusedElement() : context_menu_node_; 1138 frame_->executeCommand(WebString::fromUTF8("Copy"), current_node); 1139} 1140 1141void RenderFrameImpl::OnPaste() { 1142 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1143 frame_->executeCommand(WebString::fromUTF8("Paste"), GetFocusedElement()); 1144} 1145 1146void RenderFrameImpl::OnPasteAndMatchStyle() { 1147 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1148 frame_->executeCommand( 1149 WebString::fromUTF8("PasteAndMatchStyle"), GetFocusedElement()); 1150} 1151 1152#if defined(OS_MACOSX) 1153void RenderFrameImpl::OnCopyToFindPboard() { 1154 // Since the find pasteboard supports only plain text, this can be simpler 1155 // than the |OnCopy()| case. 1156 if (frame_->hasSelection()) { 1157 base::string16 selection = frame_->selectionAsText(); 1158 RenderThread::Get()->Send( 1159 new ClipboardHostMsg_FindPboardWriteStringAsync(selection)); 1160 } 1161} 1162#endif 1163 1164void RenderFrameImpl::OnDelete() { 1165 frame_->executeCommand(WebString::fromUTF8("Delete"), GetFocusedElement()); 1166} 1167 1168void RenderFrameImpl::OnSelectAll() { 1169 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1170 frame_->executeCommand(WebString::fromUTF8("SelectAll"), GetFocusedElement()); 1171} 1172 1173void RenderFrameImpl::OnSelectRange(const gfx::Point& start, 1174 const gfx::Point& end) { 1175 // This IPC is dispatched by RenderWidgetHost, so use its routing id. 1176 Send(new ViewHostMsg_SelectRange_ACK(GetRenderWidget()->routing_id())); 1177 1178 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1179 frame_->selectRange(start, end); 1180} 1181 1182void RenderFrameImpl::OnUnselect() { 1183 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1184 frame_->executeCommand(WebString::fromUTF8("Unselect"), GetFocusedElement()); 1185} 1186 1187void RenderFrameImpl::OnReplace(const base::string16& text) { 1188 if (!frame_->hasSelection()) 1189 frame_->selectWordAroundCaret(); 1190 1191 frame_->replaceSelection(text); 1192} 1193 1194void RenderFrameImpl::OnReplaceMisspelling(const base::string16& text) { 1195 if (!frame_->hasSelection()) 1196 return; 1197 1198 frame_->replaceMisspelledRange(text); 1199} 1200 1201void RenderFrameImpl::OnCSSInsertRequest(const std::string& css) { 1202 frame_->document().insertStyleSheet(WebString::fromUTF8(css)); 1203} 1204 1205void RenderFrameImpl::OnJavaScriptExecuteRequest( 1206 const base::string16& jscript, 1207 int id, 1208 bool notify_result) { 1209 TRACE_EVENT_INSTANT0("test_tracing", "OnJavaScriptExecuteRequest", 1210 TRACE_EVENT_SCOPE_THREAD); 1211 1212 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 1213 v8::Handle<v8::Value> result = 1214 frame_->executeScriptAndReturnValue(WebScriptSource(jscript)); 1215 if (notify_result) { 1216 base::ListValue list; 1217 if (!result.IsEmpty()) { 1218 v8::Local<v8::Context> context = frame_->mainWorldScriptContext(); 1219 v8::Context::Scope context_scope(context); 1220 V8ValueConverterImpl converter; 1221 converter.SetDateAllowed(true); 1222 converter.SetRegExpAllowed(true); 1223 base::Value* result_value = converter.FromV8Value(result, context); 1224 list.Set(0, result_value ? result_value : base::Value::CreateNullValue()); 1225 } else { 1226 list.Set(0, base::Value::CreateNullValue()); 1227 } 1228 Send(new FrameHostMsg_JavaScriptExecuteResponse(routing_id_, id, list)); 1229 } 1230} 1231 1232void RenderFrameImpl::OnSetEditableSelectionOffsets(int start, int end) { 1233 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1234 if (!GetRenderWidget()->ShouldHandleImeEvent()) 1235 return; 1236 ImeEventGuard guard(GetRenderWidget()); 1237 frame_->setEditableSelectionOffsets(start, end); 1238} 1239 1240void RenderFrameImpl::OnSetCompositionFromExistingText( 1241 int start, int end, 1242 const std::vector<blink::WebCompositionUnderline>& underlines) { 1243 if (!GetRenderWidget()->ShouldHandleImeEvent()) 1244 return; 1245 ImeEventGuard guard(GetRenderWidget()); 1246 frame_->setCompositionFromExistingText(start, end, underlines); 1247} 1248 1249void RenderFrameImpl::OnExtendSelectionAndDelete(int before, int after) { 1250 if (!GetRenderWidget()->ShouldHandleImeEvent()) 1251 return; 1252 ImeEventGuard guard(GetRenderWidget()); 1253 frame_->extendSelectionAndDelete(before, after); 1254} 1255 1256void RenderFrameImpl::OnSetAccessibilityMode(AccessibilityMode new_mode) { 1257 if (accessibility_mode_ == new_mode) 1258 return; 1259 accessibility_mode_ = new_mode; 1260 if (renderer_accessibility_) { 1261 delete renderer_accessibility_; 1262 renderer_accessibility_ = NULL; 1263 } 1264 if (accessibility_mode_ == AccessibilityModeOff) 1265 return; 1266 1267 if (accessibility_mode_ & AccessibilityModeFlagFullTree) 1268 renderer_accessibility_ = new RendererAccessibilityComplete(this); 1269#if !defined(OS_ANDROID) 1270 else 1271 renderer_accessibility_ = new RendererAccessibilityFocusOnly(this); 1272#endif 1273} 1274 1275void RenderFrameImpl::OnReload(bool ignore_cache) { 1276 frame_->reload(ignore_cache); 1277} 1278 1279void RenderFrameImpl::OnTextSurroundingSelectionRequest(size_t max_length) { 1280 blink::WebSurroundingText surroundingText; 1281 surroundingText.initialize(frame_->selectionRange(), max_length); 1282 1283 if (surroundingText.isNull()) { 1284 // |surroundingText| might not be correctly initialized, for example if 1285 // |frame_->selectionRange().isNull()|, in other words, if there was no 1286 // selection. 1287 Send(new FrameHostMsg_TextSurroundingSelectionResponse( 1288 routing_id_, base::string16(), 0, 0)); 1289 return; 1290 } 1291 1292 Send(new FrameHostMsg_TextSurroundingSelectionResponse( 1293 routing_id_, 1294 surroundingText.textContent(), 1295 surroundingText.startOffsetInTextContent(), 1296 surroundingText.endOffsetInTextContent())); 1297} 1298 1299void RenderFrameImpl::OnAddStyleSheetByURL(const std::string& url) { 1300 frame_->addStyleSheetByURL(WebString::fromUTF8(url)); 1301} 1302 1303void RenderFrameImpl::OnSetupTransitionView(const std::string& markup) { 1304 frame_->document().setIsTransitionDocument(); 1305 frame_->navigateToSandboxedMarkup(WebData(markup.data(), markup.length())); 1306} 1307 1308void RenderFrameImpl::OnBeginExitTransition(const std::string& css_selector) { 1309 frame_->document().setIsTransitionDocument(); 1310 frame_->document().beginExitTransition(WebString::fromUTF8(css_selector)); 1311} 1312 1313bool RenderFrameImpl::ShouldUpdateSelectionTextFromContextMenuParams( 1314 const base::string16& selection_text, 1315 size_t selection_text_offset, 1316 const gfx::Range& selection_range, 1317 const ContextMenuParams& params) { 1318 base::string16 trimmed_selection_text; 1319 if (!selection_text.empty() && !selection_range.is_empty()) { 1320 const int start = selection_range.GetMin() - selection_text_offset; 1321 const size_t length = selection_range.length(); 1322 if (start >= 0 && start + length <= selection_text.length()) { 1323 base::TrimWhitespace(selection_text.substr(start, length), base::TRIM_ALL, 1324 &trimmed_selection_text); 1325 } 1326 } 1327 base::string16 trimmed_params_text; 1328 base::TrimWhitespace(params.selection_text, base::TRIM_ALL, 1329 &trimmed_params_text); 1330 return trimmed_params_text != trimmed_selection_text; 1331} 1332 1333bool RenderFrameImpl::RunJavaScriptMessage(JavaScriptMessageType type, 1334 const base::string16& message, 1335 const base::string16& default_value, 1336 const GURL& frame_url, 1337 base::string16* result) { 1338 // Don't allow further dialogs if we are waiting to swap out, since the 1339 // PageGroupLoadDeferrer in our stack prevents it. 1340 if (render_view()->suppress_dialogs_until_swap_out_) 1341 return false; 1342 1343 bool success = false; 1344 base::string16 result_temp; 1345 if (!result) 1346 result = &result_temp; 1347 1348 render_view()->SendAndRunNestedMessageLoop( 1349 new FrameHostMsg_RunJavaScriptMessage( 1350 routing_id_, message, default_value, frame_url, type, &success, 1351 result)); 1352 return success; 1353} 1354 1355void RenderFrameImpl::LoadNavigationErrorPage( 1356 const WebURLRequest& failed_request, 1357 const WebURLError& error, 1358 bool replace) { 1359 std::string error_html; 1360 GetContentClient()->renderer()->GetNavigationErrorStrings( 1361 render_view(), frame_, failed_request, error, &error_html, NULL); 1362 1363 frame_->loadHTMLString(error_html, 1364 GURL(kUnreachableWebDataURL), 1365 error.unreachableURL, 1366 replace); 1367} 1368 1369void RenderFrameImpl::DidCommitCompositorFrame() { 1370 FOR_EACH_OBSERVER( 1371 RenderFrameObserver, observers_, DidCommitCompositorFrame()); 1372} 1373 1374RenderView* RenderFrameImpl::GetRenderView() { 1375 return render_view_.get(); 1376} 1377 1378int RenderFrameImpl::GetRoutingID() { 1379 return routing_id_; 1380} 1381 1382blink::WebFrame* RenderFrameImpl::GetWebFrame() { 1383 DCHECK(frame_); 1384 return frame_; 1385} 1386 1387WebPreferences& RenderFrameImpl::GetWebkitPreferences() { 1388 return render_view_->GetWebkitPreferences(); 1389} 1390 1391int RenderFrameImpl::ShowContextMenu(ContextMenuClient* client, 1392 const ContextMenuParams& params) { 1393 DCHECK(client); // A null client means "internal" when we issue callbacks. 1394 ContextMenuParams our_params(params); 1395 our_params.custom_context.request_id = pending_context_menus_.Add(client); 1396 Send(new FrameHostMsg_ContextMenu(routing_id_, our_params)); 1397 return our_params.custom_context.request_id; 1398} 1399 1400void RenderFrameImpl::CancelContextMenu(int request_id) { 1401 DCHECK(pending_context_menus_.Lookup(request_id)); 1402 pending_context_menus_.Remove(request_id); 1403} 1404 1405blink::WebNode RenderFrameImpl::GetContextMenuNode() const { 1406 return context_menu_node_; 1407} 1408 1409blink::WebPlugin* RenderFrameImpl::CreatePlugin( 1410 blink::WebFrame* frame, 1411 const WebPluginInfo& info, 1412 const blink::WebPluginParams& params) { 1413 DCHECK_EQ(frame_, frame); 1414#if defined(ENABLE_PLUGINS) 1415 bool pepper_plugin_was_registered = false; 1416 scoped_refptr<PluginModule> pepper_module(PluginModule::Create( 1417 this, info, &pepper_plugin_was_registered)); 1418 if (pepper_plugin_was_registered) { 1419 if (pepper_module.get()) { 1420 return new PepperWebPluginImpl(pepper_module.get(), params, this); 1421 } 1422 } 1423#if defined(OS_CHROMEOS) 1424 LOG(WARNING) << "Pepper module/plugin creation failed."; 1425 return NULL; 1426#else 1427 // TODO(jam): change to take RenderFrame. 1428 return new WebPluginImpl(frame, params, info.path, render_view_, this); 1429#endif 1430#else 1431 return NULL; 1432#endif 1433} 1434 1435void RenderFrameImpl::LoadURLExternally(blink::WebLocalFrame* frame, 1436 const blink::WebURLRequest& request, 1437 blink::WebNavigationPolicy policy) { 1438 DCHECK(!frame_ || frame_ == frame); 1439 loadURLExternally(frame, request, policy, WebString()); 1440} 1441 1442void RenderFrameImpl::ExecuteJavaScript(const base::string16& javascript) { 1443 OnJavaScriptExecuteRequest(javascript, 0, false); 1444} 1445 1446ServiceRegistry* RenderFrameImpl::GetServiceRegistry() { 1447 return &service_registry_; 1448} 1449 1450bool RenderFrameImpl::IsFTPDirectoryListing() { 1451 WebURLResponseExtraDataImpl* extra_data = 1452 GetExtraDataFromResponse(frame_->dataSource()->response()); 1453 return extra_data ? extra_data->is_ftp_directory_listing() : false; 1454} 1455 1456void RenderFrameImpl::AttachGuest(int element_instance_id) { 1457 render_view_->GetBrowserPluginManager()->Attach(element_instance_id); 1458} 1459 1460// blink::WebFrameClient implementation ---------------------------------------- 1461 1462blink::WebPlugin* RenderFrameImpl::createPlugin( 1463 blink::WebLocalFrame* frame, 1464 const blink::WebPluginParams& params) { 1465 DCHECK_EQ(frame_, frame); 1466 blink::WebPlugin* plugin = NULL; 1467 if (GetContentClient()->renderer()->OverrideCreatePlugin( 1468 this, frame, params, &plugin)) { 1469 return plugin; 1470 } 1471 1472 if (base::UTF16ToUTF8(params.mimeType) == kBrowserPluginMimeType) { 1473 return render_view_->GetBrowserPluginManager()->CreateBrowserPlugin( 1474 render_view_.get(), frame, false); 1475 } 1476 1477#if defined(ENABLE_PLUGINS) 1478 WebPluginInfo info; 1479 std::string mime_type; 1480 bool found = false; 1481 Send(new FrameHostMsg_GetPluginInfo( 1482 routing_id_, params.url, frame->top()->document().url(), 1483 params.mimeType.utf8(), &found, &info, &mime_type)); 1484 if (!found) 1485 return NULL; 1486 1487 if (info.type == content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN) { 1488 return render_view_->GetBrowserPluginManager()->CreateBrowserPlugin( 1489 render_view_.get(), frame, true); 1490 } 1491 1492 1493 WebPluginParams params_to_use = params; 1494 params_to_use.mimeType = WebString::fromUTF8(mime_type); 1495 return CreatePlugin(frame, info, params_to_use); 1496#else 1497 return NULL; 1498#endif // defined(ENABLE_PLUGINS) 1499} 1500 1501blink::WebMediaPlayer* RenderFrameImpl::createMediaPlayer( 1502 blink::WebLocalFrame* frame, 1503 const blink::WebURL& url, 1504 blink::WebMediaPlayerClient* client) { 1505#if defined(VIDEO_HOLE) 1506 if (!contains_media_player_) { 1507 render_view_->RegisterVideoHoleFrame(this); 1508 contains_media_player_ = true; 1509 } 1510#endif // defined(VIDEO_HOLE) 1511 1512 blink::WebMediaStream web_stream( 1513 blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url)); 1514 if (!web_stream.isNull()) 1515 return CreateWebMediaPlayerForMediaStream(url, client); 1516 1517#if defined(OS_ANDROID) 1518 return CreateAndroidWebMediaPlayer(url, client); 1519#else 1520 WebMediaPlayerParams params( 1521 base::Bind(&ContentRendererClient::DeferMediaLoad, 1522 base::Unretained(GetContentClient()->renderer()), 1523 static_cast<RenderFrame*>(this)), 1524 RenderThreadImpl::current()->GetAudioRendererMixerManager()->CreateInput( 1525 render_view_->routing_id_, routing_id_)); 1526 return new WebMediaPlayerImpl(frame, client, weak_factory_.GetWeakPtr(), 1527 params); 1528#endif // defined(OS_ANDROID) 1529} 1530 1531blink::WebContentDecryptionModule* 1532RenderFrameImpl::createContentDecryptionModule( 1533 blink::WebLocalFrame* frame, 1534 const blink::WebSecurityOrigin& security_origin, 1535 const blink::WebString& key_system) { 1536 DCHECK(!frame_ || frame_ == frame); 1537 return WebContentDecryptionModuleImpl::Create( 1538#if defined(ENABLE_PEPPER_CDMS) 1539 frame, 1540#elif defined(ENABLE_BROWSER_CDMS) 1541 GetCdmManager(), 1542#endif 1543 security_origin, 1544 key_system); 1545} 1546 1547blink::WebApplicationCacheHost* RenderFrameImpl::createApplicationCacheHost( 1548 blink::WebLocalFrame* frame, 1549 blink::WebApplicationCacheHostClient* client) { 1550 if (!frame || !frame->view()) 1551 return NULL; 1552 DCHECK(!frame_ || frame_ == frame); 1553 return new RendererWebApplicationCacheHostImpl( 1554 RenderViewImpl::FromWebView(frame->view()), client, 1555 RenderThreadImpl::current()->appcache_dispatcher()->backend_proxy()); 1556} 1557 1558blink::WebWorkerPermissionClientProxy* 1559RenderFrameImpl::createWorkerPermissionClientProxy( 1560 blink::WebLocalFrame* frame) { 1561 if (!frame || !frame->view()) 1562 return NULL; 1563 DCHECK(!frame_ || frame_ == frame); 1564 return GetContentClient()->renderer()->CreateWorkerPermissionClientProxy( 1565 this, frame); 1566} 1567 1568WebExternalPopupMenu* RenderFrameImpl::createExternalPopupMenu( 1569 const WebPopupMenuInfo& popup_menu_info, 1570 WebExternalPopupMenuClient* popup_menu_client) { 1571 return render_view_->createExternalPopupMenu(popup_menu_info, 1572 popup_menu_client); 1573} 1574 1575blink::WebCookieJar* RenderFrameImpl::cookieJar(blink::WebLocalFrame* frame) { 1576 DCHECK(!frame_ || frame_ == frame); 1577 return &cookie_jar_; 1578} 1579 1580blink::WebServiceWorkerProvider* RenderFrameImpl::createServiceWorkerProvider( 1581 blink::WebLocalFrame* frame) { 1582 DCHECK(!frame_ || frame_ == frame); 1583 // At this point we should have non-null data source. 1584 DCHECK(frame->dataSource()); 1585 if (!ChildThread::current()) 1586 return NULL; // May be null in some tests. 1587 ServiceWorkerNetworkProvider* provider = 1588 ServiceWorkerNetworkProvider::FromDocumentState( 1589 DocumentState::FromDataSource(frame->dataSource())); 1590 return new WebServiceWorkerProviderImpl( 1591 ChildThread::current()->thread_safe_sender(), 1592 provider ? provider->context() : NULL); 1593} 1594 1595void RenderFrameImpl::didAccessInitialDocument(blink::WebLocalFrame* frame) { 1596 DCHECK(!frame_ || frame_ == frame); 1597 // Notify the browser process that it is no longer safe to show the pending 1598 // URL of the main frame, since a URL spoof is now possible. 1599 if (!frame->parent() && render_view_->page_id_ == -1) 1600 Send(new FrameHostMsg_DidAccessInitialDocument(routing_id_)); 1601} 1602 1603blink::WebFrame* RenderFrameImpl::createChildFrame( 1604 blink::WebLocalFrame* parent, 1605 const blink::WebString& name) { 1606 // Synchronously notify the browser of a child frame creation to get the 1607 // routing_id for the RenderFrame. 1608 int child_routing_id = MSG_ROUTING_NONE; 1609 Send(new FrameHostMsg_CreateChildFrame(routing_id_, 1610 base::UTF16ToUTF8(name), 1611 &child_routing_id)); 1612 // Allocation of routing id failed, so we can't create a child frame. This can 1613 // happen if this RenderFrameImpl's IPCs are being filtered when in swapped 1614 // out state. 1615 if (child_routing_id == MSG_ROUTING_NONE) { 1616#if !defined(OS_LINUX) 1617 // DumpWithoutCrashing() crashes on Linux in renderer processes when 1618 // breakpad and sandboxing are enabled: crbug.com/349600 1619 base::debug::Alias(parent); 1620 base::debug::Alias(&routing_id_); 1621 bool render_view_is_swapped_out = GetRenderWidget()->is_swapped_out(); 1622 base::debug::Alias(&render_view_is_swapped_out); 1623 bool render_view_is_closing = GetRenderWidget()->closing(); 1624 base::debug::Alias(&render_view_is_closing); 1625 base::debug::Alias(&is_swapped_out_); 1626 base::debug::DumpWithoutCrashing(); 1627#endif 1628 return NULL; 1629 } 1630 1631 // Create the RenderFrame and WebLocalFrame, linking the two. 1632 RenderFrameImpl* child_render_frame = RenderFrameImpl::Create( 1633 render_view_.get(), child_routing_id); 1634 blink::WebLocalFrame* web_frame = WebLocalFrame::create(child_render_frame); 1635 child_render_frame->SetWebFrame(web_frame); 1636 1637 // Add the frame to the frame tree and initialize it. 1638 parent->appendChild(web_frame); 1639 child_render_frame->Initialize(); 1640 1641 return web_frame; 1642} 1643 1644void RenderFrameImpl::didDisownOpener(blink::WebLocalFrame* frame) { 1645 DCHECK(!frame_ || frame_ == frame); 1646 // We only need to notify the browser if the active, top-level frame clears 1647 // its opener. We can ignore cases where a swapped out frame clears its 1648 // opener after hearing about it from the browser, and the browser does not 1649 // (yet) care about subframe openers. 1650 if (render_view_->is_swapped_out_ || frame->parent()) 1651 return; 1652 1653 // Notify WebContents and all its swapped out RenderViews. 1654 Send(new FrameHostMsg_DidDisownOpener(routing_id_)); 1655} 1656 1657void RenderFrameImpl::frameDetached(blink::WebFrame* frame) { 1658 // NOTE: This function is called on the frame that is being detached and not 1659 // the parent frame. This is different from createChildFrame() which is 1660 // called on the parent frame. 1661 CHECK(!is_detaching_); 1662 DCHECK(!frame_ || frame_ == frame); 1663 1664 bool is_subframe = !!frame->parent(); 1665 1666 Send(new FrameHostMsg_Detach(routing_id_)); 1667 1668 // The |is_detaching_| flag disables Send(). FrameHostMsg_Detach must be 1669 // sent before setting |is_detaching_| to true. In contrast, Observers 1670 // should only be notified afterwards so they cannot call back into here and 1671 // have IPCs fired off. 1672 is_detaching_ = true; 1673 1674 FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(), 1675 FrameDetached(frame)); 1676 1677 // We need to clean up subframes by removing them from the map and deleting 1678 // the RenderFrameImpl. In contrast, the main frame is owned by its 1679 // containing RenderViewHost (so that they have the same lifetime), so only 1680 // removal from the map is needed and no deletion. 1681 FrameMap::iterator it = g_frame_map.Get().find(frame); 1682 CHECK(it != g_frame_map.Get().end()); 1683 CHECK_EQ(it->second, this); 1684 g_frame_map.Get().erase(it); 1685 1686 if (is_subframe) 1687 frame->parent()->removeChild(frame); 1688 1689 // |frame| is invalid after here. 1690 frame->close(); 1691 1692 if (is_subframe) { 1693 delete this; 1694 // Object is invalid after this point. 1695 } 1696} 1697 1698void RenderFrameImpl::frameFocused() { 1699 Send(new FrameHostMsg_FrameFocused(routing_id_)); 1700} 1701 1702void RenderFrameImpl::willClose(blink::WebFrame* frame) { 1703 DCHECK(!frame_ || frame_ == frame); 1704 1705 FOR_EACH_OBSERVER(RenderFrameObserver, observers_, FrameWillClose()); 1706 FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(), 1707 FrameWillClose(frame)); 1708} 1709 1710void RenderFrameImpl::didChangeName(blink::WebLocalFrame* frame, 1711 const blink::WebString& name) { 1712 DCHECK(!frame_ || frame_ == frame); 1713 if (!render_view_->renderer_preferences_.report_frame_name_changes) 1714 return; 1715 1716 FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidChangeName(name)); 1717} 1718 1719void RenderFrameImpl::didMatchCSS( 1720 blink::WebLocalFrame* frame, 1721 const blink::WebVector<blink::WebString>& newly_matching_selectors, 1722 const blink::WebVector<blink::WebString>& stopped_matching_selectors) { 1723 DCHECK(!frame_ || frame_ == frame); 1724 1725 FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(), 1726 DidMatchCSS(frame, 1727 newly_matching_selectors, 1728 stopped_matching_selectors)); 1729} 1730 1731bool RenderFrameImpl::shouldReportDetailedMessageForSource( 1732 const blink::WebString& source) { 1733 return GetContentClient()->renderer()->ShouldReportDetailedMessageForSource( 1734 source); 1735} 1736 1737void RenderFrameImpl::didAddMessageToConsole( 1738 const blink::WebConsoleMessage& message, 1739 const blink::WebString& source_name, 1740 unsigned source_line, 1741 const blink::WebString& stack_trace) { 1742 logging::LogSeverity log_severity = logging::LOG_VERBOSE; 1743 switch (message.level) { 1744 case blink::WebConsoleMessage::LevelDebug: 1745 log_severity = logging::LOG_VERBOSE; 1746 break; 1747 case blink::WebConsoleMessage::LevelLog: 1748 case blink::WebConsoleMessage::LevelInfo: 1749 log_severity = logging::LOG_INFO; 1750 break; 1751 case blink::WebConsoleMessage::LevelWarning: 1752 log_severity = logging::LOG_WARNING; 1753 break; 1754 case blink::WebConsoleMessage::LevelError: 1755 log_severity = logging::LOG_ERROR; 1756 break; 1757 default: 1758 NOTREACHED(); 1759 } 1760 1761 if (shouldReportDetailedMessageForSource(source_name)) { 1762 FOR_EACH_OBSERVER( 1763 RenderFrameObserver, observers_, 1764 DetailedConsoleMessageAdded(message.text, 1765 source_name, 1766 stack_trace, 1767 source_line, 1768 static_cast<int32>(log_severity))); 1769 } 1770 1771 Send(new FrameHostMsg_AddMessageToConsole(routing_id_, 1772 static_cast<int32>(log_severity), 1773 message.text, 1774 static_cast<int32>(source_line), 1775 source_name)); 1776} 1777 1778void RenderFrameImpl::loadURLExternally( 1779 blink::WebLocalFrame* frame, 1780 const blink::WebURLRequest& request, 1781 blink::WebNavigationPolicy policy, 1782 const blink::WebString& suggested_name) { 1783 DCHECK(!frame_ || frame_ == frame); 1784 Referrer referrer(RenderViewImpl::GetReferrerFromRequest(frame, request)); 1785 if (policy == blink::WebNavigationPolicyDownload) { 1786 render_view_->Send(new ViewHostMsg_DownloadUrl(render_view_->GetRoutingID(), 1787 request.url(), referrer, 1788 suggested_name, false)); 1789 } else if (policy == blink::WebNavigationPolicyDownloadTo) { 1790 render_view_->Send(new ViewHostMsg_DownloadUrl(render_view_->GetRoutingID(), 1791 request.url(), referrer, 1792 suggested_name, true)); 1793 } else { 1794 OpenURL(frame, request.url(), referrer, policy); 1795 } 1796} 1797 1798blink::WebNavigationPolicy RenderFrameImpl::decidePolicyForNavigation( 1799 const NavigationPolicyInfo& info) { 1800 DCHECK(!frame_ || frame_ == info.frame); 1801 return DecidePolicyForNavigation(this, info); 1802} 1803 1804blink::WebHistoryItem RenderFrameImpl::historyItemForNewChildFrame( 1805 blink::WebFrame* frame) { 1806 DCHECK(!frame_ || frame_ == frame); 1807 return render_view_->history_controller()->GetItemForNewChildFrame(this); 1808} 1809 1810void RenderFrameImpl::willSendSubmitEvent(blink::WebLocalFrame* frame, 1811 const blink::WebFormElement& form) { 1812 DCHECK(!frame_ || frame_ == frame); 1813 1814 FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(), 1815 WillSendSubmitEvent(frame, form)); 1816} 1817 1818void RenderFrameImpl::willSubmitForm(blink::WebLocalFrame* frame, 1819 const blink::WebFormElement& form) { 1820 DCHECK(!frame_ || frame_ == frame); 1821 DocumentState* document_state = 1822 DocumentState::FromDataSource(frame->provisionalDataSource()); 1823 NavigationState* navigation_state = document_state->navigation_state(); 1824 InternalDocumentStateData* internal_data = 1825 InternalDocumentStateData::FromDocumentState(document_state); 1826 1827 if (PageTransitionCoreTypeIs(navigation_state->transition_type(), 1828 PAGE_TRANSITION_LINK)) { 1829 navigation_state->set_transition_type(PAGE_TRANSITION_FORM_SUBMIT); 1830 } 1831 1832 // Save these to be processed when the ensuing navigation is committed. 1833 WebSearchableFormData web_searchable_form_data(form); 1834 internal_data->set_searchable_form_url(web_searchable_form_data.url()); 1835 internal_data->set_searchable_form_encoding( 1836 web_searchable_form_data.encoding().utf8()); 1837 1838 FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(), 1839 WillSubmitForm(frame, form)); 1840} 1841 1842void RenderFrameImpl::didCreateDataSource(blink::WebLocalFrame* frame, 1843 blink::WebDataSource* datasource) { 1844 DCHECK(!frame_ || frame_ == frame); 1845 1846 // TODO(nasko): Move implementation here. Needed state: 1847 // * pending_navigation_params_ 1848 // * webview 1849 // Needed methods: 1850 // * PopulateDocumentStateFromPending 1851 // * CreateNavigationStateFromPending 1852 render_view_->didCreateDataSource(frame, datasource); 1853 1854 // Create the serviceworker's per-document network observing object. 1855 scoped_ptr<ServiceWorkerNetworkProvider> 1856 network_provider(new ServiceWorkerNetworkProvider()); 1857 ServiceWorkerNetworkProvider::AttachToDocumentState( 1858 DocumentState::FromDataSource(datasource), 1859 network_provider.Pass()); 1860} 1861 1862void RenderFrameImpl::didStartProvisionalLoad(blink::WebLocalFrame* frame, 1863 bool is_transition_navigation) { 1864 DCHECK(!frame_ || frame_ == frame); 1865 WebDataSource* ds = frame->provisionalDataSource(); 1866 1867 // In fast/loader/stop-provisional-loads.html, we abort the load before this 1868 // callback is invoked. 1869 if (!ds) 1870 return; 1871 1872 DocumentState* document_state = DocumentState::FromDataSource(ds); 1873 1874 // We should only navigate to swappedout:// when is_swapped_out_ is true. 1875 CHECK((ds->request().url() != GURL(kSwappedOutURL)) || 1876 is_swapped_out_ || 1877 render_view_->is_swapped_out()) << 1878 "Heard swappedout:// when not swapped out."; 1879 1880 // Update the request time if WebKit has better knowledge of it. 1881 if (document_state->request_time().is_null()) { 1882 double event_time = ds->triggeringEventTime(); 1883 if (event_time != 0.0) 1884 document_state->set_request_time(Time::FromDoubleT(event_time)); 1885 } 1886 1887 // Start time is only set after request time. 1888 document_state->set_start_load_time(Time::Now()); 1889 1890 bool is_top_most = !frame->parent(); 1891 if (is_top_most) { 1892 render_view_->set_navigation_gesture( 1893 WebUserGestureIndicator::isProcessingUserGesture() ? 1894 NavigationGestureUser : NavigationGestureAuto); 1895 } else if (ds->replacesCurrentHistoryItem()) { 1896 // Subframe navigations that don't add session history items must be 1897 // marked with AUTO_SUBFRAME. See also didFailProvisionalLoad for how we 1898 // handle loading of error pages. 1899 document_state->navigation_state()->set_transition_type( 1900 PAGE_TRANSITION_AUTO_SUBFRAME); 1901 } 1902 1903 FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(), 1904 DidStartProvisionalLoad(frame)); 1905 FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidStartProvisionalLoad()); 1906 1907 Send(new FrameHostMsg_DidStartProvisionalLoadForFrame( 1908 routing_id_, ds->request().url(), is_transition_navigation)); 1909} 1910 1911void RenderFrameImpl::didReceiveServerRedirectForProvisionalLoad( 1912 blink::WebLocalFrame* frame) { 1913 DCHECK(!frame_ || frame_ == frame); 1914 render_view_->history_controller()->RemoveChildrenForRedirect(this); 1915 if (frame->parent()) 1916 return; 1917 // Received a redirect on the main frame. 1918 WebDataSource* data_source = frame->provisionalDataSource(); 1919 if (!data_source) { 1920 // Should only be invoked when we have a data source. 1921 NOTREACHED(); 1922 return; 1923 } 1924 std::vector<GURL> redirects; 1925 GetRedirectChain(data_source, &redirects); 1926 if (redirects.size() >= 2) { 1927 Send(new FrameHostMsg_DidRedirectProvisionalLoad( 1928 routing_id_, 1929 render_view_->page_id_, 1930 redirects[redirects.size() - 2], 1931 redirects.back())); 1932 } 1933} 1934 1935void RenderFrameImpl::didFailProvisionalLoad(blink::WebLocalFrame* frame, 1936 const blink::WebURLError& error) { 1937 DCHECK(!frame_ || frame_ == frame); 1938 WebDataSource* ds = frame->provisionalDataSource(); 1939 DCHECK(ds); 1940 1941 const WebURLRequest& failed_request = ds->request(); 1942 1943 // Notify the browser that we failed a provisional load with an error. 1944 // 1945 // Note: It is important this notification occur before DidStopLoading so the 1946 // SSL manager can react to the provisional load failure before being 1947 // notified the load stopped. 1948 // 1949 FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(), 1950 DidFailProvisionalLoad(frame, error)); 1951 FOR_EACH_OBSERVER(RenderFrameObserver, observers_, 1952 DidFailProvisionalLoad(error)); 1953 1954 bool show_repost_interstitial = 1955 (error.reason == net::ERR_CACHE_MISS && 1956 EqualsASCII(failed_request.httpMethod(), "POST")); 1957 1958 FrameHostMsg_DidFailProvisionalLoadWithError_Params params; 1959 params.error_code = error.reason; 1960 GetContentClient()->renderer()->GetNavigationErrorStrings( 1961 render_view_.get(), 1962 frame, 1963 failed_request, 1964 error, 1965 NULL, 1966 ¶ms.error_description); 1967 params.url = error.unreachableURL; 1968 params.showing_repost_interstitial = show_repost_interstitial; 1969 Send(new FrameHostMsg_DidFailProvisionalLoadWithError( 1970 routing_id_, params)); 1971 1972 // Don't display an error page if this is simply a cancelled load. Aside 1973 // from being dumb, WebCore doesn't expect it and it will cause a crash. 1974 if (error.reason == net::ERR_ABORTED) 1975 return; 1976 1977 // Don't display "client blocked" error page if browser has asked us not to. 1978 if (error.reason == net::ERR_BLOCKED_BY_CLIENT && 1979 render_view_->renderer_preferences_.disable_client_blocked_error_page) { 1980 return; 1981 } 1982 1983 // Allow the embedder to suppress an error page. 1984 if (GetContentClient()->renderer()->ShouldSuppressErrorPage(this, 1985 error.unreachableURL)) { 1986 return; 1987 } 1988 1989 if (RenderThreadImpl::current() && 1990 RenderThreadImpl::current()->layout_test_mode()) { 1991 return; 1992 } 1993 1994 // Make sure we never show errors in view source mode. 1995 frame->enableViewSourceMode(false); 1996 1997 DocumentState* document_state = DocumentState::FromDataSource(ds); 1998 NavigationState* navigation_state = document_state->navigation_state(); 1999 2000 // If this is a failed back/forward/reload navigation, then we need to do a 2001 // 'replace' load. This is necessary to avoid messing up session history. 2002 // Otherwise, we do a normal load, which simulates a 'go' navigation as far 2003 // as session history is concerned. 2004 // 2005 // AUTO_SUBFRAME loads should always be treated as loads that do not advance 2006 // the page id. 2007 // 2008 // TODO(davidben): This should also take the failed navigation's replacement 2009 // state into account, if a location.replace() failed. 2010 bool replace = 2011 navigation_state->pending_page_id() != -1 || 2012 PageTransitionCoreTypeIs(navigation_state->transition_type(), 2013 PAGE_TRANSITION_AUTO_SUBFRAME); 2014 2015 // If we failed on a browser initiated request, then make sure that our error 2016 // page load is regarded as the same browser initiated request. 2017 if (!navigation_state->is_content_initiated()) { 2018 render_view_->pending_navigation_params_.reset( 2019 new FrameMsg_Navigate_Params); 2020 render_view_->pending_navigation_params_->page_id = 2021 navigation_state->pending_page_id(); 2022 render_view_->pending_navigation_params_->pending_history_list_offset = 2023 navigation_state->pending_history_list_offset(); 2024 render_view_->pending_navigation_params_->should_clear_history_list = 2025 navigation_state->history_list_was_cleared(); 2026 render_view_->pending_navigation_params_->transition = 2027 navigation_state->transition_type(); 2028 render_view_->pending_navigation_params_->request_time = 2029 document_state->request_time(); 2030 render_view_->pending_navigation_params_->should_replace_current_entry = 2031 replace; 2032 } 2033 2034 // Load an error page. 2035 LoadNavigationErrorPage(failed_request, error, replace); 2036} 2037 2038void RenderFrameImpl::didCommitProvisionalLoad( 2039 blink::WebLocalFrame* frame, 2040 const blink::WebHistoryItem& item, 2041 blink::WebHistoryCommitType commit_type) { 2042 DCHECK(!frame_ || frame_ == frame); 2043 DocumentState* document_state = 2044 DocumentState::FromDataSource(frame->dataSource()); 2045 NavigationState* navigation_state = document_state->navigation_state(); 2046 2047 // When we perform a new navigation, we need to update the last committed 2048 // session history entry with state for the page we are leaving. Do this 2049 // before updating the HistoryController state. 2050 render_view_->UpdateSessionHistory(frame); 2051 2052 render_view_->history_controller()->UpdateForCommit(this, item, commit_type, 2053 navigation_state->was_within_same_page()); 2054 2055 InternalDocumentStateData* internal_data = 2056 InternalDocumentStateData::FromDocumentState(document_state); 2057 2058 if (document_state->commit_load_time().is_null()) 2059 document_state->set_commit_load_time(Time::Now()); 2060 2061 if (internal_data->must_reset_scroll_and_scale_state()) { 2062 render_view_->webview()->resetScrollAndScaleState(); 2063 internal_data->set_must_reset_scroll_and_scale_state(false); 2064 } 2065 internal_data->set_use_error_page(false); 2066 2067 bool is_new_navigation = commit_type == blink::WebStandardCommit; 2068 if (is_new_navigation) { 2069 // We bump our Page ID to correspond with the new session history entry. 2070 render_view_->page_id_ = render_view_->next_page_id_++; 2071 2072 // Don't update history_page_ids_ (etc) for kSwappedOutURL, since 2073 // we don't want to forget the entry that was there, and since we will 2074 // never come back to kSwappedOutURL. Note that we have to call 2075 // UpdateSessionHistory and update page_id_ even in this case, so that 2076 // the current entry gets a state update and so that we don't send a 2077 // state update to the wrong entry when we swap back in. 2078 if (GetLoadingUrl() != GURL(kSwappedOutURL)) { 2079 // Advance our offset in session history, applying the length limit. 2080 // There is now no forward history. 2081 render_view_->history_list_offset_++; 2082 if (render_view_->history_list_offset_ >= kMaxSessionHistoryEntries) 2083 render_view_->history_list_offset_ = kMaxSessionHistoryEntries - 1; 2084 render_view_->history_list_length_ = 2085 render_view_->history_list_offset_ + 1; 2086 render_view_->history_page_ids_.resize( 2087 render_view_->history_list_length_, -1); 2088 render_view_->history_page_ids_[render_view_->history_list_offset_] = 2089 render_view_->page_id_; 2090 } 2091 } else { 2092 // Inspect the navigation_state on this frame to see if the navigation 2093 // corresponds to a session history navigation... Note: |frame| may or 2094 // may not be the toplevel frame, but for the case of capturing session 2095 // history, the first committed frame suffices. We keep track of whether 2096 // we've seen this commit before so that only capture session history once 2097 // per navigation. 2098 // 2099 // Note that we need to check if the page ID changed. In the case of a 2100 // reload, the page ID doesn't change, and UpdateSessionHistory gets the 2101 // previous URL and the current page ID, which would be wrong. 2102 if (navigation_state->pending_page_id() != -1 && 2103 navigation_state->pending_page_id() != render_view_->page_id_ && 2104 !navigation_state->request_committed()) { 2105 // This is a successful session history navigation! 2106 render_view_->page_id_ = navigation_state->pending_page_id(); 2107 2108 render_view_->history_list_offset_ = 2109 navigation_state->pending_history_list_offset(); 2110 2111 // If the history list is valid, our list of page IDs should be correct. 2112 DCHECK(render_view_->history_list_length_ <= 0 || 2113 render_view_->history_list_offset_ < 0 || 2114 render_view_->history_list_offset_ >= 2115 render_view_->history_list_length_ || 2116 render_view_->history_page_ids_[render_view_->history_list_offset_] 2117 == render_view_->page_id_); 2118 } 2119 } 2120 2121 FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers_, 2122 DidCommitProvisionalLoad(frame, is_new_navigation)); 2123 FOR_EACH_OBSERVER(RenderFrameObserver, observers_, 2124 DidCommitProvisionalLoad(is_new_navigation)); 2125 2126 if (!frame->parent()) { // Only for top frames. 2127 RenderThreadImpl* render_thread_impl = RenderThreadImpl::current(); 2128 if (render_thread_impl) { // Can be NULL in tests. 2129 render_thread_impl->histogram_customizer()-> 2130 RenderViewNavigatedToHost(GURL(GetLoadingUrl()).host(), 2131 RenderViewImpl::GetRenderViewCount()); 2132 } 2133 } 2134 2135 // Remember that we've already processed this request, so we don't update 2136 // the session history again. We do this regardless of whether this is 2137 // a session history navigation, because if we attempted a session history 2138 // navigation without valid HistoryItem state, WebCore will think it is a 2139 // new navigation. 2140 navigation_state->set_request_committed(true); 2141 2142 SendDidCommitProvisionalLoad(frame); 2143 2144 // Check whether we have new encoding name. 2145 UpdateEncoding(frame, frame->view()->pageEncoding().utf8()); 2146} 2147 2148void RenderFrameImpl::didClearWindowObject(blink::WebLocalFrame* frame) { 2149 DCHECK(!frame_ || frame_ == frame); 2150 // TODO(nasko): Move implementation here. Needed state: 2151 // * enabled_bindings_ 2152 // * dom_automation_controller_ 2153 // * stats_collection_controller_ 2154 2155 render_view_->didClearWindowObject(frame); 2156 2157 if (render_view_->GetEnabledBindings() & BINDINGS_POLICY_DOM_AUTOMATION) 2158 DomAutomationController::Install(this, frame); 2159 2160 FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidClearWindowObject()); 2161} 2162 2163void RenderFrameImpl::didCreateDocumentElement(blink::WebLocalFrame* frame) { 2164 DCHECK(!frame_ || frame_ == frame); 2165 2166 // Notify the browser about non-blank documents loading in the top frame. 2167 GURL url = frame->document().url(); 2168 if (url.is_valid() && url.spec() != url::kAboutBlankURL) { 2169 // TODO(nasko): Check if webview()->mainFrame() is the same as the 2170 // frame->tree()->top(). 2171 blink::WebFrame* main_frame = render_view_->webview()->mainFrame(); 2172 if (frame == main_frame) { 2173 // For now, don't remember plugin zoom values. We don't want to mix them 2174 // with normal web content (i.e. a fixed layout plugin would usually want 2175 // them different). 2176 render_view_->Send(new ViewHostMsg_DocumentAvailableInMainFrame( 2177 render_view_->GetRoutingID(), 2178 main_frame->document().isPluginDocument())); 2179 } 2180 } 2181 2182 FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(), 2183 DidCreateDocumentElement(frame)); 2184} 2185 2186void RenderFrameImpl::didReceiveTitle(blink::WebLocalFrame* frame, 2187 const blink::WebString& title, 2188 blink::WebTextDirection direction) { 2189 DCHECK(!frame_ || frame_ == frame); 2190 // Ignore all but top level navigations. 2191 if (!frame->parent()) { 2192 base::string16 title16 = title; 2193 base::debug::TraceLog::GetInstance()->UpdateProcessLabel( 2194 routing_id_, base::UTF16ToUTF8(title16)); 2195 2196 base::string16 shortened_title = title16.substr(0, kMaxTitleChars); 2197 Send(new FrameHostMsg_UpdateTitle(routing_id_, 2198 render_view_->page_id_, 2199 shortened_title, direction)); 2200 } 2201 2202 // Also check whether we have new encoding name. 2203 UpdateEncoding(frame, frame->view()->pageEncoding().utf8()); 2204} 2205 2206void RenderFrameImpl::didChangeIcon(blink::WebLocalFrame* frame, 2207 blink::WebIconURL::Type icon_type) { 2208 DCHECK(!frame_ || frame_ == frame); 2209 // TODO(nasko): Investigate wheather implementation should move here. 2210 render_view_->didChangeIcon(frame, icon_type); 2211} 2212 2213void RenderFrameImpl::didFinishDocumentLoad(blink::WebLocalFrame* frame) { 2214 DCHECK(!frame_ || frame_ == frame); 2215 WebDataSource* ds = frame->dataSource(); 2216 DocumentState* document_state = DocumentState::FromDataSource(ds); 2217 document_state->set_finish_document_load_time(Time::Now()); 2218 2219 Send(new FrameHostMsg_DidFinishDocumentLoad(routing_id_)); 2220 2221 FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(), 2222 DidFinishDocumentLoad(frame)); 2223 FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidFinishDocumentLoad()); 2224 2225 // Check whether we have new encoding name. 2226 UpdateEncoding(frame, frame->view()->pageEncoding().utf8()); 2227} 2228 2229void RenderFrameImpl::didHandleOnloadEvents(blink::WebLocalFrame* frame) { 2230 DCHECK(!frame_ || frame_ == frame); 2231 if (!frame->parent()) 2232 Send(new FrameHostMsg_DocumentOnLoadCompleted(routing_id_)); 2233} 2234 2235void RenderFrameImpl::didFailLoad(blink::WebLocalFrame* frame, 2236 const blink::WebURLError& error) { 2237 DCHECK(!frame_ || frame_ == frame); 2238 // TODO(nasko): Move implementation here. No state needed. 2239 WebDataSource* ds = frame->dataSource(); 2240 DCHECK(ds); 2241 2242 FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(), 2243 DidFailLoad(frame, error)); 2244 2245 const WebURLRequest& failed_request = ds->request(); 2246 base::string16 error_description; 2247 GetContentClient()->renderer()->GetNavigationErrorStrings( 2248 render_view_.get(), 2249 frame, 2250 failed_request, 2251 error, 2252 NULL, 2253 &error_description); 2254 Send(new FrameHostMsg_DidFailLoadWithError(routing_id_, 2255 failed_request.url(), 2256 error.reason, 2257 error_description)); 2258} 2259 2260void RenderFrameImpl::didFinishLoad(blink::WebLocalFrame* frame) { 2261 DCHECK(!frame_ || frame_ == frame); 2262 WebDataSource* ds = frame->dataSource(); 2263 DocumentState* document_state = DocumentState::FromDataSource(ds); 2264 if (document_state->finish_load_time().is_null()) { 2265 if (!frame->parent()) { 2266 TRACE_EVENT_INSTANT0("WebCore", "LoadFinished", 2267 TRACE_EVENT_SCOPE_PROCESS); 2268 } 2269 document_state->set_finish_load_time(Time::Now()); 2270 } 2271 2272 FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(), 2273 DidFinishLoad(frame)); 2274 FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidFinishLoad()); 2275 2276 // Don't send this message while the frame is swapped out. 2277 if (is_swapped_out()) 2278 return; 2279 2280 Send(new FrameHostMsg_DidFinishLoad(routing_id_, 2281 ds->request().url())); 2282} 2283 2284void RenderFrameImpl::didNavigateWithinPage(blink::WebLocalFrame* frame, 2285 const blink::WebHistoryItem& item, 2286 blink::WebHistoryCommitType commit_type) { 2287 DCHECK(!frame_ || frame_ == frame); 2288 // If this was a reference fragment navigation that we initiated, then we 2289 // could end up having a non-null pending navigation params. We just need to 2290 // update the ExtraData on the datasource so that others who read the 2291 // ExtraData will get the new NavigationState. Similarly, if we did not 2292 // initiate this navigation, then we need to take care to reset any pre- 2293 // existing navigation state to a content-initiated navigation state. 2294 // DidCreateDataSource conveniently takes care of this for us. 2295 didCreateDataSource(frame, frame->dataSource()); 2296 2297 DocumentState* document_state = 2298 DocumentState::FromDataSource(frame->dataSource()); 2299 NavigationState* new_state = document_state->navigation_state(); 2300 new_state->set_was_within_same_page(true); 2301 2302 didCommitProvisionalLoad(frame, item, commit_type); 2303} 2304 2305void RenderFrameImpl::didUpdateCurrentHistoryItem(blink::WebLocalFrame* frame) { 2306 DCHECK(!frame_ || frame_ == frame); 2307 // TODO(nasko): Move implementation here. Needed methods: 2308 // * StartNavStateSyncTimerIfNecessary 2309 render_view_->didUpdateCurrentHistoryItem(frame); 2310} 2311 2312void RenderFrameImpl::addNavigationTransitionData( 2313 const blink::WebString& allowed_destination_host_pattern, 2314 const blink::WebString& selector, 2315 const blink::WebString& markup) { 2316 Send(new FrameHostMsg_AddNavigationTransitionData( 2317 routing_id_, allowed_destination_host_pattern.utf8(), selector.utf8(), 2318 markup.utf8())); 2319} 2320 2321void RenderFrameImpl::didChangeThemeColor() { 2322 if (frame_->parent()) 2323 return; 2324 2325 Send(new FrameHostMsg_DidChangeThemeColor( 2326 routing_id_, frame_->document().themeColor())); 2327} 2328 2329void RenderFrameImpl::requestNotificationPermission( 2330 const blink::WebSecurityOrigin& origin, 2331 blink::WebNotificationPermissionCallback* callback) { 2332 if (!notification_permission_dispatcher_) { 2333 notification_permission_dispatcher_ = 2334 new NotificationPermissionDispatcher(this); 2335 } 2336 2337 notification_permission_dispatcher_->RequestPermission(origin, callback); 2338} 2339 2340blink::WebNotificationPresenter* RenderFrameImpl::notificationPresenter() { 2341 return notification_provider_; 2342} 2343 2344void RenderFrameImpl::didChangeSelection(bool is_empty_selection) { 2345 if (!GetRenderWidget()->handling_input_event() && !handling_select_range_) 2346 return; 2347 2348 if (is_empty_selection) 2349 selection_text_.clear(); 2350 2351 // UpdateTextInputState should be called before SyncSelectionIfRequired. 2352 // UpdateTextInputState may send TextInputStateChanged to notify the focus 2353 // was changed, and SyncSelectionIfRequired may send SelectionChanged 2354 // to notify the selection was changed. Focus change should be notified 2355 // before selection change. 2356 GetRenderWidget()->UpdateTextInputState( 2357 RenderWidget::NO_SHOW_IME, RenderWidget::FROM_NON_IME); 2358 SyncSelectionIfRequired(); 2359} 2360 2361blink::WebColorChooser* RenderFrameImpl::createColorChooser( 2362 blink::WebColorChooserClient* client, 2363 const blink::WebColor& initial_color, 2364 const blink::WebVector<blink::WebColorSuggestion>& suggestions) { 2365 RendererWebColorChooserImpl* color_chooser = 2366 new RendererWebColorChooserImpl(this, client); 2367 std::vector<content::ColorSuggestion> color_suggestions; 2368 for (size_t i = 0; i < suggestions.size(); i++) { 2369 color_suggestions.push_back(content::ColorSuggestion(suggestions[i])); 2370 } 2371 color_chooser->Open(static_cast<SkColor>(initial_color), color_suggestions); 2372 return color_chooser; 2373} 2374 2375void RenderFrameImpl::runModalAlertDialog(const blink::WebString& message) { 2376 RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_ALERT, 2377 message, 2378 base::string16(), 2379 frame_->document().url(), 2380 NULL); 2381} 2382 2383bool RenderFrameImpl::runModalConfirmDialog(const blink::WebString& message) { 2384 return RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_CONFIRM, 2385 message, 2386 base::string16(), 2387 frame_->document().url(), 2388 NULL); 2389} 2390 2391bool RenderFrameImpl::runModalPromptDialog( 2392 const blink::WebString& message, 2393 const blink::WebString& default_value, 2394 blink::WebString* actual_value) { 2395 base::string16 result; 2396 bool ok = RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_PROMPT, 2397 message, 2398 default_value, 2399 frame_->document().url(), 2400 &result); 2401 if (ok) 2402 actual_value->assign(result); 2403 return ok; 2404} 2405 2406bool RenderFrameImpl::runModalBeforeUnloadDialog( 2407 bool is_reload, 2408 const blink::WebString& message) { 2409 // If we are swapping out, we have already run the beforeunload handler. 2410 // TODO(creis): Fix OnSwapOut to clear the frame without running beforeunload 2411 // at all, to avoid running it twice. 2412 if (render_view()->is_swapped_out_) 2413 return true; 2414 2415 // Don't allow further dialogs if we are waiting to swap out, since the 2416 // PageGroupLoadDeferrer in our stack prevents it. 2417 if (render_view()->suppress_dialogs_until_swap_out_) 2418 return false; 2419 2420 bool success = false; 2421 // This is an ignored return value, but is included so we can accept the same 2422 // response as RunJavaScriptMessage. 2423 base::string16 ignored_result; 2424 render_view()->SendAndRunNestedMessageLoop( 2425 new FrameHostMsg_RunBeforeUnloadConfirm( 2426 routing_id_, frame_->document().url(), message, is_reload, 2427 &success, &ignored_result)); 2428 return success; 2429} 2430 2431void RenderFrameImpl::showContextMenu(const blink::WebContextMenuData& data) { 2432 ContextMenuParams params = ContextMenuParamsBuilder::Build(data); 2433 params.source_type = GetRenderWidget()->context_menu_source_type(); 2434 GetRenderWidget()->OnShowHostContextMenu(¶ms); 2435 if (GetRenderWidget()->has_host_context_menu_location()) { 2436 params.x = GetRenderWidget()->host_context_menu_location().x(); 2437 params.y = GetRenderWidget()->host_context_menu_location().y(); 2438 } 2439 2440 // Plugins, e.g. PDF, don't currently update the render view when their 2441 // selected text changes, but the context menu params do contain the updated 2442 // selection. If that's the case, update the render view's state just prior 2443 // to showing the context menu. 2444 // TODO(asvitkine): http://crbug.com/152432 2445 if (ShouldUpdateSelectionTextFromContextMenuParams( 2446 selection_text_, selection_text_offset_, selection_range_, params)) { 2447 selection_text_ = params.selection_text; 2448 // TODO(asvitkine): Text offset and range is not available in this case. 2449 selection_text_offset_ = 0; 2450 selection_range_ = gfx::Range(0, selection_text_.length()); 2451 // This IPC is dispatched by RenderWidetHost, so use its routing ID. 2452 Send(new ViewHostMsg_SelectionChanged( 2453 GetRenderWidget()->routing_id(), selection_text_, 2454 selection_text_offset_, selection_range_)); 2455 } 2456 2457 // Serializing a GURL longer than kMaxURLChars will fail, so don't do 2458 // it. We replace it with an empty GURL so the appropriate items are disabled 2459 // in the context menu. 2460 // TODO(jcivelli): http://crbug.com/45160 This prevents us from saving large 2461 // data encoded images. We should have a way to save them. 2462 if (params.src_url.spec().size() > GetMaxURLChars()) 2463 params.src_url = GURL(); 2464 context_menu_node_ = data.node; 2465 2466#if defined(OS_ANDROID) 2467 gfx::Rect start_rect; 2468 gfx::Rect end_rect; 2469 GetRenderWidget()->GetSelectionBounds(&start_rect, &end_rect); 2470 params.selection_start = gfx::Point(start_rect.x(), start_rect.bottom()); 2471 params.selection_end = gfx::Point(end_rect.right(), end_rect.bottom()); 2472#endif 2473 2474 Send(new FrameHostMsg_ContextMenu(routing_id_, params)); 2475} 2476 2477void RenderFrameImpl::clearContextMenu() { 2478 context_menu_node_.reset(); 2479} 2480 2481void RenderFrameImpl::willSendRequest( 2482 blink::WebLocalFrame* frame, 2483 unsigned identifier, 2484 blink::WebURLRequest& request, 2485 const blink::WebURLResponse& redirect_response) { 2486 DCHECK(!frame_ || frame_ == frame); 2487 // The request my be empty during tests. 2488 if (request.url().isEmpty()) 2489 return; 2490 2491 // Set the first party for cookies url if it has not been set yet (new 2492 // requests). For redirects, it is updated by WebURLLoaderImpl. 2493 if (request.firstPartyForCookies().isEmpty()) { 2494 if (request.frameType() == blink::WebURLRequest::FrameTypeTopLevel) { 2495 request.setFirstPartyForCookies(request.url()); 2496 } else { 2497 // TODO(nasko): When the top-level frame is remote, there is no document. 2498 // This is broken and should be fixed to propagate the first party. 2499 WebFrame* top = frame->top(); 2500 if (top->isWebLocalFrame()) { 2501 request.setFirstPartyForCookies( 2502 frame->top()->document().firstPartyForCookies()); 2503 } 2504 } 2505 } 2506 2507 WebFrame* top_frame = frame->top(); 2508 // TODO(nasko): Hack around asking about top-frame data source. This means 2509 // for out-of-process iframes we are treating the current frame as the 2510 // top-level frame, which is wrong. 2511 if (!top_frame || top_frame->isWebRemoteFrame()) 2512 top_frame = frame; 2513 WebDataSource* provisional_data_source = top_frame->provisionalDataSource(); 2514 WebDataSource* top_data_source = top_frame->dataSource(); 2515 WebDataSource* data_source = 2516 provisional_data_source ? provisional_data_source : top_data_source; 2517 2518 PageTransition transition_type = PAGE_TRANSITION_LINK; 2519 DocumentState* document_state = DocumentState::FromDataSource(data_source); 2520 DCHECK(document_state); 2521 InternalDocumentStateData* internal_data = 2522 InternalDocumentStateData::FromDocumentState(document_state); 2523 NavigationState* navigation_state = document_state->navigation_state(); 2524 transition_type = navigation_state->transition_type(); 2525 2526 GURL request_url(request.url()); 2527 GURL new_url; 2528 if (GetContentClient()->renderer()->WillSendRequest( 2529 frame, 2530 transition_type, 2531 request_url, 2532 request.firstPartyForCookies(), 2533 &new_url)) { 2534 request.setURL(WebURL(new_url)); 2535 } 2536 2537 if (internal_data->is_cache_policy_override_set()) 2538 request.setCachePolicy(internal_data->cache_policy_override()); 2539 2540 // The request's extra data may indicate that we should set a custom user 2541 // agent. This needs to be done here, after WebKit is through with setting the 2542 // user agent on its own. Similarly, it may indicate that we should set an 2543 // X-Requested-With header. This must be done here to avoid breaking CORS 2544 // checks. 2545 WebString custom_user_agent; 2546 WebString requested_with; 2547 if (request.extraData()) { 2548 RequestExtraData* old_extra_data = 2549 static_cast<RequestExtraData*>(request.extraData()); 2550 2551 custom_user_agent = old_extra_data->custom_user_agent(); 2552 if (!custom_user_agent.isNull()) { 2553 if (custom_user_agent.isEmpty()) 2554 request.clearHTTPHeaderField("User-Agent"); 2555 else 2556 request.setHTTPHeaderField("User-Agent", custom_user_agent); 2557 } 2558 2559 requested_with = old_extra_data->requested_with(); 2560 if (!requested_with.isNull()) { 2561 if (requested_with.isEmpty()) 2562 request.clearHTTPHeaderField("X-Requested-With"); 2563 else 2564 request.setHTTPHeaderField("X-Requested-With", requested_with); 2565 } 2566 } 2567 2568 // Add the default accept header for frame request if it has not been set 2569 // already. 2570 if ((request.frameType() == blink::WebURLRequest::FrameTypeTopLevel || 2571 request.frameType() == blink::WebURLRequest::FrameTypeNested) && 2572 request.httpHeaderField(WebString::fromUTF8(kAcceptHeader)).isEmpty()) { 2573 request.setHTTPHeaderField(WebString::fromUTF8(kAcceptHeader), 2574 WebString::fromUTF8(kDefaultAcceptHeader)); 2575 } 2576 2577 // Add an empty HTTP origin header for non GET methods if none is currently 2578 // present. 2579 request.addHTTPOriginIfNeeded(WebString()); 2580 2581 // Attach |should_replace_current_entry| state to requests so that, should 2582 // this navigation later require a request transfer, all state is preserved 2583 // when it is re-created in the new process. 2584 bool should_replace_current_entry = false; 2585 if (navigation_state->is_content_initiated()) { 2586 should_replace_current_entry = data_source->replacesCurrentHistoryItem(); 2587 } else { 2588 // If the navigation is browser-initiated, the NavigationState contains the 2589 // correct value instead of the WebDataSource. 2590 // 2591 // TODO(davidben): Avoid this awkward duplication of state. See comment on 2592 // NavigationState::should_replace_current_entry(). 2593 should_replace_current_entry = 2594 navigation_state->should_replace_current_entry(); 2595 } 2596 2597 int provider_id = kInvalidServiceWorkerProviderId; 2598 if (request.frameType() == blink::WebURLRequest::FrameTypeTopLevel || 2599 request.frameType() == blink::WebURLRequest::FrameTypeNested) { 2600 // |provisionalDataSource| may be null in some content::ResourceFetcher 2601 // use cases, we don't hook those requests. 2602 if (frame->provisionalDataSource()) { 2603 ServiceWorkerNetworkProvider* provider = 2604 ServiceWorkerNetworkProvider::FromDocumentState( 2605 DocumentState::FromDataSource(frame->provisionalDataSource())); 2606 provider_id = provider->provider_id(); 2607 } 2608 } else if (frame->dataSource()) { 2609 ServiceWorkerNetworkProvider* provider = 2610 ServiceWorkerNetworkProvider::FromDocumentState( 2611 DocumentState::FromDataSource(frame->dataSource())); 2612 provider_id = provider->provider_id(); 2613 } 2614 2615 WebFrame* parent = frame->parent(); 2616 int parent_routing_id = MSG_ROUTING_NONE; 2617 if (!parent) { 2618 parent_routing_id = -1; 2619 } else if (parent->isWebLocalFrame()) { 2620 parent_routing_id = FromWebFrame(parent)->GetRoutingID(); 2621 } else { 2622 parent_routing_id = RenderFrameProxy::FromWebFrame(parent)->routing_id(); 2623 } 2624 2625 RequestExtraData* extra_data = new RequestExtraData(); 2626 extra_data->set_visibility_state(render_view_->visibilityState()); 2627 extra_data->set_custom_user_agent(custom_user_agent); 2628 extra_data->set_requested_with(requested_with); 2629 extra_data->set_render_frame_id(routing_id_); 2630 extra_data->set_is_main_frame(frame == top_frame); 2631 extra_data->set_frame_origin( 2632 GURL(frame->document().securityOrigin().toString())); 2633 extra_data->set_parent_is_main_frame(frame->parent() == top_frame); 2634 extra_data->set_parent_render_frame_id(parent_routing_id); 2635 extra_data->set_allow_download(navigation_state->allow_download()); 2636 extra_data->set_transition_type(transition_type); 2637 extra_data->set_should_replace_current_entry(should_replace_current_entry); 2638 extra_data->set_transferred_request_child_id( 2639 navigation_state->transferred_request_child_id()); 2640 extra_data->set_transferred_request_request_id( 2641 navigation_state->transferred_request_request_id()); 2642 extra_data->set_service_worker_provider_id(provider_id); 2643 request.setExtraData(extra_data); 2644 2645 DocumentState* top_document_state = 2646 DocumentState::FromDataSource(top_data_source); 2647 if (top_document_state) { 2648 // TODO(gavinp): separate out prefetching and prerender field trials 2649 // if the rel=prerender rel type is sticking around. 2650 if (request.requestContext() == WebURLRequest::RequestContextPrefetch) 2651 top_document_state->set_was_prefetcher(true); 2652 } 2653 2654 // This is an instance where we embed a copy of the routing id 2655 // into the data portion of the message. This can cause problems if we 2656 // don't register this id on the browser side, since the download manager 2657 // expects to find a RenderViewHost based off the id. 2658 request.setRequestorID(render_view_->GetRoutingID()); 2659 request.setHasUserGesture(WebUserGestureIndicator::isProcessingUserGesture()); 2660 2661 if (!navigation_state->extra_headers().empty()) { 2662 for (net::HttpUtil::HeadersIterator i( 2663 navigation_state->extra_headers().begin(), 2664 navigation_state->extra_headers().end(), "\n"); 2665 i.GetNext(); ) { 2666 if (LowerCaseEqualsASCII(i.name(), "referer")) { 2667 WebString referrer = WebSecurityPolicy::generateReferrerHeader( 2668 blink::WebReferrerPolicyDefault, 2669 request.url(), 2670 WebString::fromUTF8(i.values())); 2671 request.setHTTPReferrer(referrer, blink::WebReferrerPolicyDefault); 2672 } else { 2673 request.setHTTPHeaderField(WebString::fromUTF8(i.name()), 2674 WebString::fromUTF8(i.values())); 2675 } 2676 } 2677 } 2678 2679 if (!render_view_->renderer_preferences_.enable_referrers) 2680 request.setHTTPReferrer(WebString(), blink::WebReferrerPolicyDefault); 2681} 2682 2683void RenderFrameImpl::didReceiveResponse( 2684 blink::WebLocalFrame* frame, 2685 unsigned identifier, 2686 const blink::WebURLResponse& response) { 2687 DCHECK(!frame_ || frame_ == frame); 2688 // Only do this for responses that correspond to a provisional data source 2689 // of the top-most frame. If we have a provisional data source, then we 2690 // can't have any sub-resources yet, so we know that this response must 2691 // correspond to a frame load. 2692 if (!frame->provisionalDataSource() || frame->parent()) 2693 return; 2694 2695 // If we are in view source mode, then just let the user see the source of 2696 // the server's error page. 2697 if (frame->isViewSourceModeEnabled()) 2698 return; 2699 2700 DocumentState* document_state = 2701 DocumentState::FromDataSource(frame->provisionalDataSource()); 2702 int http_status_code = response.httpStatusCode(); 2703 2704 // Record page load flags. 2705 WebURLResponseExtraDataImpl* extra_data = GetExtraDataFromResponse(response); 2706 if (extra_data) { 2707 document_state->set_was_fetched_via_spdy( 2708 extra_data->was_fetched_via_spdy()); 2709 document_state->set_was_npn_negotiated( 2710 extra_data->was_npn_negotiated()); 2711 document_state->set_npn_negotiated_protocol( 2712 extra_data->npn_negotiated_protocol()); 2713 document_state->set_was_alternate_protocol_available( 2714 extra_data->was_alternate_protocol_available()); 2715 document_state->set_connection_info( 2716 extra_data->connection_info()); 2717 document_state->set_was_fetched_via_proxy( 2718 extra_data->was_fetched_via_proxy()); 2719 } 2720 InternalDocumentStateData* internal_data = 2721 InternalDocumentStateData::FromDocumentState(document_state); 2722 internal_data->set_http_status_code(http_status_code); 2723 // Whether or not the http status code actually corresponds to an error is 2724 // only checked when the page is done loading, if |use_error_page| is 2725 // still true. 2726 internal_data->set_use_error_page(true); 2727} 2728 2729void RenderFrameImpl::didFinishResourceLoad(blink::WebLocalFrame* frame, 2730 unsigned identifier) { 2731 DCHECK(!frame_ || frame_ == frame); 2732 InternalDocumentStateData* internal_data = 2733 InternalDocumentStateData::FromDataSource(frame->dataSource()); 2734 if (!internal_data->use_error_page()) 2735 return; 2736 2737 // Do not show error page when DevTools is attached. 2738 if (render_view_->devtools_agent_->IsAttached()) 2739 return; 2740 2741 // Display error page, if appropriate. 2742 std::string error_domain = "http"; 2743 int http_status_code = internal_data->http_status_code(); 2744 if (GetContentClient()->renderer()->HasErrorPage( 2745 http_status_code, &error_domain)) { 2746 WebURLError error; 2747 error.unreachableURL = frame->document().url(); 2748 error.domain = WebString::fromUTF8(error_domain); 2749 error.reason = http_status_code; 2750 LoadNavigationErrorPage(frame->dataSource()->request(), error, true); 2751 } 2752} 2753 2754void RenderFrameImpl::didLoadResourceFromMemoryCache( 2755 blink::WebLocalFrame* frame, 2756 const blink::WebURLRequest& request, 2757 const blink::WebURLResponse& response) { 2758 DCHECK(!frame_ || frame_ == frame); 2759 // The recipients of this message have no use for data: URLs: they don't 2760 // affect the page's insecure content list and are not in the disk cache. To 2761 // prevent large (1M+) data: URLs from crashing in the IPC system, we simply 2762 // filter them out here. 2763 GURL url(request.url()); 2764 if (url.SchemeIs("data")) 2765 return; 2766 2767 // Let the browser know we loaded a resource from the memory cache. This 2768 // message is needed to display the correct SSL indicators. 2769 render_view_->Send(new ViewHostMsg_DidLoadResourceFromMemoryCache( 2770 render_view_->GetRoutingID(), 2771 url, 2772 response.securityInfo(), 2773 request.httpMethod().utf8(), 2774 response.mimeType().utf8(), 2775 WebURLRequestToResourceType(request))); 2776} 2777 2778void RenderFrameImpl::didDisplayInsecureContent(blink::WebLocalFrame* frame) { 2779 DCHECK(!frame_ || frame_ == frame); 2780 render_view_->Send(new ViewHostMsg_DidDisplayInsecureContent( 2781 render_view_->GetRoutingID())); 2782} 2783 2784void RenderFrameImpl::didRunInsecureContent( 2785 blink::WebLocalFrame* frame, 2786 const blink::WebSecurityOrigin& origin, 2787 const blink::WebURL& target) { 2788 DCHECK(!frame_ || frame_ == frame); 2789 render_view_->Send(new ViewHostMsg_DidRunInsecureContent( 2790 render_view_->GetRoutingID(), 2791 origin.toString().utf8(), 2792 target)); 2793} 2794 2795void RenderFrameImpl::didAbortLoading(blink::WebLocalFrame* frame) { 2796 DCHECK(!frame_ || frame_ == frame); 2797#if defined(ENABLE_PLUGINS) 2798 if (frame != render_view_->webview()->mainFrame()) 2799 return; 2800 PluginChannelHost::Broadcast( 2801 new PluginHostMsg_DidAbortLoading(render_view_->GetRoutingID())); 2802#endif 2803} 2804 2805void RenderFrameImpl::didCreateScriptContext(blink::WebLocalFrame* frame, 2806 v8::Handle<v8::Context> context, 2807 int extension_group, 2808 int world_id) { 2809 DCHECK(!frame_ || frame_ == frame); 2810 GetContentClient()->renderer()->DidCreateScriptContext( 2811 frame, context, extension_group, world_id); 2812} 2813 2814void RenderFrameImpl::willReleaseScriptContext(blink::WebLocalFrame* frame, 2815 v8::Handle<v8::Context> context, 2816 int world_id) { 2817 DCHECK(!frame_ || frame_ == frame); 2818 2819 FOR_EACH_OBSERVER(RenderFrameObserver, 2820 observers_, 2821 WillReleaseScriptContext(context, world_id)); 2822} 2823 2824void RenderFrameImpl::didFirstVisuallyNonEmptyLayout( 2825 blink::WebLocalFrame* frame) { 2826 DCHECK(!frame_ || frame_ == frame); 2827 if (frame->parent()) 2828 return; 2829 2830 InternalDocumentStateData* data = 2831 InternalDocumentStateData::FromDataSource(frame->dataSource()); 2832 data->set_did_first_visually_non_empty_layout(true); 2833 2834#if defined(OS_ANDROID) 2835 GetRenderWidget()->DidChangeBodyBackgroundColor( 2836 render_view_->webwidget_->backgroundColor()); 2837#endif 2838 2839 GetRenderWidget()->QueueMessage( 2840 new FrameHostMsg_DidFirstVisuallyNonEmptyPaint(routing_id_), 2841 MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE); 2842} 2843 2844void RenderFrameImpl::didChangeScrollOffset(blink::WebLocalFrame* frame) { 2845 DCHECK(!frame_ || frame_ == frame); 2846 // TODO(nasko): Move implementation here. Needed methods: 2847 // * StartNavStateSyncTimerIfNecessary 2848 render_view_->didChangeScrollOffset(frame); 2849} 2850 2851void RenderFrameImpl::willInsertBody(blink::WebLocalFrame* frame) { 2852 DCHECK(!frame_ || frame_ == frame); 2853 if (!frame->parent()) { 2854 render_view_->Send(new ViewHostMsg_WillInsertBody( 2855 render_view_->GetRoutingID())); 2856 } 2857} 2858 2859void RenderFrameImpl::reportFindInPageMatchCount(int request_id, 2860 int count, 2861 bool final_update) { 2862 int active_match_ordinal = -1; // -1 = don't update active match ordinal 2863 if (!count) 2864 active_match_ordinal = 0; 2865 2866 render_view_->Send(new ViewHostMsg_Find_Reply( 2867 render_view_->GetRoutingID(), request_id, count, 2868 gfx::Rect(), active_match_ordinal, final_update)); 2869} 2870 2871void RenderFrameImpl::reportFindInPageSelection( 2872 int request_id, 2873 int active_match_ordinal, 2874 const blink::WebRect& selection_rect) { 2875 render_view_->Send(new ViewHostMsg_Find_Reply( 2876 render_view_->GetRoutingID(), request_id, -1, selection_rect, 2877 active_match_ordinal, false)); 2878} 2879 2880void RenderFrameImpl::requestStorageQuota( 2881 blink::WebLocalFrame* frame, 2882 blink::WebStorageQuotaType type, 2883 unsigned long long requested_size, 2884 blink::WebStorageQuotaCallbacks callbacks) { 2885 DCHECK(!frame_ || frame_ == frame); 2886 WebSecurityOrigin origin = frame->document().securityOrigin(); 2887 if (origin.isUnique()) { 2888 // Unique origins cannot store persistent state. 2889 callbacks.didFail(blink::WebStorageQuotaErrorAbort); 2890 return; 2891 } 2892 ChildThread::current()->quota_dispatcher()->RequestStorageQuota( 2893 render_view_->GetRoutingID(), 2894 GURL(origin.toString()), 2895 static_cast<storage::StorageType>(type), 2896 requested_size, 2897 QuotaDispatcher::CreateWebStorageQuotaCallbacksWrapper(callbacks)); 2898} 2899 2900void RenderFrameImpl::willOpenSocketStream( 2901 blink::WebSocketStreamHandle* handle) { 2902 WebSocketStreamHandleImpl* impl = 2903 static_cast<WebSocketStreamHandleImpl*>(handle); 2904 impl->SetUserData(handle, new SocketStreamHandleData(routing_id_)); 2905} 2906 2907void RenderFrameImpl::willOpenWebSocket(blink::WebSocketHandle* handle) { 2908 WebSocketBridge* impl = static_cast<WebSocketBridge*>(handle); 2909 impl->set_render_frame_id(routing_id_); 2910} 2911 2912blink::WebGeolocationClient* RenderFrameImpl::geolocationClient() { 2913 if (!geolocation_dispatcher_) 2914 geolocation_dispatcher_ = new GeolocationDispatcher(this); 2915 return geolocation_dispatcher_; 2916} 2917 2918blink::WebPushClient* RenderFrameImpl::pushClient() { 2919 if (!push_messaging_dispatcher_) 2920 push_messaging_dispatcher_ = new PushMessagingDispatcher(this); 2921 return push_messaging_dispatcher_; 2922} 2923 2924void RenderFrameImpl::willStartUsingPeerConnectionHandler( 2925 blink::WebLocalFrame* frame, 2926 blink::WebRTCPeerConnectionHandler* handler) { 2927 DCHECK(!frame_ || frame_ == frame); 2928#if defined(ENABLE_WEBRTC) 2929 static_cast<RTCPeerConnectionHandler*>(handler)->associateWithFrame(frame); 2930#endif 2931} 2932 2933blink::WebUserMediaClient* RenderFrameImpl::userMediaClient() { 2934 if (!web_user_media_client_) 2935 InitializeUserMediaClient(); 2936 return web_user_media_client_; 2937} 2938 2939blink::WebMIDIClient* RenderFrameImpl::webMIDIClient() { 2940 if (!midi_dispatcher_) 2941 midi_dispatcher_ = new MidiDispatcher(this); 2942 return midi_dispatcher_; 2943} 2944 2945bool RenderFrameImpl::willCheckAndDispatchMessageEvent( 2946 blink::WebLocalFrame* source_frame, 2947 blink::WebFrame* target_frame, 2948 blink::WebSecurityOrigin target_origin, 2949 blink::WebDOMMessageEvent event) { 2950 DCHECK(!frame_ || frame_ == target_frame); 2951 2952 if (!render_view_->is_swapped_out_) 2953 return false; 2954 2955 ViewMsg_PostMessage_Params params; 2956 params.is_data_raw_string = false; 2957 params.data = event.data().toString(); 2958 params.source_origin = event.origin(); 2959 if (!target_origin.isNull()) 2960 params.target_origin = target_origin.toString(); 2961 2962 blink::WebMessagePortChannelArray channels = event.releaseChannels(); 2963 if (!channels.isEmpty()) { 2964 std::vector<int> message_port_ids(channels.size()); 2965 // Extract the port IDs from the channel array. 2966 for (size_t i = 0; i < channels.size(); ++i) { 2967 WebMessagePortChannelImpl* webchannel = 2968 static_cast<WebMessagePortChannelImpl*>(channels[i]); 2969 message_port_ids[i] = webchannel->message_port_id(); 2970 webchannel->QueueMessages(); 2971 DCHECK_NE(message_port_ids[i], MSG_ROUTING_NONE); 2972 } 2973 params.message_port_ids = message_port_ids; 2974 } 2975 2976 // Include the routing ID for the source frame (if one exists), which the 2977 // browser process will translate into the routing ID for the equivalent 2978 // frame in the target process. 2979 params.source_routing_id = MSG_ROUTING_NONE; 2980 if (source_frame) { 2981 RenderViewImpl* source_view = 2982 RenderViewImpl::FromWebView(source_frame->view()); 2983 if (source_view) 2984 params.source_routing_id = source_view->routing_id(); 2985 } 2986 2987 Send(new ViewHostMsg_RouteMessageEvent(render_view_->routing_id_, params)); 2988 return true; 2989} 2990 2991blink::WebString RenderFrameImpl::userAgentOverride(blink::WebLocalFrame* frame, 2992 const blink::WebURL& url) { 2993 DCHECK(!frame_ || frame_ == frame); 2994 if (!render_view_->webview() || !render_view_->webview()->mainFrame() || 2995 render_view_->renderer_preferences_.user_agent_override.empty()) { 2996 return blink::WebString(); 2997 } 2998 2999 // If we're in the middle of committing a load, the data source we need 3000 // will still be provisional. 3001 WebFrame* main_frame = render_view_->webview()->mainFrame(); 3002 WebDataSource* data_source = NULL; 3003 if (main_frame->provisionalDataSource()) 3004 data_source = main_frame->provisionalDataSource(); 3005 else 3006 data_source = main_frame->dataSource(); 3007 3008 InternalDocumentStateData* internal_data = data_source ? 3009 InternalDocumentStateData::FromDataSource(data_source) : NULL; 3010 if (internal_data && internal_data->is_overriding_user_agent()) 3011 return WebString::fromUTF8( 3012 render_view_->renderer_preferences_.user_agent_override); 3013 return blink::WebString(); 3014} 3015 3016blink::WebString RenderFrameImpl::doNotTrackValue(blink::WebLocalFrame* frame) { 3017 DCHECK(!frame_ || frame_ == frame); 3018 if (render_view_->renderer_preferences_.enable_do_not_track) 3019 return WebString::fromUTF8("1"); 3020 return WebString(); 3021} 3022 3023bool RenderFrameImpl::allowWebGL(blink::WebLocalFrame* frame, 3024 bool default_value) { 3025 DCHECK(!frame_ || frame_ == frame); 3026 if (!default_value) 3027 return false; 3028 3029 bool blocked = true; 3030 render_view_->Send(new ViewHostMsg_Are3DAPIsBlocked( 3031 render_view_->GetRoutingID(), 3032 GURL(frame->top()->document().securityOrigin().toString()), 3033 THREE_D_API_TYPE_WEBGL, 3034 &blocked)); 3035 return !blocked; 3036} 3037 3038void RenderFrameImpl::didLoseWebGLContext(blink::WebLocalFrame* frame, 3039 int arb_robustness_status_code) { 3040 DCHECK(!frame_ || frame_ == frame); 3041 render_view_->Send(new ViewHostMsg_DidLose3DContext( 3042 GURL(frame->top()->document().securityOrigin().toString()), 3043 THREE_D_API_TYPE_WEBGL, 3044 arb_robustness_status_code)); 3045} 3046 3047void RenderFrameImpl::forwardInputEvent(const blink::WebInputEvent* event) { 3048 Send(new FrameHostMsg_ForwardInputEvent(routing_id_, event)); 3049} 3050 3051void RenderFrameImpl::initializeChildFrame(const blink::WebRect& frame_rect, 3052 float scale_factor) { 3053 Send(new FrameHostMsg_InitializeChildFrame( 3054 routing_id_, frame_rect, scale_factor)); 3055} 3056 3057blink::WebScreenOrientationClient* 3058 RenderFrameImpl::webScreenOrientationClient() { 3059 if (!screen_orientation_dispatcher_) 3060 screen_orientation_dispatcher_ = new ScreenOrientationDispatcher(this); 3061 return screen_orientation_dispatcher_; 3062} 3063 3064void RenderFrameImpl::DidPlay(blink::WebMediaPlayer* player) { 3065 Send(new FrameHostMsg_MediaPlayingNotification( 3066 routing_id_, reinterpret_cast<int64>(player), player->hasVideo(), 3067 player->hasAudio())); 3068} 3069 3070void RenderFrameImpl::DidPause(blink::WebMediaPlayer* player) { 3071 Send(new FrameHostMsg_MediaPausedNotification( 3072 routing_id_, reinterpret_cast<int64>(player))); 3073} 3074 3075void RenderFrameImpl::PlayerGone(blink::WebMediaPlayer* player) { 3076 DidPause(player); 3077} 3078 3079void RenderFrameImpl::AddObserver(RenderFrameObserver* observer) { 3080 observers_.AddObserver(observer); 3081} 3082 3083void RenderFrameImpl::RemoveObserver(RenderFrameObserver* observer) { 3084 observer->RenderFrameGone(); 3085 observers_.RemoveObserver(observer); 3086} 3087 3088void RenderFrameImpl::OnStop() { 3089 DCHECK(frame_); 3090 frame_->stopLoading(); 3091 if (!frame_->parent()) 3092 FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers_, OnStop()); 3093 3094 FOR_EACH_OBSERVER(RenderFrameObserver, observers_, OnStop()); 3095} 3096 3097void RenderFrameImpl::WasHidden() { 3098 FOR_EACH_OBSERVER(RenderFrameObserver, observers_, WasHidden()); 3099} 3100 3101void RenderFrameImpl::WasShown() { 3102 FOR_EACH_OBSERVER(RenderFrameObserver, observers_, WasShown()); 3103} 3104 3105bool RenderFrameImpl::IsHidden() { 3106 return GetRenderWidget()->is_hidden(); 3107} 3108 3109// Tell the embedding application that the URL of the active page has changed. 3110void RenderFrameImpl::SendDidCommitProvisionalLoad(blink::WebFrame* frame) { 3111 DCHECK(!frame_ || frame_ == frame); 3112 WebDataSource* ds = frame->dataSource(); 3113 DCHECK(ds); 3114 3115 const WebURLRequest& request = ds->request(); 3116 const WebURLResponse& response = ds->response(); 3117 3118 DocumentState* document_state = DocumentState::FromDataSource(ds); 3119 NavigationState* navigation_state = document_state->navigation_state(); 3120 InternalDocumentStateData* internal_data = 3121 InternalDocumentStateData::FromDocumentState(document_state); 3122 3123 FrameHostMsg_DidCommitProvisionalLoad_Params params; 3124 params.http_status_code = response.httpStatusCode(); 3125 params.is_post = false; 3126 params.post_id = -1; 3127 params.page_id = render_view_->page_id_; 3128 // We need to track the RenderViewHost routing_id because of downstream 3129 // dependencies (crbug.com/392171 DownloadRequestHandle, SaveFileManager, 3130 // ResourceDispatcherHostImpl, MediaStreamUIProxy, 3131 // SpeechRecognitionDispatcherHost and possibly others). They look up the view 3132 // based on the ID stored in the resource requests. Once those dependencies 3133 // are unwound or moved to RenderFrameHost (crbug.com/304341) we can move the 3134 // client to be based on the routing_id of the RenderFrameHost. 3135 params.render_view_routing_id = render_view_->routing_id(); 3136 params.socket_address.set_host(response.remoteIPAddress().utf8()); 3137 params.socket_address.set_port(response.remotePort()); 3138 WebURLResponseExtraDataImpl* extra_data = GetExtraDataFromResponse(response); 3139 if (extra_data) 3140 params.was_fetched_via_proxy = extra_data->was_fetched_via_proxy(); 3141 params.was_within_same_page = navigation_state->was_within_same_page(); 3142 params.security_info = response.securityInfo(); 3143 3144 // Set the URL to be displayed in the browser UI to the user. 3145 params.url = GetLoadingUrl(); 3146 DCHECK(!is_swapped_out_ || params.url == GURL(kSwappedOutURL)); 3147 3148 if (frame->document().baseURL() != params.url) 3149 params.base_url = frame->document().baseURL(); 3150 3151 GetRedirectChain(ds, ¶ms.redirects); 3152 params.should_update_history = !ds->hasUnreachableURL() && 3153 !response.isMultipartPayload() && (response.httpStatusCode() != 404); 3154 3155 params.searchable_form_url = internal_data->searchable_form_url(); 3156 params.searchable_form_encoding = internal_data->searchable_form_encoding(); 3157 3158 params.gesture = render_view_->navigation_gesture_; 3159 render_view_->navigation_gesture_ = NavigationGestureUnknown; 3160 3161 // Make navigation state a part of the DidCommitProvisionalLoad message so 3162 // that commited entry has it at all times. 3163 HistoryEntry* entry = render_view_->history_controller()->GetCurrentEntry(); 3164 if (entry) 3165 params.page_state = HistoryEntryToPageState(entry); 3166 else 3167 params.page_state = PageState::CreateFromURL(request.url()); 3168 3169 if (!frame->parent()) { 3170 // Top-level navigation. 3171 3172 // Reset the zoom limits in case a plugin had changed them previously. This 3173 // will also call us back which will cause us to send a message to 3174 // update WebContentsImpl. 3175 render_view_->webview()->zoomLimitsChanged( 3176 ZoomFactorToZoomLevel(kMinimumZoomFactor), 3177 ZoomFactorToZoomLevel(kMaximumZoomFactor)); 3178 3179 // Set zoom level, but don't do it for full-page plugin since they don't use 3180 // the same zoom settings. 3181 HostZoomLevels::iterator host_zoom = 3182 render_view_->host_zoom_levels_.find(GURL(request.url())); 3183 if (render_view_->webview()->mainFrame()->document().isPluginDocument()) { 3184 // Reset the zoom levels for plugins. 3185 render_view_->webview()->setZoomLevel(0); 3186 } else { 3187 if (host_zoom != render_view_->host_zoom_levels_.end()) 3188 render_view_->webview()->setZoomLevel(host_zoom->second); 3189 } 3190 3191 if (host_zoom != render_view_->host_zoom_levels_.end()) { 3192 // This zoom level was merely recorded transiently for this load. We can 3193 // erase it now. If at some point we reload this page, the browser will 3194 // send us a new, up-to-date zoom level. 3195 render_view_->host_zoom_levels_.erase(host_zoom); 3196 } 3197 3198 // Update contents MIME type for main frame. 3199 params.contents_mime_type = ds->response().mimeType().utf8(); 3200 3201 params.transition = navigation_state->transition_type(); 3202 if (!PageTransitionIsMainFrame(params.transition)) { 3203 // If the main frame does a load, it should not be reported as a subframe 3204 // navigation. This can occur in the following case: 3205 // 1. You're on a site with frames. 3206 // 2. You do a subframe navigation. This is stored with transition type 3207 // MANUAL_SUBFRAME. 3208 // 3. You navigate to some non-frame site, say, google.com. 3209 // 4. You navigate back to the page from step 2. Since it was initially 3210 // MANUAL_SUBFRAME, it will be that same transition type here. 3211 // We don't want that, because any navigation that changes the toplevel 3212 // frame should be tracked as a toplevel navigation (this allows us to 3213 // update the URL bar, etc). 3214 params.transition = PAGE_TRANSITION_LINK; 3215 } 3216 3217 // If the page contained a client redirect (meta refresh, document.loc...), 3218 // set the referrer and transition appropriately. 3219 if (ds->isClientRedirect()) { 3220 params.referrer = 3221 Referrer(params.redirects[0], ds->request().referrerPolicy()); 3222 params.transition = static_cast<PageTransition>( 3223 params.transition | PAGE_TRANSITION_CLIENT_REDIRECT); 3224 } else { 3225 params.referrer = RenderViewImpl::GetReferrerFromRequest( 3226 frame, ds->request()); 3227 } 3228 3229 base::string16 method = request.httpMethod(); 3230 if (EqualsASCII(method, "POST")) { 3231 params.is_post = true; 3232 params.post_id = ExtractPostId(entry->root()); 3233 } 3234 3235 // Send the user agent override back. 3236 params.is_overriding_user_agent = internal_data->is_overriding_user_agent(); 3237 3238 // Track the URL of the original request. We use the first entry of the 3239 // redirect chain if it exists because the chain may have started in another 3240 // process. 3241 params.original_request_url = GetOriginalRequestURL(ds); 3242 3243 params.history_list_was_cleared = 3244 navigation_state->history_list_was_cleared(); 3245 3246 // Save some histogram data so we can compute the average memory used per 3247 // page load of the glyphs. 3248 UMA_HISTOGRAM_COUNTS_10000("Memory.GlyphPagesPerLoad", 3249 blink::WebGlyphCache::pageCount()); 3250 3251 // This message needs to be sent before any of allowScripts(), 3252 // allowImages(), allowPlugins() is called for the new page, so that when 3253 // these functions send a ViewHostMsg_ContentBlocked message, it arrives 3254 // after the FrameHostMsg_DidCommitProvisionalLoad message. 3255 Send(new FrameHostMsg_DidCommitProvisionalLoad(routing_id_, params)); 3256 } else { 3257 // Subframe navigation: the type depends on whether this navigation 3258 // generated a new session history entry. When they do generate a session 3259 // history entry, it means the user initiated the navigation and we should 3260 // mark it as such. This test checks if this is the first time 3261 // SendDidCommitProvisionalLoad has been called since WillNavigateToURL was 3262 // called to initiate the load. 3263 if (render_view_->page_id_ > render_view_->last_page_id_sent_to_browser_) 3264 params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME; 3265 else 3266 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME; 3267 3268 DCHECK(!navigation_state->history_list_was_cleared()); 3269 params.history_list_was_cleared = false; 3270 3271 // Don't send this message while the subframe is swapped out. 3272 if (!is_swapped_out()) 3273 Send(new FrameHostMsg_DidCommitProvisionalLoad(routing_id_, params)); 3274 } 3275 3276 render_view_->last_page_id_sent_to_browser_ = 3277 std::max(render_view_->last_page_id_sent_to_browser_, 3278 render_view_->page_id_); 3279 3280 // If we end up reusing this WebRequest (for example, due to a #ref click), 3281 // we don't want the transition type to persist. Just clear it. 3282 navigation_state->set_transition_type(PAGE_TRANSITION_LINK); 3283} 3284 3285WebElement RenderFrameImpl::GetFocusedElement() { 3286 WebDocument doc = frame_->document(); 3287 if (!doc.isNull()) 3288 return doc.focusedElement(); 3289 3290 return WebElement(); 3291} 3292 3293void RenderFrameImpl::didStartLoading(bool to_different_document) { 3294 render_view_->FrameDidStartLoading(frame_); 3295 Send(new FrameHostMsg_DidStartLoading(routing_id_, to_different_document)); 3296} 3297 3298void RenderFrameImpl::didStopLoading() { 3299 render_view_->FrameDidStopLoading(frame_); 3300 Send(new FrameHostMsg_DidStopLoading(routing_id_)); 3301} 3302 3303void RenderFrameImpl::didChangeLoadProgress(double load_progress) { 3304 Send(new FrameHostMsg_DidChangeLoadProgress(routing_id_, load_progress)); 3305} 3306 3307void RenderFrameImpl::HandleWebAccessibilityEvent( 3308 const blink::WebAXObject& obj, blink::WebAXEvent event) { 3309 if (renderer_accessibility_) 3310 renderer_accessibility_->HandleWebAccessibilityEvent(obj, event); 3311} 3312 3313void RenderFrameImpl::FocusedNodeChanged(const WebNode& node) { 3314 if (renderer_accessibility_) 3315 renderer_accessibility_->FocusedNodeChanged(node); 3316} 3317 3318WebNavigationPolicy RenderFrameImpl::DecidePolicyForNavigation( 3319 RenderFrame* render_frame, 3320 const NavigationPolicyInfo& info) { 3321#ifdef OS_ANDROID 3322 // The handlenavigation API is deprecated and will be removed once 3323 // crbug.com/325351 is resolved. 3324 if (info.urlRequest.url() != GURL(kSwappedOutURL) && 3325 GetContentClient()->renderer()->HandleNavigation( 3326 render_frame, 3327 static_cast<DocumentState*>(info.extraData), 3328 render_view_->opener_id_, 3329 info.frame, 3330 info.urlRequest, 3331 info.navigationType, 3332 info.defaultPolicy, 3333 info.isRedirect)) { 3334 return blink::WebNavigationPolicyIgnore; 3335 } 3336#endif 3337 3338 Referrer referrer(RenderViewImpl::GetReferrerFromRequest(info.frame, 3339 info.urlRequest)); 3340 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 3341 3342 bool is_subframe = !!info.frame->parent(); 3343 3344 if (command_line.HasSwitch(switches::kSitePerProcess) && is_subframe) { 3345 // There's no reason to ignore navigations on subframes, since the swap out 3346 // logic no longer applies. 3347 } else { 3348 if (is_swapped_out_ || render_view_->is_swapped_out()) { 3349 if (info.urlRequest.url() != GURL(kSwappedOutURL)) { 3350 // Targeted links may try to navigate a swapped out frame. Allow the 3351 // browser process to navigate the tab instead. Note that it is also 3352 // possible for non-targeted navigations (from this view) to arrive 3353 // here just after we are swapped out. It's ok to send them to the 3354 // browser, as long as they're for the top level frame. 3355 // TODO(creis): Ensure this supports targeted form submissions when 3356 // fixing http://crbug.com/101395. 3357 if (info.frame->parent() == NULL) { 3358 OpenURL(info.frame, info.urlRequest.url(), referrer, 3359 info.defaultPolicy); 3360 return blink::WebNavigationPolicyIgnore; // Suppress the load here. 3361 } 3362 3363 // We should otherwise ignore in-process iframe navigations, if they 3364 // arrive just after we are swapped out. 3365 return blink::WebNavigationPolicyIgnore; 3366 } 3367 3368 // Allow kSwappedOutURL to complete. 3369 return info.defaultPolicy; 3370 } 3371 } 3372 3373 // Webkit is asking whether to navigate to a new URL. 3374 // This is fine normally, except if we're showing UI from one security 3375 // context and they're trying to navigate to a different context. 3376 const GURL& url = info.urlRequest.url(); 3377 3378 // A content initiated navigation may have originated from a link-click, 3379 // script, drag-n-drop operation, etc. 3380 bool is_content_initiated = static_cast<DocumentState*>(info.extraData)-> 3381 navigation_state()->is_content_initiated(); 3382 3383 // Experimental: 3384 // If --enable-strict-site-isolation or --site-per-process is enabled, send 3385 // all top-level navigations to the browser to let it swap processes when 3386 // crossing site boundaries. This is currently expected to break some script 3387 // calls and navigations, such as form submissions. 3388 bool force_swap_due_to_flag = 3389 command_line.HasSwitch(switches::kEnableStrictSiteIsolation) || 3390 command_line.HasSwitch(switches::kSitePerProcess); 3391 if (force_swap_due_to_flag && 3392 !info.frame->parent() && (is_content_initiated || info.isRedirect)) { 3393 WebString origin_str = info.frame->document().securityOrigin().toString(); 3394 GURL frame_url(origin_str.utf8().data()); 3395 // TODO(cevans): revisit whether this site check is still necessary once 3396 // crbug.com/101395 is fixed. 3397 bool same_domain_or_host = 3398 net::registry_controlled_domains::SameDomainOrHost( 3399 frame_url, 3400 url, 3401 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); 3402 if (!same_domain_or_host || frame_url.scheme() != url.scheme()) { 3403 OpenURL(info.frame, url, referrer, info.defaultPolicy); 3404 return blink::WebNavigationPolicyIgnore; 3405 } 3406 } 3407 3408 // If the browser is interested, then give it a chance to look at the request. 3409 if (is_content_initiated) { 3410 bool is_form_post = 3411 ((info.navigationType == blink::WebNavigationTypeFormSubmitted) || 3412 (info.navigationType == blink::WebNavigationTypeFormResubmitted)) && 3413 EqualsASCII(info.urlRequest.httpMethod(), "POST"); 3414 bool browser_handles_request = 3415 render_view_->renderer_preferences_ 3416 .browser_handles_non_local_top_level_requests 3417 && IsNonLocalTopLevelNavigation(url, info.frame, info.navigationType, 3418 is_form_post); 3419 if (!browser_handles_request) { 3420 browser_handles_request = IsTopLevelNavigation(info.frame) && 3421 render_view_->renderer_preferences_ 3422 .browser_handles_all_top_level_requests; 3423 } 3424 3425 if (browser_handles_request) { 3426 // Reset these counters as the RenderView could be reused for the next 3427 // navigation. 3428 render_view_->page_id_ = -1; 3429 render_view_->last_page_id_sent_to_browser_ = -1; 3430 OpenURL(info.frame, url, referrer, info.defaultPolicy); 3431 return blink::WebNavigationPolicyIgnore; // Suppress the load here. 3432 } 3433 } 3434 3435 // Use the frame's original request's URL rather than the document's URL for 3436 // subsequent checks. For a popup, the document's URL may become the opener 3437 // window's URL if the opener has called document.write(). 3438 // See http://crbug.com/93517. 3439 GURL old_url(info.frame->dataSource()->request().url()); 3440 3441 // Detect when we're crossing a permission-based boundary (e.g. into or out of 3442 // an extension or app origin, leaving a WebUI page, etc). We only care about 3443 // top-level navigations (not iframes). But we sometimes navigate to 3444 // about:blank to clear a tab, and we want to still allow that. 3445 // 3446 // Note: this is known to break POST submissions when crossing process 3447 // boundaries until http://crbug.com/101395 is fixed. This is better for 3448 // security than loading a WebUI, extension or app page in the wrong process. 3449 // POST requests don't work because this mechanism does not preserve form 3450 // POST data. We will need to send the request's httpBody data up to the 3451 // browser process, and issue a special POST navigation in WebKit (via 3452 // FrameLoader::loadFrameRequest). See ResourceDispatcher and WebURLLoaderImpl 3453 // for examples of how to send the httpBody data. 3454 if (!info.frame->parent() && is_content_initiated && 3455 !url.SchemeIs(url::kAboutScheme)) { 3456 bool send_referrer = false; 3457 3458 // All navigations to or from WebUI URLs or within WebUI-enabled 3459 // RenderProcesses must be handled by the browser process so that the 3460 // correct bindings and data sources can be registered. 3461 // Similarly, navigations to view-source URLs or within ViewSource mode 3462 // must be handled by the browser process (except for reloads - those are 3463 // safe to leave within the renderer). 3464 // Lastly, access to file:// URLs from non-file:// URL pages must be 3465 // handled by the browser so that ordinary renderer processes don't get 3466 // blessed with file permissions. 3467 int cumulative_bindings = RenderProcess::current()->GetEnabledBindings(); 3468 bool is_initial_navigation = render_view_->page_id_ == -1; 3469 bool should_fork = HasWebUIScheme(url) || HasWebUIScheme(old_url) || 3470 (cumulative_bindings & BINDINGS_POLICY_WEB_UI) || 3471 url.SchemeIs(kViewSourceScheme) || 3472 (info.frame->isViewSourceModeEnabled() && 3473 info.navigationType != blink::WebNavigationTypeReload); 3474 3475 if (!should_fork && url.SchemeIs(url::kFileScheme)) { 3476 // Fork non-file to file opens. Check the opener URL if this is the 3477 // initial navigation in a newly opened window. 3478 GURL source_url(old_url); 3479 if (is_initial_navigation && source_url.is_empty() && 3480 info.frame->opener()) 3481 source_url = info.frame->opener()->top()->document().url(); 3482 DCHECK(!source_url.is_empty()); 3483 should_fork = !source_url.SchemeIs(url::kFileScheme); 3484 } 3485 3486 if (!should_fork) { 3487 // Give the embedder a chance. 3488 should_fork = GetContentClient()->renderer()->ShouldFork( 3489 info.frame, url, info.urlRequest.httpMethod().utf8(), 3490 is_initial_navigation, info.isRedirect, &send_referrer); 3491 } 3492 3493 if (should_fork) { 3494 OpenURL(info.frame, url, send_referrer ? referrer : Referrer(), 3495 info.defaultPolicy); 3496 return blink::WebNavigationPolicyIgnore; // Suppress the load here. 3497 } 3498 } 3499 3500 // Detect when a page is "forking" a new tab that can be safely rendered in 3501 // its own process. This is done by sites like Gmail that try to open links 3502 // in new windows without script connections back to the original page. We 3503 // treat such cases as browser navigations (in which we will create a new 3504 // renderer for a cross-site navigation), rather than WebKit navigations. 3505 // 3506 // We use the following heuristic to decide whether to fork a new page in its 3507 // own process: 3508 // The parent page must open a new tab to about:blank, set the new tab's 3509 // window.opener to null, and then redirect the tab to a cross-site URL using 3510 // JavaScript. 3511 // 3512 // TODO(creis): Deprecate this logic once we can rely on rel=noreferrer 3513 // (see below). 3514 bool is_fork = 3515 // Must start from a tab showing about:blank, which is later redirected. 3516 old_url == GURL(url::kAboutBlankURL) && 3517 // Must be the first real navigation of the tab. 3518 render_view_->historyBackListCount() < 1 && 3519 render_view_->historyForwardListCount() < 1 && 3520 // The parent page must have set the child's window.opener to null before 3521 // redirecting to the desired URL. 3522 info.frame->opener() == NULL && 3523 // Must be a top-level frame. 3524 info.frame->parent() == NULL && 3525 // Must not have issued the request from this page. 3526 is_content_initiated && 3527 // Must be targeted at the current tab. 3528 info.defaultPolicy == blink::WebNavigationPolicyCurrentTab && 3529 // Must be a JavaScript navigation, which appears as "other". 3530 info.navigationType == blink::WebNavigationTypeOther; 3531 3532 if (is_fork) { 3533 // Open the URL via the browser, not via WebKit. 3534 OpenURL(info.frame, url, Referrer(), info.defaultPolicy); 3535 return blink::WebNavigationPolicyIgnore; 3536 } 3537 3538 return info.defaultPolicy; 3539} 3540 3541void RenderFrameImpl::OpenURL(WebFrame* frame, 3542 const GURL& url, 3543 const Referrer& referrer, 3544 WebNavigationPolicy policy) { 3545 DCHECK_EQ(frame_, frame); 3546 3547 FrameHostMsg_OpenURL_Params params; 3548 params.url = url; 3549 params.referrer = referrer; 3550 params.disposition = RenderViewImpl::NavigationPolicyToDisposition(policy); 3551 WebDataSource* ds = frame->provisionalDataSource(); 3552 if (ds) { 3553 DocumentState* document_state = DocumentState::FromDataSource(ds); 3554 NavigationState* navigation_state = document_state->navigation_state(); 3555 if (navigation_state->is_content_initiated()) { 3556 params.should_replace_current_entry = ds->replacesCurrentHistoryItem(); 3557 } else { 3558 // This is necessary to preserve the should_replace_current_entry value on 3559 // cross-process redirects, in the event it was set by a previous process. 3560 // 3561 // TODO(davidben): Avoid this awkward duplication of state. See comment on 3562 // NavigationState::should_replace_current_entry(). 3563 params.should_replace_current_entry = 3564 navigation_state->should_replace_current_entry(); 3565 } 3566 } else { 3567 params.should_replace_current_entry = false; 3568 } 3569 params.user_gesture = WebUserGestureIndicator::isProcessingUserGesture(); 3570 if (GetContentClient()->renderer()->AllowPopup()) 3571 params.user_gesture = true; 3572 3573 if (policy == blink::WebNavigationPolicyNewBackgroundTab || 3574 policy == blink::WebNavigationPolicyNewForegroundTab || 3575 policy == blink::WebNavigationPolicyNewWindow || 3576 policy == blink::WebNavigationPolicyNewPopup) { 3577 WebUserGestureIndicator::consumeUserGesture(); 3578 } 3579 3580 Send(new FrameHostMsg_OpenURL(routing_id_, params)); 3581} 3582 3583void RenderFrameImpl::UpdateEncoding(WebFrame* frame, 3584 const std::string& encoding_name) { 3585 // Only update main frame's encoding_name. 3586 if (!frame->parent()) 3587 Send(new FrameHostMsg_UpdateEncoding(routing_id_, encoding_name)); 3588} 3589 3590void RenderFrameImpl::SyncSelectionIfRequired() { 3591 base::string16 text; 3592 size_t offset; 3593 gfx::Range range; 3594#if defined(ENABLE_PLUGINS) 3595 if (render_view_->focused_pepper_plugin_) { 3596 render_view_->focused_pepper_plugin_->GetSurroundingText(&text, &range); 3597 offset = 0; // Pepper API does not support offset reporting. 3598 // TODO(kinaba): cut as needed. 3599 } else 3600#endif 3601 { 3602 size_t location, length; 3603 if (!GetRenderWidget()->webwidget()->caretOrSelectionRange( 3604 &location, &length)) { 3605 return; 3606 } 3607 3608 range = gfx::Range(location, location + length); 3609 3610 if (GetRenderWidget()->webwidget()->textInputInfo().type != 3611 blink::WebTextInputTypeNone) { 3612 // If current focused element is editable, we will send 100 more chars 3613 // before and after selection. It is for input method surrounding text 3614 // feature. 3615 if (location > kExtraCharsBeforeAndAfterSelection) 3616 offset = location - kExtraCharsBeforeAndAfterSelection; 3617 else 3618 offset = 0; 3619 length = location + length - offset + kExtraCharsBeforeAndAfterSelection; 3620 WebRange webrange = WebRange::fromDocumentRange(frame_, offset, length); 3621 if (!webrange.isNull()) 3622 text = WebRange::fromDocumentRange( 3623 frame_, offset, length).toPlainText(); 3624 } else { 3625 offset = location; 3626 text = frame_->selectionAsText(); 3627 // http://crbug.com/101435 3628 // In some case, frame->selectionAsText() returned text's length is not 3629 // equal to the length returned from webwidget()->caretOrSelectionRange(). 3630 // So we have to set the range according to text.length(). 3631 range.set_end(range.start() + text.length()); 3632 } 3633 } 3634 3635 // Sometimes we get repeated didChangeSelection calls from webkit when 3636 // the selection hasn't actually changed. We don't want to report these 3637 // because it will cause us to continually claim the X clipboard. 3638 if (selection_text_offset_ != offset || 3639 selection_range_ != range || 3640 selection_text_ != text) { 3641 selection_text_ = text; 3642 selection_text_offset_ = offset; 3643 selection_range_ = range; 3644 // This IPC is dispatched by RenderWidetHost, so use its routing ID. 3645 Send(new ViewHostMsg_SelectionChanged( 3646 GetRenderWidget()->routing_id(), text, offset, range)); 3647 } 3648 GetRenderWidget()->UpdateSelectionBounds(); 3649} 3650 3651void RenderFrameImpl::InitializeUserMediaClient() { 3652 if (!RenderThreadImpl::current()) // Will be NULL during unit tests. 3653 return; 3654 3655#if defined(OS_ANDROID) 3656 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableWebRTC)) 3657 return; 3658#endif 3659 3660#if defined(ENABLE_WEBRTC) 3661 DCHECK(!web_user_media_client_); 3662 web_user_media_client_ = new MediaStreamImpl( 3663 this, 3664 RenderThreadImpl::current()->GetPeerConnectionDependencyFactory(), 3665 make_scoped_ptr(new MediaStreamDispatcher(this)).Pass()); 3666#endif 3667} 3668 3669WebMediaPlayer* RenderFrameImpl::CreateWebMediaPlayerForMediaStream( 3670 const blink::WebURL& url, 3671 WebMediaPlayerClient* client) { 3672#if defined(ENABLE_WEBRTC) 3673#if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL) 3674 bool found_neon = 3675 (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; 3676 UMA_HISTOGRAM_BOOLEAN("Platform.WebRtcNEONFound", found_neon); 3677#endif // defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL) 3678 return new WebMediaPlayerMS(frame_, client, weak_factory_.GetWeakPtr(), 3679 new RenderMediaLog(), 3680 CreateRendererFactory()); 3681#else 3682 return NULL; 3683#endif // defined(ENABLE_WEBRTC) 3684} 3685 3686scoped_ptr<MediaStreamRendererFactory> 3687RenderFrameImpl::CreateRendererFactory() { 3688#if defined(ENABLE_WEBRTC) 3689 return scoped_ptr<MediaStreamRendererFactory>( 3690 new MediaStreamRendererFactory()); 3691#else 3692 return scoped_ptr<MediaStreamRendererFactory>( 3693 static_cast<MediaStreamRendererFactory*>(NULL)); 3694#endif 3695} 3696 3697GURL RenderFrameImpl::GetLoadingUrl() const { 3698 WebDataSource* ds = frame_->dataSource(); 3699 if (ds->hasUnreachableURL()) 3700 return ds->unreachableURL(); 3701 3702 const WebURLRequest& request = ds->request(); 3703 return request.url(); 3704} 3705 3706#if defined(OS_ANDROID) 3707 3708WebMediaPlayer* RenderFrameImpl::CreateAndroidWebMediaPlayer( 3709 const blink::WebURL& url, 3710 WebMediaPlayerClient* client) { 3711 GpuChannelHost* gpu_channel_host = 3712 RenderThreadImpl::current()->EstablishGpuChannelSync( 3713 CAUSE_FOR_GPU_LAUNCH_VIDEODECODEACCELERATOR_INITIALIZE); 3714 if (!gpu_channel_host) { 3715 LOG(ERROR) << "Failed to establish GPU channel for media player"; 3716 return NULL; 3717 } 3718 3719 scoped_refptr<StreamTextureFactory> stream_texture_factory; 3720 if (SynchronousCompositorFactory* factory = 3721 SynchronousCompositorFactory::GetInstance()) { 3722 stream_texture_factory = factory->CreateStreamTextureFactory(routing_id_); 3723 } else { 3724 scoped_refptr<webkit::gpu::ContextProviderWebContext> context_provider = 3725 RenderThreadImpl::current()->SharedMainThreadContextProvider(); 3726 3727 if (!context_provider.get()) { 3728 LOG(ERROR) << "Failed to get context3d for media player"; 3729 return NULL; 3730 } 3731 3732 stream_texture_factory = StreamTextureFactoryImpl::Create( 3733 context_provider, gpu_channel_host, routing_id_); 3734 } 3735 3736 return new WebMediaPlayerAndroid( 3737 frame_, 3738 client, 3739 weak_factory_.GetWeakPtr(), 3740 GetMediaPlayerManager(), 3741 GetCdmManager(), 3742 stream_texture_factory, 3743 RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy(), 3744 new RenderMediaLog()); 3745} 3746 3747RendererMediaPlayerManager* RenderFrameImpl::GetMediaPlayerManager() { 3748 if (!media_player_manager_) 3749 media_player_manager_ = new RendererMediaPlayerManager(this); 3750 return media_player_manager_; 3751} 3752 3753#endif // defined(OS_ANDROID) 3754 3755#if defined(ENABLE_BROWSER_CDMS) 3756RendererCdmManager* RenderFrameImpl::GetCdmManager() { 3757 if (!cdm_manager_) 3758 cdm_manager_ = new RendererCdmManager(this); 3759 return cdm_manager_; 3760} 3761#endif // defined(ENABLE_BROWSER_CDMS) 3762 3763} // namespace content 3764