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/asan_invalid_access.h"
14 #include "base/debug/dump_without_crashing.h"
15 #include "base/i18n/char_iterator.h"
16 #include "base/metrics/histogram.h"
17 #include "base/process/kill.h"
18 #include "base/process/process.h"
19 #include "base/strings/string16.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/time/time.h"
22 #include "content/child/appcache/appcache_dispatcher.h"
23 #include "content/child/plugin_messages.h"
24 #include "content/child/quota_dispatcher.h"
25 #include "content/child/request_extra_data.h"
26 #include "content/child/service_worker/service_worker_network_provider.h"
27 #include "content/child/service_worker/web_service_worker_provider_impl.h"
28 #include "content/child/web_socket_stream_handle_impl.h"
29 #include "content/child/web_url_request_util.h"
30 #include "content/child/webmessageportchannel_impl.h"
31 #include "content/child/websocket_bridge.h"
32 #include "content/child/weburlresponse_extradata_impl.h"
33 #include "content/common/clipboard_messages.h"
34 #include "content/common/frame_messages.h"
35 #include "content/common/input_messages.h"
36 #include "content/common/service_worker/service_worker_types.h"
37 #include "content/common/socket_stream_handle_data.h"
38 #include "content/common/swapped_out_messages.h"
39 #include "content/common/view_messages.h"
40 #include "content/public/common/bindings_policy.h"
41 #include "content/public/common/content_constants.h"
42 #include "content/public/common/content_switches.h"
43 #include "content/public/common/context_menu_params.h"
44 #include "content/public/common/url_constants.h"
45 #include "content/public/common/url_utils.h"
46 #include "content/public/renderer/content_renderer_client.h"
47 #include "content/public/renderer/context_menu_client.h"
48 #include "content/public/renderer/document_state.h"
49 #include "content/public/renderer/navigation_state.h"
50 #include "content/public/renderer/render_frame_observer.h"
51 #include "content/renderer/accessibility/renderer_accessibility.h"
52 #include "content/renderer/accessibility/renderer_accessibility_complete.h"
53 #include "content/renderer/accessibility/renderer_accessibility_focus_only.h"
54 #include "content/renderer/browser_plugin/browser_plugin.h"
55 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
56 #include "content/renderer/child_frame_compositing_helper.h"
57 #include "content/renderer/context_menu_params_builder.h"
58 #include "content/renderer/devtools/devtools_agent.h"
59 #include "content/renderer/dom_automation_controller.h"
60 #include "content/renderer/dom_utils.h"
61 #include "content/renderer/external_popup_menu.h"
62 #include "content/renderer/geolocation_dispatcher.h"
63 #include "content/renderer/history_controller.h"
64 #include "content/renderer/history_serialization.h"
65 #include "content/renderer/image_loading_helper.h"
66 #include "content/renderer/ime_event_guard.h"
67 #include "content/renderer/internal_document_state_data.h"
68 #include "content/renderer/media/audio_renderer_mixer_manager.h"
69 #include "content/renderer/media/media_stream_dispatcher.h"
70 #include "content/renderer/media/media_stream_impl.h"
71 #include "content/renderer/media/media_stream_renderer_factory.h"
72 #include "content/renderer/media/midi_dispatcher.h"
73 #include "content/renderer/media/render_media_log.h"
74 #include "content/renderer/media/webcontentdecryptionmodule_impl.h"
75 #include "content/renderer/media/webmediaplayer_impl.h"
76 #include "content/renderer/media/webmediaplayer_ms.h"
77 #include "content/renderer/media/webmediaplayer_params.h"
78 #include "content/renderer/notification_permission_dispatcher.h"
79 #include "content/renderer/notification_provider.h"
80 #include "content/renderer/npapi/plugin_channel_host.h"
81 #include "content/renderer/push_messaging_dispatcher.h"
82 #include "content/renderer/render_frame_proxy.h"
83 #include "content/renderer/render_process.h"
84 #include "content/renderer/render_thread_impl.h"
85 #include "content/renderer/render_view_impl.h"
86 #include "content/renderer/render_widget_fullscreen_pepper.h"
87 #include "content/renderer/renderer_webapplicationcachehost_impl.h"
88 #include "content/renderer/renderer_webcolorchooser_impl.h"
89 #include "content/renderer/screen_orientation/screen_orientation_dispatcher.h"
90 #include "content/renderer/shared_worker_repository.h"
91 #include "content/renderer/v8_value_converter_impl.h"
92 #include "content/renderer/websharedworker_proxy.h"
93 #include "media/base/audio_renderer_mixer_input.h"
94 #include "net/base/data_url.h"
95 #include "net/base/net_errors.h"
96 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
97 #include "net/http/http_util.h"
98 #include "third_party/WebKit/public/platform/WebStorageQuotaCallbacks.h"
99 #include "third_party/WebKit/public/platform/WebString.h"
100 #include "third_party/WebKit/public/platform/WebURL.h"
101 #include "third_party/WebKit/public/platform/WebURLError.h"
102 #include "third_party/WebKit/public/platform/WebURLResponse.h"
103 #include "third_party/WebKit/public/platform/WebVector.h"
104 #include "third_party/WebKit/public/web/WebColorSuggestion.h"
105 #include "third_party/WebKit/public/web/WebDocument.h"
106 #include "third_party/WebKit/public/web/WebGlyphCache.h"
107 #include "third_party/WebKit/public/web/WebLocalFrame.h"
108 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
109 #include "third_party/WebKit/public/web/WebNavigationPolicy.h"
110 #include "third_party/WebKit/public/web/WebPlugin.h"
111 #include "third_party/WebKit/public/web/WebPluginParams.h"
112 #include "third_party/WebKit/public/web/WebRange.h"
113 #include "third_party/WebKit/public/web/WebScriptSource.h"
114 #include "third_party/WebKit/public/web/WebSearchableFormData.h"
115 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
116 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
117 #include "third_party/WebKit/public/web/WebSurroundingText.h"
118 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
119 #include "third_party/WebKit/public/web/WebView.h"
121 #if defined(ENABLE_PLUGINS)
122 #include "content/renderer/npapi/webplugin_impl.h"
123 #include "content/renderer/pepper/pepper_browser_connection.h"
124 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
125 #include "content/renderer/pepper/pepper_webplugin_impl.h"
126 #include "content/renderer/pepper/plugin_module.h"
129 #if defined(ENABLE_WEBRTC)
130 #include "content/renderer/media/rtc_peer_connection_handler.h"
133 #if defined(OS_ANDROID)
134 #include <cpu-features.h>
136 #include "content/common/gpu/client/context_provider_command_buffer.h"
137 #include "content/renderer/android/synchronous_compositor_factory.h"
138 #include "content/renderer/java/gin_java_bridge_dispatcher.h"
139 #include "content/renderer/media/android/renderer_media_player_manager.h"
140 #include "content/renderer/media/android/stream_texture_factory_impl.h"
141 #include "content/renderer/media/android/webmediaplayer_android.h"
144 #if defined(ENABLE_BROWSER_CDMS)
145 #include "content/renderer/media/crypto/renderer_cdm_manager.h"
148 using blink::WebContextMenuData
;
149 using blink::WebData
;
150 using blink::WebDataSource
;
151 using blink::WebDocument
;
152 using blink::WebElement
;
153 using blink::WebExternalPopupMenu
;
154 using blink::WebExternalPopupMenuClient
;
155 using blink::WebFrame
;
156 using blink::WebHistoryItem
;
157 using blink::WebHTTPBody
;
158 using blink::WebLocalFrame
;
159 using blink::WebMediaPlayer
;
160 using blink::WebMediaPlayerClient
;
161 using blink::WebNavigationPolicy
;
162 using blink::WebNavigationType
;
163 using blink::WebNode
;
164 using blink::WebPluginParams
;
165 using blink::WebPopupMenuInfo
;
166 using blink::WebRange
;
167 using blink::WebReferrerPolicy
;
168 using blink::WebScriptSource
;
169 using blink::WebSearchableFormData
;
170 using blink::WebSecurityOrigin
;
171 using blink::WebSecurityPolicy
;
172 using blink::WebServiceWorkerProvider
;
173 using blink::WebStorageQuotaCallbacks
;
174 using blink::WebString
;
176 using blink::WebURLError
;
177 using blink::WebURLRequest
;
178 using blink::WebURLResponse
;
179 using blink::WebUserGestureIndicator
;
180 using blink::WebVector
;
181 using blink::WebView
;
183 using base::TimeDelta
;
189 const char kDefaultAcceptHeader
[] =
190 "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/"
192 const char kAcceptHeader
[] = "Accept";
194 const size_t kExtraCharsBeforeAndAfterSelection
= 100;
196 typedef std::map
<int, RenderFrameImpl
*> RoutingIDFrameMap
;
197 static base::LazyInstance
<RoutingIDFrameMap
> g_routing_id_frame_map
=
198 LAZY_INSTANCE_INITIALIZER
;
200 typedef std::map
<blink::WebFrame
*, RenderFrameImpl
*> FrameMap
;
201 base::LazyInstance
<FrameMap
> g_frame_map
= LAZY_INSTANCE_INITIALIZER
;
203 int64
ExtractPostId(const WebHistoryItem
& item
) {
207 if (item
.httpBody().isNull())
210 return item
.httpBody().identifier();
213 WebURLResponseExtraDataImpl
* GetExtraDataFromResponse(
214 const WebURLResponse
& response
) {
215 return static_cast<WebURLResponseExtraDataImpl
*>(response
.extraData());
218 void GetRedirectChain(WebDataSource
* ds
, std::vector
<GURL
>* result
) {
219 // Replace any occurrences of swappedout:// with about:blank.
220 const WebURL
& blank_url
= GURL(url::kAboutBlankURL
);
221 WebVector
<WebURL
> urls
;
222 ds
->redirectChain(urls
);
223 result
->reserve(urls
.size());
224 for (size_t i
= 0; i
< urls
.size(); ++i
) {
225 if (urls
[i
] != GURL(kSwappedOutURL
))
226 result
->push_back(urls
[i
]);
228 result
->push_back(blank_url
);
232 // Returns the original request url. If there is no redirect, the original
233 // url is the same as ds->request()->url(). If the WebDataSource belongs to a
234 // frame was loaded by loadData, the original url will be ds->unreachableURL()
235 static GURL
GetOriginalRequestURL(WebDataSource
* ds
) {
236 // WebDataSource has unreachable URL means that the frame is loaded through
237 // blink::WebFrame::loadData(), and the base URL will be in the redirect
238 // chain. However, we never visited the baseURL. So in this case, we should
239 // use the unreachable URL as the original URL.
240 if (ds
->hasUnreachableURL())
241 return ds
->unreachableURL();
243 std::vector
<GURL
> redirects
;
244 GetRedirectChain(ds
, &redirects
);
245 if (!redirects
.empty())
246 return redirects
.at(0);
248 return ds
->originalRequest().url();
251 NOINLINE
static void CrashIntentionally() {
252 // NOTE(shess): Crash directly rather than using NOTREACHED() so
253 // that the signature is easier to triage in crash reports.
254 volatile int* zero
= NULL
;
258 #if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
259 NOINLINE
static void MaybeTriggerAsanError(const GURL
& url
) {
260 // NOTE(rogerm): We intentionally perform an invalid heap access here in
261 // order to trigger an Address Sanitizer (ASAN) error report.
262 const char kCrashDomain
[] = "crash";
263 const char kHeapOverflow
[] = "/heap-overflow";
264 const char kHeapUnderflow
[] = "/heap-underflow";
265 const char kUseAfterFree
[] = "/use-after-free";
266 #if defined(SYZYASAN)
267 const char kCorruptHeapBlock
[] = "/corrupt-heap-block";
268 const char kCorruptHeap
[] = "/corrupt-heap";
271 if (!url
.DomainIs(kCrashDomain
, sizeof(kCrashDomain
) - 1))
277 std::string
crash_type(url
.path());
278 if (crash_type
== kHeapOverflow
) {
279 base::debug::AsanHeapOverflow();
280 } else if (crash_type
== kHeapUnderflow
) {
281 base::debug::AsanHeapUnderflow();
282 } else if (crash_type
== kUseAfterFree
) {
283 base::debug::AsanHeapUseAfterFree();
284 #if defined(SYZYASAN)
285 } else if (crash_type
== kCorruptHeapBlock
) {
286 base::debug::AsanCorruptHeapBlock();
287 } else if (crash_type
== kCorruptHeap
) {
288 base::debug::AsanCorruptHeap();
292 #endif // ADDRESS_SANITIZER || SYZYASAN
294 static void MaybeHandleDebugURL(const GURL
& url
) {
295 if (!url
.SchemeIs(kChromeUIScheme
))
297 if (url
== GURL(kChromeUICrashURL
)) {
298 CrashIntentionally();
299 } else if (url
== GURL(kChromeUIDumpURL
)) {
300 // This URL will only correctly create a crash dump file if content is
301 // hosted in a process that has correctly called
302 // base::debug::SetDumpWithoutCrashingFunction. Refer to the documentation
303 // of base::debug::DumpWithoutCrashing for more details.
304 base::debug::DumpWithoutCrashing();
305 } else if (url
== GURL(kChromeUIKillURL
)) {
306 base::KillProcess(base::GetCurrentProcessHandle(), 1, false);
307 } else if (url
== GURL(kChromeUIHangURL
)) {
309 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
311 } else if (url
== GURL(kChromeUIShorthangURL
)) {
312 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(20));
315 #if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
316 MaybeTriggerAsanError(url
);
317 #endif // ADDRESS_SANITIZER || SYZYASAN
320 // Returns false unless this is a top-level navigation.
321 static bool IsTopLevelNavigation(WebFrame
* frame
) {
322 return frame
->parent() == NULL
;
325 // Returns false unless this is a top-level navigation that crosses origins.
326 static bool IsNonLocalTopLevelNavigation(const GURL
& url
,
328 WebNavigationType type
,
330 if (!IsTopLevelNavigation(frame
))
333 // Navigations initiated within Webkit are not sent out to the external host
334 // in the following cases.
335 // 1. The url scheme is not http/https
336 // 2. The origin of the url and the opener is the same in which case the
337 // opener relationship is maintained.
338 // 3. Reloads/form submits/back forward navigations
339 if (!url
.SchemeIs(url::kHttpScheme
) && !url
.SchemeIs(url::kHttpsScheme
))
342 if (type
!= blink::WebNavigationTypeReload
&&
343 type
!= blink::WebNavigationTypeBackForward
&& !is_form_post
) {
344 // The opener relationship between the new window and the parent allows the
345 // new window to script the parent and vice versa. This is not allowed if
346 // the origins of the two domains are different. This can be treated as a
347 // top level navigation and routed back to the host.
348 blink::WebFrame
* opener
= frame
->opener();
352 if (url
.GetOrigin() != GURL(opener
->document().url()).GetOrigin())
360 static RenderFrameImpl
* (*g_create_render_frame_impl
)(RenderViewImpl
*, int32
) =
364 RenderFrameImpl
* RenderFrameImpl::Create(RenderViewImpl
* render_view
,
366 DCHECK(routing_id
!= MSG_ROUTING_NONE
);
368 if (g_create_render_frame_impl
)
369 return g_create_render_frame_impl(render_view
, routing_id
);
371 return new RenderFrameImpl(render_view
, routing_id
);
375 RenderFrameImpl
* RenderFrameImpl::FromRoutingID(int32 routing_id
) {
376 RoutingIDFrameMap::iterator iter
=
377 g_routing_id_frame_map
.Get().find(routing_id
);
378 if (iter
!= g_routing_id_frame_map
.Get().end())
384 void RenderFrameImpl::CreateFrame(int routing_id
, int parent_routing_id
) {
385 // TODO(nasko): For now, this message is only sent for subframes, as the
386 // top level frame is created when the RenderView is created through the
388 CHECK_NE(MSG_ROUTING_NONE
, parent_routing_id
);
390 RenderFrameProxy
* proxy
= RenderFrameProxy::FromRoutingID(parent_routing_id
);
392 // If the browser is sending a valid parent routing id, it should already be
393 // created and registered.
395 blink::WebRemoteFrame
* parent_web_frame
= proxy
->web_frame();
397 // Create the RenderFrame and WebLocalFrame, linking the two.
398 RenderFrameImpl
* render_frame
=
399 RenderFrameImpl::Create(proxy
->render_view(), routing_id
);
400 blink::WebLocalFrame
* web_frame
=
401 parent_web_frame
->createLocalChild("", render_frame
);
402 render_frame
->SetWebFrame(web_frame
);
403 render_frame
->Initialize();
407 RenderFrame
* RenderFrame::FromWebFrame(blink::WebFrame
* web_frame
) {
408 return RenderFrameImpl::FromWebFrame(web_frame
);
412 RenderFrameImpl
* RenderFrameImpl::FromWebFrame(blink::WebFrame
* web_frame
) {
413 FrameMap::iterator iter
= g_frame_map
.Get().find(web_frame
);
414 if (iter
!= g_frame_map
.Get().end())
420 void RenderFrameImpl::InstallCreateHook(
421 RenderFrameImpl
* (*create_render_frame_impl
)(RenderViewImpl
*, int32
)) {
422 CHECK(!g_create_render_frame_impl
);
423 g_create_render_frame_impl
= create_render_frame_impl
;
426 // RenderFrameImpl ----------------------------------------------------------
427 RenderFrameImpl::RenderFrameImpl(RenderViewImpl
* render_view
, int routing_id
)
429 render_view_(render_view
->AsWeakPtr()),
430 routing_id_(routing_id
),
431 is_swapped_out_(false),
432 render_frame_proxy_(NULL
),
433 is_detaching_(false),
435 selection_text_offset_(0),
436 selection_range_(gfx::Range::InvalidRange()),
437 handling_select_range_(false),
438 notification_permission_dispatcher_(NULL
),
439 notification_provider_(NULL
),
440 web_user_media_client_(NULL
),
441 midi_dispatcher_(NULL
),
442 #if defined(OS_ANDROID)
443 media_player_manager_(NULL
),
445 #if defined(ENABLE_BROWSER_CDMS)
448 #if defined(VIDEO_HOLE)
449 contains_media_player_(false),
451 geolocation_dispatcher_(NULL
),
452 push_messaging_dispatcher_(NULL
),
453 screen_orientation_dispatcher_(NULL
),
454 accessibility_mode_(AccessibilityModeOff
),
455 renderer_accessibility_(NULL
),
456 weak_factory_(this) {
457 std::pair
<RoutingIDFrameMap::iterator
, bool> result
=
458 g_routing_id_frame_map
.Get().insert(std::make_pair(routing_id_
, this));
459 CHECK(result
.second
) << "Inserting a duplicate item.";
461 RenderThread::Get()->AddRoute(routing_id_
, this);
463 render_view_
->RegisterRenderFrame(this);
465 #if defined(OS_ANDROID)
466 new GinJavaBridgeDispatcher(this);
469 #if defined(ENABLE_NOTIFICATIONS)
470 notification_provider_
= new NotificationProvider(this);
474 RenderFrameImpl::~RenderFrameImpl() {
475 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, RenderFrameGone());
476 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, OnDestruct());
478 #if defined(VIDEO_HOLE)
479 if (contains_media_player_
)
480 render_view_
->UnregisterVideoHoleFrame(this);
483 render_view_
->UnregisterRenderFrame(this);
484 g_routing_id_frame_map
.Get().erase(routing_id_
);
485 RenderThread::Get()->RemoveRoute(routing_id_
);
488 void RenderFrameImpl::SetWebFrame(blink::WebLocalFrame
* web_frame
) {
491 std::pair
<FrameMap::iterator
, bool> result
= g_frame_map
.Get().insert(
492 std::make_pair(web_frame
, this));
493 CHECK(result
.second
) << "Inserting a duplicate item.";
498 void RenderFrameImpl::Initialize() {
499 #if defined(ENABLE_PLUGINS)
500 new PepperBrowserConnection(this);
502 new SharedWorkerRepository(this);
504 if (!frame_
->parent())
505 new ImageLoadingHelper(this);
507 // We delay calling this until we have the WebFrame so that any observer or
508 // embedder can call GetWebFrame on any RenderFrame.
509 GetContentClient()->renderer()->RenderFrameCreated(this);
512 RenderWidget
* RenderFrameImpl::GetRenderWidget() {
513 return render_view_
.get();
516 #if defined(ENABLE_PLUGINS)
517 void RenderFrameImpl::PepperPluginCreated(RendererPpapiHost
* host
) {
518 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
,
519 DidCreatePepperPlugin(host
));
522 void RenderFrameImpl::PepperDidChangeCursor(
523 PepperPluginInstanceImpl
* instance
,
524 const blink::WebCursorInfo
& cursor
) {
525 // Update the cursor appearance immediately if the requesting plugin is the
526 // one which receives the last mouse event. Otherwise, the new cursor won't be
527 // picked up until the plugin gets the next input event. That is bad if, e.g.,
528 // the plugin would like to set an invisible cursor when there isn't any user
529 // input for a while.
530 if (instance
== render_view_
->pepper_last_mouse_event_target())
531 GetRenderWidget()->didChangeCursor(cursor
);
534 void RenderFrameImpl::PepperDidReceiveMouseEvent(
535 PepperPluginInstanceImpl
* instance
) {
536 render_view_
->set_pepper_last_mouse_event_target(instance
);
539 void RenderFrameImpl::PepperTextInputTypeChanged(
540 PepperPluginInstanceImpl
* instance
) {
541 if (instance
!= render_view_
->focused_pepper_plugin())
544 GetRenderWidget()->UpdateTextInputState(
545 RenderWidget::NO_SHOW_IME
, RenderWidget::FROM_NON_IME
);
546 if (renderer_accessibility())
547 renderer_accessibility()->FocusedNodeChanged(WebNode());
550 void RenderFrameImpl::PepperCaretPositionChanged(
551 PepperPluginInstanceImpl
* instance
) {
552 if (instance
!= render_view_
->focused_pepper_plugin())
554 GetRenderWidget()->UpdateSelectionBounds();
557 void RenderFrameImpl::PepperCancelComposition(
558 PepperPluginInstanceImpl
* instance
) {
559 if (instance
!= render_view_
->focused_pepper_plugin())
561 Send(new InputHostMsg_ImeCancelComposition(render_view_
->GetRoutingID()));;
562 #if defined(OS_MACOSX) || defined(USE_AURA)
563 GetRenderWidget()->UpdateCompositionInfo(true);
567 void RenderFrameImpl::PepperSelectionChanged(
568 PepperPluginInstanceImpl
* instance
) {
569 if (instance
!= render_view_
->focused_pepper_plugin())
571 SyncSelectionIfRequired();
574 RenderWidgetFullscreenPepper
* RenderFrameImpl::CreatePepperFullscreenContainer(
575 PepperPluginInstanceImpl
* plugin
) {
577 if (render_view_
->webview() && render_view_
->webview()->mainFrame())
578 active_url
= GURL(render_view_
->webview()->mainFrame()->document().url());
579 RenderWidgetFullscreenPepper
* widget
= RenderWidgetFullscreenPepper::Create(
580 GetRenderWidget()->routing_id(), plugin
, active_url
,
581 GetRenderWidget()->screenInfo());
582 widget
->show(blink::WebNavigationPolicyIgnore
);
586 bool RenderFrameImpl::IsPepperAcceptingCompositionEvents() const {
587 if (!render_view_
->focused_pepper_plugin())
589 return render_view_
->focused_pepper_plugin()->
590 IsPluginAcceptingCompositionEvents();
593 void RenderFrameImpl::PluginCrashed(const base::FilePath
& plugin_path
,
594 base::ProcessId plugin_pid
) {
595 // TODO(jam): dispatch this IPC in RenderFrameHost and switch to use
596 // routing_id_ as a result.
597 Send(new FrameHostMsg_PluginCrashed(routing_id_
, plugin_path
, plugin_pid
));
600 void RenderFrameImpl::SimulateImeSetComposition(
601 const base::string16
& text
,
602 const std::vector
<blink::WebCompositionUnderline
>& underlines
,
605 render_view_
->OnImeSetComposition(
606 text
, underlines
, selection_start
, selection_end
);
609 void RenderFrameImpl::SimulateImeConfirmComposition(
610 const base::string16
& text
,
611 const gfx::Range
& replacement_range
) {
612 render_view_
->OnImeConfirmComposition(text
, replacement_range
, false);
616 void RenderFrameImpl::OnImeSetComposition(
617 const base::string16
& text
,
618 const std::vector
<blink::WebCompositionUnderline
>& underlines
,
621 // When a PPAPI plugin has focus, we bypass WebKit.
622 if (!IsPepperAcceptingCompositionEvents()) {
623 pepper_composition_text_
= text
;
625 // TODO(kinaba) currently all composition events are sent directly to
626 // plugins. Use DOM event mechanism after WebKit is made aware about
627 // plugins that support composition.
628 // The code below mimics the behavior of WebCore::Editor::setComposition.
630 // Empty -> nonempty: composition started.
631 if (pepper_composition_text_
.empty() && !text
.empty()) {
632 render_view_
->focused_pepper_plugin()->HandleCompositionStart(
635 // Nonempty -> empty: composition canceled.
636 if (!pepper_composition_text_
.empty() && text
.empty()) {
637 render_view_
->focused_pepper_plugin()->HandleCompositionEnd(
640 pepper_composition_text_
= text
;
641 // Nonempty: composition is ongoing.
642 if (!pepper_composition_text_
.empty()) {
643 render_view_
->focused_pepper_plugin()->HandleCompositionUpdate(
644 pepper_composition_text_
, underlines
, selection_start
,
650 void RenderFrameImpl::OnImeConfirmComposition(
651 const base::string16
& text
,
652 const gfx::Range
& replacement_range
,
653 bool keep_selection
) {
654 // When a PPAPI plugin has focus, we bypass WebKit.
655 // Here, text.empty() has a special meaning. It means to commit the last
656 // update of composition text (see
657 // RenderWidgetHost::ImeConfirmComposition()).
658 const base::string16
& last_text
= text
.empty() ? pepper_composition_text_
661 // last_text is empty only when both text and pepper_composition_text_ is.
663 if (last_text
.empty())
666 if (!IsPepperAcceptingCompositionEvents()) {
667 base::i18n::UTF16CharIterator
iterator(&last_text
);
669 while (iterator
.Advance()) {
670 blink::WebKeyboardEvent char_event
;
671 char_event
.type
= blink::WebInputEvent::Char
;
672 char_event
.timeStampSeconds
= base::Time::Now().ToDoubleT();
673 char_event
.modifiers
= 0;
674 char_event
.windowsKeyCode
= last_text
[i
];
675 char_event
.nativeKeyCode
= last_text
[i
];
677 const int32 char_start
= i
;
678 for (; i
< iterator
.array_pos(); ++i
) {
679 char_event
.text
[i
- char_start
] = last_text
[i
];
680 char_event
.unmodifiedText
[i
- char_start
] = last_text
[i
];
683 if (GetRenderWidget()->webwidget())
684 GetRenderWidget()->webwidget()->handleInputEvent(char_event
);
687 // Mimics the order of events sent by WebKit.
688 // See WebCore::Editor::setComposition() for the corresponding code.
689 render_view_
->focused_pepper_plugin()->HandleCompositionEnd(last_text
);
690 render_view_
->focused_pepper_plugin()->HandleTextInput(last_text
);
692 pepper_composition_text_
.clear();
695 #endif // ENABLE_PLUGINS
697 MediaStreamDispatcher
* RenderFrameImpl::GetMediaStreamDispatcher() {
698 if (!web_user_media_client_
)
699 InitializeUserMediaClient();
700 return web_user_media_client_
?
701 web_user_media_client_
->media_stream_dispatcher() : NULL
;
704 bool RenderFrameImpl::Send(IPC::Message
* message
) {
709 if (frame_
->parent() == NULL
&&
710 (is_swapped_out_
|| render_view_
->is_swapped_out())) {
711 if (!SwappedOutMessages::CanSendWhileSwappedOut(message
)) {
716 // In most cases, send IPCs through the proxy when swapped out. In some
717 // calls the associated RenderViewImpl routing id is used to send
718 // messages, so don't use the proxy.
719 if (render_frame_proxy_
&& message
->routing_id() == routing_id_
)
720 return render_frame_proxy_
->Send(message
);
723 return RenderThread::Get()->Send(message
);
726 #if defined(OS_MACOSX) || defined(OS_ANDROID)
727 void RenderFrameImpl::DidHideExternalPopupMenu() {
728 // We need to clear external_popup_menu_ as soon as ExternalPopupMenu::close
729 // is called. Otherwise, createExternalPopupMenu() for new popup will fail.
730 external_popup_menu_
.reset();
734 bool RenderFrameImpl::OnMessageReceived(const IPC::Message
& msg
) {
735 // TODO(kenrb): document() should not be null, but as a transitional step
736 // we have RenderFrameProxy 'wrapping' a RenderFrameImpl, passing messages
737 // to this method. This happens for a top-level remote frame, where a
738 // document-less RenderFrame is replaced by a RenderFrameProxy but kept
739 // around and is still able to receive messages.
740 if (!frame_
->document().isNull())
741 GetContentClient()->SetActiveURL(frame_
->document().url());
743 ObserverListBase
<RenderFrameObserver
>::Iterator
it(observers_
);
744 RenderFrameObserver
* observer
;
745 while ((observer
= it
.GetNext()) != NULL
) {
746 if (observer
->OnMessageReceived(msg
))
751 IPC_BEGIN_MESSAGE_MAP(RenderFrameImpl
, msg
)
752 IPC_MESSAGE_HANDLER(FrameMsg_Navigate
, OnNavigate
)
753 IPC_MESSAGE_HANDLER(FrameMsg_BeforeUnload
, OnBeforeUnload
)
754 IPC_MESSAGE_HANDLER(FrameMsg_SwapOut
, OnSwapOut
)
755 IPC_MESSAGE_HANDLER(FrameMsg_ContextMenuClosed
, OnContextMenuClosed
)
756 IPC_MESSAGE_HANDLER(FrameMsg_CustomContextMenuAction
,
757 OnCustomContextMenuAction
)
758 IPC_MESSAGE_HANDLER(InputMsg_Undo
, OnUndo
)
759 IPC_MESSAGE_HANDLER(InputMsg_Redo
, OnRedo
)
760 IPC_MESSAGE_HANDLER(InputMsg_Cut
, OnCut
)
761 IPC_MESSAGE_HANDLER(InputMsg_Copy
, OnCopy
)
762 IPC_MESSAGE_HANDLER(InputMsg_Paste
, OnPaste
)
763 IPC_MESSAGE_HANDLER(InputMsg_PasteAndMatchStyle
, OnPasteAndMatchStyle
)
764 IPC_MESSAGE_HANDLER(InputMsg_Delete
, OnDelete
)
765 IPC_MESSAGE_HANDLER(InputMsg_SelectAll
, OnSelectAll
)
766 IPC_MESSAGE_HANDLER(InputMsg_SelectRange
, OnSelectRange
)
767 IPC_MESSAGE_HANDLER(InputMsg_Unselect
, OnUnselect
)
768 IPC_MESSAGE_HANDLER(InputMsg_Replace
, OnReplace
)
769 IPC_MESSAGE_HANDLER(InputMsg_ReplaceMisspelling
, OnReplaceMisspelling
)
770 IPC_MESSAGE_HANDLER(InputMsg_ExtendSelectionAndDelete
,
771 OnExtendSelectionAndDelete
)
772 IPC_MESSAGE_HANDLER(InputMsg_SetCompositionFromExistingText
,
773 OnSetCompositionFromExistingText
)
774 IPC_MESSAGE_HANDLER(FrameMsg_CSSInsertRequest
, OnCSSInsertRequest
)
775 IPC_MESSAGE_HANDLER(FrameMsg_JavaScriptExecuteRequest
,
776 OnJavaScriptExecuteRequest
)
777 IPC_MESSAGE_HANDLER(FrameMsg_SetEditableSelectionOffsets
,
778 OnSetEditableSelectionOffsets
)
779 IPC_MESSAGE_HANDLER(FrameMsg_SetupTransitionView
, OnSetupTransitionView
)
780 IPC_MESSAGE_HANDLER(FrameMsg_BeginExitTransition
, OnBeginExitTransition
)
781 IPC_MESSAGE_HANDLER(FrameMsg_Reload
, OnReload
)
782 IPC_MESSAGE_HANDLER(FrameMsg_TextSurroundingSelectionRequest
,
783 OnTextSurroundingSelectionRequest
)
784 IPC_MESSAGE_HANDLER(FrameMsg_AddStyleSheetByURL
,
785 OnAddStyleSheetByURL
)
786 IPC_MESSAGE_HANDLER(FrameMsg_SetAccessibilityMode
,
787 OnSetAccessibilityMode
)
788 IPC_MESSAGE_HANDLER(FrameMsg_DisownOpener
, OnDisownOpener
)
789 #if defined(OS_ANDROID)
790 IPC_MESSAGE_HANDLER(FrameMsg_SelectPopupMenuItems
, OnSelectPopupMenuItems
)
791 #elif defined(OS_MACOSX)
792 IPC_MESSAGE_HANDLER(FrameMsg_SelectPopupMenuItem
, OnSelectPopupMenuItem
)
793 IPC_MESSAGE_HANDLER(InputMsg_CopyToFindPboard
, OnCopyToFindPboard
)
795 IPC_END_MESSAGE_MAP()
800 void RenderFrameImpl::OnNavigate(const FrameMsg_Navigate_Params
& params
) {
801 MaybeHandleDebugURL(params
.url
);
802 if (!render_view_
->webview())
806 RenderViewObserver
, render_view_
->observers_
, Navigate(params
.url
));
808 bool is_reload
= RenderViewImpl::IsReload(params
);
809 WebURLRequest::CachePolicy cache_policy
=
810 WebURLRequest::UseProtocolCachePolicy
;
812 // If this is a stale back/forward (due to a recent navigation the browser
813 // didn't know about), ignore it.
814 if (render_view_
->IsBackForwardToStaleEntry(params
, is_reload
))
817 // Swap this renderer back in if necessary.
818 if (render_view_
->is_swapped_out_
&&
819 GetWebFrame() == render_view_
->webview()->mainFrame()) {
820 // We marked the view as hidden when swapping the view out, so be sure to
821 // reset the visibility state before navigating to the new URL.
822 render_view_
->webview()->setVisibilityState(
823 render_view_
->visibilityState(), false);
825 // If this is an attempt to reload while we are swapped out, we should not
826 // reload swappedout://, but the previous page, which is stored in
827 // params.state. Setting is_reload to false will treat this like a back
828 // navigation to accomplish that.
830 cache_policy
= WebURLRequest::ReloadIgnoringCacheData
;
832 // We refresh timezone when a view is swapped in since timezone
833 // can get out of sync when the system timezone is updated while
834 // the view is swapped out.
835 RenderThreadImpl::NotifyTimezoneChange();
837 render_view_
->SetSwappedOut(false);
838 is_swapped_out_
= false;
841 if (params
.should_clear_history_list
) {
842 CHECK_EQ(params
.pending_history_list_offset
, -1);
843 CHECK_EQ(params
.current_history_list_offset
, -1);
844 CHECK_EQ(params
.current_history_list_length
, 0);
846 render_view_
->history_list_offset_
= params
.current_history_list_offset
;
847 render_view_
->history_list_length_
= params
.current_history_list_length
;
848 if (render_view_
->history_list_length_
>= 0) {
849 render_view_
->history_page_ids_
.resize(
850 render_view_
->history_list_length_
, -1);
852 if (params
.pending_history_list_offset
>= 0 &&
853 params
.pending_history_list_offset
< render_view_
->history_list_length_
) {
854 render_view_
->history_page_ids_
[params
.pending_history_list_offset
] =
858 GetContentClient()->SetActiveURL(params
.url
);
860 WebFrame
* frame
= frame_
;
861 if (!params
.frame_to_navigate
.empty()) {
862 // TODO(nasko): Move this lookup to the browser process.
863 frame
= render_view_
->webview()->findFrameByName(
864 WebString::fromUTF8(params
.frame_to_navigate
));
865 CHECK(frame
) << "Invalid frame name passed: " << params
.frame_to_navigate
;
868 if (is_reload
&& !render_view_
->history_controller()->GetCurrentEntry()) {
869 // We cannot reload if we do not have any history state. This happens, for
870 // example, when recovering from a crash.
872 cache_policy
= WebURLRequest::ReloadIgnoringCacheData
;
875 render_view_
->pending_navigation_params_
.reset(
876 new FrameMsg_Navigate_Params(params
));
878 // If we are reloading, then WebKit will use the history state of the current
879 // page, so we should just ignore any given history state. Otherwise, if we
880 // have history state, then we need to navigate to it, which corresponds to a
881 // back/forward navigation event.
883 bool reload_original_url
=
884 (params
.navigation_type
==
885 FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL
);
886 bool ignore_cache
= (params
.navigation_type
==
887 FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE
);
889 if (reload_original_url
)
890 frame
->reloadWithOverrideURL(params
.url
, true);
892 frame
->reload(ignore_cache
);
893 } else if (params
.page_state
.IsValid()) {
894 // We must know the page ID of the page we are navigating back to.
895 DCHECK_NE(params
.page_id
, -1);
896 scoped_ptr
<HistoryEntry
> entry
=
897 PageStateToHistoryEntry(params
.page_state
);
899 // Ensure we didn't save the swapped out URL in UpdateState, since the
900 // browser should never be telling us to navigate to swappedout://.
901 CHECK(entry
->root().urlString() != WebString::fromUTF8(kSwappedOutURL
));
902 render_view_
->history_controller()->GoToEntry(entry
.Pass(), cache_policy
);
904 } else if (!params
.base_url_for_data_url
.is_empty()) {
905 // A loadData request with a specified base URL.
906 std::string mime_type
, charset
, data
;
907 if (net::DataURL::Parse(params
.url
, &mime_type
, &charset
, &data
)) {
909 WebData(data
.c_str(), data
.length()),
910 WebString::fromUTF8(mime_type
),
911 WebString::fromUTF8(charset
),
912 params
.base_url_for_data_url
,
913 params
.history_url_for_data_url
,
917 "Invalid URL passed: " << params
.url
.possibly_invalid_spec();
920 // Navigate to the given URL.
921 WebURLRequest
request(params
.url
);
923 // A session history navigation should have been accompanied by state.
924 CHECK_EQ(params
.page_id
, -1);
926 if (frame
->isViewSourceModeEnabled())
927 request
.setCachePolicy(WebURLRequest::ReturnCacheDataElseLoad
);
929 if (params
.referrer
.url
.is_valid()) {
930 WebString referrer
= WebSecurityPolicy::generateReferrerHeader(
931 params
.referrer
.policy
,
933 WebString::fromUTF8(params
.referrer
.url
.spec()));
934 if (!referrer
.isEmpty())
935 request
.setHTTPReferrer(referrer
, params
.referrer
.policy
);
938 if (!params
.extra_headers
.empty()) {
939 for (net::HttpUtil::HeadersIterator
i(params
.extra_headers
.begin(),
940 params
.extra_headers
.end(), "\n");
942 request
.addHTTPHeaderField(WebString::fromUTF8(i
.name()),
943 WebString::fromUTF8(i
.values()));
947 if (params
.is_post
) {
948 request
.setHTTPMethod(WebString::fromUTF8("POST"));
951 WebHTTPBody http_body
;
952 http_body
.initialize();
953 const char* data
= NULL
;
954 if (params
.browser_initiated_post_data
.size()) {
955 data
= reinterpret_cast<const char*>(
956 ¶ms
.browser_initiated_post_data
.front());
958 http_body
.appendData(
959 WebData(data
, params
.browser_initiated_post_data
.size()));
960 request
.setHTTPBody(http_body
);
963 // Record this before starting the load, we need a lower bound of this time
964 // to sanitize the navigationStart override set below.
965 base::TimeTicks renderer_navigation_start
= base::TimeTicks::Now();
966 frame
->loadRequest(request
);
968 // The browser provides the navigation_start time to bootstrap the
969 // Navigation Timing information for the browser-initiated navigations. In
970 // case of cross-process navigations, this carries over the time of
971 // finishing the onbeforeunload handler of the previous page.
972 DCHECK(!params
.browser_navigation_start
.is_null());
973 if (frame
->provisionalDataSource()) {
974 // |browser_navigation_start| is likely before this process existed, so we
975 // can't use InterProcessTimeTicksConverter. We need at least to ensure
976 // that the browser-side navigation start we set is not later than the one
977 // on the renderer side.
978 base::TimeTicks navigation_start
= std::min(
979 params
.browser_navigation_start
, renderer_navigation_start
);
980 double navigation_start_seconds
=
981 (navigation_start
- base::TimeTicks()).InSecondsF();
982 frame
->provisionalDataSource()->setNavigationStartTime(
983 navigation_start_seconds
);
987 // In case LoadRequest failed before DidCreateDataSource was called.
988 render_view_
->pending_navigation_params_
.reset();
991 void RenderFrameImpl::BindServiceRegistry(
992 mojo::ScopedMessagePipeHandle service_provider_handle
) {
993 service_registry_
.BindRemoteServiceProvider(service_provider_handle
.Pass());
996 void RenderFrameImpl::OnBeforeUnload() {
997 // TODO(creis): Right now, this is only called on the main frame. Make the
998 // browser process send dispatchBeforeUnloadEvent to every frame that needs
1000 CHECK(!frame_
->parent());
1002 base::TimeTicks before_unload_start_time
= base::TimeTicks::Now();
1003 bool proceed
= frame_
->dispatchBeforeUnloadEvent();
1004 base::TimeTicks before_unload_end_time
= base::TimeTicks::Now();
1005 Send(new FrameHostMsg_BeforeUnload_ACK(routing_id_
, proceed
,
1006 before_unload_start_time
,
1007 before_unload_end_time
));
1010 void RenderFrameImpl::OnSwapOut(int proxy_routing_id
) {
1011 RenderFrameProxy
* proxy
= NULL
;
1012 bool is_site_per_process
=
1013 CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess
);
1015 // Only run unload if we're not swapped out yet, but send the ack either way.
1016 if (!is_swapped_out_
|| !render_view_
->is_swapped_out_
) {
1017 // Swap this RenderFrame out so the frame can navigate to a page rendered by
1018 // a different process. This involves running the unload handler and
1019 // clearing the page. We also allow this process to exit if there are no
1020 // other active RenderFrames in it.
1022 // Send an UpdateState message before we get swapped out. Create the
1023 // RenderFrameProxy as well so its routing id is registered for receiving
1025 render_view_
->SyncNavigationState();
1026 proxy
= RenderFrameProxy::CreateProxyToReplaceFrame(this,
1029 // Synchronously run the unload handler before sending the ACK.
1030 // TODO(creis): Call dispatchUnloadEvent unconditionally here to support
1031 // unload on subframes as well.
1032 if (!frame_
->parent())
1033 frame_
->dispatchUnloadEvent();
1035 // Swap out and stop sending any IPC messages that are not ACKs.
1036 // TODO(nasko): Do we need RenderFrameImpl::is_swapped_out_ anymore?
1037 if (!frame_
->parent())
1038 render_view_
->SetSwappedOut(true);
1039 is_swapped_out_
= true;
1041 // Now that we're swapped out and filtering IPC messages, stop loading to
1042 // ensure that no other in-progress navigation continues. We do this here
1043 // to avoid sending a DidStopLoading message to the browser process.
1044 // TODO(creis): Should we be stopping all frames here and using
1045 // StopAltErrorPageFetcher with RenderView::OnStop, or just stopping this
1047 if (!frame_
->parent())
1048 render_view_
->OnStop();
1050 frame_
->stopLoading();
1052 // Let subframes know that the frame is now rendered remotely, for the
1053 // purposes of compositing and input events.
1054 if (frame_
->parent())
1055 frame_
->setIsRemote(true);
1057 // Replace the page with a blank dummy URL. The unload handler will not be
1058 // run a second time, thanks to a check in FrameLoader::stopLoading.
1059 // TODO(creis): Need to add a better way to do this that avoids running the
1060 // beforeunload handler. For now, we just run it a second time silently.
1061 if (!is_site_per_process
|| frame_
->parent() == NULL
)
1062 render_view_
->NavigateToSwappedOutURL(frame_
);
1064 // Let WebKit know that this view is hidden so it can drop resources and
1065 // stop compositing.
1066 // TODO(creis): Support this for subframes as well.
1067 if (!frame_
->parent()) {
1068 render_view_
->webview()->setVisibilityState(
1069 blink::WebPageVisibilityStateHidden
, false);
1073 // It is now safe to show modal dialogs again.
1074 // TODO(creis): Deal with modal dialogs from subframes.
1075 if (!frame_
->parent())
1076 render_view_
->suppress_dialogs_until_swap_out_
= false;
1078 Send(new FrameHostMsg_SwapOut_ACK(routing_id_
));
1080 // Now that all of the cleanup is complete and the browser side is notified,
1081 // start using the RenderFrameProxy, if one is created.
1083 if (frame_
->parent()) {
1084 frame_
->swap(proxy
->web_frame());
1085 if (is_site_per_process
) {
1086 // TODO(nasko): delete the frame here, since we've replaced it with a
1090 set_render_frame_proxy(proxy
);
1094 // Safe to exit if no one else is using the process.
1095 if (!frame_
->parent())
1096 render_view_
->WasSwappedOut();
1099 void RenderFrameImpl::OnContextMenuClosed(
1100 const CustomContextMenuContext
& custom_context
) {
1101 if (custom_context
.request_id
) {
1102 // External request, should be in our map.
1103 ContextMenuClient
* client
=
1104 pending_context_menus_
.Lookup(custom_context
.request_id
);
1106 client
->OnMenuClosed(custom_context
.request_id
);
1107 pending_context_menus_
.Remove(custom_context
.request_id
);
1110 if (custom_context
.link_followed
.is_valid()) {
1112 DomUtils::ExtractParentAnchorNode(context_menu_node_
),
1113 custom_context
.link_followed
);
1115 // Internal request, forward to WebKit.
1116 context_menu_node_
.reset();
1120 void RenderFrameImpl::OnCustomContextMenuAction(
1121 const CustomContextMenuContext
& custom_context
,
1123 if (custom_context
.request_id
) {
1124 // External context menu request, look in our map.
1125 ContextMenuClient
* client
=
1126 pending_context_menus_
.Lookup(custom_context
.request_id
);
1128 client
->OnMenuAction(custom_context
.request_id
, action
);
1130 // Internal request, forward to WebKit.
1131 render_view_
->webview()->performCustomContextMenuAction(action
);
1135 void RenderFrameImpl::OnUndo() {
1136 frame_
->executeCommand(WebString::fromUTF8("Undo"), GetFocusedElement());
1139 void RenderFrameImpl::OnRedo() {
1140 frame_
->executeCommand(WebString::fromUTF8("Redo"), GetFocusedElement());
1143 void RenderFrameImpl::OnCut() {
1144 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
1145 frame_
->executeCommand(WebString::fromUTF8("Cut"), GetFocusedElement());
1148 void RenderFrameImpl::OnCopy() {
1149 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
1150 WebNode current_node
= context_menu_node_
.isNull() ?
1151 GetFocusedElement() : context_menu_node_
;
1152 frame_
->executeCommand(WebString::fromUTF8("Copy"), current_node
);
1155 void RenderFrameImpl::OnPaste() {
1156 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
1157 frame_
->executeCommand(WebString::fromUTF8("Paste"), GetFocusedElement());
1160 void RenderFrameImpl::OnPasteAndMatchStyle() {
1161 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
1162 frame_
->executeCommand(
1163 WebString::fromUTF8("PasteAndMatchStyle"), GetFocusedElement());
1166 #if defined(OS_MACOSX)
1167 void RenderFrameImpl::OnCopyToFindPboard() {
1168 // Since the find pasteboard supports only plain text, this can be simpler
1169 // than the |OnCopy()| case.
1170 if (frame_
->hasSelection()) {
1171 base::string16 selection
= frame_
->selectionAsText();
1172 RenderThread::Get()->Send(
1173 new ClipboardHostMsg_FindPboardWriteStringAsync(selection
));
1178 void RenderFrameImpl::OnDelete() {
1179 frame_
->executeCommand(WebString::fromUTF8("Delete"), GetFocusedElement());
1182 void RenderFrameImpl::OnSelectAll() {
1183 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
1184 frame_
->executeCommand(WebString::fromUTF8("SelectAll"), GetFocusedElement());
1187 void RenderFrameImpl::OnSelectRange(const gfx::Point
& start
,
1188 const gfx::Point
& end
) {
1189 // This IPC is dispatched by RenderWidgetHost, so use its routing id.
1190 Send(new ViewHostMsg_SelectRange_ACK(GetRenderWidget()->routing_id()));
1192 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
1193 frame_
->selectRange(start
, end
);
1196 void RenderFrameImpl::OnUnselect() {
1197 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
1198 frame_
->executeCommand(WebString::fromUTF8("Unselect"), GetFocusedElement());
1201 void RenderFrameImpl::OnReplace(const base::string16
& text
) {
1202 if (!frame_
->hasSelection())
1203 frame_
->selectWordAroundCaret();
1205 frame_
->replaceSelection(text
);
1208 void RenderFrameImpl::OnReplaceMisspelling(const base::string16
& text
) {
1209 if (!frame_
->hasSelection())
1212 frame_
->replaceMisspelledRange(text
);
1215 void RenderFrameImpl::OnCSSInsertRequest(const std::string
& css
) {
1216 frame_
->document().insertStyleSheet(WebString::fromUTF8(css
));
1219 void RenderFrameImpl::OnJavaScriptExecuteRequest(
1220 const base::string16
& jscript
,
1222 bool notify_result
) {
1223 TRACE_EVENT_INSTANT0("test_tracing", "OnJavaScriptExecuteRequest",
1224 TRACE_EVENT_SCOPE_THREAD
);
1226 v8::HandleScope
handle_scope(v8::Isolate::GetCurrent());
1227 v8::Handle
<v8::Value
> result
=
1228 frame_
->executeScriptAndReturnValue(WebScriptSource(jscript
));
1229 if (notify_result
) {
1230 base::ListValue list
;
1231 if (!result
.IsEmpty()) {
1232 v8::Local
<v8::Context
> context
= frame_
->mainWorldScriptContext();
1233 v8::Context::Scope
context_scope(context
);
1234 V8ValueConverterImpl converter
;
1235 converter
.SetDateAllowed(true);
1236 converter
.SetRegExpAllowed(true);
1237 base::Value
* result_value
= converter
.FromV8Value(result
, context
);
1238 list
.Set(0, result_value
? result_value
: base::Value::CreateNullValue());
1240 list
.Set(0, base::Value::CreateNullValue());
1242 Send(new FrameHostMsg_JavaScriptExecuteResponse(routing_id_
, id
, list
));
1246 void RenderFrameImpl::OnSetEditableSelectionOffsets(int start
, int end
) {
1247 base::AutoReset
<bool> handling_select_range(&handling_select_range_
, true);
1248 if (!GetRenderWidget()->ShouldHandleImeEvent())
1250 ImeEventGuard
guard(GetRenderWidget());
1251 frame_
->setEditableSelectionOffsets(start
, end
);
1254 void RenderFrameImpl::OnSetCompositionFromExistingText(
1256 const std::vector
<blink::WebCompositionUnderline
>& underlines
) {
1257 if (!GetRenderWidget()->ShouldHandleImeEvent())
1259 ImeEventGuard
guard(GetRenderWidget());
1260 frame_
->setCompositionFromExistingText(start
, end
, underlines
);
1263 void RenderFrameImpl::OnExtendSelectionAndDelete(int before
, int after
) {
1264 if (!GetRenderWidget()->ShouldHandleImeEvent())
1266 ImeEventGuard
guard(GetRenderWidget());
1267 frame_
->extendSelectionAndDelete(before
, after
);
1270 void RenderFrameImpl::OnSetAccessibilityMode(AccessibilityMode new_mode
) {
1271 if (accessibility_mode_
== new_mode
)
1273 accessibility_mode_
= new_mode
;
1274 if (renderer_accessibility_
) {
1275 delete renderer_accessibility_
;
1276 renderer_accessibility_
= NULL
;
1278 if (accessibility_mode_
== AccessibilityModeOff
)
1281 if (accessibility_mode_
& AccessibilityModeFlagFullTree
)
1282 renderer_accessibility_
= new RendererAccessibilityComplete(this);
1283 #if !defined(OS_ANDROID)
1285 renderer_accessibility_
= new RendererAccessibilityFocusOnly(this);
1289 void RenderFrameImpl::OnDisownOpener() {
1290 // TODO(creis): We should only see this for main frames for now. To support
1291 // disowning the opener on subframes, we will need to move WebContentsImpl's
1292 // opener_ to FrameTreeNode.
1293 CHECK(!frame_
->parent());
1295 if (frame_
->opener())
1296 frame_
->setOpener(NULL
);
1299 #if defined(OS_ANDROID)
1300 void RenderFrameImpl::OnSelectPopupMenuItems(
1302 const std::vector
<int>& selected_indices
) {
1303 // It is possible to receive more than one of these calls if the user presses
1304 // a select faster than it takes for the show-select-popup IPC message to make
1305 // it to the browser UI thread. Ignore the extra-messages.
1306 // TODO(jcivelli): http:/b/5793321 Implement a better fix, as detailed in bug.
1307 if (!external_popup_menu_
)
1310 external_popup_menu_
->DidSelectItems(canceled
, selected_indices
);
1311 external_popup_menu_
.reset();
1315 #if defined(OS_MACOSX)
1316 void RenderFrameImpl::OnSelectPopupMenuItem(int selected_index
) {
1317 if (external_popup_menu_
== NULL
)
1319 external_popup_menu_
->DidSelectItem(selected_index
);
1320 external_popup_menu_
.reset();
1324 void RenderFrameImpl::OnReload(bool ignore_cache
) {
1325 frame_
->reload(ignore_cache
);
1328 void RenderFrameImpl::OnTextSurroundingSelectionRequest(size_t max_length
) {
1329 blink::WebSurroundingText surroundingText
;
1330 surroundingText
.initialize(frame_
->selectionRange(), max_length
);
1332 if (surroundingText
.isNull()) {
1333 // |surroundingText| might not be correctly initialized, for example if
1334 // |frame_->selectionRange().isNull()|, in other words, if there was no
1336 Send(new FrameHostMsg_TextSurroundingSelectionResponse(
1337 routing_id_
, base::string16(), 0, 0));
1341 Send(new FrameHostMsg_TextSurroundingSelectionResponse(
1343 surroundingText
.textContent(),
1344 surroundingText
.startOffsetInTextContent(),
1345 surroundingText
.endOffsetInTextContent()));
1348 void RenderFrameImpl::OnAddStyleSheetByURL(const std::string
& url
) {
1349 frame_
->addStyleSheetByURL(WebString::fromUTF8(url
));
1352 void RenderFrameImpl::OnSetupTransitionView(const std::string
& markup
) {
1353 frame_
->document().setIsTransitionDocument();
1354 frame_
->navigateToSandboxedMarkup(WebData(markup
.data(), markup
.length()));
1357 void RenderFrameImpl::OnBeginExitTransition(const std::string
& css_selector
) {
1358 frame_
->document().setIsTransitionDocument();
1359 frame_
->document().beginExitTransition(WebString::fromUTF8(css_selector
));
1362 bool RenderFrameImpl::ShouldUpdateSelectionTextFromContextMenuParams(
1363 const base::string16
& selection_text
,
1364 size_t selection_text_offset
,
1365 const gfx::Range
& selection_range
,
1366 const ContextMenuParams
& params
) {
1367 base::string16 trimmed_selection_text
;
1368 if (!selection_text
.empty() && !selection_range
.is_empty()) {
1369 const int start
= selection_range
.GetMin() - selection_text_offset
;
1370 const size_t length
= selection_range
.length();
1371 if (start
>= 0 && start
+ length
<= selection_text
.length()) {
1372 base::TrimWhitespace(selection_text
.substr(start
, length
), base::TRIM_ALL
,
1373 &trimmed_selection_text
);
1376 base::string16 trimmed_params_text
;
1377 base::TrimWhitespace(params
.selection_text
, base::TRIM_ALL
,
1378 &trimmed_params_text
);
1379 return trimmed_params_text
!= trimmed_selection_text
;
1382 bool RenderFrameImpl::RunJavaScriptMessage(JavaScriptMessageType type
,
1383 const base::string16
& message
,
1384 const base::string16
& default_value
,
1385 const GURL
& frame_url
,
1386 base::string16
* result
) {
1387 // Don't allow further dialogs if we are waiting to swap out, since the
1388 // PageGroupLoadDeferrer in our stack prevents it.
1389 if (render_view()->suppress_dialogs_until_swap_out_
)
1392 bool success
= false;
1393 base::string16 result_temp
;
1395 result
= &result_temp
;
1397 render_view()->SendAndRunNestedMessageLoop(
1398 new FrameHostMsg_RunJavaScriptMessage(
1399 routing_id_
, message
, default_value
, frame_url
, type
, &success
,
1404 void RenderFrameImpl::LoadNavigationErrorPage(
1405 const WebURLRequest
& failed_request
,
1406 const WebURLError
& error
,
1408 std::string error_html
;
1409 GetContentClient()->renderer()->GetNavigationErrorStrings(
1410 render_view(), frame_
, failed_request
, error
, &error_html
, NULL
);
1412 frame_
->loadHTMLString(error_html
,
1413 GURL(kUnreachableWebDataURL
),
1414 error
.unreachableURL
,
1418 void RenderFrameImpl::DidCommitCompositorFrame() {
1420 RenderFrameObserver
, observers_
, DidCommitCompositorFrame());
1423 RenderView
* RenderFrameImpl::GetRenderView() {
1424 return render_view_
.get();
1427 int RenderFrameImpl::GetRoutingID() {
1431 blink::WebFrame
* RenderFrameImpl::GetWebFrame() {
1436 WebPreferences
& RenderFrameImpl::GetWebkitPreferences() {
1437 return render_view_
->GetWebkitPreferences();
1440 int RenderFrameImpl::ShowContextMenu(ContextMenuClient
* client
,
1441 const ContextMenuParams
& params
) {
1442 DCHECK(client
); // A null client means "internal" when we issue callbacks.
1443 ContextMenuParams
our_params(params
);
1444 our_params
.custom_context
.request_id
= pending_context_menus_
.Add(client
);
1445 Send(new FrameHostMsg_ContextMenu(routing_id_
, our_params
));
1446 return our_params
.custom_context
.request_id
;
1449 void RenderFrameImpl::CancelContextMenu(int request_id
) {
1450 DCHECK(pending_context_menus_
.Lookup(request_id
));
1451 pending_context_menus_
.Remove(request_id
);
1454 blink::WebNode
RenderFrameImpl::GetContextMenuNode() const {
1455 return context_menu_node_
;
1458 blink::WebPlugin
* RenderFrameImpl::CreatePlugin(
1459 blink::WebFrame
* frame
,
1460 const WebPluginInfo
& info
,
1461 const blink::WebPluginParams
& params
) {
1462 DCHECK_EQ(frame_
, frame
);
1463 #if defined(ENABLE_PLUGINS)
1464 bool pepper_plugin_was_registered
= false;
1465 scoped_refptr
<PluginModule
> pepper_module(PluginModule::Create(
1466 this, info
, &pepper_plugin_was_registered
));
1467 if (pepper_plugin_was_registered
) {
1468 if (pepper_module
.get()) {
1469 return new PepperWebPluginImpl(pepper_module
.get(), params
, this);
1472 #if defined(OS_CHROMEOS)
1473 LOG(WARNING
) << "Pepper module/plugin creation failed.";
1476 // TODO(jam): change to take RenderFrame.
1477 return new WebPluginImpl(frame
, params
, info
.path
, render_view_
, this);
1484 void RenderFrameImpl::LoadURLExternally(blink::WebLocalFrame
* frame
,
1485 const blink::WebURLRequest
& request
,
1486 blink::WebNavigationPolicy policy
) {
1487 DCHECK(!frame_
|| frame_
== frame
);
1488 loadURLExternally(frame
, request
, policy
, WebString());
1491 void RenderFrameImpl::ExecuteJavaScript(const base::string16
& javascript
) {
1492 OnJavaScriptExecuteRequest(javascript
, 0, false);
1495 ServiceRegistry
* RenderFrameImpl::GetServiceRegistry() {
1496 return &service_registry_
;
1499 bool RenderFrameImpl::IsFTPDirectoryListing() {
1500 WebURLResponseExtraDataImpl
* extra_data
=
1501 GetExtraDataFromResponse(frame_
->dataSource()->response());
1502 return extra_data
? extra_data
->is_ftp_directory_listing() : false;
1505 void RenderFrameImpl::AttachGuest(int element_instance_id
) {
1506 render_view_
->GetBrowserPluginManager()->Attach(element_instance_id
);
1509 // blink::WebFrameClient implementation ----------------------------------------
1511 blink::WebPlugin
* RenderFrameImpl::createPlugin(
1512 blink::WebLocalFrame
* frame
,
1513 const blink::WebPluginParams
& params
) {
1514 DCHECK_EQ(frame_
, frame
);
1515 blink::WebPlugin
* plugin
= NULL
;
1516 if (GetContentClient()->renderer()->OverrideCreatePlugin(
1517 this, frame
, params
, &plugin
)) {
1521 if (base::UTF16ToUTF8(params
.mimeType
) == kBrowserPluginMimeType
) {
1522 return render_view_
->GetBrowserPluginManager()->CreateBrowserPlugin(
1523 render_view_
.get(), frame
, false);
1526 #if defined(ENABLE_PLUGINS)
1528 std::string mime_type
;
1530 Send(new FrameHostMsg_GetPluginInfo(
1531 routing_id_
, params
.url
, frame
->top()->document().url(),
1532 params
.mimeType
.utf8(), &found
, &info
, &mime_type
));
1536 if (info
.type
== content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN
) {
1537 return render_view_
->GetBrowserPluginManager()->CreateBrowserPlugin(
1538 render_view_
.get(), frame
, true);
1542 WebPluginParams params_to_use
= params
;
1543 params_to_use
.mimeType
= WebString::fromUTF8(mime_type
);
1544 return CreatePlugin(frame
, info
, params_to_use
);
1547 #endif // defined(ENABLE_PLUGINS)
1550 blink::WebMediaPlayer
* RenderFrameImpl::createMediaPlayer(
1551 blink::WebLocalFrame
* frame
,
1552 const blink::WebURL
& url
,
1553 blink::WebMediaPlayerClient
* client
) {
1554 #if defined(VIDEO_HOLE)
1555 if (!contains_media_player_
) {
1556 render_view_
->RegisterVideoHoleFrame(this);
1557 contains_media_player_
= true;
1559 #endif // defined(VIDEO_HOLE)
1561 blink::WebMediaStream
web_stream(
1562 blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url
));
1563 if (!web_stream
.isNull())
1564 return CreateWebMediaPlayerForMediaStream(url
, client
);
1566 #if defined(OS_ANDROID)
1567 return CreateAndroidWebMediaPlayer(url
, client
);
1569 WebMediaPlayerParams
params(
1570 base::Bind(&ContentRendererClient::DeferMediaLoad
,
1571 base::Unretained(GetContentClient()->renderer()),
1572 static_cast<RenderFrame
*>(this)),
1573 RenderThreadImpl::current()->GetAudioRendererMixerManager()->CreateInput(
1574 render_view_
->routing_id_
, routing_id_
));
1575 return new WebMediaPlayerImpl(frame
, client
, weak_factory_
.GetWeakPtr(),
1577 #endif // defined(OS_ANDROID)
1580 blink::WebContentDecryptionModule
*
1581 RenderFrameImpl::createContentDecryptionModule(
1582 blink::WebLocalFrame
* frame
,
1583 const blink::WebSecurityOrigin
& security_origin
,
1584 const blink::WebString
& key_system
) {
1585 DCHECK(!frame_
|| frame_
== frame
);
1586 return WebContentDecryptionModuleImpl::Create(
1587 #if defined(ENABLE_PEPPER_CDMS)
1589 #elif defined(ENABLE_BROWSER_CDMS)
1596 blink::WebApplicationCacheHost
* RenderFrameImpl::createApplicationCacheHost(
1597 blink::WebLocalFrame
* frame
,
1598 blink::WebApplicationCacheHostClient
* client
) {
1599 if (!frame
|| !frame
->view())
1601 DCHECK(!frame_
|| frame_
== frame
);
1602 return new RendererWebApplicationCacheHostImpl(
1603 RenderViewImpl::FromWebView(frame
->view()), client
,
1604 RenderThreadImpl::current()->appcache_dispatcher()->backend_proxy());
1607 blink::WebWorkerPermissionClientProxy
*
1608 RenderFrameImpl::createWorkerPermissionClientProxy(
1609 blink::WebLocalFrame
* frame
) {
1610 if (!frame
|| !frame
->view())
1612 DCHECK(!frame_
|| frame_
== frame
);
1613 return GetContentClient()->renderer()->CreateWorkerPermissionClientProxy(
1617 WebExternalPopupMenu
* RenderFrameImpl::createExternalPopupMenu(
1618 const WebPopupMenuInfo
& popup_menu_info
,
1619 WebExternalPopupMenuClient
* popup_menu_client
) {
1620 #if defined(OS_MACOSX) || defined(OS_ANDROID)
1621 // An IPC message is sent to the browser to build and display the actual
1622 // popup. The user could have time to click a different select by the time
1623 // the popup is shown. In that case external_popup_menu_ is non NULL.
1624 // By returning NULL in that case, we instruct Blink to cancel that new
1625 // popup. So from the user perspective, only the first one will show, and
1626 // will have to close the first one before another one can be shown.
1627 if (external_popup_menu_
)
1629 external_popup_menu_
.reset(
1630 new ExternalPopupMenu(this, popup_menu_info
, popup_menu_client
));
1631 if (render_view_
->screen_metrics_emulator_
) {
1632 render_view_
->SetExternalPopupOriginAdjustmentsForEmulation(
1633 external_popup_menu_
.get(),
1634 render_view_
->screen_metrics_emulator_
.get());
1636 return external_popup_menu_
.get();
1642 blink::WebCookieJar
* RenderFrameImpl::cookieJar(blink::WebLocalFrame
* frame
) {
1643 DCHECK(!frame_
|| frame_
== frame
);
1644 return &cookie_jar_
;
1647 blink::WebServiceWorkerProvider
* RenderFrameImpl::createServiceWorkerProvider(
1648 blink::WebLocalFrame
* frame
) {
1649 DCHECK(!frame_
|| frame_
== frame
);
1650 // At this point we should have non-null data source.
1651 DCHECK(frame
->dataSource());
1652 if (!ChildThread::current())
1653 return NULL
; // May be null in some tests.
1654 ServiceWorkerNetworkProvider
* provider
=
1655 ServiceWorkerNetworkProvider::FromDocumentState(
1656 DocumentState::FromDataSource(frame
->dataSource()));
1657 return new WebServiceWorkerProviderImpl(
1658 ChildThread::current()->thread_safe_sender(),
1659 provider
? provider
->context() : NULL
);
1662 void RenderFrameImpl::didAccessInitialDocument(blink::WebLocalFrame
* frame
) {
1663 DCHECK(!frame_
|| frame_
== frame
);
1664 // Notify the browser process that it is no longer safe to show the pending
1665 // URL of the main frame, since a URL spoof is now possible.
1666 if (!frame
->parent() && render_view_
->page_id_
== -1)
1667 Send(new FrameHostMsg_DidAccessInitialDocument(routing_id_
));
1670 blink::WebFrame
* RenderFrameImpl::createChildFrame(
1671 blink::WebLocalFrame
* parent
,
1672 const blink::WebString
& name
) {
1673 // Synchronously notify the browser of a child frame creation to get the
1674 // routing_id for the RenderFrame.
1675 int child_routing_id
= MSG_ROUTING_NONE
;
1676 Send(new FrameHostMsg_CreateChildFrame(routing_id_
,
1677 base::UTF16ToUTF8(name
),
1678 &child_routing_id
));
1679 // Allocation of routing id failed, so we can't create a child frame. This can
1680 // happen if this RenderFrameImpl's IPCs are being filtered when in swapped
1682 if (child_routing_id
== MSG_ROUTING_NONE
) {
1683 #if !defined(OS_LINUX)
1684 // DumpWithoutCrashing() crashes on Linux in renderer processes when
1685 // breakpad and sandboxing are enabled: crbug.com/349600
1686 base::debug::Alias(parent
);
1687 base::debug::Alias(&routing_id_
);
1688 bool render_view_is_swapped_out
= GetRenderWidget()->is_swapped_out();
1689 base::debug::Alias(&render_view_is_swapped_out
);
1690 bool render_view_is_closing
= GetRenderWidget()->closing();
1691 base::debug::Alias(&render_view_is_closing
);
1692 base::debug::Alias(&is_swapped_out_
);
1693 base::debug::DumpWithoutCrashing();
1698 // Create the RenderFrame and WebLocalFrame, linking the two.
1699 RenderFrameImpl
* child_render_frame
= RenderFrameImpl::Create(
1700 render_view_
.get(), child_routing_id
);
1701 blink::WebLocalFrame
* web_frame
= WebLocalFrame::create(child_render_frame
);
1702 child_render_frame
->SetWebFrame(web_frame
);
1704 // Add the frame to the frame tree and initialize it.
1705 parent
->appendChild(web_frame
);
1706 child_render_frame
->Initialize();
1711 void RenderFrameImpl::didDisownOpener(blink::WebLocalFrame
* frame
) {
1712 DCHECK(!frame_
|| frame_
== frame
);
1713 // We only need to notify the browser if the active, top-level frame clears
1714 // its opener. We can ignore cases where a swapped out frame clears its
1715 // opener after hearing about it from the browser, and the browser does not
1716 // (yet) care about subframe openers.
1717 if (render_view_
->is_swapped_out_
|| frame
->parent())
1720 // Notify WebContents and all its swapped out RenderViews.
1721 Send(new FrameHostMsg_DidDisownOpener(routing_id_
));
1724 void RenderFrameImpl::frameDetached(blink::WebFrame
* frame
) {
1725 // NOTE: This function is called on the frame that is being detached and not
1726 // the parent frame. This is different from createChildFrame() which is
1727 // called on the parent frame.
1728 CHECK(!is_detaching_
);
1729 DCHECK(!frame_
|| frame_
== frame
);
1731 bool is_subframe
= !!frame
->parent();
1733 Send(new FrameHostMsg_Detach(routing_id_
));
1735 // The |is_detaching_| flag disables Send(). FrameHostMsg_Detach must be
1736 // sent before setting |is_detaching_| to true. In contrast, Observers
1737 // should only be notified afterwards so they cannot call back into here and
1738 // have IPCs fired off.
1739 is_detaching_
= true;
1741 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1742 FrameDetached(frame
));
1744 // We need to clean up subframes by removing them from the map and deleting
1745 // the RenderFrameImpl. In contrast, the main frame is owned by its
1746 // containing RenderViewHost (so that they have the same lifetime), so only
1747 // removal from the map is needed and no deletion.
1748 FrameMap::iterator it
= g_frame_map
.Get().find(frame
);
1749 CHECK(it
!= g_frame_map
.Get().end());
1750 CHECK_EQ(it
->second
, this);
1751 g_frame_map
.Get().erase(it
);
1754 frame
->parent()->removeChild(frame
);
1756 // |frame| is invalid after here.
1761 // Object is invalid after this point.
1765 void RenderFrameImpl::frameFocused() {
1766 Send(new FrameHostMsg_FrameFocused(routing_id_
));
1769 void RenderFrameImpl::willClose(blink::WebFrame
* frame
) {
1770 DCHECK(!frame_
|| frame_
== frame
);
1772 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, FrameWillClose());
1773 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1774 FrameWillClose(frame
));
1777 void RenderFrameImpl::didChangeName(blink::WebLocalFrame
* frame
,
1778 const blink::WebString
& name
) {
1779 DCHECK(!frame_
|| frame_
== frame
);
1780 if (!render_view_
->renderer_preferences_
.report_frame_name_changes
)
1783 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, DidChangeName(name
));
1786 void RenderFrameImpl::didMatchCSS(
1787 blink::WebLocalFrame
* frame
,
1788 const blink::WebVector
<blink::WebString
>& newly_matching_selectors
,
1789 const blink::WebVector
<blink::WebString
>& stopped_matching_selectors
) {
1790 DCHECK(!frame_
|| frame_
== frame
);
1792 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1794 newly_matching_selectors
,
1795 stopped_matching_selectors
));
1798 bool RenderFrameImpl::shouldReportDetailedMessageForSource(
1799 const blink::WebString
& source
) {
1800 return GetContentClient()->renderer()->ShouldReportDetailedMessageForSource(
1804 void RenderFrameImpl::didAddMessageToConsole(
1805 const blink::WebConsoleMessage
& message
,
1806 const blink::WebString
& source_name
,
1807 unsigned source_line
,
1808 const blink::WebString
& stack_trace
) {
1809 logging::LogSeverity log_severity
= logging::LOG_VERBOSE
;
1810 switch (message
.level
) {
1811 case blink::WebConsoleMessage::LevelDebug
:
1812 log_severity
= logging::LOG_VERBOSE
;
1814 case blink::WebConsoleMessage::LevelLog
:
1815 case blink::WebConsoleMessage::LevelInfo
:
1816 log_severity
= logging::LOG_INFO
;
1818 case blink::WebConsoleMessage::LevelWarning
:
1819 log_severity
= logging::LOG_WARNING
;
1821 case blink::WebConsoleMessage::LevelError
:
1822 log_severity
= logging::LOG_ERROR
;
1828 if (shouldReportDetailedMessageForSource(source_name
)) {
1830 RenderFrameObserver
, observers_
,
1831 DetailedConsoleMessageAdded(message
.text
,
1835 static_cast<int32
>(log_severity
)));
1838 Send(new FrameHostMsg_AddMessageToConsole(routing_id_
,
1839 static_cast<int32
>(log_severity
),
1841 static_cast<int32
>(source_line
),
1845 void RenderFrameImpl::loadURLExternally(
1846 blink::WebLocalFrame
* frame
,
1847 const blink::WebURLRequest
& request
,
1848 blink::WebNavigationPolicy policy
,
1849 const blink::WebString
& suggested_name
) {
1850 DCHECK(!frame_
|| frame_
== frame
);
1851 Referrer
referrer(RenderViewImpl::GetReferrerFromRequest(frame
, request
));
1852 if (policy
== blink::WebNavigationPolicyDownload
) {
1853 render_view_
->Send(new ViewHostMsg_DownloadUrl(render_view_
->GetRoutingID(),
1854 request
.url(), referrer
,
1855 suggested_name
, false));
1856 } else if (policy
== blink::WebNavigationPolicyDownloadTo
) {
1857 render_view_
->Send(new ViewHostMsg_DownloadUrl(render_view_
->GetRoutingID(),
1858 request
.url(), referrer
,
1859 suggested_name
, true));
1861 OpenURL(frame
, request
.url(), referrer
, policy
);
1865 blink::WebNavigationPolicy
RenderFrameImpl::decidePolicyForNavigation(
1866 const NavigationPolicyInfo
& info
) {
1867 DCHECK(!frame_
|| frame_
== info
.frame
);
1868 return DecidePolicyForNavigation(this, info
);
1871 blink::WebHistoryItem
RenderFrameImpl::historyItemForNewChildFrame(
1872 blink::WebFrame
* frame
) {
1873 DCHECK(!frame_
|| frame_
== frame
);
1874 return render_view_
->history_controller()->GetItemForNewChildFrame(this);
1877 void RenderFrameImpl::willSendSubmitEvent(blink::WebLocalFrame
* frame
,
1878 const blink::WebFormElement
& form
) {
1879 DCHECK(!frame_
|| frame_
== frame
);
1881 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1882 WillSendSubmitEvent(frame
, form
));
1885 void RenderFrameImpl::willSubmitForm(blink::WebLocalFrame
* frame
,
1886 const blink::WebFormElement
& form
) {
1887 DCHECK(!frame_
|| frame_
== frame
);
1888 DocumentState
* document_state
=
1889 DocumentState::FromDataSource(frame
->provisionalDataSource());
1890 NavigationState
* navigation_state
= document_state
->navigation_state();
1891 InternalDocumentStateData
* internal_data
=
1892 InternalDocumentStateData::FromDocumentState(document_state
);
1894 if (PageTransitionCoreTypeIs(navigation_state
->transition_type(),
1895 PAGE_TRANSITION_LINK
)) {
1896 navigation_state
->set_transition_type(PAGE_TRANSITION_FORM_SUBMIT
);
1899 // Save these to be processed when the ensuing navigation is committed.
1900 WebSearchableFormData
web_searchable_form_data(form
);
1901 internal_data
->set_searchable_form_url(web_searchable_form_data
.url());
1902 internal_data
->set_searchable_form_encoding(
1903 web_searchable_form_data
.encoding().utf8());
1905 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1906 WillSubmitForm(frame
, form
));
1909 void RenderFrameImpl::didCreateDataSource(blink::WebLocalFrame
* frame
,
1910 blink::WebDataSource
* datasource
) {
1911 DCHECK(!frame_
|| frame_
== frame
);
1913 // TODO(nasko): Move implementation here. Needed state:
1914 // * pending_navigation_params_
1917 // * PopulateDocumentStateFromPending
1918 // * CreateNavigationStateFromPending
1919 render_view_
->didCreateDataSource(frame
, datasource
);
1921 // Create the serviceworker's per-document network observing object.
1922 scoped_ptr
<ServiceWorkerNetworkProvider
>
1923 network_provider(new ServiceWorkerNetworkProvider());
1924 ServiceWorkerNetworkProvider::AttachToDocumentState(
1925 DocumentState::FromDataSource(datasource
),
1926 network_provider
.Pass());
1929 void RenderFrameImpl::didStartProvisionalLoad(blink::WebLocalFrame
* frame
,
1930 bool is_transition_navigation
) {
1931 DCHECK(!frame_
|| frame_
== frame
);
1932 WebDataSource
* ds
= frame
->provisionalDataSource();
1934 // In fast/loader/stop-provisional-loads.html, we abort the load before this
1935 // callback is invoked.
1939 DocumentState
* document_state
= DocumentState::FromDataSource(ds
);
1941 // We should only navigate to swappedout:// when is_swapped_out_ is true.
1942 CHECK((ds
->request().url() != GURL(kSwappedOutURL
)) ||
1944 render_view_
->is_swapped_out()) <<
1945 "Heard swappedout:// when not swapped out.";
1947 // Update the request time if WebKit has better knowledge of it.
1948 if (document_state
->request_time().is_null()) {
1949 double event_time
= ds
->triggeringEventTime();
1950 if (event_time
!= 0.0)
1951 document_state
->set_request_time(Time::FromDoubleT(event_time
));
1954 // Start time is only set after request time.
1955 document_state
->set_start_load_time(Time::Now());
1957 bool is_top_most
= !frame
->parent();
1959 render_view_
->set_navigation_gesture(
1960 WebUserGestureIndicator::isProcessingUserGesture() ?
1961 NavigationGestureUser
: NavigationGestureAuto
);
1962 } else if (ds
->replacesCurrentHistoryItem()) {
1963 // Subframe navigations that don't add session history items must be
1964 // marked with AUTO_SUBFRAME. See also didFailProvisionalLoad for how we
1965 // handle loading of error pages.
1966 document_state
->navigation_state()->set_transition_type(
1967 PAGE_TRANSITION_AUTO_SUBFRAME
);
1970 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
1971 DidStartProvisionalLoad(frame
));
1972 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, DidStartProvisionalLoad());
1974 Send(new FrameHostMsg_DidStartProvisionalLoadForFrame(
1975 routing_id_
, ds
->request().url(), is_transition_navigation
));
1978 void RenderFrameImpl::didReceiveServerRedirectForProvisionalLoad(
1979 blink::WebLocalFrame
* frame
) {
1980 DCHECK(!frame_
|| frame_
== frame
);
1981 render_view_
->history_controller()->RemoveChildrenForRedirect(this);
1982 if (frame
->parent())
1984 // Received a redirect on the main frame.
1985 WebDataSource
* data_source
= frame
->provisionalDataSource();
1987 // Should only be invoked when we have a data source.
1991 std::vector
<GURL
> redirects
;
1992 GetRedirectChain(data_source
, &redirects
);
1993 if (redirects
.size() >= 2) {
1994 Send(new FrameHostMsg_DidRedirectProvisionalLoad(
1996 render_view_
->page_id_
,
1997 redirects
[redirects
.size() - 2],
2002 void RenderFrameImpl::didFailProvisionalLoad(blink::WebLocalFrame
* frame
,
2003 const blink::WebURLError
& error
) {
2004 DCHECK(!frame_
|| frame_
== frame
);
2005 WebDataSource
* ds
= frame
->provisionalDataSource();
2008 const WebURLRequest
& failed_request
= ds
->request();
2010 // Notify the browser that we failed a provisional load with an error.
2012 // Note: It is important this notification occur before DidStopLoading so the
2013 // SSL manager can react to the provisional load failure before being
2014 // notified the load stopped.
2016 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
2017 DidFailProvisionalLoad(frame
, error
));
2018 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
,
2019 DidFailProvisionalLoad(error
));
2021 bool show_repost_interstitial
=
2022 (error
.reason
== net::ERR_CACHE_MISS
&&
2023 EqualsASCII(failed_request
.httpMethod(), "POST"));
2025 FrameHostMsg_DidFailProvisionalLoadWithError_Params params
;
2026 params
.error_code
= error
.reason
;
2027 GetContentClient()->renderer()->GetNavigationErrorStrings(
2033 ¶ms
.error_description
);
2034 params
.url
= error
.unreachableURL
;
2035 params
.showing_repost_interstitial
= show_repost_interstitial
;
2036 Send(new FrameHostMsg_DidFailProvisionalLoadWithError(
2037 routing_id_
, params
));
2039 // Don't display an error page if this is simply a cancelled load. Aside
2040 // from being dumb, WebCore doesn't expect it and it will cause a crash.
2041 if (error
.reason
== net::ERR_ABORTED
)
2044 // Don't display "client blocked" error page if browser has asked us not to.
2045 if (error
.reason
== net::ERR_BLOCKED_BY_CLIENT
&&
2046 render_view_
->renderer_preferences_
.disable_client_blocked_error_page
) {
2050 // Allow the embedder to suppress an error page.
2051 if (GetContentClient()->renderer()->ShouldSuppressErrorPage(this,
2052 error
.unreachableURL
)) {
2056 if (RenderThreadImpl::current() &&
2057 RenderThreadImpl::current()->layout_test_mode()) {
2061 // Make sure we never show errors in view source mode.
2062 frame
->enableViewSourceMode(false);
2064 DocumentState
* document_state
= DocumentState::FromDataSource(ds
);
2065 NavigationState
* navigation_state
= document_state
->navigation_state();
2067 // If this is a failed back/forward/reload navigation, then we need to do a
2068 // 'replace' load. This is necessary to avoid messing up session history.
2069 // Otherwise, we do a normal load, which simulates a 'go' navigation as far
2070 // as session history is concerned.
2072 // AUTO_SUBFRAME loads should always be treated as loads that do not advance
2075 // TODO(davidben): This should also take the failed navigation's replacement
2076 // state into account, if a location.replace() failed.
2078 navigation_state
->pending_page_id() != -1 ||
2079 PageTransitionCoreTypeIs(navigation_state
->transition_type(),
2080 PAGE_TRANSITION_AUTO_SUBFRAME
);
2082 // If we failed on a browser initiated request, then make sure that our error
2083 // page load is regarded as the same browser initiated request.
2084 if (!navigation_state
->is_content_initiated()) {
2085 render_view_
->pending_navigation_params_
.reset(
2086 new FrameMsg_Navigate_Params
);
2087 render_view_
->pending_navigation_params_
->page_id
=
2088 navigation_state
->pending_page_id();
2089 render_view_
->pending_navigation_params_
->pending_history_list_offset
=
2090 navigation_state
->pending_history_list_offset();
2091 render_view_
->pending_navigation_params_
->should_clear_history_list
=
2092 navigation_state
->history_list_was_cleared();
2093 render_view_
->pending_navigation_params_
->transition
=
2094 navigation_state
->transition_type();
2095 render_view_
->pending_navigation_params_
->request_time
=
2096 document_state
->request_time();
2097 render_view_
->pending_navigation_params_
->should_replace_current_entry
=
2101 // Load an error page.
2102 LoadNavigationErrorPage(failed_request
, error
, replace
);
2105 void RenderFrameImpl::didCommitProvisionalLoad(
2106 blink::WebLocalFrame
* frame
,
2107 const blink::WebHistoryItem
& item
,
2108 blink::WebHistoryCommitType commit_type
) {
2109 DCHECK(!frame_
|| frame_
== frame
);
2110 DocumentState
* document_state
=
2111 DocumentState::FromDataSource(frame
->dataSource());
2112 NavigationState
* navigation_state
= document_state
->navigation_state();
2114 // When we perform a new navigation, we need to update the last committed
2115 // session history entry with state for the page we are leaving. Do this
2116 // before updating the HistoryController state.
2117 render_view_
->UpdateSessionHistory(frame
);
2119 render_view_
->history_controller()->UpdateForCommit(this, item
, commit_type
,
2120 navigation_state
->was_within_same_page());
2122 InternalDocumentStateData
* internal_data
=
2123 InternalDocumentStateData::FromDocumentState(document_state
);
2125 if (document_state
->commit_load_time().is_null())
2126 document_state
->set_commit_load_time(Time::Now());
2128 if (internal_data
->must_reset_scroll_and_scale_state()) {
2129 render_view_
->webview()->resetScrollAndScaleState();
2130 internal_data
->set_must_reset_scroll_and_scale_state(false);
2132 internal_data
->set_use_error_page(false);
2134 bool is_new_navigation
= commit_type
== blink::WebStandardCommit
;
2135 if (is_new_navigation
) {
2136 // We bump our Page ID to correspond with the new session history entry.
2137 render_view_
->page_id_
= render_view_
->next_page_id_
++;
2139 // Don't update history_page_ids_ (etc) for kSwappedOutURL, since
2140 // we don't want to forget the entry that was there, and since we will
2141 // never come back to kSwappedOutURL. Note that we have to call
2142 // UpdateSessionHistory and update page_id_ even in this case, so that
2143 // the current entry gets a state update and so that we don't send a
2144 // state update to the wrong entry when we swap back in.
2145 if (GetLoadingUrl() != GURL(kSwappedOutURL
)) {
2146 // Advance our offset in session history, applying the length limit.
2147 // There is now no forward history.
2148 render_view_
->history_list_offset_
++;
2149 if (render_view_
->history_list_offset_
>= kMaxSessionHistoryEntries
)
2150 render_view_
->history_list_offset_
= kMaxSessionHistoryEntries
- 1;
2151 render_view_
->history_list_length_
=
2152 render_view_
->history_list_offset_
+ 1;
2153 render_view_
->history_page_ids_
.resize(
2154 render_view_
->history_list_length_
, -1);
2155 render_view_
->history_page_ids_
[render_view_
->history_list_offset_
] =
2156 render_view_
->page_id_
;
2159 // Inspect the navigation_state on this frame to see if the navigation
2160 // corresponds to a session history navigation... Note: |frame| may or
2161 // may not be the toplevel frame, but for the case of capturing session
2162 // history, the first committed frame suffices. We keep track of whether
2163 // we've seen this commit before so that only capture session history once
2166 // Note that we need to check if the page ID changed. In the case of a
2167 // reload, the page ID doesn't change, and UpdateSessionHistory gets the
2168 // previous URL and the current page ID, which would be wrong.
2169 if (navigation_state
->pending_page_id() != -1 &&
2170 navigation_state
->pending_page_id() != render_view_
->page_id_
&&
2171 !navigation_state
->request_committed()) {
2172 // This is a successful session history navigation!
2173 render_view_
->page_id_
= navigation_state
->pending_page_id();
2175 render_view_
->history_list_offset_
=
2176 navigation_state
->pending_history_list_offset();
2178 // If the history list is valid, our list of page IDs should be correct.
2179 DCHECK(render_view_
->history_list_length_
<= 0 ||
2180 render_view_
->history_list_offset_
< 0 ||
2181 render_view_
->history_list_offset_
>=
2182 render_view_
->history_list_length_
||
2183 render_view_
->history_page_ids_
[render_view_
->history_list_offset_
]
2184 == render_view_
->page_id_
);
2188 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers_
,
2189 DidCommitProvisionalLoad(frame
, is_new_navigation
));
2190 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
,
2191 DidCommitProvisionalLoad(is_new_navigation
));
2193 if (!frame
->parent()) { // Only for top frames.
2194 RenderThreadImpl
* render_thread_impl
= RenderThreadImpl::current();
2195 if (render_thread_impl
) { // Can be NULL in tests.
2196 render_thread_impl
->histogram_customizer()->
2197 RenderViewNavigatedToHost(GURL(GetLoadingUrl()).host(),
2198 RenderViewImpl::GetRenderViewCount());
2202 // Remember that we've already processed this request, so we don't update
2203 // the session history again. We do this regardless of whether this is
2204 // a session history navigation, because if we attempted a session history
2205 // navigation without valid HistoryItem state, WebCore will think it is a
2207 navigation_state
->set_request_committed(true);
2209 SendDidCommitProvisionalLoad(frame
);
2211 // Check whether we have new encoding name.
2212 UpdateEncoding(frame
, frame
->view()->pageEncoding().utf8());
2215 void RenderFrameImpl::didClearWindowObject(blink::WebLocalFrame
* frame
) {
2216 DCHECK(!frame_
|| frame_
== frame
);
2217 // TODO(nasko): Move implementation here. Needed state:
2218 // * enabled_bindings_
2219 // * dom_automation_controller_
2220 // * stats_collection_controller_
2222 render_view_
->didClearWindowObject(frame
);
2224 if (render_view_
->GetEnabledBindings() & BINDINGS_POLICY_DOM_AUTOMATION
)
2225 DomAutomationController::Install(this, frame
);
2227 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, DidClearWindowObject());
2230 void RenderFrameImpl::didCreateDocumentElement(blink::WebLocalFrame
* frame
) {
2231 DCHECK(!frame_
|| frame_
== frame
);
2233 // Notify the browser about non-blank documents loading in the top frame.
2234 GURL url
= frame
->document().url();
2235 if (url
.is_valid() && url
.spec() != url::kAboutBlankURL
) {
2236 // TODO(nasko): Check if webview()->mainFrame() is the same as the
2237 // frame->tree()->top().
2238 blink::WebFrame
* main_frame
= render_view_
->webview()->mainFrame();
2239 if (frame
== main_frame
) {
2240 // For now, don't remember plugin zoom values. We don't want to mix them
2241 // with normal web content (i.e. a fixed layout plugin would usually want
2243 render_view_
->Send(new ViewHostMsg_DocumentAvailableInMainFrame(
2244 render_view_
->GetRoutingID(),
2245 main_frame
->document().isPluginDocument()));
2249 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
2250 DidCreateDocumentElement(frame
));
2253 void RenderFrameImpl::didReceiveTitle(blink::WebLocalFrame
* frame
,
2254 const blink::WebString
& title
,
2255 blink::WebTextDirection direction
) {
2256 DCHECK(!frame_
|| frame_
== frame
);
2257 // Ignore all but top level navigations.
2258 if (!frame
->parent()) {
2259 base::string16 title16
= title
;
2260 base::debug::TraceLog::GetInstance()->UpdateProcessLabel(
2261 routing_id_
, base::UTF16ToUTF8(title16
));
2263 base::string16 shortened_title
= title16
.substr(0, kMaxTitleChars
);
2264 Send(new FrameHostMsg_UpdateTitle(routing_id_
,
2265 render_view_
->page_id_
,
2266 shortened_title
, direction
));
2269 // Also check whether we have new encoding name.
2270 UpdateEncoding(frame
, frame
->view()->pageEncoding().utf8());
2273 void RenderFrameImpl::didChangeIcon(blink::WebLocalFrame
* frame
,
2274 blink::WebIconURL::Type icon_type
) {
2275 DCHECK(!frame_
|| frame_
== frame
);
2276 // TODO(nasko): Investigate wheather implementation should move here.
2277 render_view_
->didChangeIcon(frame
, icon_type
);
2280 void RenderFrameImpl::didFinishDocumentLoad(blink::WebLocalFrame
* frame
) {
2281 DCHECK(!frame_
|| frame_
== frame
);
2282 WebDataSource
* ds
= frame
->dataSource();
2283 DocumentState
* document_state
= DocumentState::FromDataSource(ds
);
2284 document_state
->set_finish_document_load_time(Time::Now());
2286 Send(new FrameHostMsg_DidFinishDocumentLoad(routing_id_
));
2288 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
2289 DidFinishDocumentLoad(frame
));
2290 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, DidFinishDocumentLoad());
2292 // Check whether we have new encoding name.
2293 UpdateEncoding(frame
, frame
->view()->pageEncoding().utf8());
2296 void RenderFrameImpl::didHandleOnloadEvents(blink::WebLocalFrame
* frame
) {
2297 DCHECK(!frame_
|| frame_
== frame
);
2298 if (!frame
->parent())
2299 Send(new FrameHostMsg_DocumentOnLoadCompleted(routing_id_
));
2302 void RenderFrameImpl::didFailLoad(blink::WebLocalFrame
* frame
,
2303 const blink::WebURLError
& error
) {
2304 DCHECK(!frame_
|| frame_
== frame
);
2305 // TODO(nasko): Move implementation here. No state needed.
2306 WebDataSource
* ds
= frame
->dataSource();
2309 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
2310 DidFailLoad(frame
, error
));
2312 const WebURLRequest
& failed_request
= ds
->request();
2313 base::string16 error_description
;
2314 GetContentClient()->renderer()->GetNavigationErrorStrings(
2320 &error_description
);
2321 Send(new FrameHostMsg_DidFailLoadWithError(routing_id_
,
2322 failed_request
.url(),
2324 error_description
));
2327 void RenderFrameImpl::didFinishLoad(blink::WebLocalFrame
* frame
) {
2328 DCHECK(!frame_
|| frame_
== frame
);
2329 WebDataSource
* ds
= frame
->dataSource();
2330 DocumentState
* document_state
= DocumentState::FromDataSource(ds
);
2331 if (document_state
->finish_load_time().is_null()) {
2332 if (!frame
->parent()) {
2333 TRACE_EVENT_INSTANT0("WebCore", "LoadFinished",
2334 TRACE_EVENT_SCOPE_PROCESS
);
2336 document_state
->set_finish_load_time(Time::Now());
2339 FOR_EACH_OBSERVER(RenderViewObserver
, render_view_
->observers(),
2340 DidFinishLoad(frame
));
2341 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, DidFinishLoad());
2343 // Don't send this message while the frame is swapped out.
2344 if (is_swapped_out())
2347 Send(new FrameHostMsg_DidFinishLoad(routing_id_
,
2348 ds
->request().url()));
2351 void RenderFrameImpl::didNavigateWithinPage(blink::WebLocalFrame
* frame
,
2352 const blink::WebHistoryItem
& item
,
2353 blink::WebHistoryCommitType commit_type
) {
2354 DCHECK(!frame_
|| frame_
== frame
);
2355 // If this was a reference fragment navigation that we initiated, then we
2356 // could end up having a non-null pending navigation params. We just need to
2357 // update the ExtraData on the datasource so that others who read the
2358 // ExtraData will get the new NavigationState. Similarly, if we did not
2359 // initiate this navigation, then we need to take care to reset any pre-
2360 // existing navigation state to a content-initiated navigation state.
2361 // DidCreateDataSource conveniently takes care of this for us.
2362 didCreateDataSource(frame
, frame
->dataSource());
2364 DocumentState
* document_state
=
2365 DocumentState::FromDataSource(frame
->dataSource());
2366 NavigationState
* new_state
= document_state
->navigation_state();
2367 new_state
->set_was_within_same_page(true);
2369 didCommitProvisionalLoad(frame
, item
, commit_type
);
2372 void RenderFrameImpl::didUpdateCurrentHistoryItem(blink::WebLocalFrame
* frame
) {
2373 DCHECK(!frame_
|| frame_
== frame
);
2374 // TODO(nasko): Move implementation here. Needed methods:
2375 // * StartNavStateSyncTimerIfNecessary
2376 render_view_
->didUpdateCurrentHistoryItem(frame
);
2379 void RenderFrameImpl::addNavigationTransitionData(
2380 const blink::WebString
& allowed_destination_host_pattern
,
2381 const blink::WebString
& selector
,
2382 const blink::WebString
& markup
) {
2383 Send(new FrameHostMsg_AddNavigationTransitionData(
2384 routing_id_
, allowed_destination_host_pattern
.utf8(), selector
.utf8(),
2388 void RenderFrameImpl::didChangeThemeColor() {
2389 if (frame_
->parent())
2392 Send(new FrameHostMsg_DidChangeThemeColor(
2393 routing_id_
, frame_
->document().themeColor()));
2396 void RenderFrameImpl::requestNotificationPermission(
2397 const blink::WebSecurityOrigin
& origin
,
2398 blink::WebNotificationPermissionCallback
* callback
) {
2399 if (!notification_permission_dispatcher_
) {
2400 notification_permission_dispatcher_
=
2401 new NotificationPermissionDispatcher(this);
2404 notification_permission_dispatcher_
->RequestPermission(origin
, callback
);
2407 blink::WebNotificationPresenter
* RenderFrameImpl::notificationPresenter() {
2408 return notification_provider_
;
2411 void RenderFrameImpl::didChangeSelection(bool is_empty_selection
) {
2412 if (!GetRenderWidget()->handling_input_event() && !handling_select_range_
)
2415 if (is_empty_selection
)
2416 selection_text_
.clear();
2418 // UpdateTextInputState should be called before SyncSelectionIfRequired.
2419 // UpdateTextInputState may send TextInputStateChanged to notify the focus
2420 // was changed, and SyncSelectionIfRequired may send SelectionChanged
2421 // to notify the selection was changed. Focus change should be notified
2422 // before selection change.
2423 GetRenderWidget()->UpdateTextInputState(
2424 RenderWidget::NO_SHOW_IME
, RenderWidget::FROM_NON_IME
);
2425 SyncSelectionIfRequired();
2428 blink::WebColorChooser
* RenderFrameImpl::createColorChooser(
2429 blink::WebColorChooserClient
* client
,
2430 const blink::WebColor
& initial_color
,
2431 const blink::WebVector
<blink::WebColorSuggestion
>& suggestions
) {
2432 RendererWebColorChooserImpl
* color_chooser
=
2433 new RendererWebColorChooserImpl(this, client
);
2434 std::vector
<content::ColorSuggestion
> color_suggestions
;
2435 for (size_t i
= 0; i
< suggestions
.size(); i
++) {
2436 color_suggestions
.push_back(content::ColorSuggestion(suggestions
[i
]));
2438 color_chooser
->Open(static_cast<SkColor
>(initial_color
), color_suggestions
);
2439 return color_chooser
;
2442 void RenderFrameImpl::runModalAlertDialog(const blink::WebString
& message
) {
2443 RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_ALERT
,
2446 frame_
->document().url(),
2450 bool RenderFrameImpl::runModalConfirmDialog(const blink::WebString
& message
) {
2451 return RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_CONFIRM
,
2454 frame_
->document().url(),
2458 bool RenderFrameImpl::runModalPromptDialog(
2459 const blink::WebString
& message
,
2460 const blink::WebString
& default_value
,
2461 blink::WebString
* actual_value
) {
2462 base::string16 result
;
2463 bool ok
= RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_PROMPT
,
2466 frame_
->document().url(),
2469 actual_value
->assign(result
);
2473 bool RenderFrameImpl::runModalBeforeUnloadDialog(
2475 const blink::WebString
& message
) {
2476 // If we are swapping out, we have already run the beforeunload handler.
2477 // TODO(creis): Fix OnSwapOut to clear the frame without running beforeunload
2478 // at all, to avoid running it twice.
2479 if (render_view()->is_swapped_out_
)
2482 // Don't allow further dialogs if we are waiting to swap out, since the
2483 // PageGroupLoadDeferrer in our stack prevents it.
2484 if (render_view()->suppress_dialogs_until_swap_out_
)
2487 bool success
= false;
2488 // This is an ignored return value, but is included so we can accept the same
2489 // response as RunJavaScriptMessage.
2490 base::string16 ignored_result
;
2491 render_view()->SendAndRunNestedMessageLoop(
2492 new FrameHostMsg_RunBeforeUnloadConfirm(
2493 routing_id_
, frame_
->document().url(), message
, is_reload
,
2494 &success
, &ignored_result
));
2498 void RenderFrameImpl::showContextMenu(const blink::WebContextMenuData
& data
) {
2499 ContextMenuParams params
= ContextMenuParamsBuilder::Build(data
);
2500 params
.source_type
= GetRenderWidget()->context_menu_source_type();
2501 GetRenderWidget()->OnShowHostContextMenu(¶ms
);
2502 if (GetRenderWidget()->has_host_context_menu_location()) {
2503 params
.x
= GetRenderWidget()->host_context_menu_location().x();
2504 params
.y
= GetRenderWidget()->host_context_menu_location().y();
2507 // Plugins, e.g. PDF, don't currently update the render view when their
2508 // selected text changes, but the context menu params do contain the updated
2509 // selection. If that's the case, update the render view's state just prior
2510 // to showing the context menu.
2511 // TODO(asvitkine): http://crbug.com/152432
2512 if (ShouldUpdateSelectionTextFromContextMenuParams(
2513 selection_text_
, selection_text_offset_
, selection_range_
, params
)) {
2514 selection_text_
= params
.selection_text
;
2515 // TODO(asvitkine): Text offset and range is not available in this case.
2516 selection_text_offset_
= 0;
2517 selection_range_
= gfx::Range(0, selection_text_
.length());
2518 // This IPC is dispatched by RenderWidetHost, so use its routing ID.
2519 Send(new ViewHostMsg_SelectionChanged(
2520 GetRenderWidget()->routing_id(), selection_text_
,
2521 selection_text_offset_
, selection_range_
));
2524 // Serializing a GURL longer than kMaxURLChars will fail, so don't do
2525 // it. We replace it with an empty GURL so the appropriate items are disabled
2526 // in the context menu.
2527 // TODO(jcivelli): http://crbug.com/45160 This prevents us from saving large
2528 // data encoded images. We should have a way to save them.
2529 if (params
.src_url
.spec().size() > GetMaxURLChars())
2530 params
.src_url
= GURL();
2531 context_menu_node_
= data
.node
;
2533 #if defined(OS_ANDROID)
2534 gfx::Rect start_rect
;
2536 GetRenderWidget()->GetSelectionBounds(&start_rect
, &end_rect
);
2537 params
.selection_start
= gfx::Point(start_rect
.x(), start_rect
.bottom());
2538 params
.selection_end
= gfx::Point(end_rect
.right(), end_rect
.bottom());
2541 Send(new FrameHostMsg_ContextMenu(routing_id_
, params
));
2544 void RenderFrameImpl::clearContextMenu() {
2545 context_menu_node_
.reset();
2548 void RenderFrameImpl::willSendRequest(
2549 blink::WebLocalFrame
* frame
,
2550 unsigned identifier
,
2551 blink::WebURLRequest
& request
,
2552 const blink::WebURLResponse
& redirect_response
) {
2553 DCHECK(!frame_
|| frame_
== frame
);
2554 // The request my be empty during tests.
2555 if (request
.url().isEmpty())
2558 // Set the first party for cookies url if it has not been set yet (new
2559 // requests). For redirects, it is updated by WebURLLoaderImpl.
2560 if (request
.firstPartyForCookies().isEmpty()) {
2561 if (request
.frameType() == blink::WebURLRequest::FrameTypeTopLevel
) {
2562 request
.setFirstPartyForCookies(request
.url());
2564 // TODO(nasko): When the top-level frame is remote, there is no document.
2565 // This is broken and should be fixed to propagate the first party.
2566 WebFrame
* top
= frame
->top();
2567 if (top
->isWebLocalFrame()) {
2568 request
.setFirstPartyForCookies(
2569 frame
->top()->document().firstPartyForCookies());
2574 WebFrame
* top_frame
= frame
->top();
2575 // TODO(nasko): Hack around asking about top-frame data source. This means
2576 // for out-of-process iframes we are treating the current frame as the
2577 // top-level frame, which is wrong.
2578 if (!top_frame
|| top_frame
->isWebRemoteFrame())
2580 WebDataSource
* provisional_data_source
= top_frame
->provisionalDataSource();
2581 WebDataSource
* top_data_source
= top_frame
->dataSource();
2582 WebDataSource
* data_source
=
2583 provisional_data_source
? provisional_data_source
: top_data_source
;
2585 PageTransition transition_type
= PAGE_TRANSITION_LINK
;
2586 DocumentState
* document_state
= DocumentState::FromDataSource(data_source
);
2587 DCHECK(document_state
);
2588 InternalDocumentStateData
* internal_data
=
2589 InternalDocumentStateData::FromDocumentState(document_state
);
2590 NavigationState
* navigation_state
= document_state
->navigation_state();
2591 transition_type
= navigation_state
->transition_type();
2593 GURL
request_url(request
.url());
2595 if (GetContentClient()->renderer()->WillSendRequest(
2599 request
.firstPartyForCookies(),
2601 request
.setURL(WebURL(new_url
));
2604 if (internal_data
->is_cache_policy_override_set())
2605 request
.setCachePolicy(internal_data
->cache_policy_override());
2607 // The request's extra data may indicate that we should set a custom user
2608 // agent. This needs to be done here, after WebKit is through with setting the
2609 // user agent on its own. Similarly, it may indicate that we should set an
2610 // X-Requested-With header. This must be done here to avoid breaking CORS
2612 WebString custom_user_agent
;
2613 WebString requested_with
;
2614 if (request
.extraData()) {
2615 RequestExtraData
* old_extra_data
=
2616 static_cast<RequestExtraData
*>(request
.extraData());
2618 custom_user_agent
= old_extra_data
->custom_user_agent();
2619 if (!custom_user_agent
.isNull()) {
2620 if (custom_user_agent
.isEmpty())
2621 request
.clearHTTPHeaderField("User-Agent");
2623 request
.setHTTPHeaderField("User-Agent", custom_user_agent
);
2626 requested_with
= old_extra_data
->requested_with();
2627 if (!requested_with
.isNull()) {
2628 if (requested_with
.isEmpty())
2629 request
.clearHTTPHeaderField("X-Requested-With");
2631 request
.setHTTPHeaderField("X-Requested-With", requested_with
);
2635 // Add the default accept header for frame request if it has not been set
2637 if ((request
.frameType() == blink::WebURLRequest::FrameTypeTopLevel
||
2638 request
.frameType() == blink::WebURLRequest::FrameTypeNested
) &&
2639 request
.httpHeaderField(WebString::fromUTF8(kAcceptHeader
)).isEmpty()) {
2640 request
.setHTTPHeaderField(WebString::fromUTF8(kAcceptHeader
),
2641 WebString::fromUTF8(kDefaultAcceptHeader
));
2644 // Add an empty HTTP origin header for non GET methods if none is currently
2646 request
.addHTTPOriginIfNeeded(WebString());
2648 // Attach |should_replace_current_entry| state to requests so that, should
2649 // this navigation later require a request transfer, all state is preserved
2650 // when it is re-created in the new process.
2651 bool should_replace_current_entry
= false;
2652 if (navigation_state
->is_content_initiated()) {
2653 should_replace_current_entry
= data_source
->replacesCurrentHistoryItem();
2655 // If the navigation is browser-initiated, the NavigationState contains the
2656 // correct value instead of the WebDataSource.
2658 // TODO(davidben): Avoid this awkward duplication of state. See comment on
2659 // NavigationState::should_replace_current_entry().
2660 should_replace_current_entry
=
2661 navigation_state
->should_replace_current_entry();
2664 int provider_id
= kInvalidServiceWorkerProviderId
;
2665 if (request
.frameType() == blink::WebURLRequest::FrameTypeTopLevel
||
2666 request
.frameType() == blink::WebURLRequest::FrameTypeNested
) {
2667 // |provisionalDataSource| may be null in some content::ResourceFetcher
2668 // use cases, we don't hook those requests.
2669 if (frame
->provisionalDataSource()) {
2670 ServiceWorkerNetworkProvider
* provider
=
2671 ServiceWorkerNetworkProvider::FromDocumentState(
2672 DocumentState::FromDataSource(frame
->provisionalDataSource()));
2673 provider_id
= provider
->provider_id();
2675 } else if (frame
->dataSource()) {
2676 ServiceWorkerNetworkProvider
* provider
=
2677 ServiceWorkerNetworkProvider::FromDocumentState(
2678 DocumentState::FromDataSource(frame
->dataSource()));
2679 provider_id
= provider
->provider_id();
2682 WebFrame
* parent
= frame
->parent();
2683 int parent_routing_id
= MSG_ROUTING_NONE
;
2685 parent_routing_id
= -1;
2686 } else if (parent
->isWebLocalFrame()) {
2687 parent_routing_id
= FromWebFrame(parent
)->GetRoutingID();
2689 parent_routing_id
= RenderFrameProxy::FromWebFrame(parent
)->routing_id();
2692 RequestExtraData
* extra_data
= new RequestExtraData();
2693 extra_data
->set_visibility_state(render_view_
->visibilityState());
2694 extra_data
->set_custom_user_agent(custom_user_agent
);
2695 extra_data
->set_requested_with(requested_with
);
2696 extra_data
->set_render_frame_id(routing_id_
);
2697 extra_data
->set_is_main_frame(frame
== top_frame
);
2698 extra_data
->set_frame_origin(
2699 GURL(frame
->document().securityOrigin().toString()));
2700 extra_data
->set_parent_is_main_frame(frame
->parent() == top_frame
);
2701 extra_data
->set_parent_render_frame_id(parent_routing_id
);
2702 extra_data
->set_allow_download(navigation_state
->allow_download());
2703 extra_data
->set_transition_type(transition_type
);
2704 extra_data
->set_should_replace_current_entry(should_replace_current_entry
);
2705 extra_data
->set_transferred_request_child_id(
2706 navigation_state
->transferred_request_child_id());
2707 extra_data
->set_transferred_request_request_id(
2708 navigation_state
->transferred_request_request_id());
2709 extra_data
->set_service_worker_provider_id(provider_id
);
2710 request
.setExtraData(extra_data
);
2712 DocumentState
* top_document_state
=
2713 DocumentState::FromDataSource(top_data_source
);
2714 if (top_document_state
) {
2715 // TODO(gavinp): separate out prefetching and prerender field trials
2716 // if the rel=prerender rel type is sticking around.
2717 if (request
.requestContext() == WebURLRequest::RequestContextPrefetch
)
2718 top_document_state
->set_was_prefetcher(true);
2721 // This is an instance where we embed a copy of the routing id
2722 // into the data portion of the message. This can cause problems if we
2723 // don't register this id on the browser side, since the download manager
2724 // expects to find a RenderViewHost based off the id.
2725 request
.setRequestorID(render_view_
->GetRoutingID());
2726 request
.setHasUserGesture(WebUserGestureIndicator::isProcessingUserGesture());
2728 if (!navigation_state
->extra_headers().empty()) {
2729 for (net::HttpUtil::HeadersIterator
i(
2730 navigation_state
->extra_headers().begin(),
2731 navigation_state
->extra_headers().end(), "\n");
2733 if (LowerCaseEqualsASCII(i
.name(), "referer")) {
2734 WebString referrer
= WebSecurityPolicy::generateReferrerHeader(
2735 blink::WebReferrerPolicyDefault
,
2737 WebString::fromUTF8(i
.values()));
2738 request
.setHTTPReferrer(referrer
, blink::WebReferrerPolicyDefault
);
2740 request
.setHTTPHeaderField(WebString::fromUTF8(i
.name()),
2741 WebString::fromUTF8(i
.values()));
2746 if (!render_view_
->renderer_preferences_
.enable_referrers
)
2747 request
.setHTTPReferrer(WebString(), blink::WebReferrerPolicyDefault
);
2750 void RenderFrameImpl::didReceiveResponse(
2751 blink::WebLocalFrame
* frame
,
2752 unsigned identifier
,
2753 const blink::WebURLResponse
& response
) {
2754 DCHECK(!frame_
|| frame_
== frame
);
2755 // Only do this for responses that correspond to a provisional data source
2756 // of the top-most frame. If we have a provisional data source, then we
2757 // can't have any sub-resources yet, so we know that this response must
2758 // correspond to a frame load.
2759 if (!frame
->provisionalDataSource() || frame
->parent())
2762 // If we are in view source mode, then just let the user see the source of
2763 // the server's error page.
2764 if (frame
->isViewSourceModeEnabled())
2767 DocumentState
* document_state
=
2768 DocumentState::FromDataSource(frame
->provisionalDataSource());
2769 int http_status_code
= response
.httpStatusCode();
2771 // Record page load flags.
2772 WebURLResponseExtraDataImpl
* extra_data
= GetExtraDataFromResponse(response
);
2774 document_state
->set_was_fetched_via_spdy(
2775 extra_data
->was_fetched_via_spdy());
2776 document_state
->set_was_npn_negotiated(
2777 extra_data
->was_npn_negotiated());
2778 document_state
->set_npn_negotiated_protocol(
2779 extra_data
->npn_negotiated_protocol());
2780 document_state
->set_was_alternate_protocol_available(
2781 extra_data
->was_alternate_protocol_available());
2782 document_state
->set_connection_info(
2783 extra_data
->connection_info());
2784 document_state
->set_was_fetched_via_proxy(
2785 extra_data
->was_fetched_via_proxy());
2787 InternalDocumentStateData
* internal_data
=
2788 InternalDocumentStateData::FromDocumentState(document_state
);
2789 internal_data
->set_http_status_code(http_status_code
);
2790 // Whether or not the http status code actually corresponds to an error is
2791 // only checked when the page is done loading, if |use_error_page| is
2793 internal_data
->set_use_error_page(true);
2796 void RenderFrameImpl::didFinishResourceLoad(blink::WebLocalFrame
* frame
,
2797 unsigned identifier
) {
2798 DCHECK(!frame_
|| frame_
== frame
);
2799 InternalDocumentStateData
* internal_data
=
2800 InternalDocumentStateData::FromDataSource(frame
->dataSource());
2801 if (!internal_data
->use_error_page())
2804 // Do not show error page when DevTools is attached.
2805 if (render_view_
->devtools_agent_
->IsAttached())
2808 // Display error page, if appropriate.
2809 std::string error_domain
= "http";
2810 int http_status_code
= internal_data
->http_status_code();
2811 if (GetContentClient()->renderer()->HasErrorPage(
2812 http_status_code
, &error_domain
)) {
2814 error
.unreachableURL
= frame
->document().url();
2815 error
.domain
= WebString::fromUTF8(error_domain
);
2816 error
.reason
= http_status_code
;
2817 LoadNavigationErrorPage(frame
->dataSource()->request(), error
, true);
2821 void RenderFrameImpl::didLoadResourceFromMemoryCache(
2822 blink::WebLocalFrame
* frame
,
2823 const blink::WebURLRequest
& request
,
2824 const blink::WebURLResponse
& response
) {
2825 DCHECK(!frame_
|| frame_
== frame
);
2826 // The recipients of this message have no use for data: URLs: they don't
2827 // affect the page's insecure content list and are not in the disk cache. To
2828 // prevent large (1M+) data: URLs from crashing in the IPC system, we simply
2829 // filter them out here.
2830 GURL
url(request
.url());
2831 if (url
.SchemeIs("data"))
2834 // Let the browser know we loaded a resource from the memory cache. This
2835 // message is needed to display the correct SSL indicators.
2836 render_view_
->Send(new ViewHostMsg_DidLoadResourceFromMemoryCache(
2837 render_view_
->GetRoutingID(),
2839 response
.securityInfo(),
2840 request
.httpMethod().utf8(),
2841 response
.mimeType().utf8(),
2842 WebURLRequestToResourceType(request
)));
2845 void RenderFrameImpl::didDisplayInsecureContent(blink::WebLocalFrame
* frame
) {
2846 DCHECK(!frame_
|| frame_
== frame
);
2847 render_view_
->Send(new ViewHostMsg_DidDisplayInsecureContent(
2848 render_view_
->GetRoutingID()));
2851 void RenderFrameImpl::didRunInsecureContent(
2852 blink::WebLocalFrame
* frame
,
2853 const blink::WebSecurityOrigin
& origin
,
2854 const blink::WebURL
& target
) {
2855 DCHECK(!frame_
|| frame_
== frame
);
2856 render_view_
->Send(new ViewHostMsg_DidRunInsecureContent(
2857 render_view_
->GetRoutingID(),
2858 origin
.toString().utf8(),
2862 void RenderFrameImpl::didAbortLoading(blink::WebLocalFrame
* frame
) {
2863 DCHECK(!frame_
|| frame_
== frame
);
2864 #if defined(ENABLE_PLUGINS)
2865 if (frame
!= render_view_
->webview()->mainFrame())
2867 PluginChannelHost::Broadcast(
2868 new PluginHostMsg_DidAbortLoading(render_view_
->GetRoutingID()));
2872 void RenderFrameImpl::didCreateScriptContext(blink::WebLocalFrame
* frame
,
2873 v8::Handle
<v8::Context
> context
,
2874 int extension_group
,
2876 DCHECK(!frame_
|| frame_
== frame
);
2877 GetContentClient()->renderer()->DidCreateScriptContext(
2878 frame
, context
, extension_group
, world_id
);
2881 void RenderFrameImpl::willReleaseScriptContext(blink::WebLocalFrame
* frame
,
2882 v8::Handle
<v8::Context
> context
,
2884 DCHECK(!frame_
|| frame_
== frame
);
2886 FOR_EACH_OBSERVER(RenderFrameObserver
,
2888 WillReleaseScriptContext(context
, world_id
));
2891 void RenderFrameImpl::didFirstVisuallyNonEmptyLayout(
2892 blink::WebLocalFrame
* frame
) {
2893 DCHECK(!frame_
|| frame_
== frame
);
2894 if (frame
->parent())
2897 InternalDocumentStateData
* data
=
2898 InternalDocumentStateData::FromDataSource(frame
->dataSource());
2899 data
->set_did_first_visually_non_empty_layout(true);
2901 #if defined(OS_ANDROID)
2902 GetRenderWidget()->DidChangeBodyBackgroundColor(
2903 render_view_
->webwidget_
->backgroundColor());
2906 GetRenderWidget()->QueueMessage(
2907 new FrameHostMsg_DidFirstVisuallyNonEmptyPaint(routing_id_
),
2908 MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE
);
2911 void RenderFrameImpl::didChangeScrollOffset(blink::WebLocalFrame
* frame
) {
2912 DCHECK(!frame_
|| frame_
== frame
);
2913 // TODO(nasko): Move implementation here. Needed methods:
2914 // * StartNavStateSyncTimerIfNecessary
2915 render_view_
->didChangeScrollOffset(frame
);
2918 void RenderFrameImpl::willInsertBody(blink::WebLocalFrame
* frame
) {
2919 DCHECK(!frame_
|| frame_
== frame
);
2920 if (!frame
->parent()) {
2921 render_view_
->Send(new ViewHostMsg_WillInsertBody(
2922 render_view_
->GetRoutingID()));
2926 void RenderFrameImpl::reportFindInPageMatchCount(int request_id
,
2928 bool final_update
) {
2929 int active_match_ordinal
= -1; // -1 = don't update active match ordinal
2931 active_match_ordinal
= 0;
2933 render_view_
->Send(new ViewHostMsg_Find_Reply(
2934 render_view_
->GetRoutingID(), request_id
, count
,
2935 gfx::Rect(), active_match_ordinal
, final_update
));
2938 void RenderFrameImpl::reportFindInPageSelection(
2940 int active_match_ordinal
,
2941 const blink::WebRect
& selection_rect
) {
2942 render_view_
->Send(new ViewHostMsg_Find_Reply(
2943 render_view_
->GetRoutingID(), request_id
, -1, selection_rect
,
2944 active_match_ordinal
, false));
2947 void RenderFrameImpl::requestStorageQuota(
2948 blink::WebLocalFrame
* frame
,
2949 blink::WebStorageQuotaType type
,
2950 unsigned long long requested_size
,
2951 blink::WebStorageQuotaCallbacks callbacks
) {
2952 DCHECK(!frame_
|| frame_
== frame
);
2953 WebSecurityOrigin origin
= frame
->document().securityOrigin();
2954 if (origin
.isUnique()) {
2955 // Unique origins cannot store persistent state.
2956 callbacks
.didFail(blink::WebStorageQuotaErrorAbort
);
2959 ChildThread::current()->quota_dispatcher()->RequestStorageQuota(
2960 render_view_
->GetRoutingID(),
2961 GURL(origin
.toString()),
2962 static_cast<storage::StorageType
>(type
),
2964 QuotaDispatcher::CreateWebStorageQuotaCallbacksWrapper(callbacks
));
2967 void RenderFrameImpl::willOpenSocketStream(
2968 blink::WebSocketStreamHandle
* handle
) {
2969 WebSocketStreamHandleImpl
* impl
=
2970 static_cast<WebSocketStreamHandleImpl
*>(handle
);
2971 impl
->SetUserData(handle
, new SocketStreamHandleData(routing_id_
));
2974 void RenderFrameImpl::willOpenWebSocket(blink::WebSocketHandle
* handle
) {
2975 WebSocketBridge
* impl
= static_cast<WebSocketBridge
*>(handle
);
2976 impl
->set_render_frame_id(routing_id_
);
2979 blink::WebGeolocationClient
* RenderFrameImpl::geolocationClient() {
2980 if (!geolocation_dispatcher_
)
2981 geolocation_dispatcher_
= new GeolocationDispatcher(this);
2982 return geolocation_dispatcher_
;
2985 blink::WebPushClient
* RenderFrameImpl::pushClient() {
2986 if (!push_messaging_dispatcher_
)
2987 push_messaging_dispatcher_
= new PushMessagingDispatcher(this);
2988 return push_messaging_dispatcher_
;
2991 void RenderFrameImpl::willStartUsingPeerConnectionHandler(
2992 blink::WebLocalFrame
* frame
,
2993 blink::WebRTCPeerConnectionHandler
* handler
) {
2994 DCHECK(!frame_
|| frame_
== frame
);
2995 #if defined(ENABLE_WEBRTC)
2996 static_cast<RTCPeerConnectionHandler
*>(handler
)->associateWithFrame(frame
);
3000 blink::WebUserMediaClient
* RenderFrameImpl::userMediaClient() {
3001 if (!web_user_media_client_
)
3002 InitializeUserMediaClient();
3003 return web_user_media_client_
;
3006 blink::WebMIDIClient
* RenderFrameImpl::webMIDIClient() {
3007 if (!midi_dispatcher_
)
3008 midi_dispatcher_
= new MidiDispatcher(this);
3009 return midi_dispatcher_
;
3012 bool RenderFrameImpl::willCheckAndDispatchMessageEvent(
3013 blink::WebLocalFrame
* source_frame
,
3014 blink::WebFrame
* target_frame
,
3015 blink::WebSecurityOrigin target_origin
,
3016 blink::WebDOMMessageEvent event
) {
3017 DCHECK(!frame_
|| frame_
== target_frame
);
3019 if (!render_view_
->is_swapped_out_
)
3022 ViewMsg_PostMessage_Params params
;
3023 params
.is_data_raw_string
= false;
3024 params
.data
= event
.data().toString();
3025 params
.source_origin
= event
.origin();
3026 if (!target_origin
.isNull())
3027 params
.target_origin
= target_origin
.toString();
3029 blink::WebMessagePortChannelArray channels
= event
.releaseChannels();
3030 if (!channels
.isEmpty()) {
3031 std::vector
<int> message_port_ids(channels
.size());
3032 // Extract the port IDs from the channel array.
3033 for (size_t i
= 0; i
< channels
.size(); ++i
) {
3034 WebMessagePortChannelImpl
* webchannel
=
3035 static_cast<WebMessagePortChannelImpl
*>(channels
[i
]);
3036 message_port_ids
[i
] = webchannel
->message_port_id();
3037 webchannel
->QueueMessages();
3038 DCHECK_NE(message_port_ids
[i
], MSG_ROUTING_NONE
);
3040 params
.message_port_ids
= message_port_ids
;
3043 // Include the routing ID for the source frame (if one exists), which the
3044 // browser process will translate into the routing ID for the equivalent
3045 // frame in the target process.
3046 params
.source_routing_id
= MSG_ROUTING_NONE
;
3048 RenderViewImpl
* source_view
=
3049 RenderViewImpl::FromWebView(source_frame
->view());
3051 params
.source_routing_id
= source_view
->routing_id();
3054 Send(new ViewHostMsg_RouteMessageEvent(render_view_
->routing_id_
, params
));
3058 blink::WebString
RenderFrameImpl::userAgentOverride(blink::WebLocalFrame
* frame
,
3059 const blink::WebURL
& url
) {
3060 DCHECK(!frame_
|| frame_
== frame
);
3061 if (!render_view_
->webview() || !render_view_
->webview()->mainFrame() ||
3062 render_view_
->renderer_preferences_
.user_agent_override
.empty()) {
3063 return blink::WebString();
3066 // If we're in the middle of committing a load, the data source we need
3067 // will still be provisional.
3068 WebFrame
* main_frame
= render_view_
->webview()->mainFrame();
3069 WebDataSource
* data_source
= NULL
;
3070 if (main_frame
->provisionalDataSource())
3071 data_source
= main_frame
->provisionalDataSource();
3073 data_source
= main_frame
->dataSource();
3075 InternalDocumentStateData
* internal_data
= data_source
?
3076 InternalDocumentStateData::FromDataSource(data_source
) : NULL
;
3077 if (internal_data
&& internal_data
->is_overriding_user_agent())
3078 return WebString::fromUTF8(
3079 render_view_
->renderer_preferences_
.user_agent_override
);
3080 return blink::WebString();
3083 blink::WebString
RenderFrameImpl::doNotTrackValue(blink::WebLocalFrame
* frame
) {
3084 DCHECK(!frame_
|| frame_
== frame
);
3085 if (render_view_
->renderer_preferences_
.enable_do_not_track
)
3086 return WebString::fromUTF8("1");
3090 bool RenderFrameImpl::allowWebGL(blink::WebLocalFrame
* frame
,
3091 bool default_value
) {
3092 DCHECK(!frame_
|| frame_
== frame
);
3096 bool blocked
= true;
3097 render_view_
->Send(new ViewHostMsg_Are3DAPIsBlocked(
3098 render_view_
->GetRoutingID(),
3099 GURL(frame
->top()->document().securityOrigin().toString()),
3100 THREE_D_API_TYPE_WEBGL
,
3105 void RenderFrameImpl::didLoseWebGLContext(blink::WebLocalFrame
* frame
,
3106 int arb_robustness_status_code
) {
3107 DCHECK(!frame_
|| frame_
== frame
);
3108 render_view_
->Send(new ViewHostMsg_DidLose3DContext(
3109 GURL(frame
->top()->document().securityOrigin().toString()),
3110 THREE_D_API_TYPE_WEBGL
,
3111 arb_robustness_status_code
));
3114 void RenderFrameImpl::forwardInputEvent(const blink::WebInputEvent
* event
) {
3115 Send(new FrameHostMsg_ForwardInputEvent(routing_id_
, event
));
3118 void RenderFrameImpl::initializeChildFrame(const blink::WebRect
& frame_rect
,
3119 float scale_factor
) {
3120 Send(new FrameHostMsg_InitializeChildFrame(
3121 routing_id_
, frame_rect
, scale_factor
));
3124 blink::WebScreenOrientationClient
*
3125 RenderFrameImpl::webScreenOrientationClient() {
3126 if (!screen_orientation_dispatcher_
)
3127 screen_orientation_dispatcher_
= new ScreenOrientationDispatcher(this);
3128 return screen_orientation_dispatcher_
;
3131 void RenderFrameImpl::DidPlay(blink::WebMediaPlayer
* player
) {
3132 Send(new FrameHostMsg_MediaPlayingNotification(
3133 routing_id_
, reinterpret_cast<int64
>(player
), player
->hasVideo(),
3134 player
->hasAudio()));
3137 void RenderFrameImpl::DidPause(blink::WebMediaPlayer
* player
) {
3138 Send(new FrameHostMsg_MediaPausedNotification(
3139 routing_id_
, reinterpret_cast<int64
>(player
)));
3142 void RenderFrameImpl::PlayerGone(blink::WebMediaPlayer
* player
) {
3146 void RenderFrameImpl::AddObserver(RenderFrameObserver
* observer
) {
3147 observers_
.AddObserver(observer
);
3150 void RenderFrameImpl::RemoveObserver(RenderFrameObserver
* observer
) {
3151 observer
->RenderFrameGone();
3152 observers_
.RemoveObserver(observer
);
3155 void RenderFrameImpl::OnStop() {
3156 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, OnStop());
3159 void RenderFrameImpl::WasHidden() {
3160 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, WasHidden());
3163 void RenderFrameImpl::WasShown() {
3164 FOR_EACH_OBSERVER(RenderFrameObserver
, observers_
, WasShown());
3167 bool RenderFrameImpl::IsHidden() {
3168 return GetRenderWidget()->is_hidden();
3171 // Tell the embedding application that the URL of the active page has changed.
3172 void RenderFrameImpl::SendDidCommitProvisionalLoad(blink::WebFrame
* frame
) {
3173 DCHECK(!frame_
|| frame_
== frame
);
3174 WebDataSource
* ds
= frame
->dataSource();
3177 const WebURLRequest
& request
= ds
->request();
3178 const WebURLResponse
& response
= ds
->response();
3180 DocumentState
* document_state
= DocumentState::FromDataSource(ds
);
3181 NavigationState
* navigation_state
= document_state
->navigation_state();
3182 InternalDocumentStateData
* internal_data
=
3183 InternalDocumentStateData::FromDocumentState(document_state
);
3185 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
3186 params
.http_status_code
= response
.httpStatusCode();
3187 params
.is_post
= false;
3188 params
.post_id
= -1;
3189 params
.page_id
= render_view_
->page_id_
;
3190 // We need to track the RenderViewHost routing_id because of downstream
3191 // dependencies (crbug.com/392171 DownloadRequestHandle, SaveFileManager,
3192 // ResourceDispatcherHostImpl, MediaStreamUIProxy,
3193 // SpeechRecognitionDispatcherHost and possibly others). They look up the view
3194 // based on the ID stored in the resource requests. Once those dependencies
3195 // are unwound or moved to RenderFrameHost (crbug.com/304341) we can move the
3196 // client to be based on the routing_id of the RenderFrameHost.
3197 params
.render_view_routing_id
= render_view_
->routing_id();
3198 params
.socket_address
.set_host(response
.remoteIPAddress().utf8());
3199 params
.socket_address
.set_port(response
.remotePort());
3200 WebURLResponseExtraDataImpl
* extra_data
= GetExtraDataFromResponse(response
);
3202 params
.was_fetched_via_proxy
= extra_data
->was_fetched_via_proxy();
3203 params
.was_within_same_page
= navigation_state
->was_within_same_page();
3204 params
.security_info
= response
.securityInfo();
3206 // Set the URL to be displayed in the browser UI to the user.
3207 params
.url
= GetLoadingUrl();
3208 DCHECK(!is_swapped_out_
|| params
.url
== GURL(kSwappedOutURL
));
3210 if (frame
->document().baseURL() != params
.url
)
3211 params
.base_url
= frame
->document().baseURL();
3213 GetRedirectChain(ds
, ¶ms
.redirects
);
3214 params
.should_update_history
= !ds
->hasUnreachableURL() &&
3215 !response
.isMultipartPayload() && (response
.httpStatusCode() != 404);
3217 params
.searchable_form_url
= internal_data
->searchable_form_url();
3218 params
.searchable_form_encoding
= internal_data
->searchable_form_encoding();
3220 params
.gesture
= render_view_
->navigation_gesture_
;
3221 render_view_
->navigation_gesture_
= NavigationGestureUnknown
;
3223 // Make navigation state a part of the DidCommitProvisionalLoad message so
3224 // that commited entry has it at all times.
3225 HistoryEntry
* entry
= render_view_
->history_controller()->GetCurrentEntry();
3227 params
.page_state
= HistoryEntryToPageState(entry
);
3229 params
.page_state
= PageState::CreateFromURL(request
.url());
3231 if (!frame
->parent()) {
3232 // Top-level navigation.
3234 // Reset the zoom limits in case a plugin had changed them previously. This
3235 // will also call us back which will cause us to send a message to
3236 // update WebContentsImpl.
3237 render_view_
->webview()->zoomLimitsChanged(
3238 ZoomFactorToZoomLevel(kMinimumZoomFactor
),
3239 ZoomFactorToZoomLevel(kMaximumZoomFactor
));
3241 // Set zoom level, but don't do it for full-page plugin since they don't use
3242 // the same zoom settings.
3243 HostZoomLevels::iterator host_zoom
=
3244 render_view_
->host_zoom_levels_
.find(GURL(request
.url()));
3245 if (render_view_
->webview()->mainFrame()->document().isPluginDocument()) {
3246 // Reset the zoom levels for plugins.
3247 render_view_
->webview()->setZoomLevel(0);
3249 if (host_zoom
!= render_view_
->host_zoom_levels_
.end())
3250 render_view_
->webview()->setZoomLevel(host_zoom
->second
);
3253 if (host_zoom
!= render_view_
->host_zoom_levels_
.end()) {
3254 // This zoom level was merely recorded transiently for this load. We can
3255 // erase it now. If at some point we reload this page, the browser will
3256 // send us a new, up-to-date zoom level.
3257 render_view_
->host_zoom_levels_
.erase(host_zoom
);
3260 // Update contents MIME type for main frame.
3261 params
.contents_mime_type
= ds
->response().mimeType().utf8();
3263 params
.transition
= navigation_state
->transition_type();
3264 if (!PageTransitionIsMainFrame(params
.transition
)) {
3265 // If the main frame does a load, it should not be reported as a subframe
3266 // navigation. This can occur in the following case:
3267 // 1. You're on a site with frames.
3268 // 2. You do a subframe navigation. This is stored with transition type
3270 // 3. You navigate to some non-frame site, say, google.com.
3271 // 4. You navigate back to the page from step 2. Since it was initially
3272 // MANUAL_SUBFRAME, it will be that same transition type here.
3273 // We don't want that, because any navigation that changes the toplevel
3274 // frame should be tracked as a toplevel navigation (this allows us to
3275 // update the URL bar, etc).
3276 params
.transition
= PAGE_TRANSITION_LINK
;
3279 // If the page contained a client redirect (meta refresh, document.loc...),
3280 // set the referrer and transition appropriately.
3281 if (ds
->isClientRedirect()) {
3283 Referrer(params
.redirects
[0], ds
->request().referrerPolicy());
3284 params
.transition
= static_cast<PageTransition
>(
3285 params
.transition
| PAGE_TRANSITION_CLIENT_REDIRECT
);
3287 params
.referrer
= RenderViewImpl::GetReferrerFromRequest(
3288 frame
, ds
->request());
3291 base::string16 method
= request
.httpMethod();
3292 if (EqualsASCII(method
, "POST")) {
3293 params
.is_post
= true;
3294 params
.post_id
= ExtractPostId(entry
->root());
3297 // Send the user agent override back.
3298 params
.is_overriding_user_agent
= internal_data
->is_overriding_user_agent();
3300 // Track the URL of the original request. We use the first entry of the
3301 // redirect chain if it exists because the chain may have started in another
3303 params
.original_request_url
= GetOriginalRequestURL(ds
);
3305 params
.history_list_was_cleared
=
3306 navigation_state
->history_list_was_cleared();
3308 // Save some histogram data so we can compute the average memory used per
3309 // page load of the glyphs.
3310 UMA_HISTOGRAM_COUNTS_10000("Memory.GlyphPagesPerLoad",
3311 blink::WebGlyphCache::pageCount());
3313 // This message needs to be sent before any of allowScripts(),
3314 // allowImages(), allowPlugins() is called for the new page, so that when
3315 // these functions send a ViewHostMsg_ContentBlocked message, it arrives
3316 // after the FrameHostMsg_DidCommitProvisionalLoad message.
3317 Send(new FrameHostMsg_DidCommitProvisionalLoad(routing_id_
, params
));
3319 // Subframe navigation: the type depends on whether this navigation
3320 // generated a new session history entry. When they do generate a session
3321 // history entry, it means the user initiated the navigation and we should
3322 // mark it as such. This test checks if this is the first time
3323 // SendDidCommitProvisionalLoad has been called since WillNavigateToURL was
3324 // called to initiate the load.
3325 if (render_view_
->page_id_
> render_view_
->last_page_id_sent_to_browser_
)
3326 params
.transition
= PAGE_TRANSITION_MANUAL_SUBFRAME
;
3328 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
3330 DCHECK(!navigation_state
->history_list_was_cleared());
3331 params
.history_list_was_cleared
= false;
3333 // Don't send this message while the subframe is swapped out.
3334 if (!is_swapped_out())
3335 Send(new FrameHostMsg_DidCommitProvisionalLoad(routing_id_
, params
));
3338 render_view_
->last_page_id_sent_to_browser_
=
3339 std::max(render_view_
->last_page_id_sent_to_browser_
,
3340 render_view_
->page_id_
);
3342 // If we end up reusing this WebRequest (for example, due to a #ref click),
3343 // we don't want the transition type to persist. Just clear it.
3344 navigation_state
->set_transition_type(PAGE_TRANSITION_LINK
);
3347 WebElement
RenderFrameImpl::GetFocusedElement() {
3348 WebDocument doc
= frame_
->document();
3350 return doc
.focusedElement();
3352 return WebElement();
3355 void RenderFrameImpl::didStartLoading(bool to_different_document
) {
3356 render_view_
->FrameDidStartLoading(frame_
);
3357 Send(new FrameHostMsg_DidStartLoading(routing_id_
, to_different_document
));
3360 void RenderFrameImpl::didStopLoading() {
3361 render_view_
->FrameDidStopLoading(frame_
);
3362 Send(new FrameHostMsg_DidStopLoading(routing_id_
));
3365 void RenderFrameImpl::didChangeLoadProgress(double load_progress
) {
3366 Send(new FrameHostMsg_DidChangeLoadProgress(routing_id_
, load_progress
));
3369 void RenderFrameImpl::HandleWebAccessibilityEvent(
3370 const blink::WebAXObject
& obj
, blink::WebAXEvent event
) {
3371 if (renderer_accessibility_
)
3372 renderer_accessibility_
->HandleWebAccessibilityEvent(obj
, event
);
3375 void RenderFrameImpl::FocusedNodeChanged(const WebNode
& node
) {
3376 if (renderer_accessibility_
)
3377 renderer_accessibility_
->FocusedNodeChanged(node
);
3380 WebNavigationPolicy
RenderFrameImpl::DecidePolicyForNavigation(
3381 RenderFrame
* render_frame
,
3382 const NavigationPolicyInfo
& info
) {
3384 // The handlenavigation API is deprecated and will be removed once
3385 // crbug.com/325351 is resolved.
3386 if (info
.urlRequest
.url() != GURL(kSwappedOutURL
) &&
3387 GetContentClient()->renderer()->HandleNavigation(
3389 static_cast<DocumentState
*>(info
.extraData
),
3390 render_view_
->opener_id_
,
3393 info
.navigationType
,
3396 return blink::WebNavigationPolicyIgnore
;
3400 Referrer
referrer(RenderViewImpl::GetReferrerFromRequest(info
.frame
,
3402 const CommandLine
& command_line
= *CommandLine::ForCurrentProcess();
3404 bool is_subframe
= !!info
.frame
->parent();
3406 if (command_line
.HasSwitch(switches::kSitePerProcess
) && is_subframe
) {
3407 // There's no reason to ignore navigations on subframes, since the swap out
3408 // logic no longer applies.
3410 if (is_swapped_out_
|| render_view_
->is_swapped_out()) {
3411 if (info
.urlRequest
.url() != GURL(kSwappedOutURL
)) {
3412 // Targeted links may try to navigate a swapped out frame. Allow the
3413 // browser process to navigate the tab instead. Note that it is also
3414 // possible for non-targeted navigations (from this view) to arrive
3415 // here just after we are swapped out. It's ok to send them to the
3416 // browser, as long as they're for the top level frame.
3417 // TODO(creis): Ensure this supports targeted form submissions when
3418 // fixing http://crbug.com/101395.
3419 if (info
.frame
->parent() == NULL
) {
3420 OpenURL(info
.frame
, info
.urlRequest
.url(), referrer
,
3421 info
.defaultPolicy
);
3422 return blink::WebNavigationPolicyIgnore
; // Suppress the load here.
3425 // We should otherwise ignore in-process iframe navigations, if they
3426 // arrive just after we are swapped out.
3427 return blink::WebNavigationPolicyIgnore
;
3430 // Allow kSwappedOutURL to complete.
3431 return info
.defaultPolicy
;
3435 // Webkit is asking whether to navigate to a new URL.
3436 // This is fine normally, except if we're showing UI from one security
3437 // context and they're trying to navigate to a different context.
3438 const GURL
& url
= info
.urlRequest
.url();
3440 // A content initiated navigation may have originated from a link-click,
3441 // script, drag-n-drop operation, etc.
3442 bool is_content_initiated
= static_cast<DocumentState
*>(info
.extraData
)->
3443 navigation_state()->is_content_initiated();
3446 // If --enable-strict-site-isolation or --site-per-process is enabled, send
3447 // all top-level navigations to the browser to let it swap processes when
3448 // crossing site boundaries. This is currently expected to break some script
3449 // calls and navigations, such as form submissions.
3450 bool force_swap_due_to_flag
=
3451 command_line
.HasSwitch(switches::kEnableStrictSiteIsolation
) ||
3452 command_line
.HasSwitch(switches::kSitePerProcess
);
3453 if (force_swap_due_to_flag
&&
3454 !info
.frame
->parent() && (is_content_initiated
|| info
.isRedirect
)) {
3455 WebString origin_str
= info
.frame
->document().securityOrigin().toString();
3456 GURL
frame_url(origin_str
.utf8().data());
3457 // TODO(cevans): revisit whether this site check is still necessary once
3458 // crbug.com/101395 is fixed.
3459 bool same_domain_or_host
=
3460 net::registry_controlled_domains::SameDomainOrHost(
3463 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES
);
3464 if (!same_domain_or_host
|| frame_url
.scheme() != url
.scheme()) {
3465 OpenURL(info
.frame
, url
, referrer
, info
.defaultPolicy
);
3466 return blink::WebNavigationPolicyIgnore
;
3470 // If the browser is interested, then give it a chance to look at the request.
3471 if (is_content_initiated
) {
3473 ((info
.navigationType
== blink::WebNavigationTypeFormSubmitted
) ||
3474 (info
.navigationType
== blink::WebNavigationTypeFormResubmitted
)) &&
3475 EqualsASCII(info
.urlRequest
.httpMethod(), "POST");
3476 bool browser_handles_request
=
3477 render_view_
->renderer_preferences_
3478 .browser_handles_non_local_top_level_requests
3479 && IsNonLocalTopLevelNavigation(url
, info
.frame
, info
.navigationType
,
3481 if (!browser_handles_request
) {
3482 browser_handles_request
= IsTopLevelNavigation(info
.frame
) &&
3483 render_view_
->renderer_preferences_
3484 .browser_handles_all_top_level_requests
;
3487 if (browser_handles_request
) {
3488 // Reset these counters as the RenderView could be reused for the next
3490 render_view_
->page_id_
= -1;
3491 render_view_
->last_page_id_sent_to_browser_
= -1;
3492 OpenURL(info
.frame
, url
, referrer
, info
.defaultPolicy
);
3493 return blink::WebNavigationPolicyIgnore
; // Suppress the load here.
3497 // Use the frame's original request's URL rather than the document's URL for
3498 // subsequent checks. For a popup, the document's URL may become the opener
3499 // window's URL if the opener has called document.write().
3500 // See http://crbug.com/93517.
3501 GURL
old_url(info
.frame
->dataSource()->request().url());
3503 // Detect when we're crossing a permission-based boundary (e.g. into or out of
3504 // an extension or app origin, leaving a WebUI page, etc). We only care about
3505 // top-level navigations (not iframes). But we sometimes navigate to
3506 // about:blank to clear a tab, and we want to still allow that.
3508 // Note: this is known to break POST submissions when crossing process
3509 // boundaries until http://crbug.com/101395 is fixed. This is better for
3510 // security than loading a WebUI, extension or app page in the wrong process.
3511 // POST requests don't work because this mechanism does not preserve form
3512 // POST data. We will need to send the request's httpBody data up to the
3513 // browser process, and issue a special POST navigation in WebKit (via
3514 // FrameLoader::loadFrameRequest). See ResourceDispatcher and WebURLLoaderImpl
3515 // for examples of how to send the httpBody data.
3516 if (!info
.frame
->parent() && is_content_initiated
&&
3517 !url
.SchemeIs(url::kAboutScheme
)) {
3518 bool send_referrer
= false;
3520 // All navigations to or from WebUI URLs or within WebUI-enabled
3521 // RenderProcesses must be handled by the browser process so that the
3522 // correct bindings and data sources can be registered.
3523 // Similarly, navigations to view-source URLs or within ViewSource mode
3524 // must be handled by the browser process (except for reloads - those are
3525 // safe to leave within the renderer).
3526 // Lastly, access to file:// URLs from non-file:// URL pages must be
3527 // handled by the browser so that ordinary renderer processes don't get
3528 // blessed with file permissions.
3529 int cumulative_bindings
= RenderProcess::current()->GetEnabledBindings();
3530 bool is_initial_navigation
= render_view_
->page_id_
== -1;
3531 bool should_fork
= HasWebUIScheme(url
) || HasWebUIScheme(old_url
) ||
3532 (cumulative_bindings
& BINDINGS_POLICY_WEB_UI
) ||
3533 url
.SchemeIs(kViewSourceScheme
) ||
3534 (info
.frame
->isViewSourceModeEnabled() &&
3535 info
.navigationType
!= blink::WebNavigationTypeReload
);
3537 if (!should_fork
&& url
.SchemeIs(url::kFileScheme
)) {
3538 // Fork non-file to file opens. Check the opener URL if this is the
3539 // initial navigation in a newly opened window.
3540 GURL
source_url(old_url
);
3541 if (is_initial_navigation
&& source_url
.is_empty() &&
3542 info
.frame
->opener())
3543 source_url
= info
.frame
->opener()->top()->document().url();
3544 DCHECK(!source_url
.is_empty());
3545 should_fork
= !source_url
.SchemeIs(url::kFileScheme
);
3549 // Give the embedder a chance.
3550 should_fork
= GetContentClient()->renderer()->ShouldFork(
3551 info
.frame
, url
, info
.urlRequest
.httpMethod().utf8(),
3552 is_initial_navigation
, info
.isRedirect
, &send_referrer
);
3556 OpenURL(info
.frame
, url
, send_referrer
? referrer
: Referrer(),
3557 info
.defaultPolicy
);
3558 return blink::WebNavigationPolicyIgnore
; // Suppress the load here.
3562 // Detect when a page is "forking" a new tab that can be safely rendered in
3563 // its own process. This is done by sites like Gmail that try to open links
3564 // in new windows without script connections back to the original page. We
3565 // treat such cases as browser navigations (in which we will create a new
3566 // renderer for a cross-site navigation), rather than WebKit navigations.
3568 // We use the following heuristic to decide whether to fork a new page in its
3570 // The parent page must open a new tab to about:blank, set the new tab's
3571 // window.opener to null, and then redirect the tab to a cross-site URL using
3574 // TODO(creis): Deprecate this logic once we can rely on rel=noreferrer
3577 // Must start from a tab showing about:blank, which is later redirected.
3578 old_url
== GURL(url::kAboutBlankURL
) &&
3579 // Must be the first real navigation of the tab.
3580 render_view_
->historyBackListCount() < 1 &&
3581 render_view_
->historyForwardListCount() < 1 &&
3582 // The parent page must have set the child's window.opener to null before
3583 // redirecting to the desired URL.
3584 info
.frame
->opener() == NULL
&&
3585 // Must be a top-level frame.
3586 info
.frame
->parent() == NULL
&&
3587 // Must not have issued the request from this page.
3588 is_content_initiated
&&
3589 // Must be targeted at the current tab.
3590 info
.defaultPolicy
== blink::WebNavigationPolicyCurrentTab
&&
3591 // Must be a JavaScript navigation, which appears as "other".
3592 info
.navigationType
== blink::WebNavigationTypeOther
;
3595 // Open the URL via the browser, not via WebKit.
3596 OpenURL(info
.frame
, url
, Referrer(), info
.defaultPolicy
);
3597 return blink::WebNavigationPolicyIgnore
;
3600 return info
.defaultPolicy
;
3603 void RenderFrameImpl::OpenURL(WebFrame
* frame
,
3605 const Referrer
& referrer
,
3606 WebNavigationPolicy policy
) {
3607 DCHECK_EQ(frame_
, frame
);
3609 FrameHostMsg_OpenURL_Params params
;
3611 params
.referrer
= referrer
;
3612 params
.disposition
= RenderViewImpl::NavigationPolicyToDisposition(policy
);
3613 WebDataSource
* ds
= frame
->provisionalDataSource();
3615 DocumentState
* document_state
= DocumentState::FromDataSource(ds
);
3616 NavigationState
* navigation_state
= document_state
->navigation_state();
3617 if (navigation_state
->is_content_initiated()) {
3618 params
.should_replace_current_entry
= ds
->replacesCurrentHistoryItem();
3620 // This is necessary to preserve the should_replace_current_entry value on
3621 // cross-process redirects, in the event it was set by a previous process.
3623 // TODO(davidben): Avoid this awkward duplication of state. See comment on
3624 // NavigationState::should_replace_current_entry().
3625 params
.should_replace_current_entry
=
3626 navigation_state
->should_replace_current_entry();
3629 params
.should_replace_current_entry
= false;
3631 params
.user_gesture
= WebUserGestureIndicator::isProcessingUserGesture();
3632 if (GetContentClient()->renderer()->AllowPopup())
3633 params
.user_gesture
= true;
3635 if (policy
== blink::WebNavigationPolicyNewBackgroundTab
||
3636 policy
== blink::WebNavigationPolicyNewForegroundTab
||
3637 policy
== blink::WebNavigationPolicyNewWindow
||
3638 policy
== blink::WebNavigationPolicyNewPopup
) {
3639 WebUserGestureIndicator::consumeUserGesture();
3642 Send(new FrameHostMsg_OpenURL(routing_id_
, params
));
3645 void RenderFrameImpl::UpdateEncoding(WebFrame
* frame
,
3646 const std::string
& encoding_name
) {
3647 // Only update main frame's encoding_name.
3648 if (!frame
->parent())
3649 Send(new FrameHostMsg_UpdateEncoding(routing_id_
, encoding_name
));
3652 void RenderFrameImpl::SyncSelectionIfRequired() {
3653 base::string16 text
;
3656 #if defined(ENABLE_PLUGINS)
3657 if (render_view_
->focused_pepper_plugin_
) {
3658 render_view_
->focused_pepper_plugin_
->GetSurroundingText(&text
, &range
);
3659 offset
= 0; // Pepper API does not support offset reporting.
3660 // TODO(kinaba): cut as needed.
3664 size_t location
, length
;
3665 if (!GetRenderWidget()->webwidget()->caretOrSelectionRange(
3666 &location
, &length
)) {
3670 range
= gfx::Range(location
, location
+ length
);
3672 if (GetRenderWidget()->webwidget()->textInputInfo().type
!=
3673 blink::WebTextInputTypeNone
) {
3674 // If current focused element is editable, we will send 100 more chars
3675 // before and after selection. It is for input method surrounding text
3677 if (location
> kExtraCharsBeforeAndAfterSelection
)
3678 offset
= location
- kExtraCharsBeforeAndAfterSelection
;
3681 length
= location
+ length
- offset
+ kExtraCharsBeforeAndAfterSelection
;
3682 WebRange webrange
= WebRange::fromDocumentRange(frame_
, offset
, length
);
3683 if (!webrange
.isNull())
3684 text
= WebRange::fromDocumentRange(
3685 frame_
, offset
, length
).toPlainText();
3688 text
= frame_
->selectionAsText();
3689 // http://crbug.com/101435
3690 // In some case, frame->selectionAsText() returned text's length is not
3691 // equal to the length returned from webwidget()->caretOrSelectionRange().
3692 // So we have to set the range according to text.length().
3693 range
.set_end(range
.start() + text
.length());
3697 // Sometimes we get repeated didChangeSelection calls from webkit when
3698 // the selection hasn't actually changed. We don't want to report these
3699 // because it will cause us to continually claim the X clipboard.
3700 if (selection_text_offset_
!= offset
||
3701 selection_range_
!= range
||
3702 selection_text_
!= text
) {
3703 selection_text_
= text
;
3704 selection_text_offset_
= offset
;
3705 selection_range_
= range
;
3706 // This IPC is dispatched by RenderWidetHost, so use its routing ID.
3707 Send(new ViewHostMsg_SelectionChanged(
3708 GetRenderWidget()->routing_id(), text
, offset
, range
));
3710 GetRenderWidget()->UpdateSelectionBounds();
3713 void RenderFrameImpl::InitializeUserMediaClient() {
3714 if (!RenderThreadImpl::current()) // Will be NULL during unit tests.
3717 #if defined(OS_ANDROID)
3718 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableWebRTC
))
3722 #if defined(ENABLE_WEBRTC)
3723 DCHECK(!web_user_media_client_
);
3724 web_user_media_client_
= new MediaStreamImpl(
3726 RenderThreadImpl::current()->GetPeerConnectionDependencyFactory(),
3727 make_scoped_ptr(new MediaStreamDispatcher(this)).Pass());
3731 WebMediaPlayer
* RenderFrameImpl::CreateWebMediaPlayerForMediaStream(
3732 const blink::WebURL
& url
,
3733 WebMediaPlayerClient
* client
) {
3734 #if defined(ENABLE_WEBRTC)
3735 #if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL)
3737 (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON
) != 0;
3738 UMA_HISTOGRAM_BOOLEAN("Platform.WebRtcNEONFound", found_neon
);
3739 #endif // defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL)
3740 return new WebMediaPlayerMS(frame_
, client
, weak_factory_
.GetWeakPtr(),
3741 new RenderMediaLog(),
3742 CreateRendererFactory());
3745 #endif // defined(ENABLE_WEBRTC)
3748 scoped_ptr
<MediaStreamRendererFactory
>
3749 RenderFrameImpl::CreateRendererFactory() {
3750 #if defined(ENABLE_WEBRTC)
3751 return scoped_ptr
<MediaStreamRendererFactory
>(
3752 new MediaStreamRendererFactory());
3754 return scoped_ptr
<MediaStreamRendererFactory
>(
3755 static_cast<MediaStreamRendererFactory
*>(NULL
));
3759 GURL
RenderFrameImpl::GetLoadingUrl() const {
3760 WebDataSource
* ds
= frame_
->dataSource();
3761 if (ds
->hasUnreachableURL())
3762 return ds
->unreachableURL();
3764 const WebURLRequest
& request
= ds
->request();
3765 return request
.url();
3768 #if defined(OS_ANDROID)
3770 WebMediaPlayer
* RenderFrameImpl::CreateAndroidWebMediaPlayer(
3771 const blink::WebURL
& url
,
3772 WebMediaPlayerClient
* client
) {
3773 GpuChannelHost
* gpu_channel_host
=
3774 RenderThreadImpl::current()->EstablishGpuChannelSync(
3775 CAUSE_FOR_GPU_LAUNCH_VIDEODECODEACCELERATOR_INITIALIZE
);
3776 if (!gpu_channel_host
) {
3777 LOG(ERROR
) << "Failed to establish GPU channel for media player";
3781 scoped_refptr
<StreamTextureFactory
> stream_texture_factory
;
3782 if (SynchronousCompositorFactory
* factory
=
3783 SynchronousCompositorFactory::GetInstance()) {
3784 stream_texture_factory
= factory
->CreateStreamTextureFactory(routing_id_
);
3786 scoped_refptr
<webkit::gpu::ContextProviderWebContext
> context_provider
=
3787 RenderThreadImpl::current()->SharedMainThreadContextProvider();
3789 if (!context_provider
.get()) {
3790 LOG(ERROR
) << "Failed to get context3d for media player";
3794 stream_texture_factory
= StreamTextureFactoryImpl::Create(
3795 context_provider
, gpu_channel_host
, routing_id_
);
3798 return new WebMediaPlayerAndroid(
3801 weak_factory_
.GetWeakPtr(),
3802 GetMediaPlayerManager(),
3804 stream_texture_factory
,
3805 RenderThreadImpl::current()->GetMediaThreadTaskRunner(),
3806 new RenderMediaLog());
3809 RendererMediaPlayerManager
* RenderFrameImpl::GetMediaPlayerManager() {
3810 if (!media_player_manager_
)
3811 media_player_manager_
= new RendererMediaPlayerManager(this);
3812 return media_player_manager_
;
3815 #endif // defined(OS_ANDROID)
3817 #if defined(ENABLE_BROWSER_CDMS)
3818 RendererCdmManager
* RenderFrameImpl::GetCdmManager() {
3820 cdm_manager_
= new RendererCdmManager(this);
3821 return cdm_manager_
;
3823 #endif // defined(ENABLE_BROWSER_CDMS)
3825 } // namespace content