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