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