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