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