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.
5 #include "content/renderer/render_frame_impl.h"
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/string16.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/time/time.h"
21 #include "content/child/appcache/appcache_dispatcher.h"
22 #include "content/child/plugin_messages.h"
23 #include "content/child/quota_dispatcher.h"
24 #include "content/child/request_extra_data.h"
25 #include "content/child/service_worker/service_worker_network_provider.h"
26 #include "content/child/service_worker/web_service_worker_provider_impl.h"
27 #include "content/child/web_socket_stream_handle_impl.h"
28 #include "content/common/clipboard_messages.h"
29 #include "content/common/frame_messages.h"
30 #include "content/common/input_messages.h"
31 #include "content/common/service_worker/service_worker_types.h"
32 #include "content/common/socket_stream_handle_data.h"
33 #include "content/common/swapped_out_messages.h"
34 #include "content/common/view_messages.h"
35 #include "content/public/common/bindings_policy.h"
36 #include "content/public/common/content_constants.h"
37 #include "content/public/common/content_switches.h"
38 #include "content/public/common/context_menu_params.h"
39 #include "content/public/common/url_constants.h"
40 #include "content/public/common/url_utils.h"
41 #include "content/public/renderer/content_renderer_client.h"
42 #include "content/public/renderer/context_menu_client.h"
43 #include "content/public/renderer/document_state.h"
44 #include "content/public/renderer/history_item_serialization.h"
45 #include "content/public/renderer/navigation_state.h"
46 #include "content/public/renderer/render_frame_observer.h"
47 #include "content/renderer/accessibility/renderer_accessibility.h"
48 #include "content/renderer/browser_plugin/browser_plugin.h"
49 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
50 #include "content/renderer/child_frame_compositing_helper.h"
51 #include "content/renderer/context_menu_params_builder.h"
52 #include "content/renderer/dom_automation_controller.h"
53 #include "content/renderer/history_controller.h"
54 #include "content/renderer/image_loading_helper.h"
55 #include "content/renderer/ime_event_guard.h"
56 #include "content/renderer/internal_document_state_data.h"
57 #include "content/renderer/java/java_bridge_dispatcher.h"
58 #include "content/renderer/media/webcontentdecryptionmodule_impl.h"
59 #include "content/renderer/notification_provider.h"
60 #include "content/renderer/npapi/plugin_channel_host.h"
61 #include "content/renderer/render_process.h"
62 #include "content/renderer/render_thread_impl.h"
63 #include "content/renderer/render_view_impl.h"
64 #include "content/renderer/render_widget_fullscreen_pepper.h"
65 #include "content/renderer/renderer_webapplicationcachehost_impl.h"
66 #include "content/renderer/renderer_webcolorchooser_impl.h"
67 #include "content/renderer/shared_worker_repository.h"
68 #include "content/renderer/v8_value_converter_impl.h"
69 #include "content/renderer/websharedworker_proxy.h"
70 #include "net/base/data_url.h"
71 #include "net/base/net_errors.h"
72 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
73 #include "net/http/http_util.h"
74 #include "third_party/WebKit/public/platform/WebStorageQuotaCallbacks.h"
75 #include "third_party/WebKit/public/platform/WebString.h"
76 #include "third_party/WebKit/public/platform/WebURL.h"
77 #include "third_party/WebKit/public/platform/WebURLError.h"
78 #include "third_party/WebKit/public/platform/WebURLResponse.h"
79 #include "third_party/WebKit/public/platform/WebVector.h"
80 #include "third_party/WebKit/public/web/WebColorSuggestion.h"
81 #include "third_party/WebKit/public/web/WebDocument.h"
82 #include "third_party/WebKit/public/web/WebGlyphCache.h"
83 #include "third_party/WebKit/public/web/WebLocalFrame.h"
84 #include "third_party/WebKit/public/web/WebNavigationPolicy.h"
85 #include "third_party/WebKit/public/web/WebPlugin.h"
86 #include "third_party/WebKit/public/web/WebPluginParams.h"
87 #include "third_party/WebKit/public/web/WebRange.h"
88 #include "third_party/WebKit/public/web/WebScriptSource.h"
89 #include "third_party/WebKit/public/web/WebSearchableFormData.h"
90 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
91 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
92 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
93 #include "third_party/WebKit/public/web/WebView.h"
94 #include "webkit/child/weburlresponse_extradata_impl.h"
96 #if defined(ENABLE_PLUGINS)
97 #include "content/renderer/npapi/webplugin_impl.h"
98 #include "content/renderer/pepper/pepper_browser_connection.h"
99 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
100 #include "content/renderer/pepper/pepper_webplugin_impl.h"
101 #include "content/renderer/pepper/plugin_module.h"
104 #if defined(ENABLE_WEBRTC)
105 #include "content/renderer/media/rtc_peer_connection_handler.h"
108 using blink::WebContextMenuData
;
109 using blink::WebData
;
110 using blink::WebDataSource
;
111 using blink::WebDocument
;
112 using blink::WebElement
;
113 using blink::WebFrame
;
114 using blink::WebHistoryItem
;
115 using blink::WebHTTPBody
;
116 using blink::WebLocalFrame
;
117 using blink::WebNavigationPolicy
;
118 using blink::WebNavigationType
;
119 using blink::WebNode
;
120 using blink::WebPluginParams
;
121 using blink::WebRange
;
122 using blink::WebReferrerPolicy
;
123 using blink::WebScriptSource
;
124 using blink::WebSearchableFormData
;
125 using blink::WebSecurityOrigin
;
126 using blink::WebSecurityPolicy
;
127 using blink::WebServiceWorkerProvider
;
128 using blink::WebStorageQuotaCallbacks
;
129 using blink::WebString
;
131 using blink::WebURLError
;
132 using blink::WebURLRequest
;
133 using blink::WebURLResponse
;
134 using blink::WebUserGestureIndicator
;
135 using blink::WebVector
;
136 using blink::WebView
;
138 using base::TimeDelta
;
139 using webkit_glue::WebURLResponseExtraDataImpl
;
145 const size_t kExtraCharsBeforeAndAfterSelection
= 100;
147 typedef std::map
<blink::WebFrame
*, RenderFrameImpl
*> FrameMap
;
148 base::LazyInstance
<FrameMap
> g_frame_map
= LAZY_INSTANCE_INITIALIZER
;
150 int64
ExtractPostId(const WebHistoryItem
& item
) {
154 if (item
.httpBody().isNull())
157 return item
.httpBody().identifier();
160 WebURLResponseExtraDataImpl
* GetExtraDataFromResponse(
161 const WebURLResponse
& response
) {
162 return static_cast<WebURLResponseExtraDataImpl
*>(response
.extraData());
165 void GetRedirectChain(WebDataSource
* ds
, std::vector
<GURL
>* result
) {
166 // Replace any occurrences of swappedout:// with about:blank.
167 const WebURL
& blank_url
= GURL(kAboutBlankURL
);
168 WebVector
<WebURL
> urls
;
169 ds
->redirectChain(urls
);
170 result
->reserve(urls
.size());
171 for (size_t i
= 0; i
< urls
.size(); ++i
) {
172 if (urls
[i
] != GURL(kSwappedOutURL
))
173 result
->push_back(urls
[i
]);
175 result
->push_back(blank_url
);
179 // Returns the original request url. If there is no redirect, the original
180 // url is the same as ds->request()->url(). If the WebDataSource belongs to a
181 // frame was loaded by loadData, the original url will be ds->unreachableURL()
182 static GURL
GetOriginalRequestURL(WebDataSource
* ds
) {
183 // WebDataSource has unreachable URL means that the frame is loaded through
184 // blink::WebFrame::loadData(), and the base URL will be in the redirect
185 // chain. However, we never visited the baseURL. So in this case, we should
186 // use the unreachable URL as the original URL.
187 if (ds
->hasUnreachableURL())
188 return ds
->unreachableURL();
190 std::vector
<GURL
> redirects
;
191 GetRedirectChain(ds
, &redirects
);
192 if (!redirects
.empty())
193 return redirects
.at(0);
195 return ds
->originalRequest().url();
198 NOINLINE
static void CrashIntentionally() {
199 // NOTE(shess): Crash directly rather than using NOTREACHED() so
200 // that the signature is easier to triage in crash reports.
201 volatile int* zero
= NULL
;
205 #if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
206 NOINLINE
static void MaybeTriggerAsanError(const GURL
& url
) {
207 // NOTE(rogerm): We intentionally perform an invalid heap access here in
208 // order to trigger an Address Sanitizer (ASAN) error report.
209 static const char kCrashDomain
[] = "crash";
210 static const char kHeapOverflow
[] = "/heap-overflow";
211 static const char kHeapUnderflow
[] = "/heap-underflow";
212 static const char kUseAfterFree
[] = "/use-after-free";
213 static const int kArraySize
= 5;
215 if (!url
.DomainIs(kCrashDomain
, sizeof(kCrashDomain
) - 1))
221 scoped_ptr
<int[]> array(new int[kArraySize
]);
222 std::string
crash_type(url
.path());
224 if (crash_type
== kHeapOverflow
) {
225 dummy
= array
[kArraySize
];
226 } else if (crash_type
== kHeapUnderflow
) {
228 } else if (crash_type
== kUseAfterFree
) {
229 int* dangling
= array
.get();
231 dummy
= dangling
[kArraySize
/ 2];
234 // Make sure the assignments to the dummy value aren't optimized away.
235 base::debug::Alias(&dummy
);
237 #endif // ADDRESS_SANITIZER || SYZYASAN
239 static void MaybeHandleDebugURL(const GURL
& url
) {
240 if (!url
.SchemeIs(kChromeUIScheme
))
242 if (url
== GURL(kChromeUICrashURL
)) {
243 CrashIntentionally();
244 } else if (url
== GURL(kChromeUIKillURL
)) {
245 base::KillProcess(base::GetCurrentProcessHandle(), 1, false);
246 } else if (url
== GURL(kChromeUIHangURL
)) {
248 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
250 } else if (url
== GURL(kChromeUIShorthangURL
)) {
251 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(20));
254 #if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
255 MaybeTriggerAsanError(url
);
256 #endif // ADDRESS_SANITIZER || SYZYASAN
259 // Returns false unless this is a top-level navigation.
260 static bool IsTopLevelNavigation(WebFrame
* frame
) {
261 return frame
->parent() == NULL
;
264 // Returns false unless this is a top-level navigation that crosses origins.
265 static bool IsNonLocalTopLevelNavigation(const GURL
& url
,
267 WebNavigationType type
,
269 if (!IsTopLevelNavigation(frame
))
272 // Navigations initiated within Webkit are not sent out to the external host
273 // in the following cases.
274 // 1. The url scheme is not http/https
275 // 2. The origin of the url and the opener is the same in which case the
276 // opener relationship is maintained.
277 // 3. Reloads/form submits/back forward navigations
278 if (!url
.SchemeIs(kHttpScheme
) && !url
.SchemeIs(kHttpsScheme
))
281 if (type
!= blink::WebNavigationTypeReload
&&
282 type
!= blink::WebNavigationTypeBackForward
&& !is_form_post
) {
283 // The opener relationship between the new window and the parent allows the
284 // new window to script the parent and vice versa. This is not allowed if
285 // the origins of the two domains are different. This can be treated as a
286 // top level navigation and routed back to the host.
287 blink::WebFrame
* opener
= frame
->opener();
291 if (url
.GetOrigin() != GURL(opener
->document().url()).GetOrigin())
299 static RenderFrameImpl
* (*g_create_render_frame_impl
)(RenderViewImpl
*, int32
) =
303 RenderFrameImpl
* RenderFrameImpl::Create(RenderViewImpl
* render_view
,
305 DCHECK(routing_id
!= MSG_ROUTING_NONE
);
307 if (g_create_render_frame_impl
)
308 return g_create_render_frame_impl(render_view
, routing_id
);
310 return new RenderFrameImpl(render_view
, routing_id
);
314 RenderFrame
* RenderFrame::FromWebFrame(blink::WebFrame
* web_frame
) {
315 return RenderFrameImpl::FromWebFrame(web_frame
);
318 RenderFrameImpl
* RenderFrameImpl::FromWebFrame(blink::WebFrame
* web_frame
) {
319 FrameMap::iterator iter
= g_frame_map
.Get().find(web_frame
);
320 if (iter
!= g_frame_map
.Get().end())
326 void RenderFrameImpl::InstallCreateHook(
327 RenderFrameImpl
* (*create_render_frame_impl
)(RenderViewImpl
*, int32
)) {
328 CHECK(!g_create_render_frame_impl
);
329 g_create_render_frame_impl
= create_render_frame_impl
;
332 // RenderFrameImpl ----------------------------------------------------------
333 RenderFrameImpl::RenderFrameImpl(RenderViewImpl
* render_view
, int routing_id
)
335 render_view_(render_view
->AsWeakPtr()),
336 routing_id_(routing_id
),
337 is_swapped_out_(false),
338 is_detaching_(false),
340 selection_text_offset_(0),
341 selection_range_(gfx::Range::InvalidRange()),
342 handling_select_range_(false),
343 notification_provider_(NULL
) {
344 RenderThread::Get()->AddRoute(routing_id_
, this);
346 #if defined(OS_ANDROID)
347 new JavaBridgeDispatcher(this);
350 #if defined(ENABLE_NOTIFICATIONS)
351 notification_provider_
= new NotificationProvider(this);
355 RenderFrameImpl::~RenderFrameImpl() {
356 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, RenderFrameGone());
357 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, OnDestruct());
358 RenderThread::Get()->RemoveRoute(routing_id_
);
361 void RenderFrameImpl::SetWebFrame(blink::WebLocalFrame
* web_frame
) {
364 std::pair
<FrameMap::iterator
, bool> result
= g_frame_map
.Get().insert(
365 std::make_pair(web_frame
, this));
366 CHECK(result
.second
) << "Inserting a duplicate item.";
371 void RenderFrameImpl::Initialize() {
372 #if defined(ENABLE_PLUGINS)
373 new PepperBrowserConnection(this);
375 new SharedWorkerRepository(this);
377 if (!frame_
->parent())
378 new ImageLoadingHelper(this);
380 // We delay calling this until we have the WebFrame so that any observer or
381 // embedder can call GetWebFrame on any RenderFrame.
382 GetContentClient()->renderer()->RenderFrameCreated(this);
385 RenderWidget
* RenderFrameImpl::GetRenderWidget() {
386 return render_view_
.get();
389 #if defined(ENABLE_PLUGINS)
390 void RenderFrameImpl::PepperPluginCreated(RendererPpapiHost
* host
) {
391 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
,
392 DidCreatePepperPlugin(host
));
395 void RenderFrameImpl::PepperDidChangeCursor(
396 PepperPluginInstanceImpl
* instance
,
397 const blink::WebCursorInfo
& cursor
) {
398 // Update the cursor appearance immediately if the requesting plugin is the
399 // one which receives the last mouse event. Otherwise, the new cursor won't be
400 // picked up until the plugin gets the next input event. That is bad if, e.g.,
401 // the plugin would like to set an invisible cursor when there isn't any user
402 // input for a while.
403 if (instance
== render_view_
->pepper_last_mouse_event_target())
404 GetRenderWidget()->didChangeCursor(cursor
);
407 void RenderFrameImpl::PepperDidReceiveMouseEvent(
408 PepperPluginInstanceImpl
* instance
) {
409 render_view_
->set_pepper_last_mouse_event_target(instance
);
412 void RenderFrameImpl::PepperTextInputTypeChanged(
413 PepperPluginInstanceImpl
* instance
) {
414 if (instance
!= render_view_
->focused_pepper_plugin())
417 GetRenderWidget()->UpdateTextInputType();
418 if (render_view_
->renderer_accessibility())
419 render_view_
->renderer_accessibility()->FocusedNodeChanged(WebNode());
422 void RenderFrameImpl::PepperCaretPositionChanged(
423 PepperPluginInstanceImpl
* instance
) {
424 if (instance
!= render_view_
->focused_pepper_plugin())
426 GetRenderWidget()->UpdateSelectionBounds();
429 void RenderFrameImpl::PepperCancelComposition(
430 PepperPluginInstanceImpl
* instance
) {
431 if (instance
!= render_view_
->focused_pepper_plugin())
433 Send(new ViewHostMsg_ImeCancelComposition(render_view_
->GetRoutingID()));;
434 #if defined(OS_MACOSX) || defined(USE_AURA)
435 GetRenderWidget()->UpdateCompositionInfo(true);
439 void RenderFrameImpl::PepperSelectionChanged(
440 PepperPluginInstanceImpl
* instance
) {
441 if (instance
!= render_view_
->focused_pepper_plugin())
443 SyncSelectionIfRequired();
446 RenderWidgetFullscreenPepper
* RenderFrameImpl::CreatePepperFullscreenContainer(
447 PepperPluginInstanceImpl
* plugin
) {
449 if (render_view_
->webview() && render_view_
->webview()->mainFrame())
450 active_url
= GURL(render_view_
->webview()->mainFrame()->document().url());
451 RenderWidgetFullscreenPepper
* widget
= RenderWidgetFullscreenPepper::Create(
452 GetRenderWidget()->routing_id(), plugin
, active_url
,
453 GetRenderWidget()->screenInfo());
454 widget
->show(blink::WebNavigationPolicyIgnore
);
458 bool RenderFrameImpl::IsPepperAcceptingCompositionEvents() const {
459 if (!render_view_
->focused_pepper_plugin())
461 return render_view_
->focused_pepper_plugin()->
462 IsPluginAcceptingCompositionEvents();
465 void RenderFrameImpl::PluginCrashed(const base::FilePath
& plugin_path
,
466 base::ProcessId plugin_pid
) {
467 // TODO(jam): dispatch this IPC in RenderFrameHost and switch to use
468 // routing_id_ as a result.
469 Send(new FrameHostMsg_PluginCrashed(routing_id_
, plugin_path
, plugin_pid
));
472 void RenderFrameImpl::SimulateImeSetComposition(
473 const base::string16
& text
,
474 const std::vector
<blink::WebCompositionUnderline
>& underlines
,
477 render_view_
->OnImeSetComposition(
478 text
, underlines
, selection_start
, selection_end
);
481 void RenderFrameImpl::SimulateImeConfirmComposition(
482 const base::string16
& text
,
483 const gfx::Range
& replacement_range
) {
484 render_view_
->OnImeConfirmComposition(text
, replacement_range
, false);
488 void RenderFrameImpl::OnImeSetComposition(
489 const base::string16
& text
,
490 const std::vector
<blink::WebCompositionUnderline
>& underlines
,
493 // When a PPAPI plugin has focus, we bypass WebKit.
494 if (!IsPepperAcceptingCompositionEvents()) {
495 pepper_composition_text_
= text
;
497 // TODO(kinaba) currently all composition events are sent directly to
498 // plugins. Use DOM event mechanism after WebKit is made aware about
499 // plugins that support composition.
500 // The code below mimics the behavior of WebCore::Editor::setComposition.
502 // Empty -> nonempty: composition started.
503 if (pepper_composition_text_
.empty() && !text
.empty()) {
504 render_view_
->focused_pepper_plugin()->HandleCompositionStart(
507 // Nonempty -> empty: composition canceled.
508 if (!pepper_composition_text_
.empty() && text
.empty()) {
509 render_view_
->focused_pepper_plugin()->HandleCompositionEnd(
512 pepper_composition_text_
= text
;
513 // Nonempty: composition is ongoing.
514 if (!pepper_composition_text_
.empty()) {
515 render_view_
->focused_pepper_plugin()->HandleCompositionUpdate(
516 pepper_composition_text_
, underlines
, selection_start
,
522 void RenderFrameImpl::OnImeConfirmComposition(
523 const base::string16
& text
,
524 const gfx::Range
& replacement_range
,
525 bool keep_selection
) {
526 // When a PPAPI plugin has focus, we bypass WebKit.
527 // Here, text.empty() has a special meaning. It means to commit the last
528 // update of composition text (see
529 // RenderWidgetHost::ImeConfirmComposition()).
530 const base::string16
& last_text
= text
.empty() ? pepper_composition_text_
533 // last_text is empty only when both text and pepper_composition_text_ is.
535 if (last_text
.empty())
538 if (!IsPepperAcceptingCompositionEvents()) {
539 base::i18n::UTF16CharIterator
iterator(&last_text
);
541 while (iterator
.Advance()) {
542 blink::WebKeyboardEvent char_event
;
543 char_event
.type
= blink::WebInputEvent::Char
;
544 char_event
.timeStampSeconds
= base::Time::Now().ToDoubleT();
545 char_event
.modifiers
= 0;
546 char_event
.windowsKeyCode
= last_text
[i
];
547 char_event
.nativeKeyCode
= last_text
[i
];
549 const int32 char_start
= i
;
550 for (; i
< iterator
.array_pos(); ++i
) {
551 char_event
.text
[i
- char_start
] = last_text
[i
];
552 char_event
.unmodifiedText
[i
- char_start
] = last_text
[i
];
555 if (GetRenderWidget()->webwidget())
556 GetRenderWidget()->webwidget()->handleInputEvent(char_event
);
559 // Mimics the order of events sent by WebKit.
560 // See WebCore::Editor::setComposition() for the corresponding code.
561 render_view_
->focused_pepper_plugin()->HandleCompositionEnd(last_text
);
562 render_view_
->focused_pepper_plugin()->HandleTextInput(last_text
);
564 pepper_composition_text_
.clear();
567 #endif // ENABLE_PLUGINS
569 bool RenderFrameImpl::Send(IPC::Message
* message
) {
571 ((is_swapped_out_
|| render_view_
->is_swapped_out()) &&
572 !SwappedOutMessages::CanSendWhileSwappedOut(message
))) {
577 return RenderThread::Get()->Send(message
);
580 bool RenderFrameImpl::OnMessageReceived(const IPC::Message
& msg
) {
581 ObserverListBase
<RenderFrameObserver
>::Iterator
it(observers_
);
582 RenderFrameObserver
* observer
;
583 while ((observer
= it
.GetNext()) != NULL
) {
584 if (observer
->OnMessageReceived(msg
))
589 bool msg_is_ok
= true;
590 IPC_BEGIN_MESSAGE_MAP_EX(RenderFrameImpl
, msg
, msg_is_ok
)
591 IPC_MESSAGE_HANDLER(FrameMsg_Navigate
, OnNavigate
)
592 IPC_MESSAGE_HANDLER(FrameMsg_BeforeUnload
, OnBeforeUnload
)
593 IPC_MESSAGE_HANDLER(FrameMsg_SwapOut
, OnSwapOut
)
594 IPC_MESSAGE_HANDLER(FrameMsg_BuffersSwapped
, OnBuffersSwapped
)
595 IPC_MESSAGE_HANDLER_GENERIC(FrameMsg_CompositorFrameSwapped
,
596 OnCompositorFrameSwapped(msg
))
597 IPC_MESSAGE_HANDLER(FrameMsg_ChildFrameProcessGone
, OnChildFrameProcessGone
)
598 IPC_MESSAGE_HANDLER(FrameMsg_ContextMenuClosed
, OnContextMenuClosed
)
599 IPC_MESSAGE_HANDLER(FrameMsg_CustomContextMenuAction
,
600 OnCustomContextMenuAction
)
601 IPC_MESSAGE_HANDLER(InputMsg_Undo
, OnUndo
)
602 IPC_MESSAGE_HANDLER(InputMsg_Redo
, OnRedo
)
603 IPC_MESSAGE_HANDLER(InputMsg_Cut
, OnCut
)
604 IPC_MESSAGE_HANDLER(InputMsg_Copy
, OnCopy
)
605 IPC_MESSAGE_HANDLER(InputMsg_Paste
, OnPaste
)
606 IPC_MESSAGE_HANDLER(InputMsg_PasteAndMatchStyle
, OnPasteAndMatchStyle
)
607 IPC_MESSAGE_HANDLER(InputMsg_Delete
, OnDelete
)
608 IPC_MESSAGE_HANDLER(InputMsg_SelectAll
, OnSelectAll
)
609 IPC_MESSAGE_HANDLER(InputMsg_SelectRange
, OnSelectRange
)
610 IPC_MESSAGE_HANDLER(InputMsg_Unselect
, OnUnselect
)
611 IPC_MESSAGE_HANDLER(InputMsg_Replace
, OnReplace
)
612 IPC_MESSAGE_HANDLER(InputMsg_ReplaceMisspelling
, OnReplaceMisspelling
)
613 IPC_MESSAGE_HANDLER(FrameMsg_CSSInsertRequest
, OnCSSInsertRequest
)
614 IPC_MESSAGE_HANDLER(FrameMsg_JavaScriptExecuteRequest
,
615 OnJavaScriptExecuteRequest
)
616 IPC_MESSAGE_HANDLER(FrameMsg_SetEditableSelectionOffsets
,
617 OnSetEditableSelectionOffsets
)
618 IPC_MESSAGE_HANDLER(FrameMsg_SetCompositionFromExistingText
,
619 OnSetCompositionFromExistingText
)
620 IPC_MESSAGE_HANDLER(FrameMsg_ExtendSelectionAndDelete
,
621 OnExtendSelectionAndDelete
)
622 #if defined(OS_MACOSX)
623 IPC_MESSAGE_HANDLER(InputMsg_CopyToFindPboard
, OnCopyToFindPboard
)
625 IPC_MESSAGE_HANDLER(FrameMsg_Reload
, OnReload
)
626 IPC_END_MESSAGE_MAP_EX()
629 // The message had a handler, but its deserialization failed.
630 // Kill the renderer to avoid potential spoofing attacks.
631 CHECK(false) << "Unable to deserialize message in RenderFrameImpl.";
637 void RenderFrameImpl::OnNavigate(const FrameMsg_Navigate_Params
& params
) {
638 MaybeHandleDebugURL(params
.url
);
639 if (!render_view_
->webview())
642 render_view_
->OnNavigate(params
);
644 bool is_reload
= RenderViewImpl::IsReload(params
);
645 WebURLRequest::CachePolicy cache_policy
=
646 WebURLRequest::UseProtocolCachePolicy
;
648 // If this is a stale back/forward (due to a recent navigation the browser
649 // didn't know about), ignore it.
650 if (render_view_
->IsBackForwardToStaleEntry(params
, is_reload
))
653 // Swap this renderer back in if necessary.
654 if (render_view_
->is_swapped_out_
) {
655 // We marked the view as hidden when swapping the view out, so be sure to
656 // reset the visibility state before navigating to the new URL.
657 render_view_
->webview()->setVisibilityState(
658 render_view_
->visibilityState(), false);
660 // If this is an attempt to reload while we are swapped out, we should not
661 // reload swappedout://, but the previous page, which is stored in
662 // params.state. Setting is_reload to false will treat this like a back
663 // navigation to accomplish that.
665 cache_policy
= WebURLRequest::ReloadIgnoringCacheData
;
667 // We refresh timezone when a view is swapped in since timezone
668 // can get out of sync when the system timezone is updated while
669 // the view is swapped out.
670 RenderThreadImpl::NotifyTimezoneChange();
672 render_view_
->SetSwappedOut(false);
673 is_swapped_out_
= false;
676 if (params
.should_clear_history_list
) {
677 CHECK_EQ(params
.pending_history_list_offset
, -1);
678 CHECK_EQ(params
.current_history_list_offset
, -1);
679 CHECK_EQ(params
.current_history_list_length
, 0);
681 render_view_
->history_list_offset_
= params
.current_history_list_offset
;
682 render_view_
->history_list_length_
= params
.current_history_list_length
;
683 if (render_view_
->history_list_length_
>= 0) {
684 render_view_
->history_page_ids_
.resize(
685 render_view_
->history_list_length_
, -1);
687 if (params
.pending_history_list_offset
>= 0 &&
688 params
.pending_history_list_offset
< render_view_
->history_list_length_
) {
689 render_view_
->history_page_ids_
[params
.pending_history_list_offset
] =
693 GetContentClient()->SetActiveURL(params
.url
);
695 WebFrame
* frame
= frame_
;
696 if (!params
.frame_to_navigate
.empty()) {
697 // TODO(nasko): Move this lookup to the browser process.
698 frame
= render_view_
->webview()->findFrameByName(
699 WebString::fromUTF8(params
.frame_to_navigate
));
700 CHECK(frame
) << "Invalid frame name passed: " << params
.frame_to_navigate
;
703 WebHistoryItem item
=
704 render_view_
->history_controller()->GetCurrentItemForExport();
705 if (is_reload
&& item
.isNull()) {
706 // We cannot reload if we do not have any history state. This happens, for
707 // example, when recovering from a crash.
709 cache_policy
= WebURLRequest::ReloadIgnoringCacheData
;
712 render_view_
->pending_navigation_params_
.reset(
713 new FrameMsg_Navigate_Params(params
));
715 // If we are reloading, then WebKit will use the history state of the current
716 // page, so we should just ignore any given history state. Otherwise, if we
717 // have history state, then we need to navigate to it, which corresponds to a
718 // back/forward navigation event.
720 bool reload_original_url
=
721 (params
.navigation_type
==
722 FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL
);
723 bool ignore_cache
= (params
.navigation_type
==
724 FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE
);
726 if (reload_original_url
)
727 frame
->reloadWithOverrideURL(params
.url
, true);
729 frame
->reload(ignore_cache
);
730 } else if (params
.page_state
.IsValid()) {
731 // We must know the page ID of the page we are navigating back to.
732 DCHECK_NE(params
.page_id
, -1);
733 WebHistoryItem item
= PageStateToHistoryItem(params
.page_state
);
734 if (!item
.isNull()) {
735 // Ensure we didn't save the swapped out URL in UpdateState, since the
736 // browser should never be telling us to navigate to swappedout://.
737 CHECK(item
.urlString() != WebString::fromUTF8(kSwappedOutURL
));
738 render_view_
->history_controller()->GoToItem(item
, cache_policy
);
740 } else if (!params
.base_url_for_data_url
.is_empty()) {
741 // A loadData request with a specified base URL.
742 std::string mime_type
, charset
, data
;
743 if (net::DataURL::Parse(params
.url
, &mime_type
, &charset
, &data
)) {
745 WebData(data
.c_str(), data
.length()),
746 WebString::fromUTF8(mime_type
),
747 WebString::fromUTF8(charset
),
748 params
.base_url_for_data_url
,
749 params
.history_url_for_data_url
,
753 "Invalid URL passed: " << params
.url
.possibly_invalid_spec();
756 // Navigate to the given URL.
757 WebURLRequest
request(params
.url
);
759 // A session history navigation should have been accompanied by state.
760 CHECK_EQ(params
.page_id
, -1);
762 if (frame
->isViewSourceModeEnabled())
763 request
.setCachePolicy(WebURLRequest::ReturnCacheDataElseLoad
);
765 if (params
.referrer
.url
.is_valid()) {
766 WebString referrer
= WebSecurityPolicy::generateReferrerHeader(
767 params
.referrer
.policy
,
769 WebString::fromUTF8(params
.referrer
.url
.spec()));
770 if (!referrer
.isEmpty())
771 request
.setHTTPReferrer(referrer
, params
.referrer
.policy
);
774 if (!params
.extra_headers
.empty()) {
775 for (net::HttpUtil::HeadersIterator
i(params
.extra_headers
.begin(),
776 params
.extra_headers
.end(), "\n");
778 request
.addHTTPHeaderField(WebString::fromUTF8(i
.name()),
779 WebString::fromUTF8(i
.values()));
783 if (params
.is_post
) {
784 request
.setHTTPMethod(WebString::fromUTF8("POST"));
787 WebHTTPBody http_body
;
788 http_body
.initialize();
789 const char* data
= NULL
;
790 if (params
.browser_initiated_post_data
.size()) {
791 data
= reinterpret_cast<const char*>(
792 ¶ms
.browser_initiated_post_data
.front());
794 http_body
.appendData(
795 WebData(data
, params
.browser_initiated_post_data
.size()));
796 request
.setHTTPBody(http_body
);
799 frame
->loadRequest(request
);
801 // If this is a cross-process navigation, the browser process will send
802 // along the proper navigation start value.
803 if (!params
.browser_navigation_start
.is_null() &&
804 frame
->provisionalDataSource()) {
805 // browser_navigation_start is likely before this process existed, so we
806 // can't use InterProcessTimeTicksConverter. Instead, the best we can do
807 // is just ensure we don't report a bogus value in the future.
808 base::TimeTicks navigation_start
= std::min(
809 base::TimeTicks::Now(), params
.browser_navigation_start
);
810 double navigation_start_seconds
=
811 (navigation_start
- base::TimeTicks()).InSecondsF();
812 frame
->provisionalDataSource()->setNavigationStartTime(
813 navigation_start_seconds
);
817 // In case LoadRequest failed before DidCreateDataSource was called.
818 render_view_
->pending_navigation_params_
.reset();
821 void RenderFrameImpl::OnBeforeUnload() {
822 // TODO(creis): Right now, this is only called on the main frame. Make the
823 // browser process send dispatchBeforeUnloadEvent to every frame that needs
825 CHECK(!frame_
->parent());
827 base::TimeTicks before_unload_start_time
= base::TimeTicks::Now();
828 bool proceed
= frame_
->dispatchBeforeUnloadEvent();
829 base::TimeTicks before_unload_end_time
= base::TimeTicks::Now();
830 Send(new FrameHostMsg_BeforeUnload_ACK(routing_id_
, proceed
,
831 before_unload_start_time
,
832 before_unload_end_time
));
835 void RenderFrameImpl::OnSwapOut() {
836 // Only run unload if we're not swapped out yet, but send the ack either way.
837 if (!is_swapped_out_
|| !render_view_
->is_swapped_out_
) {
838 // Swap this RenderFrame out so the frame can navigate to a page rendered by
839 // a different process. This involves running the unload handler and
840 // clearing the page. Once WasSwappedOut is called, we also allow this
841 // process to exit if there are no other active RenderFrames in it.
843 // Send an UpdateState message before we get swapped out.
844 render_view_
->SyncNavigationState();
846 // Synchronously run the unload handler before sending the ACK.
847 // TODO(creis): Call dispatchUnloadEvent unconditionally here to support
848 // unload on subframes as well.
849 if (!frame_
->parent())
850 frame_
->dispatchUnloadEvent();
852 // Swap out and stop sending any IPC messages that are not ACKs.
853 if (!frame_
->parent())
854 render_view_
->SetSwappedOut(true);
855 is_swapped_out_
= true;
857 // Now that we're swapped out and filtering IPC messages, stop loading to
858 // ensure that no other in-progress navigation continues. We do this here
859 // to avoid sending a DidStopLoading message to the browser process.
860 // TODO(creis): Should we be stopping all frames here and using
861 // StopAltErrorPageFetcher with RenderView::OnStop, or just stopping this
863 if (!frame_
->parent())
864 render_view_
->OnStop();
866 frame_
->stopLoading();
868 // Let subframes know that the frame is now rendered remotely, for the
869 // purposes of compositing and input events.
870 if (frame_
->parent())
871 frame_
->setIsRemote(true);
873 // Replace the page with a blank dummy URL. The unload handler will not be
874 // run a second time, thanks to a check in FrameLoader::stopLoading.
875 // TODO(creis): Need to add a better way to do this that avoids running the
876 // beforeunload handler. For now, we just run it a second time silently.
877 render_view_
->NavigateToSwappedOutURL(frame_
);
879 if (frame_
->parent())
880 render_view_
->RegisterSwappedOutChildFrame(this);
882 // Let WebKit know that this view is hidden so it can drop resources and
884 // TODO(creis): Support this for subframes as well.
885 if (!frame_
->parent()) {
886 render_view_
->webview()->setVisibilityState(
887 blink::WebPageVisibilityStateHidden
, false);
891 // It is now safe to show modal dialogs again.
892 // TODO(creis): Deal with modal dialogs from subframes.
893 if (!frame_
->parent())
894 render_view_
->suppress_dialogs_until_swap_out_
= false;
896 Send(new FrameHostMsg_SwapOut_ACK(routing_id_
));
899 void RenderFrameImpl::OnBuffersSwapped(
900 const FrameMsg_BuffersSwapped_Params
& params
) {
901 if (!compositing_helper_
.get()) {
902 compositing_helper_
=
903 ChildFrameCompositingHelper::CreateCompositingHelperForRenderFrame(
904 frame_
, this, routing_id_
);
905 compositing_helper_
->EnableCompositing(true);
907 compositing_helper_
->OnBuffersSwapped(
912 render_view_
->GetWebView()->deviceScaleFactor());
915 void RenderFrameImpl::OnCompositorFrameSwapped(const IPC::Message
& message
) {
916 FrameMsg_CompositorFrameSwapped::Param param
;
917 if (!FrameMsg_CompositorFrameSwapped::Read(&message
, ¶m
))
919 scoped_ptr
<cc::CompositorFrame
> frame(new cc::CompositorFrame
);
920 param
.a
.frame
.AssignTo(frame
.get());
922 if (!compositing_helper_
.get()) {
923 compositing_helper_
=
924 ChildFrameCompositingHelper::CreateCompositingHelperForRenderFrame(
925 frame_
, this, routing_id_
);
926 compositing_helper_
->EnableCompositing(true);
928 compositing_helper_
->OnCompositorFrameSwapped(frame
.Pass(),
929 param
.a
.producing_route_id
,
930 param
.a
.output_surface_id
,
931 param
.a
.producing_host_id
,
932 param
.a
.shared_memory_handle
);
935 void RenderFrameImpl::OnContextMenuClosed(
936 const CustomContextMenuContext
& custom_context
) {
937 if (custom_context
.request_id
) {
938 // External request, should be in our map.
939 ContextMenuClient
* client
=
940 pending_context_menus_
.Lookup(custom_context
.request_id
);
942 client
->OnMenuClosed(custom_context
.request_id
);
943 pending_context_menus_
.Remove(custom_context
.request_id
);
946 // Internal request, forward to WebKit.
947 context_menu_node_
.reset();
951 void RenderFrameImpl::OnCustomContextMenuAction(
952 const CustomContextMenuContext
& custom_context
,
954 if (custom_context
.request_id
) {
955 // External context menu request, look in our map.
956 ContextMenuClient
* client
=
957 pending_context_menus_
.Lookup(custom_context
.request_id
);
959 client
->OnMenuAction(custom_context
.request_id
, action
);
961 // Internal request, forward to WebKit.
962 render_view_
->webview()->performCustomContextMenuAction(action
);
966 void RenderFrameImpl::OnUndo() {
967 frame_
->executeCommand(WebString::fromUTF8("Undo"), GetFocusedElement());
970 void RenderFrameImpl::OnRedo() {
971 frame_
->executeCommand(WebString::fromUTF8("Redo"), GetFocusedElement());
974 void RenderFrameImpl::OnCut() {
975 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
976 frame_
->executeCommand(WebString::fromUTF8("Cut"), GetFocusedElement());
979 void RenderFrameImpl::OnCopy() {
980 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
981 WebNode current_node
= context_menu_node_
.isNull() ?
982 GetFocusedElement() : context_menu_node_
;
983 frame_
->executeCommand(WebString::fromUTF8("Copy"), current_node
);
986 void RenderFrameImpl::OnPaste() {
987 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
988 frame_
->executeCommand(WebString::fromUTF8("Paste"), GetFocusedElement());
991 void RenderFrameImpl::OnPasteAndMatchStyle() {
992 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
993 frame_
->executeCommand(
994 WebString::fromUTF8("PasteAndMatchStyle"), GetFocusedElement());
997 #if defined(OS_MACOSX)
998 void RenderFrameImpl::OnCopyToFindPboard() {
999 // Since the find pasteboard supports only plain text, this can be simpler
1000 // than the |OnCopy()| case.
1001 if (frame_
->hasSelection()) {
1002 base::string16 selection
= frame_
->selectionAsText();
1003 RenderThread::Get()->Send(
1004 new ClipboardHostMsg_FindPboardWriteStringAsync(selection
));
1009 void RenderFrameImpl::OnDelete() {
1010 frame_
->executeCommand(WebString::fromUTF8("Delete"), GetFocusedElement());
1013 void RenderFrameImpl::OnSelectAll() {
1014 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
1015 frame_
->executeCommand(WebString::fromUTF8("SelectAll"), GetFocusedElement());
1018 void RenderFrameImpl::OnSelectRange(const gfx::Point
& start
,
1019 const gfx::Point
& end
) {
1020 // This IPC is dispatched by RenderWidgetHost, so use its routing id.
1021 Send(new ViewHostMsg_SelectRange_ACK(GetRenderWidget()->routing_id()));
1023 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
1024 frame_
->selectRange(start
, end
);
1027 void RenderFrameImpl::OnUnselect() {
1028 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
1029 frame_
->executeCommand(WebString::fromUTF8("Unselect"), GetFocusedElement());
1032 void RenderFrameImpl::OnReplace(const base::string16
& text
) {
1033 if (!frame_
->hasSelection())
1034 frame_
->selectWordAroundCaret();
1036 frame_
->replaceSelection(text
);
1039 void RenderFrameImpl::OnReplaceMisspelling(const base::string16
& text
) {
1040 if (!frame_
->hasSelection())
1043 frame_
->replaceMisspelledRange(text
);
1046 void RenderFrameImpl::OnCSSInsertRequest(const std::string
& css
) {
1047 frame_
->document().insertStyleSheet(WebString::fromUTF8(css
));
1050 void RenderFrameImpl::OnJavaScriptExecuteRequest(
1051 const base::string16
& jscript
,
1053 bool notify_result
) {
1054 TRACE_EVENT_INSTANT0("test_tracing", "OnJavaScriptExecuteRequest",
1055 TRACE_EVENT_SCOPE_THREAD
);
1057 v8::HandleScope
handle_scope(v8::Isolate::GetCurrent());
1058 v8::Handle
<v8::Value
> result
=
1059 frame_
->executeScriptAndReturnValue(WebScriptSource(jscript
));
1060 if (notify_result
) {
1061 base::ListValue list
;
1062 if (!result
.IsEmpty()) {
1063 v8::Local
<v8::Context
> context
= frame_
->mainWorldScriptContext();
1064 v8::Context::Scope
context_scope(context
);
1065 V8ValueConverterImpl converter
;
1066 converter
.SetDateAllowed(true);
1067 converter
.SetRegExpAllowed(true);
1068 base::Value
* result_value
= converter
.FromV8Value(result
, context
);
1069 list
.Set(0, result_value
? result_value
: base::Value::CreateNullValue());
1071 list
.Set(0, base::Value::CreateNullValue());
1073 Send(new FrameHostMsg_JavaScriptExecuteResponse(routing_id_
, id
, list
));
1077 void RenderFrameImpl::OnSetEditableSelectionOffsets(int start
, int end
) {
1078 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
1079 if (!GetRenderWidget()->ShouldHandleImeEvent())
1081 ImeEventGuard
guard(GetRenderWidget());
1082 frame_
->setEditableSelectionOffsets(start
, end
);
1085 void RenderFrameImpl::OnSetCompositionFromExistingText(
1087 const std::vector
<blink::WebCompositionUnderline
>& underlines
) {
1088 if (!GetRenderWidget()->ShouldHandleImeEvent())
1090 ImeEventGuard
guard(GetRenderWidget());
1091 frame_
->setCompositionFromExistingText(start
, end
, underlines
);
1094 void RenderFrameImpl::OnExtendSelectionAndDelete(int before
, int after
) {
1095 if (!GetRenderWidget()->ShouldHandleImeEvent())
1097 ImeEventGuard
guard(GetRenderWidget());
1098 frame_
->extendSelectionAndDelete(before
, after
);
1102 void RenderFrameImpl::OnReload(bool ignore_cache
) {
1103 frame_
->reload(ignore_cache
);
1106 bool RenderFrameImpl::ShouldUpdateSelectionTextFromContextMenuParams(
1107 const base::string16
& selection_text
,
1108 size_t selection_text_offset
,
1109 const gfx::Range
& selection_range
,
1110 const ContextMenuParams
& params
) {
1111 base::string16 trimmed_selection_text
;
1112 if (!selection_text
.empty() && !selection_range
.is_empty()) {
1113 const int start
= selection_range
.GetMin() - selection_text_offset
;
1114 const size_t length
= selection_range
.length();
1115 if (start
>= 0 && start
+ length
<= selection_text
.length()) {
1116 base::TrimWhitespace(selection_text
.substr(start
, length
), base::TRIM_ALL
,
1117 &trimmed_selection_text
);
1120 base::string16 trimmed_params_text
;
1121 base::TrimWhitespace(params
.selection_text
, base::TRIM_ALL
,
1122 &trimmed_params_text
);
1123 return trimmed_params_text
!= trimmed_selection_text
;
1126 bool RenderFrameImpl::RunJavaScriptMessage(JavaScriptMessageType type
,
1127 const base::string16
& message
,
1128 const base::string16
& default_value
,
1129 const GURL
& frame_url
,
1130 base::string16
* result
) {
1131 // Don't allow further dialogs if we are waiting to swap out, since the
1132 // PageGroupLoadDeferrer in our stack prevents it.
1133 if (render_view()->suppress_dialogs_until_swap_out_
)
1136 bool success
= false;
1137 base::string16 result_temp
;
1139 result
= &result_temp
;
1141 render_view()->SendAndRunNestedMessageLoop(
1142 new FrameHostMsg_RunJavaScriptMessage(
1143 routing_id_
, message
, default_value
, frame_url
, type
, &success
,
1148 void RenderFrameImpl::DidCommitCompositorFrame() {
1149 if (compositing_helper_
)
1150 compositing_helper_
->DidCommitCompositorFrame();
1153 RenderView
* RenderFrameImpl::GetRenderView() {
1154 return render_view_
.get();
1157 int RenderFrameImpl::GetRoutingID() {
1161 blink::WebFrame
* RenderFrameImpl::GetWebFrame() {
1166 WebPreferences
& RenderFrameImpl::GetWebkitPreferences() {
1167 return render_view_
->GetWebkitPreferences();
1170 int RenderFrameImpl::ShowContextMenu(ContextMenuClient
* client
,
1171 const ContextMenuParams
& params
) {
1172 DCHECK(client
); // A null client means "internal" when we issue callbacks.
1173 ContextMenuParams
our_params(params
);
1174 our_params
.custom_context
.request_id
= pending_context_menus_
.Add(client
);
1175 Send(new FrameHostMsg_ContextMenu(routing_id_
, our_params
));
1176 return our_params
.custom_context
.request_id
;
1179 void RenderFrameImpl::CancelContextMenu(int request_id
) {
1180 DCHECK(pending_context_menus_
.Lookup(request_id
));
1181 pending_context_menus_
.Remove(request_id
);
1184 blink::WebNode
RenderFrameImpl::GetContextMenuNode() const {
1185 return context_menu_node_
;
1188 blink::WebPlugin
* RenderFrameImpl::CreatePlugin(
1189 blink::WebFrame
* frame
,
1190 const WebPluginInfo
& info
,
1191 const blink::WebPluginParams
& params
) {
1192 DCHECK_EQ(frame_
, frame
);
1193 #if defined(ENABLE_PLUGINS)
1194 bool pepper_plugin_was_registered
= false;
1195 scoped_refptr
<PluginModule
> pepper_module(PluginModule::Create(
1196 this, info
, &pepper_plugin_was_registered
));
1197 if (pepper_plugin_was_registered
) {
1198 if (pepper_module
.get()) {
1199 return new PepperWebPluginImpl(pepper_module
.get(), params
, this);
1202 #if defined(OS_CHROMEOS)
1203 LOG(WARNING
) << "Pepper module/plugin creation failed.";
1206 // TODO(jam): change to take RenderFrame.
1207 return new WebPluginImpl(frame
, params
, info
.path
, render_view_
, this);
1214 void RenderFrameImpl::LoadURLExternally(blink::WebLocalFrame
* frame
,
1215 const blink::WebURLRequest
& request
,
1216 blink::WebNavigationPolicy policy
) {
1217 DCHECK(!frame_
|| frame_
== frame
);
1218 loadURLExternally(frame
, request
, policy
, WebString());
1221 void RenderFrameImpl::ExecuteJavaScript(const base::string16
& javascript
) {
1222 OnJavaScriptExecuteRequest(javascript
, 0, false);
1225 void RenderFrameImpl::OnChildFrameProcessGone() {
1226 if (compositing_helper_
)
1227 compositing_helper_
->ChildFrameGone();
1230 // blink::WebFrameClient implementation ----------------------------------------
1232 blink::WebPlugin
* RenderFrameImpl::createPlugin(
1233 blink::WebLocalFrame
* frame
,
1234 const blink::WebPluginParams
& params
) {
1235 DCHECK_EQ(frame_
, frame
);
1236 blink::WebPlugin
* plugin
= NULL
;
1237 if (GetContentClient()->renderer()->OverrideCreatePlugin(
1238 this, frame
, params
, &plugin
)) {
1242 if (base::UTF16ToASCII(params
.mimeType
) == kBrowserPluginMimeType
) {
1243 return render_view_
->GetBrowserPluginManager()->CreateBrowserPlugin(
1244 render_view_
.get(), frame
, false);
1247 #if defined(ENABLE_PLUGINS)
1249 std::string mime_type
;
1251 Send(new FrameHostMsg_GetPluginInfo(
1252 routing_id_
, params
.url
, frame
->top()->document().url(),
1253 params
.mimeType
.utf8(), &found
, &info
, &mime_type
));
1257 if (info
.type
== content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN
) {
1258 return render_view_
->GetBrowserPluginManager()->CreateBrowserPlugin(
1259 render_view_
.get(), frame
, true);
1263 WebPluginParams params_to_use
= params
;
1264 params_to_use
.mimeType
= WebString::fromUTF8(mime_type
);
1265 return CreatePlugin(frame
, info
, params_to_use
);
1268 #endif // defined(ENABLE_PLUGINS)
1271 blink::WebMediaPlayer
* RenderFrameImpl::createMediaPlayer(
1272 blink::WebLocalFrame
* frame
,
1273 const blink::WebURL
& url
,
1274 blink::WebMediaPlayerClient
* client
) {
1275 DCHECK(!frame_
|| frame_
== frame
);
1276 // TODO(nasko): Moving the implementation here involves moving a few media
1277 // related client objects here or referencing them in the RenderView. Needs
1278 // more work to understand where the proper place for those objects is.
1279 return render_view_
->CreateMediaPlayer(this, frame
, url
, client
);
1282 blink::WebContentDecryptionModule
*
1283 RenderFrameImpl::createContentDecryptionModule(
1284 blink::WebLocalFrame
* frame
,
1285 const blink::WebSecurityOrigin
& security_origin
,
1286 const blink::WebString
& key_system
) {
1287 DCHECK(!frame_
|| frame_
== frame
);
1288 return WebContentDecryptionModuleImpl::Create(
1289 frame
, security_origin
, key_system
);
1292 blink::WebApplicationCacheHost
* RenderFrameImpl::createApplicationCacheHost(
1293 blink::WebLocalFrame
* frame
,
1294 blink::WebApplicationCacheHostClient
* client
) {
1295 if (!frame
|| !frame
->view())
1297 DCHECK(!frame_
|| frame_
== frame
);
1298 return new RendererWebApplicationCacheHostImpl(
1299 RenderViewImpl::FromWebView(frame
->view()), client
,
1300 RenderThreadImpl::current()->appcache_dispatcher()->backend_proxy());
1303 blink::WebWorkerPermissionClientProxy
*
1304 RenderFrameImpl::createWorkerPermissionClientProxy(
1305 blink::WebLocalFrame
* frame
) {
1306 if (!frame
|| !frame
->view())
1308 DCHECK(!frame_
|| frame_
== frame
);
1309 return GetContentClient()->renderer()->CreateWorkerPermissionClientProxy(
1313 blink::WebCookieJar
* RenderFrameImpl::cookieJar(blink::WebLocalFrame
* frame
) {
1314 DCHECK(!frame_
|| frame_
== frame
);
1315 return &cookie_jar_
;
1318 blink::WebServiceWorkerProvider
* RenderFrameImpl::createServiceWorkerProvider(
1319 blink::WebLocalFrame
* frame
) {
1320 DCHECK(!frame_
|| frame_
== frame
);
1321 // At this point we should have non-null data source.
1322 DCHECK(frame
->dataSource());
1323 ServiceWorkerNetworkProvider
* provider
=
1324 ServiceWorkerNetworkProvider::FromDocumentState(
1325 DocumentState::FromDataSource(frame
->dataSource()));
1326 int provider_id
= provider
?
1327 provider
->provider_id() :
1328 kInvalidServiceWorkerProviderId
;
1329 return new WebServiceWorkerProviderImpl(
1330 ChildThread::current()->thread_safe_sender(), provider_id
);
1333 void RenderFrameImpl::didAccessInitialDocument(blink::WebLocalFrame
* frame
) {
1334 DCHECK(!frame_
|| frame_
== frame
);
1335 render_view_
->didAccessInitialDocument(frame
);
1338 blink::WebFrame
* RenderFrameImpl::createChildFrame(
1339 blink::WebLocalFrame
* parent
,
1340 const blink::WebString
& name
) {
1341 // Synchronously notify the browser of a child frame creation to get the
1342 // routing_id for the RenderFrame.
1343 int child_routing_id
= MSG_ROUTING_NONE
;
1344 Send(new FrameHostMsg_CreateChildFrame(routing_id_
,
1345 base::UTF16ToUTF8(name
),
1346 &child_routing_id
));
1347 // Allocation of routing id failed, so we can't create a child frame. This can
1348 // happen if this RenderFrameImpl's IPCs are being filtered when in swapped
1350 if (child_routing_id
== MSG_ROUTING_NONE
) {
1351 base::debug::Alias(parent
);
1352 base::debug::Alias(&routing_id_
);
1353 bool render_view_is_swapped_out
= GetRenderWidget()->is_swapped_out();
1354 base::debug::Alias(&render_view_is_swapped_out
);
1355 bool render_view_is_closing
= GetRenderWidget()->closing();
1356 base::debug::Alias(&render_view_is_closing
);
1357 base::debug::Alias(&is_swapped_out_
);
1358 base::debug::DumpWithoutCrashing();
1362 // Create the RenderFrame and WebLocalFrame, linking the two.
1363 RenderFrameImpl
* child_render_frame
= RenderFrameImpl::Create(
1364 render_view_
.get(), child_routing_id
);
1365 blink::WebLocalFrame
* web_frame
= WebLocalFrame::create(child_render_frame
);
1366 child_render_frame
->SetWebFrame(web_frame
);
1368 // Add the frame to the frame tree and initialize it.
1369 parent
->appendChild(web_frame
);
1370 child_render_frame
->Initialize();
1375 void RenderFrameImpl::didDisownOpener(blink::WebLocalFrame
* frame
) {
1376 DCHECK(!frame_
|| frame_
== frame
);
1377 render_view_
->didDisownOpener(frame
);
1380 void RenderFrameImpl::frameDetached(blink::WebFrame
* frame
) {
1381 // NOTE: This function is called on the frame that is being detached and not
1382 // the parent frame. This is different from createChildFrame() which is
1383 // called on the parent frame.
1384 CHECK(!is_detaching_
);
1385 DCHECK(!frame_
|| frame_
== frame
);
1387 bool is_subframe
= !!frame
->parent();
1389 Send(new FrameHostMsg_Detach(routing_id_
));
1391 render_view_
->UnregisterSwappedOutChildFrame(this);
1393 // The |is_detaching_| flag disables Send(). FrameHostMsg_Detach must be
1394 // sent before setting |is_detaching_| to true. In contrast, Observers
1395 // should only be notified afterwards so they cannot call back into here and
1396 // have IPCs fired off.
1397 is_detaching_
= true;
1399 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1400 FrameDetached(frame
));
1402 // We need to clean up subframes by removing them from the map and deleting
1403 // the RenderFrameImpl. In contrast, the main frame is owned by its
1404 // containing RenderViewHost (so that they have the same lifetime), so only
1405 // removal from the map is needed and no deletion.
1406 FrameMap::iterator it
= g_frame_map
.Get().find(frame
);
1407 CHECK(it
!= g_frame_map
.Get().end());
1408 CHECK_EQ(it
->second
, this);
1409 g_frame_map
.Get().erase(it
);
1412 frame
->parent()->removeChild(frame
);
1414 // |frame| is invalid after here.
1419 // Object is invalid after this point.
1423 void RenderFrameImpl::frameFocused() {
1424 Send(new FrameHostMsg_FrameFocused(routing_id_
));
1427 void RenderFrameImpl::willClose(blink::WebFrame
* frame
) {
1428 DCHECK(!frame_
|| frame_
== frame
);
1430 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1431 FrameWillClose(frame
));
1434 void RenderFrameImpl::didChangeName(blink::WebLocalFrame
* frame
,
1435 const blink::WebString
& name
) {
1436 DCHECK(!frame_
|| frame_
== frame
);
1437 if (!render_view_
->renderer_preferences_
.report_frame_name_changes
)
1441 new ViewHostMsg_UpdateFrameName(render_view_
->GetRoutingID(),
1444 base::UTF16ToUTF8(name
)));
1447 void RenderFrameImpl::didMatchCSS(
1448 blink::WebLocalFrame
* frame
,
1449 const blink::WebVector
<blink::WebString
>& newly_matching_selectors
,
1450 const blink::WebVector
<blink::WebString
>& stopped_matching_selectors
) {
1451 DCHECK(!frame_
|| frame_
== frame
);
1453 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1455 newly_matching_selectors
,
1456 stopped_matching_selectors
));
1459 bool RenderFrameImpl::shouldReportDetailedMessageForSource(
1460 const blink::WebString
& source
) {
1461 return GetContentClient()->renderer()->ShouldReportDetailedMessageForSource(
1465 void RenderFrameImpl::didAddMessageToConsole(
1466 const blink::WebConsoleMessage
& message
,
1467 const blink::WebString
& source_name
,
1468 unsigned source_line
,
1469 const blink::WebString
& stack_trace
) {
1470 logging::LogSeverity log_severity
= logging::LOG_VERBOSE
;
1471 switch (message
.level
) {
1472 case blink::WebConsoleMessage::LevelDebug
:
1473 log_severity
= logging::LOG_VERBOSE
;
1475 case blink::WebConsoleMessage::LevelLog
:
1476 case blink::WebConsoleMessage::LevelInfo
:
1477 log_severity
= logging::LOG_INFO
;
1479 case blink::WebConsoleMessage::LevelWarning
:
1480 log_severity
= logging::LOG_WARNING
;
1482 case blink::WebConsoleMessage::LevelError
:
1483 log_severity
= logging::LOG_ERROR
;
1489 if (shouldReportDetailedMessageForSource(source_name
)) {
1491 RenderViewObserver
, render_view_
->observers(),
1492 DetailedConsoleMessageAdded(message
.text
,
1496 static_cast<int32
>(log_severity
)));
1498 RenderFrameObserver
, observers_
,
1499 DetailedConsoleMessageAdded(message
.text
,
1503 static_cast<int32
>(log_severity
)));
1506 Send(new FrameHostMsg_AddMessageToConsole(routing_id_
,
1507 static_cast<int32
>(log_severity
),
1509 static_cast<int32
>(source_line
),
1513 void RenderFrameImpl::loadURLExternally(
1514 blink::WebLocalFrame
* frame
,
1515 const blink::WebURLRequest
& request
,
1516 blink::WebNavigationPolicy policy
,
1517 const blink::WebString
& suggested_name
) {
1518 DCHECK(!frame_
|| frame_
== frame
);
1519 Referrer
referrer(RenderViewImpl::GetReferrerFromRequest(frame
, request
));
1520 if (policy
== blink::WebNavigationPolicyDownload
) {
1521 render_view_
->Send(new ViewHostMsg_DownloadUrl(render_view_
->GetRoutingID(),
1522 request
.url(), referrer
,
1525 OpenURL(frame
, request
.url(), referrer
, policy
);
1529 blink::WebNavigationPolicy
RenderFrameImpl::decidePolicyForNavigation(
1530 blink::WebLocalFrame
* frame
,
1531 blink::WebDataSource::ExtraData
* extra_data
,
1532 const blink::WebURLRequest
& request
,
1533 blink::WebNavigationType type
,
1534 blink::WebNavigationPolicy default_policy
,
1536 DCHECK(!frame_
|| frame_
== frame
);
1537 return DecidePolicyForNavigation(
1538 this, frame
, extra_data
, request
, type
, default_policy
, is_redirect
);
1541 blink::WebHistoryItem
RenderFrameImpl::historyItemForNewChildFrame(
1542 blink::WebFrame
* frame
) {
1543 DCHECK(!frame_
|| frame_
== frame
);
1544 return render_view_
->history_controller()->GetItemForNewChildFrame(this);
1547 void RenderFrameImpl::willSendSubmitEvent(blink::WebLocalFrame
* frame
,
1548 const blink::WebFormElement
& form
) {
1549 DCHECK(!frame_
|| frame_
== frame
);
1551 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1552 WillSendSubmitEvent(frame
, form
));
1555 void RenderFrameImpl::willSubmitForm(blink::WebLocalFrame
* frame
,
1556 const blink::WebFormElement
& form
) {
1557 DCHECK(!frame_
|| frame_
== frame
);
1558 DocumentState
* document_state
=
1559 DocumentState::FromDataSource(frame
->provisionalDataSource());
1560 NavigationState
* navigation_state
= document_state
->navigation_state();
1561 InternalDocumentStateData
* internal_data
=
1562 InternalDocumentStateData::FromDocumentState(document_state
);
1564 if (PageTransitionCoreTypeIs(navigation_state
->transition_type(),
1565 PAGE_TRANSITION_LINK
)) {
1566 navigation_state
->set_transition_type(PAGE_TRANSITION_FORM_SUBMIT
);
1569 // Save these to be processed when the ensuing navigation is committed.
1570 WebSearchableFormData
web_searchable_form_data(form
);
1571 internal_data
->set_searchable_form_url(web_searchable_form_data
.url());
1572 internal_data
->set_searchable_form_encoding(
1573 web_searchable_form_data
.encoding().utf8());
1575 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1576 WillSubmitForm(frame
, form
));
1579 void RenderFrameImpl::didCreateDataSource(blink::WebLocalFrame
* frame
,
1580 blink::WebDataSource
* datasource
) {
1581 DCHECK(!frame_
|| frame_
== frame
);
1583 // TODO(nasko): Move implementation here. Needed state:
1584 // * pending_navigation_params_
1587 // * PopulateDocumentStateFromPending
1588 // * CreateNavigationStateFromPending
1589 render_view_
->didCreateDataSource(frame
, datasource
);
1591 // Create the serviceworker's per-document network observing object.
1592 scoped_ptr
<ServiceWorkerNetworkProvider
>
1593 network_provider(new ServiceWorkerNetworkProvider());
1594 ServiceWorkerNetworkProvider::AttachToDocumentState(
1595 DocumentState::FromDataSource(datasource
),
1596 network_provider
.Pass());
1599 void RenderFrameImpl::didStartProvisionalLoad(blink::WebLocalFrame
* frame
) {
1600 DCHECK(!frame_
|| frame_
== frame
);
1601 WebDataSource
* ds
= frame
->provisionalDataSource();
1603 // In fast/loader/stop-provisional-loads.html, we abort the load before this
1604 // callback is invoked.
1608 DocumentState
* document_state
= DocumentState::FromDataSource(ds
);
1610 // We should only navigate to swappedout:// when is_swapped_out_ is true.
1611 CHECK((ds
->request().url() != GURL(kSwappedOutURL
)) ||
1613 render_view_
->is_swapped_out()) <<
1614 "Heard swappedout:// when not swapped out.";
1616 // Update the request time if WebKit has better knowledge of it.
1617 if (document_state
->request_time().is_null()) {
1618 double event_time
= ds
->triggeringEventTime();
1619 if (event_time
!= 0.0)
1620 document_state
->set_request_time(Time::FromDoubleT(event_time
));
1623 // Start time is only set after request time.
1624 document_state
->set_start_load_time(Time::Now());
1626 bool is_top_most
= !frame
->parent();
1628 render_view_
->set_navigation_gesture(
1629 WebUserGestureIndicator::isProcessingUserGesture() ?
1630 NavigationGestureUser
: NavigationGestureAuto
);
1631 } else if (ds
->replacesCurrentHistoryItem()) {
1632 // Subframe navigations that don't add session history items must be
1633 // marked with AUTO_SUBFRAME. See also didFailProvisionalLoad for how we
1634 // handle loading of error pages.
1635 document_state
->navigation_state()->set_transition_type(
1636 PAGE_TRANSITION_AUTO_SUBFRAME
);
1639 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1640 DidStartProvisionalLoad(frame
));
1641 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, DidStartProvisionalLoad());
1643 int parent_routing_id
= frame
->parent() ?
1644 FromWebFrame(frame
->parent())->GetRoutingID() : -1;
1645 Send(new FrameHostMsg_DidStartProvisionalLoadForFrame(
1646 routing_id_
, parent_routing_id
, ds
->request().url()));
1649 void RenderFrameImpl::didReceiveServerRedirectForProvisionalLoad(
1650 blink::WebLocalFrame
* frame
) {
1651 DCHECK(!frame_
|| frame_
== frame
);
1652 render_view_
->history_controller()->RemoveChildrenForRedirect(this);
1653 if (frame
->parent())
1655 // Received a redirect on the main frame.
1656 WebDataSource
* data_source
= frame
->provisionalDataSource();
1658 // Should only be invoked when we have a data source.
1662 std::vector
<GURL
> redirects
;
1663 GetRedirectChain(data_source
, &redirects
);
1664 if (redirects
.size() >= 2) {
1665 Send(new FrameHostMsg_DidRedirectProvisionalLoad(
1667 render_view_
->page_id_
,
1668 redirects
[redirects
.size() - 2],
1673 void RenderFrameImpl::didFailProvisionalLoad(blink::WebLocalFrame
* frame
,
1674 const blink::WebURLError
& error
) {
1675 DCHECK(!frame_
|| frame_
== frame
);
1676 WebDataSource
* ds
= frame
->provisionalDataSource();
1679 const WebURLRequest
& failed_request
= ds
->request();
1681 // Notify the browser that we failed a provisional load with an error.
1683 // Note: It is important this notification occur before DidStopLoading so the
1684 // SSL manager can react to the provisional load failure before being
1685 // notified the load stopped.
1687 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1688 DidFailProvisionalLoad(frame
, error
));
1689 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
,
1690 DidFailProvisionalLoad(error
));
1692 bool show_repost_interstitial
=
1693 (error
.reason
== net::ERR_CACHE_MISS
&&
1694 EqualsASCII(failed_request
.httpMethod(), "POST"));
1696 FrameHostMsg_DidFailProvisionalLoadWithError_Params params
;
1697 params
.frame_unique_name
= frame
->uniqueName();
1698 params
.error_code
= error
.reason
;
1699 GetContentClient()->renderer()->GetNavigationErrorStrings(
1705 ¶ms
.error_description
);
1706 params
.url
= error
.unreachableURL
;
1707 params
.showing_repost_interstitial
= show_repost_interstitial
;
1708 Send(new FrameHostMsg_DidFailProvisionalLoadWithError(
1709 routing_id_
, params
));
1711 // Don't display an error page if this is simply a cancelled load. Aside
1712 // from being dumb, WebCore doesn't expect it and it will cause a crash.
1713 if (error
.reason
== net::ERR_ABORTED
)
1716 // Don't display "client blocked" error page if browser has asked us not to.
1717 if (error
.reason
== net::ERR_BLOCKED_BY_CLIENT
&&
1718 render_view_
->renderer_preferences_
.disable_client_blocked_error_page
) {
1722 // Allow the embedder to suppress an error page.
1723 if (GetContentClient()->renderer()->ShouldSuppressErrorPage(this,
1724 error
.unreachableURL
)) {
1728 if (RenderThreadImpl::current() &&
1729 RenderThreadImpl::current()->layout_test_mode()) {
1733 // Make sure we never show errors in view source mode.
1734 frame
->enableViewSourceMode(false);
1736 DocumentState
* document_state
= DocumentState::FromDataSource(ds
);
1737 NavigationState
* navigation_state
= document_state
->navigation_state();
1739 // If this is a failed back/forward/reload navigation, then we need to do a
1740 // 'replace' load. This is necessary to avoid messing up session history.
1741 // Otherwise, we do a normal load, which simulates a 'go' navigation as far
1742 // as session history is concerned.
1744 // AUTO_SUBFRAME loads should always be treated as loads that do not advance
1747 // TODO(davidben): This should also take the failed navigation's replacement
1748 // state into account, if a location.replace() failed.
1750 navigation_state
->pending_page_id() != -1 ||
1751 PageTransitionCoreTypeIs(navigation_state
->transition_type(),
1752 PAGE_TRANSITION_AUTO_SUBFRAME
);
1754 // If we failed on a browser initiated request, then make sure that our error
1755 // page load is regarded as the same browser initiated request.
1756 if (!navigation_state
->is_content_initiated()) {
1757 render_view_
->pending_navigation_params_
.reset(
1758 new FrameMsg_Navigate_Params
);
1759 render_view_
->pending_navigation_params_
->page_id
=
1760 navigation_state
->pending_page_id();
1761 render_view_
->pending_navigation_params_
->pending_history_list_offset
=
1762 navigation_state
->pending_history_list_offset();
1763 render_view_
->pending_navigation_params_
->should_clear_history_list
=
1764 navigation_state
->history_list_was_cleared();
1765 render_view_
->pending_navigation_params_
->transition
=
1766 navigation_state
->transition_type();
1767 render_view_
->pending_navigation_params_
->request_time
=
1768 document_state
->request_time();
1769 render_view_
->pending_navigation_params_
->should_replace_current_entry
=
1773 // Load an error page.
1774 render_view_
->LoadNavigationErrorPage(
1775 frame
, failed_request
, error
, replace
);
1778 void RenderFrameImpl::didCommitProvisionalLoad(
1779 blink::WebLocalFrame
* frame
,
1780 const blink::WebHistoryItem
& item
,
1781 blink::WebHistoryCommitType commit_type
) {
1782 DCHECK(!frame_
|| frame_
== frame
);
1783 DocumentState
* document_state
=
1784 DocumentState::FromDataSource(frame
->dataSource());
1785 NavigationState
* navigation_state
= document_state
->navigation_state();
1786 render_view_
->history_controller()->UpdateForCommit(this, item
, commit_type
,
1787 navigation_state
->was_within_same_page());
1789 InternalDocumentStateData
* internal_data
=
1790 InternalDocumentStateData::FromDocumentState(document_state
);
1792 if (document_state
->commit_load_time().is_null())
1793 document_state
->set_commit_load_time(Time::Now());
1795 if (internal_data
->must_reset_scroll_and_scale_state()) {
1796 render_view_
->webview()->resetScrollAndScaleState();
1797 internal_data
->set_must_reset_scroll_and_scale_state(false);
1799 internal_data
->set_use_error_page(false);
1801 bool is_new_navigation
= commit_type
== blink::WebStandardCommit
;
1802 if (is_new_navigation
) {
1803 // When we perform a new navigation, we need to update the last committed
1804 // session history entry with state for the page we are leaving.
1805 render_view_
->UpdateSessionHistory(frame
);
1807 // We bump our Page ID to correspond with the new session history entry.
1808 render_view_
->page_id_
= render_view_
->next_page_id_
++;
1810 // Don't update history_page_ids_ (etc) for kSwappedOutURL, since
1811 // we don't want to forget the entry that was there, and since we will
1812 // never come back to kSwappedOutURL. Note that we have to call
1813 // UpdateSessionHistory and update page_id_ even in this case, so that
1814 // the current entry gets a state update and so that we don't send a
1815 // state update to the wrong entry when we swap back in.
1816 if (render_view_
->GetLoadingUrl(frame
) != GURL(kSwappedOutURL
)) {
1817 // Advance our offset in session history, applying the length limit.
1818 // There is now no forward history.
1819 render_view_
->history_list_offset_
++;
1820 if (render_view_
->history_list_offset_
>= kMaxSessionHistoryEntries
)
1821 render_view_
->history_list_offset_
= kMaxSessionHistoryEntries
- 1;
1822 render_view_
->history_list_length_
=
1823 render_view_
->history_list_offset_
+ 1;
1824 render_view_
->history_page_ids_
.resize(
1825 render_view_
->history_list_length_
, -1);
1826 render_view_
->history_page_ids_
[render_view_
->history_list_offset_
] =
1827 render_view_
->page_id_
;
1830 // Inspect the navigation_state on this frame to see if the navigation
1831 // corresponds to a session history navigation... Note: |frame| may or
1832 // may not be the toplevel frame, but for the case of capturing session
1833 // history, the first committed frame suffices. We keep track of whether
1834 // we've seen this commit before so that only capture session history once
1837 // Note that we need to check if the page ID changed. In the case of a
1838 // reload, the page ID doesn't change, and UpdateSessionHistory gets the
1839 // previous URL and the current page ID, which would be wrong.
1840 if (navigation_state
->pending_page_id() != -1 &&
1841 navigation_state
->pending_page_id() != render_view_
->page_id_
&&
1842 !navigation_state
->request_committed()) {
1843 // This is a successful session history navigation!
1844 render_view_
->UpdateSessionHistory(frame
);
1845 render_view_
->page_id_
= navigation_state
->pending_page_id();
1847 render_view_
->history_list_offset_
=
1848 navigation_state
->pending_history_list_offset();
1850 // If the history list is valid, our list of page IDs should be correct.
1851 DCHECK(render_view_
->history_list_length_
<= 0 ||
1852 render_view_
->history_list_offset_
< 0 ||
1853 render_view_
->history_list_offset_
>=
1854 render_view_
->history_list_length_
||
1855 render_view_
->history_page_ids_
[render_view_
->history_list_offset_
]
1856 == render_view_
->page_id_
);
1860 render_view_
->FrameDidCommitProvisionalLoad(frame
, is_new_navigation
);
1861 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
,
1862 DidCommitProvisionalLoad(is_new_navigation
));
1864 // Remember that we've already processed this request, so we don't update
1865 // the session history again. We do this regardless of whether this is
1866 // a session history navigation, because if we attempted a session history
1867 // navigation without valid HistoryItem state, WebCore will think it is a
1869 navigation_state
->set_request_committed(true);
1873 // Check whether we have new encoding name.
1874 render_view_
->UpdateEncoding(frame
, frame
->view()->pageEncoding().utf8());
1877 void RenderFrameImpl::didClearWindowObject(blink::WebLocalFrame
* frame
,
1879 DCHECK(!frame_
|| frame_
== frame
);
1880 // TODO(nasko): Move implementation here. Needed state:
1881 // * enabled_bindings_
1882 // * dom_automation_controller_
1883 // * stats_collection_controller_
1885 render_view_
->didClearWindowObject(frame
, world_id
);
1887 // Only install controllers into the main world.
1891 if (render_view_
->GetEnabledBindings() & BINDINGS_POLICY_DOM_AUTOMATION
)
1892 DomAutomationController::Install(this, frame
);
1894 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
,
1895 DidClearWindowObject(world_id
));
1898 void RenderFrameImpl::didCreateDocumentElement(blink::WebLocalFrame
* frame
) {
1899 DCHECK(!frame_
|| frame_
== frame
);
1901 // Notify the browser about non-blank documents loading in the top frame.
1902 GURL url
= frame
->document().url();
1903 if (url
.is_valid() && url
.spec() != kAboutBlankURL
) {
1904 // TODO(nasko): Check if webview()->mainFrame() is the same as the
1905 // frame->tree()->top().
1906 if (frame
== render_view_
->webview()->mainFrame()) {
1907 render_view_
->Send(new ViewHostMsg_DocumentAvailableInMainFrame(
1908 render_view_
->GetRoutingID()));
1912 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1913 DidCreateDocumentElement(frame
));
1916 void RenderFrameImpl::didReceiveTitle(blink::WebLocalFrame
* frame
,
1917 const blink::WebString
& title
,
1918 blink::WebTextDirection direction
) {
1919 DCHECK(!frame_
|| frame_
== frame
);
1920 // TODO(nasko): Investigate wheather implementation should move here.
1921 render_view_
->didReceiveTitle(frame
, title
, direction
);
1924 void RenderFrameImpl::didChangeIcon(blink::WebLocalFrame
* frame
,
1925 blink::WebIconURL::Type icon_type
) {
1926 DCHECK(!frame_
|| frame_
== frame
);
1927 // TODO(nasko): Investigate wheather implementation should move here.
1928 render_view_
->didChangeIcon(frame
, icon_type
);
1931 void RenderFrameImpl::didFinishDocumentLoad(blink::WebLocalFrame
* frame
) {
1932 DCHECK(!frame_
|| frame_
== frame
);
1933 WebDataSource
* ds
= frame
->dataSource();
1934 DocumentState
* document_state
= DocumentState::FromDataSource(ds
);
1935 document_state
->set_finish_document_load_time(Time::Now());
1937 Send(new FrameHostMsg_DidFinishDocumentLoad(routing_id_
));
1939 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1940 DidFinishDocumentLoad(frame
));
1941 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, DidFinishDocumentLoad());
1943 // Check whether we have new encoding name.
1944 render_view_
->UpdateEncoding(frame
, frame
->view()->pageEncoding().utf8());
1947 void RenderFrameImpl::didHandleOnloadEvents(blink::WebLocalFrame
* frame
) {
1948 DCHECK(!frame_
|| frame_
== frame
);
1949 // TODO(nasko): Move implementation here. Needed state:
1951 render_view_
->didHandleOnloadEvents(frame
);
1954 void RenderFrameImpl::didFailLoad(blink::WebLocalFrame
* frame
,
1955 const blink::WebURLError
& error
) {
1956 DCHECK(!frame_
|| frame_
== frame
);
1957 // TODO(nasko): Move implementation here. No state needed.
1958 WebDataSource
* ds
= frame
->dataSource();
1961 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1962 DidFailLoad(frame
, error
));
1964 const WebURLRequest
& failed_request
= ds
->request();
1965 base::string16 error_description
;
1966 GetContentClient()->renderer()->GetNavigationErrorStrings(
1972 &error_description
);
1973 Send(new FrameHostMsg_DidFailLoadWithError(routing_id_
,
1974 failed_request
.url(),
1976 error_description
));
1979 void RenderFrameImpl::didFinishLoad(blink::WebLocalFrame
* frame
) {
1980 DCHECK(!frame_
|| frame_
== frame
);
1981 WebDataSource
* ds
= frame
->dataSource();
1982 DocumentState
* document_state
= DocumentState::FromDataSource(ds
);
1983 if (document_state
->finish_load_time().is_null()) {
1984 if (!frame
->parent()) {
1985 TRACE_EVENT_INSTANT0("WebCore", "LoadFinished",
1986 TRACE_EVENT_SCOPE_PROCESS
);
1988 document_state
->set_finish_load_time(Time::Now());
1991 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1992 DidFinishLoad(frame
));
1993 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, DidFinishLoad());
1995 // Don't send this message while the frame is swapped out.
1996 if (is_swapped_out())
1999 Send(new FrameHostMsg_DidFinishLoad(routing_id_
,
2000 ds
->request().url()));
2003 void RenderFrameImpl::didNavigateWithinPage(blink::WebLocalFrame
* frame
,
2004 const blink::WebHistoryItem
& item
,
2005 blink::WebHistoryCommitType commit_type
) {
2006 DCHECK(!frame_
|| frame_
== frame
);
2007 // If this was a reference fragment navigation that we initiated, then we
2008 // could end up having a non-null pending navigation params. We just need to
2009 // update the ExtraData on the datasource so that others who read the
2010 // ExtraData will get the new NavigationState. Similarly, if we did not
2011 // initiate this navigation, then we need to take care to reset any pre-
2012 // existing navigation state to a content-initiated navigation state.
2013 // DidCreateDataSource conveniently takes care of this for us.
2014 didCreateDataSource(frame
, frame
->dataSource());
2016 DocumentState
* document_state
=
2017 DocumentState::FromDataSource(frame
->dataSource());
2018 NavigationState
* new_state
= document_state
->navigation_state();
2019 new_state
->set_was_within_same_page(true);
2021 didCommitProvisionalLoad(frame
, item
, commit_type
);
2024 void RenderFrameImpl::didUpdateCurrentHistoryItem(blink::WebLocalFrame
* frame
) {
2025 DCHECK(!frame_
|| frame_
== frame
);
2026 // TODO(nasko): Move implementation here. Needed methods:
2027 // * StartNavStateSyncTimerIfNecessary
2028 render_view_
->didUpdateCurrentHistoryItem(frame
);
2031 blink::WebNotificationPresenter
* RenderFrameImpl::notificationPresenter() {
2032 return notification_provider_
;
2035 void RenderFrameImpl::didChangeSelection(bool is_empty_selection
) {
2036 if (!GetRenderWidget()->handling_input_event() && !handling_select_range_
)
2039 if (is_empty_selection
)
2040 selection_text_
.clear();
2042 // UpdateTextInputType should be called before SyncSelectionIfRequired.
2043 // UpdateTextInputType may send TextInputTypeChanged to notify the focus
2044 // was changed, and SyncSelectionIfRequired may send SelectionChanged
2045 // to notify the selection was changed. Focus change should be notified
2046 // before selection change.
2047 GetRenderWidget()->UpdateTextInputType();
2048 SyncSelectionIfRequired();
2049 #if defined(OS_ANDROID)
2050 GetRenderWidget()->UpdateTextInputState(RenderWidget::NO_SHOW_IME
,
2051 RenderWidget::FROM_NON_IME
);
2055 blink::WebColorChooser
* RenderFrameImpl::createColorChooser(
2056 blink::WebColorChooserClient
* client
,
2057 const blink::WebColor
& initial_color
,
2058 const blink::WebVector
<blink::WebColorSuggestion
>& suggestions
) {
2059 RendererWebColorChooserImpl
* color_chooser
=
2060 new RendererWebColorChooserImpl(this, client
);
2061 std::vector
<content::ColorSuggestion
> color_suggestions
;
2062 for (size_t i
= 0; i
< suggestions
.size(); i
++) {
2063 color_suggestions
.push_back(content::ColorSuggestion(suggestions
[i
]));
2065 color_chooser
->Open(static_cast<SkColor
>(initial_color
), color_suggestions
);
2066 return color_chooser
;
2069 void RenderFrameImpl::runModalAlertDialog(const blink::WebString
& message
) {
2070 RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_ALERT
,
2073 frame_
->document().url(),
2077 bool RenderFrameImpl::runModalConfirmDialog(const blink::WebString
& message
) {
2078 return RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_CONFIRM
,
2081 frame_
->document().url(),
2085 bool RenderFrameImpl::runModalPromptDialog(
2086 const blink::WebString
& message
,
2087 const blink::WebString
& default_value
,
2088 blink::WebString
* actual_value
) {
2089 base::string16 result
;
2090 bool ok
= RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_PROMPT
,
2093 frame_
->document().url(),
2096 actual_value
->assign(result
);
2100 bool RenderFrameImpl::runModalBeforeUnloadDialog(
2102 const blink::WebString
& message
) {
2103 // If we are swapping out, we have already run the beforeunload handler.
2104 // TODO(creis): Fix OnSwapOut to clear the frame without running beforeunload
2105 // at all, to avoid running it twice.
2106 if (render_view()->is_swapped_out_
)
2109 // Don't allow further dialogs if we are waiting to swap out, since the
2110 // PageGroupLoadDeferrer in our stack prevents it.
2111 if (render_view()->suppress_dialogs_until_swap_out_
)
2114 bool success
= false;
2115 // This is an ignored return value, but is included so we can accept the same
2116 // response as RunJavaScriptMessage.
2117 base::string16 ignored_result
;
2118 render_view()->SendAndRunNestedMessageLoop(
2119 new FrameHostMsg_RunBeforeUnloadConfirm(
2120 routing_id_
, frame_
->document().url(), message
, is_reload
,
2121 &success
, &ignored_result
));
2125 void RenderFrameImpl::showContextMenu(const blink::WebContextMenuData
& data
) {
2126 ContextMenuParams params
= ContextMenuParamsBuilder::Build(data
);
2127 params
.source_type
= GetRenderWidget()->context_menu_source_type();
2128 if (params
.source_type
== ui::MENU_SOURCE_TOUCH_EDIT_MENU
) {
2129 params
.x
= GetRenderWidget()->touch_editing_context_menu_location().x();
2130 params
.y
= GetRenderWidget()->touch_editing_context_menu_location().y();
2132 GetRenderWidget()->OnShowHostContextMenu(¶ms
);
2134 // Plugins, e.g. PDF, don't currently update the render view when their
2135 // selected text changes, but the context menu params do contain the updated
2136 // selection. If that's the case, update the render view's state just prior
2137 // to showing the context menu.
2138 // TODO(asvitkine): http://crbug.com/152432
2139 if (ShouldUpdateSelectionTextFromContextMenuParams(
2140 selection_text_
, selection_text_offset_
, selection_range_
, params
)) {
2141 selection_text_
= params
.selection_text
;
2142 // TODO(asvitkine): Text offset and range is not available in this case.
2143 selection_text_offset_
= 0;
2144 selection_range_
= gfx::Range(0, selection_text_
.length());
2145 // This IPC is dispatched by RenderWidetHost, so use its routing ID.
2146 Send(new ViewHostMsg_SelectionChanged(
2147 GetRenderWidget()->routing_id(), selection_text_
,
2148 selection_text_offset_
, selection_range_
));
2151 // Serializing a GURL longer than kMaxURLChars will fail, so don't do
2152 // it. We replace it with an empty GURL so the appropriate items are disabled
2153 // in the context menu.
2154 // TODO(jcivelli): http://crbug.com/45160 This prevents us from saving large
2155 // data encoded images. We should have a way to save them.
2156 if (params
.src_url
.spec().size() > GetMaxURLChars())
2157 params
.src_url
= GURL();
2158 context_menu_node_
= data
.node
;
2160 #if defined(OS_ANDROID)
2161 gfx::Rect start_rect
;
2163 GetRenderWidget()->GetSelectionBounds(&start_rect
, &end_rect
);
2164 params
.selection_start
= gfx::Point(start_rect
.x(), start_rect
.bottom());
2165 params
.selection_end
= gfx::Point(end_rect
.right(), end_rect
.bottom());
2168 Send(new FrameHostMsg_ContextMenu(routing_id_
, params
));
2171 void RenderFrameImpl::clearContextMenu() {
2172 context_menu_node_
.reset();
2175 void RenderFrameImpl::willRequestAfterPreconnect(
2176 blink::WebLocalFrame
* frame
,
2177 blink::WebURLRequest
& request
) {
2178 DCHECK(!frame_
|| frame_
== frame
);
2179 // FIXME(kohei): This will never be set.
2180 WebString custom_user_agent
;
2182 DCHECK(!request
.extraData());
2184 bool was_after_preconnect_request
= true;
2185 // The args after |was_after_preconnect_request| are not used, and set to
2186 // correct values at |willSendRequest|.
2187 RequestExtraData
* extra_data
= new RequestExtraData();
2188 extra_data
->set_custom_user_agent(custom_user_agent
);
2189 extra_data
->set_was_after_preconnect_request(was_after_preconnect_request
);
2190 request
.setExtraData(extra_data
);
2193 void RenderFrameImpl::willSendRequest(
2194 blink::WebLocalFrame
* frame
,
2195 unsigned identifier
,
2196 blink::WebURLRequest
& request
,
2197 const blink::WebURLResponse
& redirect_response
) {
2198 DCHECK(!frame_
|| frame_
== frame
);
2199 // The request my be empty during tests.
2200 if (request
.url().isEmpty())
2203 WebFrame
* top_frame
= frame
->top();
2206 WebDataSource
* provisional_data_source
= top_frame
->provisionalDataSource();
2207 WebDataSource
* top_data_source
= top_frame
->dataSource();
2208 WebDataSource
* data_source
=
2209 provisional_data_source
? provisional_data_source
: top_data_source
;
2211 PageTransition transition_type
= PAGE_TRANSITION_LINK
;
2212 DocumentState
* document_state
= DocumentState::FromDataSource(data_source
);
2213 DCHECK(document_state
);
2214 InternalDocumentStateData
* internal_data
=
2215 InternalDocumentStateData::FromDocumentState(document_state
);
2216 NavigationState
* navigation_state
= document_state
->navigation_state();
2217 transition_type
= navigation_state
->transition_type();
2219 GURL
request_url(request
.url());
2221 if (GetContentClient()->renderer()->WillSendRequest(
2225 request
.firstPartyForCookies(),
2227 request
.setURL(WebURL(new_url
));
2230 if (internal_data
->is_cache_policy_override_set())
2231 request
.setCachePolicy(internal_data
->cache_policy_override());
2233 // The request's extra data may indicate that we should set a custom user
2234 // agent. This needs to be done here, after WebKit is through with setting the
2235 // user agent on its own.
2236 WebString custom_user_agent
;
2237 bool was_after_preconnect_request
= false;
2238 if (request
.extraData()) {
2239 RequestExtraData
* old_extra_data
=
2240 static_cast<RequestExtraData
*>(
2241 request
.extraData());
2242 custom_user_agent
= old_extra_data
->custom_user_agent();
2243 was_after_preconnect_request
=
2244 old_extra_data
->was_after_preconnect_request();
2246 if (!custom_user_agent
.isNull()) {
2247 if (custom_user_agent
.isEmpty())
2248 request
.clearHTTPHeaderField("User-Agent");
2250 request
.setHTTPHeaderField("User-Agent", custom_user_agent
);
2254 // Attach |should_replace_current_entry| state to requests so that, should
2255 // this navigation later require a request transfer, all state is preserved
2256 // when it is re-created in the new process.
2257 bool should_replace_current_entry
= false;
2258 if (navigation_state
->is_content_initiated()) {
2259 should_replace_current_entry
= data_source
->replacesCurrentHistoryItem();
2261 // If the navigation is browser-initiated, the NavigationState contains the
2262 // correct value instead of the WebDataSource.
2264 // TODO(davidben): Avoid this awkward duplication of state. See comment on
2265 // NavigationState::should_replace_current_entry().
2266 should_replace_current_entry
=
2267 navigation_state
->should_replace_current_entry();
2270 int provider_id
= kInvalidServiceWorkerProviderId
;
2271 if (request
.targetType() == blink::WebURLRequest::TargetIsMainFrame
||
2272 request
.targetType() == blink::WebURLRequest::TargetIsSubframe
) {
2273 // |provisionalDataSource| may be null in some content::ResourceFetcher
2274 // use cases, we don't hook those requests.
2275 if (frame
->provisionalDataSource()) {
2276 ServiceWorkerNetworkProvider
* provider
=
2277 ServiceWorkerNetworkProvider::FromDocumentState(
2278 DocumentState::FromDataSource(frame
->provisionalDataSource()));
2279 provider_id
= provider
->provider_id();
2281 } else if (frame
->dataSource()) {
2282 ServiceWorkerNetworkProvider
* provider
=
2283 ServiceWorkerNetworkProvider::FromDocumentState(
2284 DocumentState::FromDataSource(frame
->dataSource()));
2285 provider_id
= provider
->provider_id();
2288 int parent_routing_id
= frame
->parent() ?
2289 FromWebFrame(frame
->parent())->GetRoutingID() : -1;
2290 RequestExtraData
* extra_data
= new RequestExtraData();
2291 extra_data
->set_visibility_state(render_view_
->visibilityState());
2292 extra_data
->set_custom_user_agent(custom_user_agent
);
2293 extra_data
->set_was_after_preconnect_request(was_after_preconnect_request
);
2294 extra_data
->set_render_frame_id(routing_id_
);
2295 extra_data
->set_is_main_frame(frame
== top_frame
);
2296 extra_data
->set_frame_origin(
2297 GURL(frame
->document().securityOrigin().toString()));
2298 extra_data
->set_parent_is_main_frame(frame
->parent() == top_frame
);
2299 extra_data
->set_parent_render_frame_id(parent_routing_id
);
2300 extra_data
->set_allow_download(navigation_state
->allow_download());
2301 extra_data
->set_transition_type(transition_type
);
2302 extra_data
->set_should_replace_current_entry(should_replace_current_entry
);
2303 extra_data
->set_transferred_request_child_id(
2304 navigation_state
->transferred_request_child_id());
2305 extra_data
->set_transferred_request_request_id(
2306 navigation_state
->transferred_request_request_id());
2307 extra_data
->set_service_worker_provider_id(provider_id
);
2308 request
.setExtraData(extra_data
);
2310 DocumentState
* top_document_state
=
2311 DocumentState::FromDataSource(top_data_source
);
2312 if (top_document_state
) {
2313 // TODO(gavinp): separate out prefetching and prerender field trials
2314 // if the rel=prerender rel type is sticking around.
2315 if (request
.targetType() == WebURLRequest::TargetIsPrefetch
)
2316 top_document_state
->set_was_prefetcher(true);
2318 if (was_after_preconnect_request
)
2319 top_document_state
->set_was_after_preconnect_request(true);
2322 // This is an instance where we embed a copy of the routing id
2323 // into the data portion of the message. This can cause problems if we
2324 // don't register this id on the browser side, since the download manager
2325 // expects to find a RenderViewHost based off the id.
2326 request
.setRequestorID(render_view_
->GetRoutingID());
2327 request
.setHasUserGesture(WebUserGestureIndicator::isProcessingUserGesture());
2329 if (!navigation_state
->extra_headers().empty()) {
2330 for (net::HttpUtil::HeadersIterator
i(
2331 navigation_state
->extra_headers().begin(),
2332 navigation_state
->extra_headers().end(), "\n");
2334 if (LowerCaseEqualsASCII(i
.name(), "referer")) {
2335 WebString referrer
= WebSecurityPolicy::generateReferrerHeader(
2336 blink::WebReferrerPolicyDefault
,
2338 WebString::fromUTF8(i
.values()));
2339 request
.setHTTPReferrer(referrer
, blink::WebReferrerPolicyDefault
);
2341 request
.setHTTPHeaderField(WebString::fromUTF8(i
.name()),
2342 WebString::fromUTF8(i
.values()));
2347 if (!render_view_
->renderer_preferences_
.enable_referrers
)
2348 request
.setHTTPReferrer(WebString(), blink::WebReferrerPolicyDefault
);
2351 void RenderFrameImpl::didReceiveResponse(
2352 blink::WebLocalFrame
* frame
,
2353 unsigned identifier
,
2354 const blink::WebURLResponse
& response
) {
2355 DCHECK(!frame_
|| frame_
== frame
);
2356 // Only do this for responses that correspond to a provisional data source
2357 // of the top-most frame. If we have a provisional data source, then we
2358 // can't have any sub-resources yet, so we know that this response must
2359 // correspond to a frame load.
2360 if (!frame
->provisionalDataSource() || frame
->parent())
2363 // If we are in view source mode, then just let the user see the source of
2364 // the server's error page.
2365 if (frame
->isViewSourceModeEnabled())
2368 DocumentState
* document_state
=
2369 DocumentState::FromDataSource(frame
->provisionalDataSource());
2370 int http_status_code
= response
.httpStatusCode();
2372 // Record page load flags.
2373 WebURLResponseExtraDataImpl
* extra_data
=
2374 GetExtraDataFromResponse(response
);
2376 document_state
->set_was_fetched_via_spdy(
2377 extra_data
->was_fetched_via_spdy());
2378 document_state
->set_was_npn_negotiated(
2379 extra_data
->was_npn_negotiated());
2380 document_state
->set_npn_negotiated_protocol(
2381 extra_data
->npn_negotiated_protocol());
2382 document_state
->set_was_alternate_protocol_available(
2383 extra_data
->was_alternate_protocol_available());
2384 document_state
->set_connection_info(
2385 extra_data
->connection_info());
2386 document_state
->set_was_fetched_via_proxy(
2387 extra_data
->was_fetched_via_proxy());
2389 InternalDocumentStateData
* internal_data
=
2390 InternalDocumentStateData::FromDocumentState(document_state
);
2391 internal_data
->set_http_status_code(http_status_code
);
2392 // Whether or not the http status code actually corresponds to an error is
2393 // only checked when the page is done loading, if |use_error_page| is
2395 internal_data
->set_use_error_page(true);
2398 void RenderFrameImpl::didFinishResourceLoad(blink::WebLocalFrame
* frame
,
2399 unsigned identifier
) {
2400 DCHECK(!frame_
|| frame_
== frame
);
2401 // TODO(nasko): Move implementation here. Needed state:
2402 // * devtools_agent_
2404 // * LoadNavigationErrorPage
2405 render_view_
->didFinishResourceLoad(frame
, identifier
);
2408 void RenderFrameImpl::didLoadResourceFromMemoryCache(
2409 blink::WebLocalFrame
* frame
,
2410 const blink::WebURLRequest
& request
,
2411 const blink::WebURLResponse
& response
) {
2412 DCHECK(!frame_
|| frame_
== frame
);
2413 // The recipients of this message have no use for data: URLs: they don't
2414 // affect the page's insecure content list and are not in the disk cache. To
2415 // prevent large (1M+) data: URLs from crashing in the IPC system, we simply
2416 // filter them out here.
2417 GURL
url(request
.url());
2418 if (url
.SchemeIs("data"))
2421 // Let the browser know we loaded a resource from the memory cache. This
2422 // message is needed to display the correct SSL indicators.
2423 render_view_
->Send(new ViewHostMsg_DidLoadResourceFromMemoryCache(
2424 render_view_
->GetRoutingID(),
2426 response
.securityInfo(),
2427 request
.httpMethod().utf8(),
2428 response
.mimeType().utf8(),
2429 ResourceType::FromTargetType(request
.targetType())));
2432 void RenderFrameImpl::didDisplayInsecureContent(blink::WebLocalFrame
* frame
) {
2433 DCHECK(!frame_
|| frame_
== frame
);
2434 render_view_
->Send(new ViewHostMsg_DidDisplayInsecureContent(
2435 render_view_
->GetRoutingID()));
2438 void RenderFrameImpl::didRunInsecureContent(
2439 blink::WebLocalFrame
* frame
,
2440 const blink::WebSecurityOrigin
& origin
,
2441 const blink::WebURL
& target
) {
2442 DCHECK(!frame_
|| frame_
== frame
);
2443 render_view_
->Send(new ViewHostMsg_DidRunInsecureContent(
2444 render_view_
->GetRoutingID(),
2445 origin
.toString().utf8(),
2449 void RenderFrameImpl::didAbortLoading(blink::WebLocalFrame
* frame
) {
2450 DCHECK(!frame_
|| frame_
== frame
);
2451 #if defined(ENABLE_PLUGINS)
2452 if (frame
!= render_view_
->webview()->mainFrame())
2454 PluginChannelHost::Broadcast(
2455 new PluginHostMsg_DidAbortLoading(render_view_
->GetRoutingID()));
2459 void RenderFrameImpl::didCreateScriptContext(blink::WebLocalFrame
* frame
,
2460 v8::Handle
<v8::Context
> context
,
2461 int extension_group
,
2463 DCHECK(!frame_
|| frame_
== frame
);
2464 GetContentClient()->renderer()->DidCreateScriptContext(
2465 frame
, context
, extension_group
, world_id
);
2468 void RenderFrameImpl::willReleaseScriptContext(blink::WebLocalFrame
* frame
,
2469 v8::Handle
<v8::Context
> context
,
2471 DCHECK(!frame_
|| frame_
== frame
);
2473 FOR_EACH_OBSERVER(RenderFrameObserver
,
2475 WillReleaseScriptContext(context
, world_id
));
2478 void RenderFrameImpl::didFirstVisuallyNonEmptyLayout(
2479 blink::WebLocalFrame
* frame
) {
2480 DCHECK(!frame_
|| frame_
== frame
);
2481 render_view_
->didFirstVisuallyNonEmptyLayout(frame
);
2484 void RenderFrameImpl::didChangeContentsSize(blink::WebLocalFrame
* frame
,
2485 const blink::WebSize
& size
) {
2486 DCHECK(!frame_
|| frame_
== frame
);
2487 // TODO(nasko): Move implementation here. Needed state:
2488 // * cached_has_main_frame_horizontal_scrollbar_
2489 // * cached_has_main_frame_vertical_scrollbar_
2490 render_view_
->didChangeContentsSize(frame
, size
);
2493 void RenderFrameImpl::didChangeScrollOffset(blink::WebLocalFrame
* frame
) {
2494 DCHECK(!frame_
|| frame_
== frame
);
2495 // TODO(nasko): Move implementation here. Needed methods:
2496 // * StartNavStateSyncTimerIfNecessary
2497 render_view_
->didChangeScrollOffset(frame
);
2500 void RenderFrameImpl::willInsertBody(blink::WebLocalFrame
* frame
) {
2501 DCHECK(!frame_
|| frame_
== frame
);
2502 if (!frame
->parent()) {
2503 render_view_
->Send(new ViewHostMsg_WillInsertBody(
2504 render_view_
->GetRoutingID()));
2508 void RenderFrameImpl::reportFindInPageMatchCount(int request_id
,
2510 bool final_update
) {
2511 int active_match_ordinal
= -1; // -1 = don't update active match ordinal
2513 active_match_ordinal
= 0;
2515 render_view_
->Send(new ViewHostMsg_Find_Reply(
2516 render_view_
->GetRoutingID(), request_id
, count
,
2517 gfx::Rect(), active_match_ordinal
, final_update
));
2520 void RenderFrameImpl::reportFindInPageSelection(
2522 int active_match_ordinal
,
2523 const blink::WebRect
& selection_rect
) {
2524 render_view_
->Send(new ViewHostMsg_Find_Reply(
2525 render_view_
->GetRoutingID(), request_id
, -1, selection_rect
,
2526 active_match_ordinal
, false));
2529 void RenderFrameImpl::requestStorageQuota(
2530 blink::WebLocalFrame
* frame
,
2531 blink::WebStorageQuotaType type
,
2532 unsigned long long requested_size
,
2533 blink::WebStorageQuotaCallbacks callbacks
) {
2534 DCHECK(!frame_
|| frame_
== frame
);
2535 WebSecurityOrigin origin
= frame
->document().securityOrigin();
2536 if (origin
.isUnique()) {
2537 // Unique origins cannot store persistent state.
2538 callbacks
.didFail(blink::WebStorageQuotaErrorAbort
);
2541 ChildThread::current()->quota_dispatcher()->RequestStorageQuota(
2542 render_view_
->GetRoutingID(), GURL(origin
.toString()),
2543 static_cast<quota::StorageType
>(type
), requested_size
,
2544 QuotaDispatcher::CreateWebStorageQuotaCallbacksWrapper(callbacks
));
2547 void RenderFrameImpl::willOpenSocketStream(
2548 blink::WebSocketStreamHandle
* handle
) {
2549 WebSocketStreamHandleImpl
* impl
=
2550 static_cast<WebSocketStreamHandleImpl
*>(handle
);
2551 impl
->SetUserData(handle
, new SocketStreamHandleData(routing_id_
));
2554 void RenderFrameImpl::willStartUsingPeerConnectionHandler(
2555 blink::WebLocalFrame
* frame
,
2556 blink::WebRTCPeerConnectionHandler
* handler
) {
2557 DCHECK(!frame_
|| frame_
== frame
);
2558 #if defined(ENABLE_WEBRTC)
2559 static_cast<RTCPeerConnectionHandler
*>(handler
)->associateWithFrame(frame
);
2563 bool RenderFrameImpl::willCheckAndDispatchMessageEvent(
2564 blink::WebLocalFrame
* sourceFrame
,
2565 blink::WebFrame
* targetFrame
,
2566 blink::WebSecurityOrigin targetOrigin
,
2567 blink::WebDOMMessageEvent event
) {
2568 DCHECK(!frame_
|| frame_
== targetFrame
);
2569 // TODO(nasko): Move implementation here. Needed state:
2570 // * is_swapped_out_
2571 return render_view_
->willCheckAndDispatchMessageEvent(
2572 sourceFrame
, targetFrame
, targetOrigin
, event
);
2575 blink::WebString
RenderFrameImpl::userAgentOverride(blink::WebLocalFrame
* frame
,
2576 const blink::WebURL
& url
) {
2577 DCHECK(!frame_
|| frame_
== frame
);
2578 if (!render_view_
->webview() || !render_view_
->webview()->mainFrame() ||
2579 render_view_
->renderer_preferences_
.user_agent_override
.empty()) {
2580 return blink::WebString();
2583 // If we're in the middle of committing a load, the data source we need
2584 // will still be provisional.
2585 WebFrame
* main_frame
= render_view_
->webview()->mainFrame();
2586 WebDataSource
* data_source
= NULL
;
2587 if (main_frame
->provisionalDataSource())
2588 data_source
= main_frame
->provisionalDataSource();
2590 data_source
= main_frame
->dataSource();
2592 InternalDocumentStateData
* internal_data
= data_source
?
2593 InternalDocumentStateData::FromDataSource(data_source
) : NULL
;
2594 if (internal_data
&& internal_data
->is_overriding_user_agent())
2595 return WebString::fromUTF8(
2596 render_view_
->renderer_preferences_
.user_agent_override
);
2597 return blink::WebString();
2600 blink::WebString
RenderFrameImpl::doNotTrackValue(blink::WebLocalFrame
* frame
) {
2601 DCHECK(!frame_
|| frame_
== frame
);
2602 if (render_view_
->renderer_preferences_
.enable_do_not_track
)
2603 return WebString::fromUTF8("1");
2607 bool RenderFrameImpl::allowWebGL(blink::WebLocalFrame
* frame
,
2608 bool default_value
) {
2609 DCHECK(!frame_
|| frame_
== frame
);
2613 bool blocked
= true;
2614 render_view_
->Send(new ViewHostMsg_Are3DAPIsBlocked(
2615 render_view_
->GetRoutingID(),
2616 GURL(frame
->top()->document().securityOrigin().toString()),
2617 THREE_D_API_TYPE_WEBGL
,
2622 void RenderFrameImpl::didLoseWebGLContext(blink::WebLocalFrame
* frame
,
2623 int arb_robustness_status_code
) {
2624 DCHECK(!frame_
|| frame_
== frame
);
2625 render_view_
->Send(new ViewHostMsg_DidLose3DContext(
2626 GURL(frame
->top()->document().securityOrigin().toString()),
2627 THREE_D_API_TYPE_WEBGL
,
2628 arb_robustness_status_code
));
2631 void RenderFrameImpl::forwardInputEvent(const blink::WebInputEvent
* event
) {
2632 Send(new FrameHostMsg_ForwardInputEvent(routing_id_
, event
));
2635 void RenderFrameImpl::initializeChildFrame(const blink::WebRect
& frame_rect
,
2636 float scale_factor
) {
2637 Send(new FrameHostMsg_InitializeChildFrame(
2638 routing_id_
, frame_rect
, scale_factor
));
2641 void RenderFrameImpl::AddObserver(RenderFrameObserver
* observer
) {
2642 observers_
.AddObserver(observer
);
2645 void RenderFrameImpl::RemoveObserver(RenderFrameObserver
* observer
) {
2646 observer
->RenderFrameGone();
2647 observers_
.RemoveObserver(observer
);
2650 void RenderFrameImpl::OnStop() {
2651 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, OnStop());
2654 // Tell the embedding application that the URL of the active page has changed.
2655 void RenderFrameImpl::UpdateURL(blink::WebFrame
* frame
) {
2656 DCHECK(!frame_
|| frame_
== frame
);
2657 WebDataSource
* ds
= frame
->dataSource();
2660 const WebURLRequest
& request
= ds
->request();
2661 const WebURLResponse
& response
= ds
->response();
2663 DocumentState
* document_state
= DocumentState::FromDataSource(ds
);
2664 NavigationState
* navigation_state
= document_state
->navigation_state();
2665 InternalDocumentStateData
* internal_data
=
2666 InternalDocumentStateData::FromDocumentState(document_state
);
2668 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
2669 params
.http_status_code
= response
.httpStatusCode();
2670 params
.is_post
= false;
2671 params
.post_id
= -1;
2672 params
.page_id
= render_view_
->page_id_
;
2673 params
.frame_unique_name
= frame
->uniqueName();
2674 params
.socket_address
.set_host(response
.remoteIPAddress().utf8());
2675 params
.socket_address
.set_port(response
.remotePort());
2676 WebURLResponseExtraDataImpl
* extra_data
= GetExtraDataFromResponse(response
);
2678 params
.was_fetched_via_proxy
= extra_data
->was_fetched_via_proxy();
2679 params
.was_within_same_page
= navigation_state
->was_within_same_page();
2680 params
.security_info
= response
.securityInfo();
2682 // Set the URL to be displayed in the browser UI to the user.
2683 params
.url
= render_view_
->GetLoadingUrl(frame
);
2684 DCHECK(!is_swapped_out_
|| params
.url
== GURL(kSwappedOutURL
));
2686 if (frame
->document().baseURL() != params
.url
)
2687 params
.base_url
= frame
->document().baseURL();
2689 GetRedirectChain(ds
, ¶ms
.redirects
);
2690 params
.should_update_history
= !ds
->hasUnreachableURL() &&
2691 !response
.isMultipartPayload() && (response
.httpStatusCode() != 404);
2693 params
.searchable_form_url
= internal_data
->searchable_form_url();
2694 params
.searchable_form_encoding
= internal_data
->searchable_form_encoding();
2696 params
.gesture
= render_view_
->navigation_gesture_
;
2697 render_view_
->navigation_gesture_
= NavigationGestureUnknown
;
2699 // Make navigation state a part of the DidCommitProvisionalLoad message so
2700 // that commited entry has it at all times.
2701 WebHistoryItem item
=
2702 render_view_
->history_controller()->GetCurrentItemForExport();
2703 if (item
.isNull()) {
2705 item
.setURLString(request
.url().spec().utf16());
2707 params
.page_state
= HistoryItemToPageState(item
);
2709 if (!frame
->parent()) {
2710 // Top-level navigation.
2712 // Reset the zoom limits in case a plugin had changed them previously. This
2713 // will also call us back which will cause us to send a message to
2714 // update WebContentsImpl.
2715 render_view_
->webview()->zoomLimitsChanged(
2716 ZoomFactorToZoomLevel(kMinimumZoomFactor
),
2717 ZoomFactorToZoomLevel(kMaximumZoomFactor
));
2719 // Set zoom level, but don't do it for full-page plugin since they don't use
2720 // the same zoom settings.
2721 HostZoomLevels::iterator host_zoom
=
2722 render_view_
->host_zoom_levels_
.find(GURL(request
.url()));
2723 if (render_view_
->webview()->mainFrame()->document().isPluginDocument()) {
2724 // Reset the zoom levels for plugins.
2725 render_view_
->webview()->setZoomLevel(0);
2727 if (host_zoom
!= render_view_
->host_zoom_levels_
.end())
2728 render_view_
->webview()->setZoomLevel(host_zoom
->second
);
2731 if (host_zoom
!= render_view_
->host_zoom_levels_
.end()) {
2732 // This zoom level was merely recorded transiently for this load. We can
2733 // erase it now. If at some point we reload this page, the browser will
2734 // send us a new, up-to-date zoom level.
2735 render_view_
->host_zoom_levels_
.erase(host_zoom
);
2738 // Update contents MIME type for main frame.
2739 params
.contents_mime_type
= ds
->response().mimeType().utf8();
2741 params
.transition
= navigation_state
->transition_type();
2742 if (!PageTransitionIsMainFrame(params
.transition
)) {
2743 // If the main frame does a load, it should not be reported as a subframe
2744 // navigation. This can occur in the following case:
2745 // 1. You're on a site with frames.
2746 // 2. You do a subframe navigation. This is stored with transition type
2748 // 3. You navigate to some non-frame site, say, google.com.
2749 // 4. You navigate back to the page from step 2. Since it was initially
2750 // MANUAL_SUBFRAME, it will be that same transition type here.
2751 // We don't want that, because any navigation that changes the toplevel
2752 // frame should be tracked as a toplevel navigation (this allows us to
2753 // update the URL bar, etc).
2754 params
.transition
= PAGE_TRANSITION_LINK
;
2757 // If the page contained a client redirect (meta refresh, document.loc...),
2758 // set the referrer and transition appropriately.
2759 if (ds
->isClientRedirect()) {
2761 Referrer(params
.redirects
[0], ds
->request().referrerPolicy());
2762 params
.transition
= static_cast<PageTransition
>(
2763 params
.transition
| PAGE_TRANSITION_CLIENT_REDIRECT
);
2765 params
.referrer
= RenderViewImpl::GetReferrerFromRequest(
2766 frame
, ds
->request());
2769 base::string16 method
= request
.httpMethod();
2770 if (EqualsASCII(method
, "POST")) {
2771 params
.is_post
= true;
2772 params
.post_id
= ExtractPostId(item
);
2775 // Send the user agent override back.
2776 params
.is_overriding_user_agent
= internal_data
->is_overriding_user_agent();
2778 // Track the URL of the original request. We use the first entry of the
2779 // redirect chain if it exists because the chain may have started in another
2781 params
.original_request_url
= GetOriginalRequestURL(ds
);
2783 params
.history_list_was_cleared
=
2784 navigation_state
->history_list_was_cleared();
2786 // Save some histogram data so we can compute the average memory used per
2787 // page load of the glyphs.
2788 UMA_HISTOGRAM_COUNTS_10000("Memory.GlyphPagesPerLoad",
2789 blink::WebGlyphCache::pageCount());
2791 // This message needs to be sent before any of allowScripts(),
2792 // allowImages(), allowPlugins() is called for the new page, so that when
2793 // these functions send a ViewHostMsg_ContentBlocked message, it arrives
2794 // after the FrameHostMsg_DidCommitProvisionalLoad message.
2795 Send(new FrameHostMsg_DidCommitProvisionalLoad(routing_id_
, params
));
2797 // Subframe navigation: the type depends on whether this navigation
2798 // generated a new session history entry. When they do generate a session
2799 // history entry, it means the user initiated the navigation and we should
2800 // mark it as such. This test checks if this is the first time UpdateURL
2801 // has been called since WillNavigateToURL was called to initiate the load.
2802 if (render_view_
->page_id_
> render_view_
->last_page_id_sent_to_browser_
)
2803 params
.transition
= PAGE_TRANSITION_MANUAL_SUBFRAME
;
2805 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
2807 DCHECK(!navigation_state
->history_list_was_cleared());
2808 params
.history_list_was_cleared
= false;
2810 // Don't send this message while the subframe is swapped out.
2811 if (!is_swapped_out())
2812 Send(new FrameHostMsg_DidCommitProvisionalLoad(routing_id_
, params
));
2815 render_view_
->last_page_id_sent_to_browser_
=
2816 std::max(render_view_
->last_page_id_sent_to_browser_
,
2817 render_view_
->page_id_
);
2819 // If we end up reusing this WebRequest (for example, due to a #ref click),
2820 // we don't want the transition type to persist. Just clear it.
2821 navigation_state
->set_transition_type(PAGE_TRANSITION_LINK
);
2824 WebElement
RenderFrameImpl::GetFocusedElement() {
2825 WebDocument doc
= frame_
->document();
2827 return doc
.focusedElement();
2829 return WebElement();
2832 void RenderFrameImpl::didStartLoading(bool to_different_document
) {
2833 bool view_was_loading
= render_view_
->is_loading();
2834 render_view_
->FrameDidStartLoading(frame_
);
2835 if (!view_was_loading
)
2836 Send(new FrameHostMsg_DidStartLoading(routing_id_
, to_different_document
));
2839 void RenderFrameImpl::didStopLoading() {
2840 if (!render_view_
->is_loading())
2842 render_view_
->FrameDidStopLoading(frame_
);
2844 // NOTE: For now we're doing the safest thing, and sending out notification
2845 // when done loading. This currently isn't an issue as the favicon is only
2846 // displayed when done loading. Ideally we would send notification when
2847 // finished parsing the head, but webkit doesn't support that yet.
2848 // The feed discovery code would also benefit from access to the head.
2849 if (!render_view_
->is_loading())
2850 Send(new FrameHostMsg_DidStopLoading(routing_id_
));
2853 void RenderFrameImpl::didChangeLoadProgress(double load_progress
) {
2854 render_view_
->FrameDidChangeLoadProgress(frame_
, load_progress
);
2857 WebNavigationPolicy
RenderFrameImpl::DecidePolicyForNavigation(
2858 RenderFrame
* render_frame
,
2860 WebDataSource::ExtraData
* extraData
,
2861 const WebURLRequest
& request
,
2862 WebNavigationType type
,
2863 WebNavigationPolicy default_policy
,
2866 // The handlenavigation API is deprecated and will be removed once
2867 // crbug.com/325351 is resolved.
2868 if (request
.url() != GURL(kSwappedOutURL
) &&
2869 GetContentClient()->renderer()->HandleNavigation(
2871 static_cast<DocumentState
*>(extraData
),
2872 render_view_
->opener_id_
,
2878 return blink::WebNavigationPolicyIgnore
;
2882 Referrer
referrer(RenderViewImpl::GetReferrerFromRequest(frame
, request
));
2884 if (is_swapped_out_
|| render_view_
->is_swapped_out()) {
2885 if (request
.url() != GURL(kSwappedOutURL
)) {
2886 // Targeted links may try to navigate a swapped out frame. Allow the
2887 // browser process to navigate the tab instead. Note that it is also
2888 // possible for non-targeted navigations (from this view) to arrive
2889 // here just after we are swapped out. It's ok to send them to the
2890 // browser, as long as they're for the top level frame.
2891 // TODO(creis): Ensure this supports targeted form submissions when
2892 // fixing http://crbug.com/101395.
2893 if (frame
->parent() == NULL
) {
2894 OpenURL(frame
, request
.url(), referrer
, default_policy
);
2895 return blink::WebNavigationPolicyIgnore
; // Suppress the load here.
2898 // We should otherwise ignore in-process iframe navigations, if they
2899 // arrive just after we are swapped out.
2900 return blink::WebNavigationPolicyIgnore
;
2903 // Allow kSwappedOutURL to complete.
2904 return default_policy
;
2907 // Webkit is asking whether to navigate to a new URL.
2908 // This is fine normally, except if we're showing UI from one security
2909 // context and they're trying to navigate to a different context.
2910 const GURL
& url
= request
.url();
2912 // A content initiated navigation may have originated from a link-click,
2913 // script, drag-n-drop operation, etc.
2914 bool is_content_initiated
= static_cast<DocumentState
*>(extraData
)->
2915 navigation_state()->is_content_initiated();
2918 // If --enable-strict-site-isolation or --site-per-process is enabled, send
2919 // all top-level navigations to the browser to let it swap processes when
2920 // crossing site boundaries. This is currently expected to break some script
2921 // calls and navigations, such as form submissions.
2922 const CommandLine
& command_line
= *CommandLine::ForCurrentProcess();
2923 bool force_swap_due_to_flag
=
2924 command_line
.HasSwitch(switches::kEnableStrictSiteIsolation
) ||
2925 command_line
.HasSwitch(switches::kSitePerProcess
);
2926 if (force_swap_due_to_flag
&&
2927 !frame
->parent() && (is_content_initiated
|| is_redirect
)) {
2928 WebString origin_str
= frame
->document().securityOrigin().toString();
2929 GURL
frame_url(origin_str
.utf8().data());
2930 // TODO(cevans): revisit whether this site check is still necessary once
2931 // crbug.com/101395 is fixed.
2932 bool same_domain_or_host
=
2933 net::registry_controlled_domains::SameDomainOrHost(
2936 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES
);
2937 if (!same_domain_or_host
|| frame_url
.scheme() != url
.scheme()) {
2938 OpenURL(frame
, url
, referrer
, default_policy
);
2939 return blink::WebNavigationPolicyIgnore
;
2943 // If the browser is interested, then give it a chance to look at the request.
2944 if (is_content_initiated
) {
2945 bool is_form_post
= ((type
== blink::WebNavigationTypeFormSubmitted
) ||
2946 (type
== blink::WebNavigationTypeFormResubmitted
)) &&
2947 EqualsASCII(request
.httpMethod(), "POST");
2948 bool browser_handles_request
=
2949 render_view_
->renderer_preferences_
2950 .browser_handles_non_local_top_level_requests
2951 && IsNonLocalTopLevelNavigation(url
, frame
, type
, is_form_post
);
2952 if (!browser_handles_request
) {
2953 browser_handles_request
= IsTopLevelNavigation(frame
) &&
2954 render_view_
->renderer_preferences_
2955 .browser_handles_all_top_level_requests
;
2958 if (browser_handles_request
) {
2959 // Reset these counters as the RenderView could be reused for the next
2961 render_view_
->page_id_
= -1;
2962 render_view_
->last_page_id_sent_to_browser_
= -1;
2963 OpenURL(frame
, url
, referrer
, default_policy
);
2964 return blink::WebNavigationPolicyIgnore
; // Suppress the load here.
2968 // Use the frame's original request's URL rather than the document's URL for
2969 // subsequent checks. For a popup, the document's URL may become the opener
2970 // window's URL if the opener has called document.write().
2971 // See http://crbug.com/93517.
2972 GURL
old_url(frame
->dataSource()->request().url());
2974 // Detect when we're crossing a permission-based boundary (e.g. into or out of
2975 // an extension or app origin, leaving a WebUI page, etc). We only care about
2976 // top-level navigations (not iframes). But we sometimes navigate to
2977 // about:blank to clear a tab, and we want to still allow that.
2979 // Note: this is known to break POST submissions when crossing process
2980 // boundaries until http://crbug.com/101395 is fixed. This is better for
2981 // security than loading a WebUI, extension or app page in the wrong process.
2982 // POST requests don't work because this mechanism does not preserve form
2983 // POST data. We will need to send the request's httpBody data up to the
2984 // browser process, and issue a special POST navigation in WebKit (via
2985 // FrameLoader::loadFrameRequest). See ResourceDispatcher and WebURLLoaderImpl
2986 // for examples of how to send the httpBody data.
2987 if (!frame
->parent() && is_content_initiated
&& !url
.SchemeIs(kAboutScheme
)) {
2988 bool send_referrer
= false;
2990 // All navigations to or from WebUI URLs or within WebUI-enabled
2991 // RenderProcesses must be handled by the browser process so that the
2992 // correct bindings and data sources can be registered.
2993 // Similarly, navigations to view-source URLs or within ViewSource mode
2994 // must be handled by the browser process (except for reloads - those are
2995 // safe to leave within the renderer).
2996 // Lastly, access to file:// URLs from non-file:// URL pages must be
2997 // handled by the browser so that ordinary renderer processes don't get
2998 // blessed with file permissions.
2999 int cumulative_bindings
= RenderProcess::current()->GetEnabledBindings();
3000 bool is_initial_navigation
= render_view_
->page_id_
== -1;
3001 bool should_fork
= HasWebUIScheme(url
) || HasWebUIScheme(old_url
) ||
3002 (cumulative_bindings
& BINDINGS_POLICY_WEB_UI
) ||
3003 url
.SchemeIs(kViewSourceScheme
) ||
3004 (frame
->isViewSourceModeEnabled() &&
3005 type
!= blink::WebNavigationTypeReload
);
3007 if (!should_fork
&& url
.SchemeIs(kFileScheme
)) {
3008 // Fork non-file to file opens. Check the opener URL if this is the
3009 // initial navigation in a newly opened window.
3010 GURL
source_url(old_url
);
3011 if (is_initial_navigation
&& source_url
.is_empty() && frame
->opener())
3012 source_url
= frame
->opener()->top()->document().url();
3013 DCHECK(!source_url
.is_empty());
3014 should_fork
= !source_url
.SchemeIs(kFileScheme
);
3018 // Give the embedder a chance.
3019 should_fork
= GetContentClient()->renderer()->ShouldFork(
3020 frame
, url
, request
.httpMethod().utf8(), is_initial_navigation
,
3021 is_redirect
, &send_referrer
);
3026 frame
, url
, send_referrer
? referrer
: Referrer(), default_policy
);
3027 return blink::WebNavigationPolicyIgnore
; // Suppress the load here.
3031 // Detect when a page is "forking" a new tab that can be safely rendered in
3032 // its own process. This is done by sites like Gmail that try to open links
3033 // in new windows without script connections back to the original page. We
3034 // treat such cases as browser navigations (in which we will create a new
3035 // renderer for a cross-site navigation), rather than WebKit navigations.
3037 // We use the following heuristic to decide whether to fork a new page in its
3039 // The parent page must open a new tab to about:blank, set the new tab's
3040 // window.opener to null, and then redirect the tab to a cross-site URL using
3043 // TODO(creis): Deprecate this logic once we can rely on rel=noreferrer
3046 // Must start from a tab showing about:blank, which is later redirected.
3047 old_url
== GURL(kAboutBlankURL
) &&
3048 // Must be the first real navigation of the tab.
3049 render_view_
->historyBackListCount() < 1 &&
3050 render_view_
->historyForwardListCount() < 1 &&
3051 // The parent page must have set the child's window.opener to null before
3052 // redirecting to the desired URL.
3053 frame
->opener() == NULL
&&
3054 // Must be a top-level frame.
3055 frame
->parent() == NULL
&&
3056 // Must not have issued the request from this page.
3057 is_content_initiated
&&
3058 // Must be targeted at the current tab.
3059 default_policy
== blink::WebNavigationPolicyCurrentTab
&&
3060 // Must be a JavaScript navigation, which appears as "other".
3061 type
== blink::WebNavigationTypeOther
;
3064 // Open the URL via the browser, not via WebKit.
3065 OpenURL(frame
, url
, Referrer(), default_policy
);
3066 return blink::WebNavigationPolicyIgnore
;
3069 return default_policy
;
3072 void RenderFrameImpl::OpenURL(WebFrame
* frame
,
3074 const Referrer
& referrer
,
3075 WebNavigationPolicy policy
) {
3076 DCHECK_EQ(frame_
, frame
);
3078 FrameHostMsg_OpenURL_Params params
;
3080 params
.referrer
= referrer
;
3081 params
.disposition
= RenderViewImpl::NavigationPolicyToDisposition(policy
);
3082 WebDataSource
* ds
= frame
->provisionalDataSource();
3084 DocumentState
* document_state
= DocumentState::FromDataSource(ds
);
3085 NavigationState
* navigation_state
= document_state
->navigation_state();
3086 if (navigation_state
->is_content_initiated()) {
3087 params
.should_replace_current_entry
= ds
->replacesCurrentHistoryItem();
3089 // This is necessary to preserve the should_replace_current_entry value on
3090 // cross-process redirects, in the event it was set by a previous process.
3092 // TODO(davidben): Avoid this awkward duplication of state. See comment on
3093 // NavigationState::should_replace_current_entry().
3094 params
.should_replace_current_entry
=
3095 navigation_state
->should_replace_current_entry();
3098 params
.should_replace_current_entry
= false;
3100 params
.user_gesture
= WebUserGestureIndicator::isProcessingUserGesture();
3101 if (GetContentClient()->renderer()->AllowPopup())
3102 params
.user_gesture
= true;
3104 if (policy
== blink::WebNavigationPolicyNewBackgroundTab
||
3105 policy
== blink::WebNavigationPolicyNewForegroundTab
||
3106 policy
== blink::WebNavigationPolicyNewWindow
||
3107 policy
== blink::WebNavigationPolicyNewPopup
) {
3108 WebUserGestureIndicator::consumeUserGesture();
3111 Send(new FrameHostMsg_OpenURL(routing_id_
, params
));
3114 void RenderFrameImpl::SyncSelectionIfRequired() {
3115 base::string16 text
;
3118 #if defined(ENABLE_PLUGINS)
3119 if (render_view_
->focused_pepper_plugin_
) {
3120 render_view_
->focused_pepper_plugin_
->GetSurroundingText(&text
, &range
);
3121 offset
= 0; // Pepper API does not support offset reporting.
3122 // TODO(kinaba): cut as needed.
3126 size_t location
, length
;
3127 if (!GetRenderWidget()->webwidget()->caretOrSelectionRange(
3128 &location
, &length
)) {
3132 range
= gfx::Range(location
, location
+ length
);
3134 if (GetRenderWidget()->webwidget()->textInputInfo().type
!=
3135 blink::WebTextInputTypeNone
) {
3136 // If current focused element is editable, we will send 100 more chars
3137 // before and after selection. It is for input method surrounding text
3139 if (location
> kExtraCharsBeforeAndAfterSelection
)
3140 offset
= location
- kExtraCharsBeforeAndAfterSelection
;
3143 length
= location
+ length
- offset
+ kExtraCharsBeforeAndAfterSelection
;
3144 WebRange webrange
= WebRange::fromDocumentRange(frame_
, offset
, length
);
3145 if (!webrange
.isNull())
3146 text
= WebRange::fromDocumentRange(
3147 frame_
, offset
, length
).toPlainText();
3150 text
= frame_
->selectionAsText();
3151 // http://crbug.com/101435
3152 // In some case, frame->selectionAsText() returned text's length is not
3153 // equal to the length returned from webwidget()->caretOrSelectionRange().
3154 // So we have to set the range according to text.length().
3155 range
.set_end(range
.start() + text
.length());
3159 // Sometimes we get repeated didChangeSelection calls from webkit when
3160 // the selection hasn't actually changed. We don't want to report these
3161 // because it will cause us to continually claim the X clipboard.
3162 if (selection_text_offset_
!= offset
||
3163 selection_range_
!= range
||
3164 selection_text_
!= text
) {
3165 selection_text_
= text
;
3166 selection_text_offset_
= offset
;
3167 selection_range_
= range
;
3168 // This IPC is dispatched by RenderWidetHost, so use its routing ID.
3169 Send(new ViewHostMsg_SelectionChanged(
3170 GetRenderWidget()->routing_id(), text
, offset
, range
));
3172 GetRenderWidget()->UpdateSelectionBounds();
3175 } // namespace content