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