[content shell] implement testRunner.overridePreference
[chromium-blink-merge.git] / content / renderer / render_view_impl.cc
blob628d3cdb07a29f243de62fffd0cbc03ba83a4875
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/render_view_impl.h"
7 #include <algorithm>
8 #include <cmath>
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/command_line.h"
13 #include "base/compiler_specific.h"
14 #include "base/debug/trace_event.h"
15 #include "base/json/json_reader.h"
16 #include "base/json/json_writer.h"
17 #include "base/lazy_instance.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "base/message_loop_proxy.h"
20 #include "base/metrics/histogram.h"
21 #include "base/path_service.h"
22 #include "base/process_util.h"
23 #include "base/string_number_conversions.h"
24 #include "base/string_piece.h"
25 #include "base/string_split.h"
26 #include "base/string_util.h"
27 #include "base/sys_string_conversions.h"
28 #include "base/time.h"
29 #include "base/utf_string_conversions.h"
30 #include "cc/output_surface.h"
31 #include "cc/switches.h"
32 #include "content/common/appcache/appcache_dispatcher.h"
33 #include "content/common/child_thread.h"
34 #include "content/common/clipboard_messages.h"
35 #include "content/common/content_constants_internal.h"
36 #include "content/common/database_messages.h"
37 #include "content/common/drag_messages.h"
38 #include "content/common/fileapi/file_system_dispatcher.h"
39 #include "content/common/fileapi/webfilesystem_callback_dispatcher.h"
40 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
41 #include "content/common/intents_messages.h"
42 #include "content/common/java_bridge_messages.h"
43 #include "content/common/pepper_messages.h"
44 #include "content/common/pepper_plugin_registry.h"
45 #include "content/common/quota_dispatcher.h"
46 #include "content/common/request_extra_data.h"
47 #include "content/common/socket_stream_handle_data.h"
48 #include "content/common/ssl_status_serialization.h"
49 #include "content/common/view_messages.h"
50 #include "content/common/webmessageportchannel_impl.h"
51 #include "content/public/common/bindings_policy.h"
52 #include "content/public/common/content_client.h"
53 #include "content/public/common/content_constants.h"
54 #include "content/public/common/content_switches.h"
55 #include "content/public/common/context_menu_params.h"
56 #include "content/public/common/file_chooser_params.h"
57 #include "content/public/common/ssl_status.h"
58 #include "content/public/common/three_d_api_types.h"
59 #include "content/public/common/url_constants.h"
60 #include "content/public/renderer/content_renderer_client.h"
61 #include "content/public/renderer/context_menu_client.h"
62 #include "content/public/renderer/document_state.h"
63 #include "content/public/renderer/navigation_state.h"
64 #include "content/public/renderer/password_form_conversion_utils.h"
65 #include "content/public/renderer/render_view_observer.h"
66 #include "content/public/renderer/render_view_visitor.h"
67 #include "content/renderer/browser_plugin/browser_plugin.h"
68 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
69 #include "content/renderer/browser_plugin/browser_plugin_manager_impl.h"
70 #include "content/renderer/device_orientation_dispatcher.h"
71 #include "content/renderer/devtools_agent.h"
72 #include "content/renderer/disambiguation_popup_helper.h"
73 #include "content/renderer/dom_automation_controller.h"
74 #include "content/renderer/dom_storage/webstoragenamespace_impl.h"
75 #include "content/renderer/do_not_track_bindings.h"
76 #include "content/renderer/external_popup_menu.h"
77 #include "content/renderer/favicon_helper.h"
78 #include "content/renderer/geolocation_dispatcher.h"
79 #include "content/renderer/gpu/compositor_thread.h"
80 #include "content/renderer/gpu/compositor_output_surface.h"
81 #include "content/renderer/gpu/compositor_software_output_device_gl_adapter.h"
82 #include "content/renderer/idle_user_detector.h"
83 #include "content/renderer/input_tag_speech_dispatcher.h"
84 #include "content/renderer/java/java_bridge_dispatcher.h"
85 #include "content/renderer/load_progress_tracker.h"
86 #include "content/renderer/media/media_stream_dependency_factory.h"
87 #include "content/renderer/media/media_stream_dispatcher.h"
88 #include "content/renderer/media/media_stream_impl.h"
89 #include "content/renderer/media/render_audiosourceprovider.h"
90 #include "content/renderer/media/render_media_log.h"
91 #include "content/renderer/media/renderer_gpu_video_decoder_factories.h"
92 #include "content/renderer/media/rtc_peer_connection_handler.h"
93 #include "content/renderer/mhtml_generator.h"
94 #include "content/renderer/notification_provider.h"
95 #include "content/renderer/pepper/pepper_plugin_delegate_impl.h"
96 #include "content/renderer/plugin_channel_host.h"
97 #include "content/renderer/render_process.h"
98 #include "content/renderer/render_thread_impl.h"
99 #include "content/renderer/render_view_impl_params.h"
100 #include "content/renderer/render_view_mouse_lock_dispatcher.h"
101 #include "content/renderer/render_widget_fullscreen_pepper.h"
102 #include "content/renderer/renderer_accessibility.h"
103 #include "content/renderer/renderer_accessibility_complete.h"
104 #include "content/renderer/renderer_accessibility_focus_only.h"
105 #include "content/renderer/renderer_date_time_picker.h"
106 #include "content/renderer/renderer_webapplicationcachehost_impl.h"
107 #include "content/renderer/renderer_webcolorchooser_impl.h"
108 #include "content/renderer/speech_recognition_dispatcher.h"
109 #include "content/renderer/text_input_client_observer.h"
110 #include "content/renderer/v8_value_converter_impl.h"
111 #include "content/renderer/web_intents_host.h"
112 #include "content/renderer/web_ui_extension.h"
113 #include "content/renderer/web_ui_extension_data.h"
114 #include "content/renderer/webplugin_delegate_proxy.h"
115 #include "content/renderer/websharedworker_proxy.h"
116 #include "media/base/filter_collection.h"
117 #include "media/base/media_switches.h"
118 #include "media/base/message_loop_factory.h"
119 #include "media/filters/audio_renderer_impl.h"
120 #include "media/filters/gpu_video_decoder.h"
121 #include "net/base/data_url.h"
122 #include "net/base/escape.h"
123 #include "net/base/net_errors.h"
124 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
125 #include "net/http/http_util.h"
126 #include "third_party/WebKit/Source/WebKit/chromium/public/WebAccessibilityObject.h"
127 #include "third_party/WebKit/Source/WebKit/chromium/public/WebColorName.h"
128 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDOMEvent.h"
129 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDOMMessageEvent.h"
130 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h"
131 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDateTimeChooserCompletion.h"
132 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDateTimeChooserParams.h"
133 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
134 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
135 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFileChooserParams.h"
136 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFileSystemCallbacks.h"
137 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFindOptions.h"
138 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFormControlElement.h"
139 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFormElement.h"
140 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
141 #include "third_party/WebKit/Source/WebKit/chromium/public/WebHelperPlugin.h"
142 #include "third_party/WebKit/Source/WebKit/chromium/public/WebHistoryItem.h"
143 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputElement.h"
144 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
145 #include "third_party/WebKit/Source/WebKit/chromium/public/WebIntent.h"
146 #include "third_party/WebKit/Source/WebKit/chromium/public/WebIntentRequest.h"
147 #include "third_party/WebKit/Source/WebKit/chromium/public/WebIntentServiceInfo.h"
148 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerAction.h"
149 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMessagePortChannel.h"
150 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNodeList.h"
151 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPageSerializer.h"
152 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPlugin.h"
153 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginAction.h"
154 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h"
155 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginDocument.h"
156 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginParams.h"
157 #include "third_party/WebKit/Source/WebKit/chromium/public/WebRange.h"
158 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptSource.h"
159 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSearchableFormData.h"
160 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
161 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityPolicy.h"
162 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSettings.h"
163 #include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageQuotaCallbacks.h"
164 #include "third_party/WebKit/Source/WebKit/chromium/public/WebUserMediaClient.h"
165 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
166 #include "third_party/WebKit/Source/WebKit/chromium/public/WebWindowFeatures.h"
167 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCString.h"
168 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebDragData.h"
169 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGraphicsContext3D.h"
170 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebHTTPBody.h"
171 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebImage.h"
172 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebPoint.h"
173 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
174 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSerializedScriptValue.h"
175 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h"
176 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSocketStreamHandle.h"
177 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
178 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h"
179 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLError.h"
180 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLRequest.h"
181 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLResponse.h"
182 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h"
183 #include "third_party/skia/include/core/SkBitmap.h"
184 #include "ui/base/dialogs/selected_file_info.h"
185 #include "ui/base/ui_base_switches.h"
186 #include "ui/gfx/native_widget_types.h"
187 #include "ui/gfx/point.h"
188 #include "ui/gfx/rect.h"
189 #include "ui/gfx/size_conversions.h"
190 #include "v8/include/v8.h"
191 #include "webkit/appcache/web_application_cache_host_impl.h"
192 #include "webkit/base/file_path_string_conversions.h"
193 #include "webkit/dom_storage/dom_storage_types.h"
194 #include "webkit/glue/alt_error_page_resource_fetcher.h"
195 #include "webkit/glue/dom_operations.h"
196 #include "webkit/glue/glue_serialize.h"
197 #include "webkit/glue/web_intent_service_data.h"
198 #include "webkit/glue/webdropdata.h"
199 #include "webkit/glue/webkit_constants.h"
200 #include "webkit/glue/webkit_glue.h"
201 #include "webkit/glue/weburlresponse_extradata_impl.h"
202 #include "webkit/gpu/webgraphicscontext3d_in_process_impl.h"
203 #include "webkit/media/webmediaplayer_impl.h"
204 #include "webkit/media/webmediaplayer_ms.h"
205 #include "webkit/plugins/npapi/plugin_list.h"
206 #include "webkit/plugins/npapi/webplugin_delegate.h"
207 #include "webkit/plugins/npapi/webplugin_delegate_impl.h"
208 #include "webkit/plugins/npapi/webplugin_impl.h"
210 #if defined(OS_ANDROID)
211 #include "content/common/android/device_info.h"
212 #include "content/renderer/android/address_detector.h"
213 #include "content/renderer/android/content_detector.h"
214 #include "content/renderer/android/email_detector.h"
215 #include "content/renderer/android/phone_number_detector.h"
216 #include "content/renderer/media/stream_texture_factory_impl_android.h"
217 #include "content/renderer/media/webmediaplayer_proxy_impl_android.h"
218 #include "third_party/WebKit/Source/WebKit/chromium/public/WebHitTestResult.h"
219 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebFloatPoint.h"
220 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebFloatRect.h"
221 #include "ui/gfx/rect_f.h"
222 #include "webkit/media/android/media_player_bridge_manager_impl.h"
223 #include "webkit/media/android/webmediaplayer_android.h"
224 #include "webkit/media/android/webmediaplayer_impl_android.h"
225 #include "webkit/media/android/webmediaplayer_in_process_android.h"
226 #include "webkit/media/android/webmediaplayer_manager_android.h"
227 #elif defined(OS_WIN)
228 // TODO(port): these files are currently Windows only because they concern:
229 // * theming
230 #include "ui/native_theme/native_theme_win.h"
231 #elif defined(USE_X11)
232 #include "third_party/WebKit/Source/WebKit/chromium/public/default/WebRenderTheme.h"
233 #include "ui/native_theme/native_theme.h"
234 #elif defined(OS_MACOSX)
235 #include "skia/ext/skia_utils_mac.h"
236 #endif
238 using WebKit::WebAccessibilityNotification;
239 using WebKit::WebAccessibilityObject;
240 using WebKit::WebApplicationCacheHost;
241 using WebKit::WebApplicationCacheHostClient;
242 using WebKit::WebCString;
243 using WebKit::WebColor;
244 using WebKit::WebColorName;
245 using WebKit::WebConsoleMessage;
246 using WebKit::WebContextMenuData;
247 using WebKit::WebCookieJar;
248 using WebKit::WebData;
249 using WebKit::WebDataSource;
250 using WebKit::WebDocument;
251 using WebKit::WebDOMEvent;
252 using WebKit::WebDOMMessageEvent;
253 using WebKit::WebDragData;
254 using WebKit::WebDragOperation;
255 using WebKit::WebDragOperationsMask;
256 using WebKit::WebEditingAction;
257 using WebKit::WebElement;
258 using WebKit::WebExternalPopupMenu;
259 using WebKit::WebExternalPopupMenuClient;
260 using WebKit::WebFileChooserCompletion;
261 using WebKit::WebFileSystem;
262 using WebKit::WebFileSystemCallbacks;
263 using WebKit::WebFindOptions;
264 using WebKit::WebFormControlElement;
265 using WebKit::WebFormElement;
266 using WebKit::WebFrame;
267 using WebKit::WebGestureEvent;
268 using WebKit::WebGraphicsContext3D;
269 using WebKit::WebHistoryItem;
270 using WebKit::WebHTTPBody;
271 using WebKit::WebIconURL;
272 using WebKit::WebImage;
273 using WebKit::WebInputElement;
274 using WebKit::WebInputEvent;
275 using WebKit::WebIntentRequest;
276 using WebKit::WebIntentServiceInfo;
277 using WebKit::WebMediaPlayer;
278 using WebKit::WebMediaPlayerAction;
279 using WebKit::WebMediaPlayerClient;
280 using WebKit::WebMouseEvent;
281 using WebKit::WebNavigationPolicy;
282 using WebKit::WebNavigationType;
283 using WebKit::WebNode;
284 using WebKit::WebPageSerializer;
285 using WebKit::WebPageSerializerClient;
286 using WebKit::WebPeerConnection00Handler;
287 using WebKit::WebPeerConnection00HandlerClient;
288 using WebKit::WebPeerConnectionHandler;
289 using WebKit::WebPeerConnectionHandlerClient;
290 using WebKit::WebPlugin;
291 using WebKit::WebPluginAction;
292 using WebKit::WebPluginContainer;
293 using WebKit::WebPluginDocument;
294 using WebKit::WebPluginParams;
295 using WebKit::WebPoint;
296 using WebKit::WebPopupMenuInfo;
297 using WebKit::WebRange;
298 using WebKit::WebRect;
299 using WebKit::WebReferrerPolicy;
300 using WebKit::WebScriptSource;
301 using WebKit::WebSearchableFormData;
302 using WebKit::WebSecurityOrigin;
303 using WebKit::WebSecurityPolicy;
304 using WebKit::WebSerializedScriptValue;
305 using WebKit::WebSettings;
306 using WebKit::WebSharedWorker;
307 using WebKit::WebSize;
308 using WebKit::WebSocketStreamHandle;
309 using WebKit::WebStorageNamespace;
310 using WebKit::WebStorageQuotaCallbacks;
311 using WebKit::WebStorageQuotaError;
312 using WebKit::WebStorageQuotaType;
313 using WebKit::WebString;
314 using WebKit::WebTextAffinity;
315 using WebKit::WebTextDirection;
316 using WebKit::WebTouchEvent;
317 using WebKit::WebURL;
318 using WebKit::WebURLError;
319 using WebKit::WebURLRequest;
320 using WebKit::WebURLResponse;
321 using WebKit::WebVector;
322 using WebKit::WebView;
323 using WebKit::WebWidget;
324 using WebKit::WebWindowFeatures;
325 using appcache::WebApplicationCacheHostImpl;
326 using base::Time;
327 using base::TimeDelta;
329 using webkit_glue::AltErrorPageResourceFetcher;
330 using webkit_glue::ResourceFetcher;
331 using webkit_glue::WebPreferences;
332 using webkit_glue::WebURLResponseExtraDataImpl;
334 #if defined(OS_ANDROID)
335 using WebKit::WebContentDetectionResult;
336 using WebKit::WebFloatPoint;
337 using WebKit::WebFloatRect;
338 using WebKit::WebHitTestResult;
339 #endif
341 namespace content {
343 //-----------------------------------------------------------------------------
345 typedef std::map<WebKit::WebView*, RenderViewImpl*> ViewMap;
346 static base::LazyInstance<ViewMap> g_view_map = LAZY_INSTANCE_INITIALIZER;
347 typedef std::map<int32, RenderViewImpl*> RoutingIDViewMap;
348 static base::LazyInstance<RoutingIDViewMap> g_routing_id_view_map =
349 LAZY_INSTANCE_INITIALIZER;
351 // Time, in seconds, we delay before sending content state changes (such as form
352 // state and scroll position) to the browser. We delay sending changes to avoid
353 // spamming the browser.
354 // To avoid having tab/session restore require sending a message to get the
355 // current content state during tab closing we use a shorter timeout for the
356 // foreground renderer. This means there is a small window of time from which
357 // content state is modified and not sent to session restore, but this is
358 // better than having to wake up all renderers during shutdown.
359 static const int kDelaySecondsForContentStateSyncHidden = 5;
360 static const int kDelaySecondsForContentStateSync = 1;
362 static const size_t kExtraCharsBeforeAndAfterSelection = 100;
364 // The maximum number of popups that can be spawned from one page.
365 static const int kMaximumNumberOfUnacknowledgedPopups = 25;
367 static const float kScalingIncrement = 0.1f;
369 static const float kScalingIncrementForGesture = 0.01f;
371 #if defined(OS_ANDROID)
372 // Delay between tapping in content and launching the associated android intent.
373 // Used to allow users see what has been recognized as content.
374 static const size_t kContentIntentDelayMilliseconds = 700;
375 #endif
377 static RenderViewImpl* (*g_create_render_view_impl)(RenderViewImplParams*) =
378 NULL;
380 static WebKit::WebFrame* FindFrameByID(WebKit::WebFrame* root, int frame_id) {
381 for (WebFrame* frame = root; frame; frame = frame->traverseNext(false)) {
382 if (frame->identifier() == frame_id)
383 return frame;
385 return NULL;
388 static void GetRedirectChain(WebDataSource* ds, std::vector<GURL>* result) {
389 // Replace any occurrences of swappedout:// with about:blank.
390 const WebURL& blank_url = GURL(chrome::kAboutBlankURL);
391 WebVector<WebURL> urls;
392 ds->redirectChain(urls);
393 result->reserve(urls.size());
394 for (size_t i = 0; i < urls.size(); ++i) {
395 if (urls[i] != GURL(kSwappedOutURL))
396 result->push_back(urls[i]);
397 else
398 result->push_back(blank_url);
402 // If |data_source| is non-null and has a DocumentState associated with it,
403 // the AltErrorPageResourceFetcher is reset.
404 static void StopAltErrorPageFetcher(WebDataSource* data_source) {
405 if (data_source) {
406 DocumentState* document_state = DocumentState::FromDataSource(data_source);
407 if (document_state)
408 document_state->set_alt_error_page_fetcher(NULL);
412 static bool IsReload(const ViewMsg_Navigate_Params& params) {
413 return
414 params.navigation_type == ViewMsg_Navigate_Type::RELOAD ||
415 params.navigation_type == ViewMsg_Navigate_Type::RELOAD_IGNORING_CACHE ||
416 params.navigation_type ==
417 ViewMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL;
420 static WebReferrerPolicy GetReferrerPolicyFromRequest(
421 WebFrame* frame,
422 const WebURLRequest& request) {
423 return request.extraData() ?
424 static_cast<RequestExtraData*>(request.extraData())->referrer_policy() :
425 frame->document().referrerPolicy();
428 static WebURLResponseExtraDataImpl* GetExtraDataFromResponse(
429 const WebURLResponse& response) {
430 return static_cast<WebURLResponseExtraDataImpl*>(
431 response.extraData());
434 NOINLINE static void CrashIntentionally() {
435 // NOTE(shess): Crash directly rather than using NOTREACHED() so
436 // that the signature is easier to triage in crash reports.
437 volatile int* zero = NULL;
438 *zero = 0;
441 static void MaybeHandleDebugURL(const GURL& url) {
442 if (!url.SchemeIs(chrome::kChromeUIScheme))
443 return;
444 if (url == GURL(chrome::kChromeUICrashURL)) {
445 CrashIntentionally();
446 } else if (url == GURL(chrome::kChromeUIKillURL)) {
447 base::KillProcess(base::GetCurrentProcessHandle(), 1, false);
448 } else if (url == GURL(chrome::kChromeUIHangURL)) {
449 for (;;) {
450 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
452 } else if (url == GURL(kChromeUIShorthangURL)) {
453 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(20));
457 // Returns false unless this is a top-level navigation.
458 static bool IsTopLevelNavigation(WebFrame* frame) {
459 return frame->parent() == NULL;
462 // Returns false unless this is a top-level navigation that crosses origins.
463 static bool IsNonLocalTopLevelNavigation(const GURL& url,
464 WebFrame* frame,
465 WebNavigationType type) {
466 if (!IsTopLevelNavigation(frame))
467 return false;
469 // Navigations initiated within Webkit are not sent out to the external host
470 // in the following cases.
471 // 1. The url scheme is not http/https
472 // 2. The origin of the url and the opener is the same in which case the
473 // opener relationship is maintained.
474 // 3. Reloads/form submits/back forward navigations
475 if (!url.SchemeIs(chrome::kHttpScheme) && !url.SchemeIs(chrome::kHttpsScheme))
476 return false;
478 // Not interested in reloads/form submits/resubmits/back forward navigations.
479 if (type != WebKit::WebNavigationTypeReload &&
480 type != WebKit::WebNavigationTypeFormSubmitted &&
481 type != WebKit::WebNavigationTypeFormResubmitted &&
482 type != WebKit::WebNavigationTypeBackForward) {
483 // The opener relationship between the new window and the parent allows the
484 // new window to script the parent and vice versa. This is not allowed if
485 // the origins of the two domains are different. This can be treated as a
486 // top level navigation and routed back to the host.
487 WebKit::WebFrame* opener = frame->opener();
488 if (!opener) {
489 return true;
492 if (url.GetOrigin() != GURL(opener->document().url()).GetOrigin())
493 return true;
495 return false;
498 static void NotifyTimezoneChange(WebKit::WebFrame* frame) {
499 v8::HandleScope handle_scope;
500 v8::Context::Scope context_scope(frame->mainWorldScriptContext());
501 v8::Date::DateTimeConfigurationChangeNotification();
502 WebKit::WebFrame* child = frame->firstChild();
503 for (; child; child = child->nextSibling())
504 NotifyTimezoneChange(child);
507 ///////////////////////////////////////////////////////////////////////////////
509 struct RenderViewImpl::PendingFileChooser {
510 PendingFileChooser(const FileChooserParams& p, WebFileChooserCompletion* c)
511 : params(p),
512 completion(c) {
514 FileChooserParams params;
515 WebFileChooserCompletion* completion; // MAY BE NULL to skip callback.
518 namespace {
520 class WebWidgetLockTarget : public MouseLockDispatcher::LockTarget {
521 public:
522 explicit WebWidgetLockTarget(WebKit::WebWidget* webwidget)
523 : webwidget_(webwidget) {}
525 virtual void OnLockMouseACK(bool succeeded) OVERRIDE {
526 if (succeeded)
527 webwidget_->didAcquirePointerLock();
528 else
529 webwidget_->didNotAcquirePointerLock();
532 virtual void OnMouseLockLost() OVERRIDE {
533 webwidget_->didLosePointerLock();
536 virtual bool HandleMouseLockedInputEvent(
537 const WebKit::WebMouseEvent &event) OVERRIDE {
538 // The WebWidget handles mouse lock in WebKit's handleInputEvent().
539 return false;
542 private:
543 WebKit::WebWidget* webwidget_;
546 int64 ExtractPostId(const WebHistoryItem& item) {
547 if (item.isNull())
548 return -1;
550 if (item.httpBody().isNull())
551 return -1;
553 return item.httpBody().identifier();
556 } // namespace
558 RenderViewImpl::RenderViewImpl(RenderViewImplParams* params)
559 : RenderWidget(WebKit::WebPopupTypeNone,
560 params->screen_info,
561 params->swapped_out),
562 webkit_preferences_(params->webkit_prefs),
563 send_content_state_immediately_(false),
564 enabled_bindings_(0),
565 send_preferred_size_changes_(false),
566 is_loading_(false),
567 navigation_gesture_(NavigationGestureUnknown),
568 opened_by_user_gesture_(true),
569 opener_suppressed_(false),
570 page_id_(-1),
571 last_page_id_sent_to_browser_(-1),
572 next_page_id_(params->next_page_id),
573 history_list_offset_(-1),
574 history_list_length_(0),
575 target_url_status_(TARGET_NONE),
576 selection_text_offset_(0),
577 cached_is_main_frame_pinned_to_left_(false),
578 cached_is_main_frame_pinned_to_right_(false),
579 cached_has_main_frame_horizontal_scrollbar_(false),
580 cached_has_main_frame_vertical_scrollbar_(false),
581 ALLOW_THIS_IN_INITIALIZER_LIST(cookie_jar_(this)),
582 geolocation_dispatcher_(NULL),
583 input_tag_speech_dispatcher_(NULL),
584 speech_recognition_dispatcher_(NULL),
585 device_orientation_dispatcher_(NULL),
586 media_stream_dispatcher_(NULL),
587 browser_plugin_manager_(NULL),
588 media_stream_impl_(NULL),
589 devtools_agent_(NULL),
590 accessibility_mode_(AccessibilityModeOff),
591 renderer_accessibility_(NULL),
592 java_bridge_dispatcher_(NULL),
593 mouse_lock_dispatcher_(NULL),
594 favicon_helper_(NULL),
595 #if defined(OS_ANDROID)
596 body_background_color_(SK_ColorWHITE),
597 update_frame_info_scheduled_(false),
598 expected_content_intent_id_(0),
599 media_player_proxy_(NULL),
600 synchronous_find_active_match_ordinal_(-1),
601 ALLOW_THIS_IN_INITIALIZER_LIST(
602 load_progress_tracker_(new LoadProgressTracker(this))),
603 #endif
604 session_storage_namespace_id_(params->session_storage_namespace_id),
605 handling_select_range_(false),
606 next_snapshot_id_(0),
607 #if defined(OS_WIN)
608 focused_plugin_id_(-1),
609 #endif
610 updating_frame_tree_(false),
611 pending_frame_tree_update_(false),
612 target_process_id_(0),
613 target_routing_id_(0) {
614 #if defined(ENABLE_PLUGINS)
615 pepper_helper_.reset(new PepperPluginDelegateImpl(this));
616 #else
617 pepper_helper_.reset(new RenderViewPepperHelper());
618 #endif
619 set_throttle_input_events(params->renderer_prefs.throttle_input_events);
620 routing_id_ = params->routing_id;
621 surface_id_ = params->surface_id;
622 if (params->opener_id != MSG_ROUTING_NONE && params->is_renderer_created)
623 opener_id_ = params->opener_id;
625 // Ensure we start with a valid next_page_id_ from the browser.
626 DCHECK_GE(next_page_id_, 0);
628 #if defined(ENABLE_NOTIFICATIONS)
629 notification_provider_ = new NotificationProvider(this);
630 #else
631 notification_provider_ = NULL;
632 #endif
634 webwidget_ = WebView::create(this);
635 webwidget_mouse_lock_target_.reset(new WebWidgetLockTarget(webwidget_));
637 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
639 #if defined(OS_ANDROID)
640 scoped_ptr<DeviceInfo> device_info(new DeviceInfo());
642 const std::string region_code =
643 command_line.HasSwitch(switches::kNetworkCountryIso)
644 ? command_line.GetSwitchValueASCII(switches::kNetworkCountryIso)
645 : device_info->GetNetworkCountryIso();
646 content_detectors_.push_back(linked_ptr<ContentDetector>(
647 new AddressDetector()));
648 content_detectors_.push_back(linked_ptr<ContentDetector>(
649 new PhoneNumberDetector(region_code)));
650 content_detectors_.push_back(linked_ptr<ContentDetector>(
651 new EmailDetector()));
652 #endif
654 if (params->counter) {
655 shared_popup_counter_ = params->counter;
656 // Only count this if it isn't swapped out upon creation.
657 if (!params->swapped_out)
658 shared_popup_counter_->data++;
659 decrement_shared_popup_at_destruction_ = true;
660 } else {
661 shared_popup_counter_ = new SharedRenderViewCounter(0);
662 decrement_shared_popup_at_destruction_ = false;
665 RenderThread::Get()->AddRoute(routing_id_, this);
666 // Take a reference on behalf of the RenderThread. This will be balanced
667 // when we receive ViewMsg_ClosePage.
668 AddRef();
670 // If this is a popup, we must wait for the CreatingNew_ACK message before
671 // completing initialization. Otherwise, we can finish it now.
672 if (opener_id_ == MSG_ROUTING_NONE) {
673 did_show_ = true;
674 CompleteInit();
677 g_view_map.Get().insert(std::make_pair(webview(), this));
678 g_routing_id_view_map.Get().insert(std::make_pair(routing_id_, this));
679 webview()->setDeviceScaleFactor(device_scale_factor_);
680 webkit_preferences_.Apply(webview());
681 webview()->initializeMainFrame(this);
683 if (command_line.HasSwitch(switches::kEnableTouchDragDrop))
684 webview()->settings()->setTouchDragDropEnabled(true);
686 if (!params->frame_name.empty())
687 webview()->mainFrame()->setName(params->frame_name);
688 webview()->settings()->setMinimumTimerInterval(
689 is_hidden() ? webkit_glue::kBackgroundTabTimerInterval :
690 webkit_glue::kForegroundTabTimerInterval);
692 OnSetRendererPrefs(params->renderer_prefs);
694 #if defined(ENABLE_WEBRTC)
695 if (!media_stream_dispatcher_)
696 media_stream_dispatcher_ = new MediaStreamDispatcher(this);
697 #endif
699 new MHTMLGenerator(this);
700 #if defined(OS_MACOSX)
701 new TextInputClientObserver(this);
702 #endif // defined(OS_MACOSX)
704 #if defined(OS_ANDROID)
705 media_player_manager_.reset(
706 new webkit_media::WebMediaPlayerManagerAndroid());
707 #endif
709 // The next group of objects all implement RenderViewObserver, so are deleted
710 // along with the RenderView automatically.
711 devtools_agent_ = new DevToolsAgent(this);
712 mouse_lock_dispatcher_ = new RenderViewMouseLockDispatcher(this);
713 intents_host_ = new WebIntentsHost(this);
714 favicon_helper_ = new FaviconHelper(this);
716 // Create renderer_accessibility_ if needed.
717 OnSetAccessibilityMode(params->accessibility_mode);
719 new IdleUserDetector(this);
721 if (command_line.HasSwitch(switches::kDomAutomationController))
722 enabled_bindings_ |= BINDINGS_POLICY_DOM_AUTOMATION;
724 ProcessViewLayoutFlags(command_line);
726 GetContentClient()->renderer()->RenderViewCreated(this);
728 // If we have an opener_id but we weren't created by a renderer, then
729 // it's the browser asking us to set our opener to another RenderView.
730 if (params->opener_id != MSG_ROUTING_NONE && !params->is_renderer_created) {
731 RenderViewImpl* opener_view = FromRoutingID(params->opener_id);
732 if (opener_view)
733 webview()->mainFrame()->setOpener(opener_view->webview()->mainFrame());
736 // If we are initially swapped out, navigate to kSwappedOutURL.
737 // This ensures we are in a unique origin that others cannot script.
738 if (is_swapped_out_)
739 NavigateToSwappedOutURL(webview()->mainFrame());
742 RenderViewImpl::~RenderViewImpl() {
743 history_page_ids_.clear();
745 if (decrement_shared_popup_at_destruction_)
746 shared_popup_counter_->data--;
748 // If file chooser is still waiting for answer, dispatch empty answer.
749 while (!file_chooser_completions_.empty()) {
750 if (file_chooser_completions_.front()->completion) {
751 file_chooser_completions_.front()->completion->didChooseFile(
752 WebVector<WebString>());
754 file_chooser_completions_.pop_front();
757 #if defined(OS_MACOSX)
758 // Destroy all fake plugin window handles on the browser side.
759 while (!fake_plugin_window_handles_.empty()) {
760 // Make sure no NULL plugin window handles were inserted into this list.
761 DCHECK(*fake_plugin_window_handles_.begin());
762 // DestroyFakePluginWindowHandle modifies fake_plugin_window_handles_.
763 DestroyFakePluginWindowHandle(*fake_plugin_window_handles_.begin());
765 #endif
767 #ifndef NDEBUG
768 // Make sure we are no longer referenced by the ViewMap or RoutingIDViewMap.
769 ViewMap* views = g_view_map.Pointer();
770 for (ViewMap::iterator it = views->begin(); it != views->end(); ++it)
771 DCHECK_NE(this, it->second) << "Failed to call Close?";
772 RoutingIDViewMap* routing_id_views = g_routing_id_view_map.Pointer();
773 for (RoutingIDViewMap::iterator it = routing_id_views->begin();
774 it != routing_id_views->end(); ++it)
775 DCHECK_NE(this, it->second) << "Failed to call Close?";
776 #endif
778 FOR_EACH_OBSERVER(RenderViewObserver, observers_, RenderViewGone());
779 FOR_EACH_OBSERVER(RenderViewObserver, observers_, OnDestruct());
782 /*static*/
783 RenderViewImpl* RenderViewImpl::FromWebView(WebView* webview) {
784 ViewMap* views = g_view_map.Pointer();
785 ViewMap::iterator it = views->find(webview);
786 return it == views->end() ? NULL : it->second;
789 /*static*/
790 RenderView* RenderView::FromWebView(WebKit::WebView* webview) {
791 return RenderViewImpl::FromWebView(webview);
794 /*static*/
795 RenderViewImpl* RenderViewImpl::FromRoutingID(int32 routing_id) {
796 RoutingIDViewMap* views = g_routing_id_view_map.Pointer();
797 RoutingIDViewMap::iterator it = views->find(routing_id);
798 return it == views->end() ? NULL : it->second;
801 /*static*/
802 RenderView* RenderView::FromRoutingID(int routing_id) {
803 return RenderViewImpl::FromRoutingID(routing_id);
806 /*static*/
807 void RenderView::ForEach(RenderViewVisitor* visitor) {
808 ViewMap* views = g_view_map.Pointer();
809 for (ViewMap::iterator it = views->begin(); it != views->end(); ++it) {
810 if (!visitor->Visit(it->second))
811 return;
815 /*static*/
816 RenderViewImpl* RenderViewImpl::Create(
817 int32 opener_id,
818 const RendererPreferences& renderer_prefs,
819 const WebPreferences& webkit_prefs,
820 SharedRenderViewCounter* counter,
821 int32 routing_id,
822 int32 surface_id,
823 int64 session_storage_namespace_id,
824 const string16& frame_name,
825 bool is_renderer_created,
826 bool swapped_out,
827 int32 next_page_id,
828 const WebKit::WebScreenInfo& screen_info,
829 AccessibilityMode accessibility_mode) {
830 DCHECK(routing_id != MSG_ROUTING_NONE);
831 RenderViewImplParams params(
832 opener_id,
833 renderer_prefs,
834 webkit_prefs,
835 counter,
836 routing_id,
837 surface_id,
838 session_storage_namespace_id,
839 frame_name,
840 is_renderer_created,
841 swapped_out,
842 next_page_id,
843 screen_info,
844 accessibility_mode);
845 if (g_create_render_view_impl)
846 return g_create_render_view_impl(&params);
847 return new RenderViewImpl(&params);
850 // static
851 void RenderViewImpl::InstallCreateHook(
852 RenderViewImpl* (*create_render_view_impl)(RenderViewImplParams*)) {
853 CHECK(!g_create_render_view_impl);
854 g_create_render_view_impl = create_render_view_impl;
857 void RenderViewImpl::AddObserver(RenderViewObserver* observer) {
858 observers_.AddObserver(observer);
861 void RenderViewImpl::RemoveObserver(RenderViewObserver* observer) {
862 observer->RenderViewGone();
863 observers_.RemoveObserver(observer);
866 WebKit::WebView* RenderViewImpl::webview() const {
867 return static_cast<WebKit::WebView*>(webwidget());
870 void RenderViewImpl::PluginCrashed(const FilePath& plugin_path) {
871 Send(new ViewHostMsg_CrashedPlugin(routing_id_, plugin_path));
874 void RenderViewImpl::RegisterPluginDelegate(WebPluginDelegateProxy* delegate) {
875 plugin_delegates_.insert(delegate);
876 // If the renderer is visible, set initial visibility and focus state.
877 if (!is_hidden()) {
878 #if defined(OS_MACOSX)
879 delegate->SetContainerVisibility(true);
880 if (webview() && webview()->isActive())
881 delegate->SetWindowFocus(true);
882 #endif
884 // Plugins start assuming the content has focus (so that they work in
885 // environments where RenderView isn't hosting them), so we always have to
886 // set the initial state. See webplugin_delegate_impl.h for details.
887 delegate->SetContentAreaFocus(has_focus());
890 void RenderViewImpl::UnregisterPluginDelegate(
891 WebPluginDelegateProxy* delegate) {
892 plugin_delegates_.erase(delegate);
895 bool RenderViewImpl::GetPluginInfo(const GURL& url,
896 const GURL& page_url,
897 const std::string& mime_type,
898 webkit::WebPluginInfo* plugin_info,
899 std::string* actual_mime_type) {
900 bool found = false;
901 Send(new ViewHostMsg_GetPluginInfo(
902 routing_id_, url, page_url, mime_type, &found, plugin_info,
903 actual_mime_type));
904 return found;
907 void RenderViewImpl::TransferActiveWheelFlingAnimation(
908 const WebKit::WebActiveWheelFlingParameters& params) {
909 if (webview())
910 webview()->transferActiveWheelFlingAnimation(params);
913 bool RenderViewImpl::HasIMETextFocus() {
914 return GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE;
917 bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) {
918 WebFrame* main_frame = webview() ? webview()->mainFrame() : NULL;
919 if (main_frame)
920 GetContentClient()->SetActiveURL(main_frame->document().url());
922 ObserverListBase<RenderViewObserver>::Iterator it(observers_);
923 RenderViewObserver* observer;
924 while ((observer = it.GetNext()) != NULL)
925 if (observer->OnMessageReceived(message))
926 return true;
928 bool handled = true;
929 bool msg_is_ok = true;
930 IPC_BEGIN_MESSAGE_MAP_EX(RenderViewImpl, message, msg_is_ok)
931 IPC_MESSAGE_HANDLER(ViewMsg_Navigate, OnNavigate)
932 IPC_MESSAGE_HANDLER(ViewMsg_Stop, OnStop)
933 IPC_MESSAGE_HANDLER(ViewMsg_ReloadFrame, OnReloadFrame)
934 IPC_MESSAGE_HANDLER(ViewMsg_Undo, OnUndo)
935 IPC_MESSAGE_HANDLER(ViewMsg_Redo, OnRedo)
936 IPC_MESSAGE_HANDLER(ViewMsg_Cut, OnCut)
937 IPC_MESSAGE_HANDLER(ViewMsg_Copy, OnCopy)
938 IPC_MESSAGE_HANDLER(ViewMsg_Paste, OnPaste)
939 IPC_MESSAGE_HANDLER(ViewMsg_PasteAndMatchStyle, OnPasteAndMatchStyle)
940 IPC_MESSAGE_HANDLER(ViewMsg_Replace, OnReplace)
941 IPC_MESSAGE_HANDLER(ViewMsg_Delete, OnDelete)
942 IPC_MESSAGE_HANDLER(ViewMsg_SelectAll, OnSelectAll)
943 IPC_MESSAGE_HANDLER(ViewMsg_Unselect, OnUnselect)
944 IPC_MESSAGE_HANDLER(ViewMsg_SetEditableSelectionOffsets,
945 OnSetEditableSelectionOffsets)
946 IPC_MESSAGE_HANDLER(ViewMsg_SetCompositionFromExistingText,
947 OnSetCompositionFromExistingText)
948 IPC_MESSAGE_HANDLER(ViewMsg_ExtendSelectionAndDelete,
949 OnExtendSelectionAndDelete)
950 IPC_MESSAGE_HANDLER(ViewMsg_SelectRange, OnSelectRange)
951 IPC_MESSAGE_HANDLER(ViewMsg_CopyImageAt, OnCopyImageAt)
952 IPC_MESSAGE_HANDLER(ViewMsg_ExecuteEditCommand, OnExecuteEditCommand)
953 IPC_MESSAGE_HANDLER(ViewMsg_Find, OnFind)
954 IPC_MESSAGE_HANDLER(ViewMsg_StopFinding, OnStopFinding)
955 IPC_MESSAGE_HANDLER(ViewMsg_Zoom, OnZoom)
956 IPC_MESSAGE_HANDLER(ViewMsg_SetZoomLevel, OnSetZoomLevel)
957 IPC_MESSAGE_HANDLER(ViewMsg_ZoomFactor, OnZoomFactor)
958 IPC_MESSAGE_HANDLER(ViewMsg_SetZoomLevelForLoadingURL,
959 OnSetZoomLevelForLoadingURL)
960 IPC_MESSAGE_HANDLER(ViewMsg_SetPageEncoding, OnSetPageEncoding)
961 IPC_MESSAGE_HANDLER(ViewMsg_ResetPageEncodingToDefault,
962 OnResetPageEncodingToDefault)
963 IPC_MESSAGE_HANDLER(ViewMsg_ScriptEvalRequest, OnScriptEvalRequest)
964 IPC_MESSAGE_HANDLER(ViewMsg_PostMessageEvent, OnPostMessageEvent)
965 IPC_MESSAGE_HANDLER(ViewMsg_CSSInsertRequest, OnCSSInsertRequest)
966 IPC_MESSAGE_HANDLER(DragMsg_TargetDragEnter, OnDragTargetDragEnter)
967 IPC_MESSAGE_HANDLER(DragMsg_TargetDragOver, OnDragTargetDragOver)
968 IPC_MESSAGE_HANDLER(DragMsg_TargetDragLeave, OnDragTargetDragLeave)
969 IPC_MESSAGE_HANDLER(DragMsg_TargetDrop, OnDragTargetDrop)
970 IPC_MESSAGE_HANDLER(DragMsg_SourceEndedOrMoved, OnDragSourceEndedOrMoved)
971 IPC_MESSAGE_HANDLER(DragMsg_SourceSystemDragEnded,
972 OnDragSourceSystemDragEnded)
973 IPC_MESSAGE_HANDLER(ViewMsg_AllowBindings, OnAllowBindings)
974 IPC_MESSAGE_HANDLER(ViewMsg_SetInitialFocus, OnSetInitialFocus)
975 IPC_MESSAGE_HANDLER(ViewMsg_ScrollFocusedEditableNodeIntoRect,
976 OnScrollFocusedEditableNodeIntoRect)
977 IPC_MESSAGE_HANDLER(ViewMsg_UpdateTargetURL_ACK, OnUpdateTargetURLAck)
978 IPC_MESSAGE_HANDLER(ViewMsg_UpdateWebPreferences, OnUpdateWebPreferences)
979 IPC_MESSAGE_HANDLER(ViewMsg_TimezoneChange, OnUpdateTimezone)
980 IPC_MESSAGE_HANDLER(ViewMsg_SetAltErrorPageURL, OnSetAltErrorPageURL)
981 IPC_MESSAGE_HANDLER(ViewMsg_EnumerateDirectoryResponse,
982 OnEnumerateDirectoryResponse)
983 IPC_MESSAGE_HANDLER(ViewMsg_RunFileChooserResponse, OnFileChooserResponse)
984 IPC_MESSAGE_HANDLER(ViewMsg_ShouldClose, OnShouldClose)
985 IPC_MESSAGE_HANDLER(ViewMsg_SwapOut, OnSwapOut)
986 IPC_MESSAGE_HANDLER(ViewMsg_ClosePage, OnClosePage)
987 IPC_MESSAGE_HANDLER(ViewMsg_ThemeChanged, OnThemeChanged)
988 IPC_MESSAGE_HANDLER(ViewMsg_DisassociateFromPopupCount,
989 OnDisassociateFromPopupCount)
990 IPC_MESSAGE_HANDLER(ViewMsg_MoveOrResizeStarted, OnMoveOrResizeStarted)
991 IPC_MESSAGE_HANDLER(ViewMsg_ClearFocusedNode, OnClearFocusedNode)
992 IPC_MESSAGE_HANDLER(ViewMsg_SetBackground, OnSetBackground)
993 IPC_MESSAGE_HANDLER(ViewMsg_EnablePreferredSizeChangedMode,
994 OnEnablePreferredSizeChangedMode)
995 IPC_MESSAGE_HANDLER(ViewMsg_EnableAutoResize, OnEnableAutoResize)
996 IPC_MESSAGE_HANDLER(ViewMsg_DisableAutoResize, OnDisableAutoResize)
997 IPC_MESSAGE_HANDLER(ViewMsg_DisableScrollbarsForSmallWindows,
998 OnDisableScrollbarsForSmallWindows)
999 IPC_MESSAGE_HANDLER(ViewMsg_SetRendererPrefs, OnSetRendererPrefs)
1000 IPC_MESSAGE_HANDLER(ViewMsg_MediaPlayerActionAt, OnMediaPlayerActionAt)
1001 IPC_MESSAGE_HANDLER(ViewMsg_OrientationChangeEvent,
1002 OnOrientationChangeEvent)
1003 IPC_MESSAGE_HANDLER(ViewMsg_PluginActionAt, OnPluginActionAt)
1004 IPC_MESSAGE_HANDLER(ViewMsg_SetActive, OnSetActive)
1005 IPC_MESSAGE_HANDLER(ViewMsg_SetNavigationStartTime,
1006 OnSetNavigationStartTime)
1007 IPC_MESSAGE_HANDLER(ViewMsg_SetEditCommandsForNextKeyEvent,
1008 OnSetEditCommandsForNextKeyEvent)
1009 IPC_MESSAGE_HANDLER(ViewMsg_CustomContextMenuAction,
1010 OnCustomContextMenuAction)
1011 IPC_MESSAGE_HANDLER(ViewMsg_AsyncOpenFile_ACK, OnAsyncFileOpened)
1012 IPC_MESSAGE_HANDLER(ViewMsg_PpapiBrokerChannelCreated,
1013 OnPpapiBrokerChannelCreated)
1014 IPC_MESSAGE_HANDLER(ViewMsg_PpapiBrokerPermissionResult,
1015 OnPpapiBrokerPermissionResult)
1016 IPC_MESSAGE_HANDLER(ViewMsg_GetAllSavableResourceLinksForCurrentPage,
1017 OnGetAllSavableResourceLinksForCurrentPage)
1018 IPC_MESSAGE_HANDLER(
1019 ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks,
1020 OnGetSerializedHtmlDataForCurrentPageWithLocalLinks)
1021 IPC_MESSAGE_HANDLER(ViewMsg_ContextMenuClosed, OnContextMenuClosed)
1022 // TODO(viettrungluu): Move to a separate message filter.
1023 IPC_MESSAGE_HANDLER(ViewMsg_SetHistoryLengthAndPrune,
1024 OnSetHistoryLengthAndPrune)
1025 IPC_MESSAGE_HANDLER(ViewMsg_EnableViewSourceMode, OnEnableViewSourceMode)
1026 IPC_MESSAGE_HANDLER(JavaBridgeMsg_Init, OnJavaBridgeInit)
1027 IPC_MESSAGE_HANDLER(ViewMsg_SetAccessibilityMode, OnSetAccessibilityMode)
1028 IPC_MESSAGE_HANDLER(ViewMsg_DisownOpener, OnDisownOpener)
1029 IPC_MESSAGE_HANDLER(ViewMsg_UpdateFrameTree, OnUpdatedFrameTree)
1030 #if defined(OS_ANDROID)
1031 IPC_MESSAGE_HANDLER(ViewMsg_ActivateNearestFindResult,
1032 OnActivateNearestFindResult)
1033 IPC_MESSAGE_HANDLER(ViewMsg_FindMatchRects, OnFindMatchRects)
1034 IPC_MESSAGE_HANDLER(ViewMsg_SelectPopupMenuItems, OnSelectPopupMenuItems)
1035 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewMsg_SynchronousFind, OnSynchronousFind)
1036 IPC_MESSAGE_HANDLER(ViewMsg_UndoScrollFocusedEditableNodeIntoView,
1037 OnUndoScrollFocusedEditableNodeIntoRect)
1038 #elif defined(OS_MACOSX)
1039 IPC_MESSAGE_HANDLER(ViewMsg_CopyToFindPboard, OnCopyToFindPboard)
1040 IPC_MESSAGE_HANDLER(ViewMsg_PluginImeCompositionCompleted,
1041 OnPluginImeCompositionCompleted)
1042 IPC_MESSAGE_HANDLER(ViewMsg_SelectPopupMenuItem, OnSelectPopupMenuItem)
1043 IPC_MESSAGE_HANDLER(ViewMsg_SetInLiveResize, OnSetInLiveResize)
1044 IPC_MESSAGE_HANDLER(ViewMsg_SetWindowVisibility, OnSetWindowVisibility)
1045 IPC_MESSAGE_HANDLER(ViewMsg_WindowFrameChanged, OnWindowFrameChanged)
1046 #endif
1047 IPC_MESSAGE_HANDLER(ViewMsg_ReleaseDisambiguationPopupDIB,
1048 OnReleaseDisambiguationPopupDIB)
1049 IPC_MESSAGE_HANDLER(ViewMsg_WindowSnapshotCompleted,
1050 OnWindowSnapshotCompleted)
1052 // Have the super handle all other messages.
1053 IPC_MESSAGE_UNHANDLED(handled = RenderWidget::OnMessageReceived(message))
1054 IPC_END_MESSAGE_MAP()
1056 if (!msg_is_ok) {
1057 // The message had a handler, but its deserialization failed.
1058 // Kill the renderer to avoid potential spoofing attacks.
1059 CHECK(false) << "Unable to deserialize message in RenderViewImpl.";
1062 return handled;
1065 void RenderViewImpl::OnNavigate(const ViewMsg_Navigate_Params& params) {
1066 MaybeHandleDebugURL(params.url);
1067 if (!webview())
1068 return;
1070 FOR_EACH_OBSERVER(RenderViewObserver, observers_, Navigate(params.url));
1072 bool is_reload = IsReload(params);
1074 // If this is a stale back/forward (due to a recent navigation the browser
1075 // didn't know about), ignore it.
1076 if (IsBackForwardToStaleEntry(params, is_reload))
1077 return;
1079 // Swap this renderer back in if necessary.
1080 if (is_swapped_out_) {
1081 // We marked the view as hidden when swapping the view out, so be sure to
1082 // reset the visibility state before navigating to the new URL.
1083 webview()->setVisibilityState(visibilityState(), false);
1085 // If this is an attempt to reload while we are swapped out, we should not
1086 // reload swappedout://, but the previous page, which is stored in
1087 // params.state. Setting is_reload to false will treat this like a back
1088 // navigation to accomplish that.
1089 is_reload = false;
1091 SetSwappedOut(false);
1094 history_list_offset_ = params.current_history_list_offset;
1095 history_list_length_ = params.current_history_list_length;
1096 if (history_list_length_ >= 0)
1097 history_page_ids_.resize(history_list_length_, -1);
1098 if (params.pending_history_list_offset >= 0 &&
1099 params.pending_history_list_offset < history_list_length_)
1100 history_page_ids_[params.pending_history_list_offset] = params.page_id;
1102 GetContentClient()->SetActiveURL(params.url);
1104 WebFrame* main_frame = webview()->mainFrame();
1105 if (is_reload && main_frame->currentHistoryItem().isNull()) {
1106 // We cannot reload if we do not have any history state. This happens, for
1107 // example, when recovering from a crash. Our workaround here is a bit of
1108 // a hack since it means that reload after a crashed tab does not cause an
1109 // end-to-end cache validation.
1110 is_reload = false;
1113 pending_navigation_params_.reset(new ViewMsg_Navigate_Params(params));
1115 // If we are reloading, then WebKit will use the history state of the current
1116 // page, so we should just ignore any given history state. Otherwise, if we
1117 // have history state, then we need to navigate to it, which corresponds to a
1118 // back/forward navigation event.
1119 if (is_reload) {
1120 bool reload_original_url =
1121 (params.navigation_type ==
1122 ViewMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL);
1123 bool ignore_cache = (params.navigation_type ==
1124 ViewMsg_Navigate_Type::RELOAD_IGNORING_CACHE);
1126 if (reload_original_url)
1127 main_frame->reloadWithOverrideURL(params.url, true);
1128 else
1129 main_frame->reload(ignore_cache);
1130 } else if (!params.state.empty()) {
1131 // We must know the page ID of the page we are navigating back to.
1132 DCHECK_NE(params.page_id, -1);
1133 WebHistoryItem item = webkit_glue::HistoryItemFromString(params.state);
1134 if (!item.isNull()) {
1135 // Ensure we didn't save the swapped out URL in UpdateState, since the
1136 // browser should never be telling us to navigate to swappedout://.
1137 CHECK(item.urlString() != WebString::fromUTF8(kSwappedOutURL));
1138 main_frame->loadHistoryItem(item);
1140 } else if (!params.base_url_for_data_url.is_empty()) {
1141 // A loadData request with a specified base URL.
1142 std::string mime_type, charset, data;
1143 if (net::DataURL::Parse(params.url, &mime_type, &charset, &data)) {
1144 main_frame->loadData(
1145 WebData(data.c_str(), data.length()),
1146 WebString::fromUTF8(mime_type),
1147 WebString::fromUTF8(charset),
1148 params.base_url_for_data_url,
1149 params.history_url_for_data_url,
1150 false);
1151 } else {
1152 CHECK(false) <<
1153 "Invalid URL passed: " << params.url.possibly_invalid_spec();
1155 } else {
1156 // Navigate to the given URL.
1157 WebURLRequest request(params.url);
1159 // A session history navigation should have been accompanied by state.
1160 CHECK_EQ(params.page_id, -1);
1162 if (main_frame->isViewSourceModeEnabled())
1163 request.setCachePolicy(WebURLRequest::ReturnCacheDataElseLoad);
1165 if (params.referrer.url.is_valid()) {
1166 WebString referrer = WebSecurityPolicy::generateReferrerHeader(
1167 params.referrer.policy,
1168 params.url,
1169 WebString::fromUTF8(params.referrer.url.spec()));
1170 if (!referrer.isEmpty())
1171 request.setHTTPHeaderField(WebString::fromUTF8("Referer"), referrer);
1174 if (!params.extra_headers.empty()) {
1175 for (net::HttpUtil::HeadersIterator i(params.extra_headers.begin(),
1176 params.extra_headers.end(), "\n");
1177 i.GetNext(); ) {
1178 request.addHTTPHeaderField(WebString::fromUTF8(i.name()),
1179 WebString::fromUTF8(i.values()));
1183 if (params.is_post) {
1184 request.setHTTPMethod(WebString::fromUTF8("POST"));
1186 // Set post data.
1187 WebHTTPBody http_body;
1188 http_body.initialize();
1189 http_body.appendData(WebData(
1190 reinterpret_cast<const char*>(
1191 &params.browser_initiated_post_data.front()),
1192 params.browser_initiated_post_data.size()));
1193 request.setHTTPBody(http_body);
1196 main_frame->loadRequest(request);
1199 // In case LoadRequest failed before DidCreateDataSource was called.
1200 pending_navigation_params_.reset();
1203 bool RenderViewImpl::IsBackForwardToStaleEntry(
1204 const ViewMsg_Navigate_Params& params,
1205 bool is_reload) {
1206 // Make sure this isn't a back/forward to an entry we have already cropped
1207 // or replaced from our history, before the browser knew about it. If so,
1208 // a new navigation has committed in the mean time, and we can ignore this.
1209 bool is_back_forward = !is_reload && !params.state.empty();
1211 // Note: if the history_list_length_ is 0 for a back/forward, we must be
1212 // restoring from a previous session. We'll update our state in OnNavigate.
1213 if (!is_back_forward || history_list_length_ <= 0)
1214 return false;
1216 DCHECK_EQ(static_cast<int>(history_page_ids_.size()), history_list_length_);
1218 // Check for whether the forward history has been cropped due to a recent
1219 // navigation the browser didn't know about.
1220 if (params.pending_history_list_offset >= history_list_length_)
1221 return true;
1223 // Check for whether this entry has been replaced with a new one.
1224 int expected_page_id =
1225 history_page_ids_[params.pending_history_list_offset];
1226 if (expected_page_id > 0 && params.page_id != expected_page_id) {
1227 if (params.page_id < expected_page_id)
1228 return true;
1230 // Otherwise we've removed an earlier entry and should have shifted all
1231 // entries left. For now, it's ok to lazily update the list.
1232 // TODO(creis): Notify all live renderers when we remove entries from
1233 // the front of the list, so that we don't hit this case.
1234 history_page_ids_[params.pending_history_list_offset] = params.page_id;
1237 return false;
1240 // Stop loading the current page
1241 void RenderViewImpl::OnStop() {
1242 if (webview()) {
1243 WebFrame* main_frame = webview()->mainFrame();
1244 // Stop the alt error page fetcher. If we let it continue it may complete
1245 // and cause RenderViewHostManager to swap to this RenderView, even though
1246 // it may no longer be active.
1247 StopAltErrorPageFetcher(main_frame->provisionalDataSource());
1248 StopAltErrorPageFetcher(main_frame->dataSource());
1249 main_frame->stopLoading();
1253 // Reload current focused frame.
1254 // E.g. called by right-clicking on the frame and picking "reload this frame".
1255 void RenderViewImpl::OnReloadFrame() {
1256 if (webview() && webview()->focusedFrame()) {
1257 // We always obey the cache (ignore_cache=false) here.
1258 // TODO(evanm): perhaps we could allow shift-clicking the menu item to do
1259 // a cache-ignoring reload of the frame.
1260 webview()->focusedFrame()->reload(false);
1264 void RenderViewImpl::OnCopyImageAt(int x, int y) {
1265 webview()->copyImageAt(WebPoint(x, y));
1268 void RenderViewImpl::OnExecuteEditCommand(const std::string& name,
1269 const std::string& value) {
1270 if (!webview() || !webview()->focusedFrame())
1271 return;
1273 webview()->focusedFrame()->executeCommand(
1274 WebString::fromUTF8(name), WebString::fromUTF8(value));
1277 void RenderViewImpl::OnUpdateTargetURLAck() {
1278 // Check if there is a targeturl waiting to be sent.
1279 if (target_url_status_ == TARGET_PENDING) {
1280 Send(new ViewHostMsg_UpdateTargetURL(routing_id_, page_id_,
1281 pending_target_url_));
1284 target_url_status_ = TARGET_NONE;
1287 void RenderViewImpl::OnUndo() {
1288 if (!webview())
1289 return;
1291 webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Undo"));
1294 void RenderViewImpl::OnRedo() {
1295 if (!webview())
1296 return;
1298 webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Redo"));
1301 void RenderViewImpl::OnCut() {
1302 if (!webview())
1303 return;
1305 webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Cut"));
1308 void RenderViewImpl::OnCopy() {
1309 if (!webview())
1310 return;
1312 webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Copy"),
1313 context_menu_node_);
1316 #if defined(OS_MACOSX)
1317 void RenderViewImpl::OnCopyToFindPboard() {
1318 if (!webview())
1319 return;
1321 // Since the find pasteboard supports only plain text, this can be simpler
1322 // than the |OnCopy()| case.
1323 WebFrame* frame = webview()->focusedFrame();
1324 if (frame->hasSelection()) {
1325 string16 selection = frame->selectionAsText();
1326 RenderThread::Get()->Send(
1327 new ClipboardHostMsg_FindPboardWriteStringAsync(selection));
1330 #endif
1332 void RenderViewImpl::OnPaste() {
1333 if (!webview())
1334 return;
1336 webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Paste"));
1339 void RenderViewImpl::OnPasteAndMatchStyle() {
1340 if (!webview())
1341 return;
1343 webview()->focusedFrame()->executeCommand(
1344 WebString::fromUTF8("PasteAndMatchStyle"));
1347 void RenderViewImpl::OnReplace(const string16& text) {
1348 if (!webview())
1349 return;
1351 WebFrame* frame = webview()->focusedFrame();
1352 if (!frame->hasSelection())
1353 frame->selectWordAroundCaret();
1354 frame->replaceSelection(text);
1357 void RenderViewImpl::OnDelete() {
1358 if (!webview())
1359 return;
1361 webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Delete"));
1364 void RenderViewImpl::OnSelectAll() {
1365 if (!webview())
1366 return;
1368 webview()->focusedFrame()->executeCommand(
1369 WebString::fromUTF8("SelectAll"));
1372 void RenderViewImpl::OnUnselect() {
1373 if (!webview())
1374 return;
1376 webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Unselect"));
1379 void RenderViewImpl::OnSetEditableSelectionOffsets(int start, int end) {
1380 webview()->setEditableSelectionOffsets(start, end);
1383 void RenderViewImpl::OnSetCompositionFromExistingText(
1384 int start, int end,
1385 const std::vector<WebKit::WebCompositionUnderline>& underlines) {
1386 if (!webview())
1387 return;
1388 webview()->setCompositionFromExistingText(start, end, underlines);
1391 void RenderViewImpl::OnExtendSelectionAndDelete(int before, int after) {
1392 if (!webview())
1393 return;
1394 webview()->extendSelectionAndDelete(before, after);
1397 void RenderViewImpl::OnSelectRange(const gfx::Point& start,
1398 const gfx::Point& end) {
1399 if (!webview())
1400 return;
1402 Send(new ViewHostMsg_SelectRange_ACK(routing_id_));
1404 handling_select_range_ = true;
1405 webview()->focusedFrame()->selectRange(start, end);
1406 handling_select_range_ = false;
1409 void RenderViewImpl::OnSetHistoryLengthAndPrune(int history_length,
1410 int32 minimum_page_id) {
1411 DCHECK_GE(history_length, 0);
1412 DCHECK(history_list_offset_ == history_list_length_ - 1);
1413 DCHECK_GE(minimum_page_id, -1);
1415 // Generate the new list.
1416 std::vector<int32> new_history_page_ids(history_length, -1);
1417 for (size_t i = 0; i < history_page_ids_.size(); ++i) {
1418 if (minimum_page_id >= 0 && history_page_ids_[i] < minimum_page_id)
1419 continue;
1420 new_history_page_ids.push_back(history_page_ids_[i]);
1422 new_history_page_ids.swap(history_page_ids_);
1424 // Update indexes.
1425 history_list_length_ = history_page_ids_.size();
1426 history_list_offset_ = history_list_length_ - 1;
1430 void RenderViewImpl::OnSetInitialFocus(bool reverse) {
1431 if (!webview())
1432 return;
1433 webview()->setInitialFocus(reverse);
1436 #if defined(OS_MACOSX)
1437 void RenderViewImpl::OnSetInLiveResize(bool in_live_resize) {
1438 if (!webview())
1439 return;
1440 if (in_live_resize)
1441 webview()->willStartLiveResize();
1442 else
1443 webview()->willEndLiveResize();
1445 #endif
1447 void RenderViewImpl::OnScrollFocusedEditableNodeIntoRect(
1448 const gfx::Rect& rect) {
1449 WebKit::WebNode node = GetFocusedNode();
1450 if (!node.isNull()) {
1451 if (IsEditableNode(node)) {
1452 webview()->saveScrollAndScaleState();
1453 webview()->scrollFocusedNodeIntoRect(rect);
1458 #if defined(OS_ANDROID)
1459 void RenderViewImpl::OnUndoScrollFocusedEditableNodeIntoRect() {
1460 const WebNode node = GetFocusedNode();
1461 if (!node.isNull() && IsEditableNode(node))
1462 webview()->restoreScrollAndScaleState();
1464 #endif
1466 ///////////////////////////////////////////////////////////////////////////////
1468 // Tell the embedding application that the URL of the active page has changed
1469 void RenderViewImpl::UpdateURL(WebFrame* frame) {
1470 WebDataSource* ds = frame->dataSource();
1471 DCHECK(ds);
1473 const WebURLRequest& request = ds->request();
1474 const WebURLRequest& original_request = ds->originalRequest();
1475 const WebURLResponse& response = ds->response();
1477 DocumentState* document_state = DocumentState::FromDataSource(ds);
1478 NavigationState* navigation_state = document_state->navigation_state();
1480 ViewHostMsg_FrameNavigate_Params params;
1481 params.http_status_code = response.httpStatusCode();
1482 params.is_post = false;
1483 params.post_id = -1;
1484 params.page_id = page_id_;
1485 params.frame_id = frame->identifier();
1486 params.socket_address.set_host(response.remoteIPAddress().utf8());
1487 params.socket_address.set_port(response.remotePort());
1488 params.was_fetched_via_proxy = response.wasFetchedViaProxy();
1489 params.was_within_same_page = navigation_state->was_within_same_page();
1490 if (!document_state->security_info().empty()) {
1491 // SSL state specified in the request takes precedence over the one in the
1492 // response.
1493 // So far this is only intended for error pages that are not expected to be
1494 // over ssl, so we should not get any clash.
1495 DCHECK(response.securityInfo().isEmpty());
1496 params.security_info = document_state->security_info();
1497 } else {
1498 params.security_info = response.securityInfo();
1501 // Set the URL to be displayed in the browser UI to the user.
1502 params.url = GetLoadingUrl(frame);
1504 if (frame->document().baseURL() != params.url)
1505 params.base_url = frame->document().baseURL();
1507 GetRedirectChain(ds, &params.redirects);
1508 params.should_update_history = !ds->hasUnreachableURL() &&
1509 !response.isMultipartPayload() && (response.httpStatusCode() != 404);
1511 params.searchable_form_url = document_state->searchable_form_url();
1512 params.searchable_form_encoding =
1513 document_state->searchable_form_encoding();
1515 const PasswordForm* password_form_data =
1516 document_state->password_form_data();
1517 if (password_form_data)
1518 params.password_form = *password_form_data;
1520 params.gesture = navigation_gesture_;
1521 navigation_gesture_ = NavigationGestureUnknown;
1523 // Make navigation state a part of the FrameNavigate message so that commited
1524 // entry had it at all times.
1525 const WebHistoryItem& item = frame->currentHistoryItem();
1526 if (!item.isNull()) {
1527 params.content_state = webkit_glue::HistoryItemToString(item);
1528 } else {
1529 params.content_state =
1530 webkit_glue::CreateHistoryStateForURL(GURL(request.url()));
1533 if (!frame->parent()) {
1534 // Top-level navigation.
1536 // Reset the zoom limits in case a plugin had changed them previously. This
1537 // will also call us back which will cause us to send a message to
1538 // update WebContentsImpl.
1539 webview()->zoomLimitsChanged(
1540 WebView::zoomFactorToZoomLevel(kMinimumZoomFactor),
1541 WebView::zoomFactorToZoomLevel(kMaximumZoomFactor));
1543 // Set zoom level, but don't do it for full-page plugin since they don't use
1544 // the same zoom settings.
1545 HostZoomLevels::iterator host_zoom =
1546 host_zoom_levels_.find(GURL(request.url()));
1547 if (webview()->mainFrame()->document().isPluginDocument()) {
1548 // Reset the zoom levels for plugins.
1549 webview()->setZoomLevel(false, 0);
1550 } else {
1551 if (host_zoom != host_zoom_levels_.end())
1552 webview()->setZoomLevel(false, host_zoom->second);
1555 if (host_zoom != host_zoom_levels_.end()) {
1556 // This zoom level was merely recorded transiently for this load. We can
1557 // erase it now. If at some point we reload this page, the browser will
1558 // send us a new, up-to-date zoom level.
1559 host_zoom_levels_.erase(host_zoom);
1562 // Update contents MIME type for main frame.
1563 params.contents_mime_type = ds->response().mimeType().utf8();
1565 params.transition = navigation_state->transition_type();
1566 if (!PageTransitionIsMainFrame(params.transition)) {
1567 // If the main frame does a load, it should not be reported as a subframe
1568 // navigation. This can occur in the following case:
1569 // 1. You're on a site with frames.
1570 // 2. You do a subframe navigation. This is stored with transition type
1571 // MANUAL_SUBFRAME.
1572 // 3. You navigate to some non-frame site, say, google.com.
1573 // 4. You navigate back to the page from step 2. Since it was initially
1574 // MANUAL_SUBFRAME, it will be that same transition type here.
1575 // We don't want that, because any navigation that changes the toplevel
1576 // frame should be tracked as a toplevel navigation (this allows us to
1577 // update the URL bar, etc).
1578 params.transition = PAGE_TRANSITION_LINK;
1581 // If we have a valid consumed client redirect source,
1582 // the page contained a client redirect (meta refresh, document.loc...),
1583 // so we set the referrer and transition to match.
1584 if (completed_client_redirect_src_.url.is_valid()) {
1585 DCHECK(completed_client_redirect_src_.url == params.redirects[0]);
1586 params.referrer = completed_client_redirect_src_;
1587 params.transition = static_cast<PageTransition>(
1588 params.transition | PAGE_TRANSITION_CLIENT_REDIRECT);
1589 } else {
1590 // Bug 654101: the referrer will be empty on https->http transitions. It
1591 // would be nice if we could get the real referrer from somewhere.
1592 params.referrer = Referrer(GURL(
1593 original_request.httpHeaderField(WebString::fromUTF8("Referer"))),
1594 GetReferrerPolicyFromRequest(frame, original_request));
1597 string16 method = request.httpMethod();
1598 if (EqualsASCII(method, "POST")) {
1599 params.is_post = true;
1600 params.post_id = ExtractPostId(item);
1603 // Send the user agent override back.
1604 params.is_overriding_user_agent =
1605 document_state->is_overriding_user_agent();
1607 // Track the URL of the original request.
1608 params.original_request_url = original_request.url();
1610 // Save some histogram data so we can compute the average memory used per
1611 // page load of the glyphs.
1612 UMA_HISTOGRAM_COUNTS_10000("Memory.GlyphPagesPerLoad",
1613 webkit_glue::GetGlyphPageCount());
1615 // This message needs to be sent before any of allowScripts(),
1616 // allowImages(), allowPlugins() is called for the new page, so that when
1617 // these functions send a ViewHostMsg_ContentBlocked message, it arrives
1618 // after the ViewHostMsg_FrameNavigate message.
1619 Send(new ViewHostMsg_FrameNavigate(routing_id_, params));
1620 } else {
1621 // Subframe navigation: the type depends on whether this navigation
1622 // generated a new session history entry. When they do generate a session
1623 // history entry, it means the user initiated the navigation and we should
1624 // mark it as such. This test checks if this is the first time UpdateURL
1625 // has been called since WillNavigateToURL was called to initiate the load.
1626 if (page_id_ > last_page_id_sent_to_browser_)
1627 params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME;
1628 else
1629 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
1631 Send(new ViewHostMsg_FrameNavigate(routing_id_, params));
1634 last_page_id_sent_to_browser_ =
1635 std::max(last_page_id_sent_to_browser_, page_id_);
1637 // If we end up reusing this WebRequest (for example, due to a #ref click),
1638 // we don't want the transition type to persist. Just clear it.
1639 navigation_state->set_transition_type(PAGE_TRANSITION_LINK);
1642 // Tell the embedding application that the title of the active page has changed
1643 void RenderViewImpl::UpdateTitle(WebFrame* frame,
1644 const string16& title,
1645 WebTextDirection title_direction) {
1646 // Ignore all but top level navigations.
1647 if (frame->parent())
1648 return;
1650 string16 shortened_title = title.substr(0, kMaxTitleChars);
1651 Send(new ViewHostMsg_UpdateTitle(routing_id_, page_id_, shortened_title,
1652 title_direction));
1655 void RenderViewImpl::UpdateEncoding(WebFrame* frame,
1656 const std::string& encoding_name) {
1657 // Only update main frame's encoding_name.
1658 if (webview()->mainFrame() == frame &&
1659 last_encoding_name_ != encoding_name) {
1660 // Save the encoding name for later comparing.
1661 last_encoding_name_ = encoding_name;
1663 Send(new ViewHostMsg_UpdateEncoding(routing_id_, last_encoding_name_));
1667 // Sends the last committed session history state to the browser so it will be
1668 // saved before we navigate to a new page. This must be called *before* the
1669 // page ID has been updated so we know what it was.
1670 void RenderViewImpl::UpdateSessionHistory(WebFrame* frame) {
1671 // If we have a valid page ID at this point, then it corresponds to the page
1672 // we are navigating away from. Otherwise, this is the first navigation, so
1673 // there is no past session history to record.
1674 if (page_id_ == -1)
1675 return;
1677 const WebHistoryItem& item =
1678 webview()->mainFrame()->previousHistoryItem();
1679 SendUpdateState(item);
1682 void RenderViewImpl::SendUpdateState(const WebHistoryItem& item) {
1683 if (item.isNull())
1684 return;
1686 // Don't send state updates for kSwappedOutURL.
1687 if (item.urlString() == WebString::fromUTF8(kSwappedOutURL))
1688 return;
1690 Send(new ViewHostMsg_UpdateState(
1691 routing_id_, page_id_, webkit_glue::HistoryItemToString(item)));
1694 void RenderViewImpl::OpenURL(WebFrame* frame,
1695 const GURL& url,
1696 const Referrer& referrer,
1697 WebNavigationPolicy policy) {
1698 ViewHostMsg_OpenURL_Params params;
1699 params.url = url;
1700 params.referrer = referrer;
1701 params.disposition = NavigationPolicyToDisposition(policy);
1702 params.frame_id = frame->identifier();
1703 WebDataSource* ds = frame->provisionalDataSource();
1704 if (ds) {
1705 params.is_cross_site_redirect = ds->isClientRedirect();
1706 } else {
1707 params.is_cross_site_redirect = false;
1710 Send(new ViewHostMsg_OpenURL(routing_id_, params));
1713 // WebViewDelegate ------------------------------------------------------------
1715 void RenderViewImpl::LoadNavigationErrorPage(
1716 WebFrame* frame,
1717 const WebURLRequest& failed_request,
1718 const WebURLError& error,
1719 const std::string& html,
1720 bool replace) {
1721 std::string alt_html;
1722 const std::string* error_html;
1724 if (!html.empty()) {
1725 error_html = &html;
1726 } else {
1727 GetContentClient()->renderer()->GetNavigationErrorStrings(
1728 failed_request, error, &alt_html, NULL);
1729 error_html = &alt_html;
1732 frame->loadHTMLString(*error_html,
1733 GURL(kUnreachableWebDataURL),
1734 error.unreachableURL,
1735 replace);
1738 bool RenderViewImpl::RunJavaScriptMessage(JavaScriptMessageType type,
1739 const string16& message,
1740 const string16& default_value,
1741 const GURL& frame_url,
1742 string16* result) {
1743 bool success = false;
1744 string16 result_temp;
1745 if (!result)
1746 result = &result_temp;
1748 SendAndRunNestedMessageLoop(new ViewHostMsg_RunJavaScriptMessage(
1749 routing_id_, message, default_value, frame_url, type, &success, result));
1750 return success;
1753 bool RenderViewImpl::SendAndRunNestedMessageLoop(IPC::SyncMessage* message) {
1754 // Before WebKit asks us to show an alert (etc.), it takes care of doing the
1755 // equivalent of WebView::willEnterModalLoop. In the case of showModalDialog
1756 // it is particularly important that we do not call willEnterModalLoop as
1757 // that would defer resource loads for the dialog itself.
1758 if (RenderThreadImpl::current()) // Will be NULL during unit tests.
1759 RenderThreadImpl::current()->DoNotNotifyWebKitOfModalLoop();
1761 message->EnableMessagePumping(); // Runs a nested message loop.
1762 return Send(message);
1765 void RenderViewImpl::GetWindowSnapshot(const WindowSnapshotCallback& callback) {
1766 int id = next_snapshot_id_++;
1767 pending_snapshots_.insert(std::make_pair(id, callback));
1768 Send(new ViewHostMsg_GetWindowSnapshot(routing_id_, id));
1771 void RenderViewImpl::OnWindowSnapshotCompleted(const int snapshot_id,
1772 const gfx::Size& size, const std::vector<unsigned char>& png) {
1773 PendingSnapshotMap::iterator it = pending_snapshots_.find(snapshot_id);
1774 DCHECK(it != pending_snapshots_.end());
1775 it->second.Run(size, png);
1776 pending_snapshots_.erase(it);
1779 // WebKit::WebViewClient ------------------------------------------------------
1781 WebView* RenderViewImpl::createView(
1782 WebFrame* creator,
1783 const WebURLRequest& request,
1784 const WebWindowFeatures& features,
1785 const WebString& frame_name,
1786 WebNavigationPolicy policy) {
1787 // Check to make sure we aren't overloading on popups.
1788 if (shared_popup_counter_->data > kMaximumNumberOfUnacknowledgedPopups)
1789 return NULL;
1791 ViewHostMsg_CreateWindow_Params params;
1792 params.opener_id = routing_id_;
1793 params.user_gesture = creator->isProcessingUserGesture();
1794 params.window_container_type = WindowFeaturesToContainerType(features);
1795 params.session_storage_namespace_id = session_storage_namespace_id_;
1796 params.frame_name = frame_name;
1797 params.opener_frame_id = creator->identifier();
1798 params.opener_url = creator->document().url();
1799 params.opener_security_origin =
1800 creator->document().securityOrigin().toString().utf8();
1801 params.opener_suppressed = creator->willSuppressOpenerInNewFrame();
1802 params.disposition = NavigationPolicyToDisposition(policy);
1803 if (!request.isNull())
1804 params.target_url = request.url();
1806 int32 routing_id = MSG_ROUTING_NONE;
1807 int32 surface_id = 0;
1808 int64 cloned_session_storage_namespace_id;
1810 RenderThread::Get()->Send(
1811 new ViewHostMsg_CreateWindow(params,
1812 &routing_id,
1813 &surface_id,
1814 &cloned_session_storage_namespace_id));
1815 if (routing_id == MSG_ROUTING_NONE)
1816 return NULL;
1818 creator->consumeUserGesture();
1820 RenderViewImpl* view = RenderViewImpl::Create(
1821 routing_id_,
1822 renderer_preferences_,
1823 webkit_preferences_,
1824 shared_popup_counter_,
1825 routing_id,
1826 surface_id,
1827 cloned_session_storage_namespace_id,
1828 frame_name,
1829 true,
1830 false,
1832 screen_info_,
1833 accessibility_mode_);
1834 view->opened_by_user_gesture_ = params.user_gesture;
1836 // Record whether the creator frame is trying to suppress the opener field.
1837 view->opener_suppressed_ = params.opener_suppressed;
1839 // Copy over the alternate error page URL so we can have alt error pages in
1840 // the new render view (we don't need the browser to send the URL back down).
1841 view->alternate_error_page_url_ = alternate_error_page_url_;
1843 return view->webview();
1846 WebWidget* RenderViewImpl::createPopupMenu(WebKit::WebPopupType popup_type) {
1847 RenderWidget* widget =
1848 RenderWidget::Create(routing_id_, popup_type, screen_info_);
1849 return widget->webwidget();
1852 WebExternalPopupMenu* RenderViewImpl::createExternalPopupMenu(
1853 const WebPopupMenuInfo& popup_menu_info,
1854 WebExternalPopupMenuClient* popup_menu_client) {
1855 // An IPC message is sent to the browser to build and display the actual
1856 // popup. The user could have time to click a different select by the time
1857 // the popup is shown. In that case external_popup_menu_ is non NULL.
1858 // By returning NULL in that case, we instruct WebKit to cancel that new
1859 // popup. So from the user perspective, only the first one will show, and
1860 // will have to close the first one before another one can be shown.
1861 if (external_popup_menu_.get())
1862 return NULL;
1863 external_popup_menu_.reset(
1864 new ExternalPopupMenu(this, popup_menu_info, popup_menu_client));
1865 return external_popup_menu_.get();
1868 RenderWidgetFullscreenPepper* RenderViewImpl::CreatePepperFullscreenContainer(
1869 webkit::ppapi::PluginInstance* plugin) {
1870 GURL active_url;
1871 if (webview() && webview()->mainFrame())
1872 active_url = GURL(webview()->mainFrame()->document().url());
1873 RenderWidgetFullscreenPepper* widget = RenderWidgetFullscreenPepper::Create(
1874 routing_id_, plugin, active_url, screen_info_);
1875 widget->show(WebKit::WebNavigationPolicyIgnore);
1876 return widget;
1879 WebStorageNamespace* RenderViewImpl::createSessionStorageNamespace(
1880 unsigned quota) {
1881 CHECK(session_storage_namespace_id_ !=
1882 dom_storage::kInvalidSessionStorageNamespaceId);
1883 return new WebStorageNamespaceImpl(session_storage_namespace_id_);
1886 WebKit::WebCompositorOutputSurface* RenderViewImpl::createOutputSurface() {
1887 // Explicitly disable antialiasing for the compositor. As of the time of
1888 // this writing, the only platform that supported antialiasing for the
1889 // compositor was Mac OS X, because the on-screen OpenGL context creation
1890 // code paths on Windows and Linux didn't yet have multisampling support.
1891 // Mac OS X essentially always behaves as though it's rendering offscreen.
1892 // Multisampling has a heavy cost especially on devices with relatively low
1893 // fill rate like most notebooks, and the Mac implementation would need to
1894 // be optimized to resolve directly into the IOSurface shared between the
1895 // GPU and browser processes. For these reasons and to avoid platform
1896 // disparities we explicitly disable antialiasing.
1897 WebKit::WebGraphicsContext3D::Attributes attributes;
1898 attributes.antialias = false;
1899 attributes.shareResources = true;
1900 attributes.noAutomaticFlushes = true;
1901 WebGraphicsContext3D* context = CreateGraphicsContext3D(attributes);
1902 if (!context)
1903 return NULL;
1905 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
1906 if (command_line.HasSwitch(switches::kEnableSoftwareCompositingGLAdapter)) {
1907 // In the absence of a software-based delegating renderer, use this
1908 // stopgap adapter class to present the software renderer output using a
1909 // 3d context.
1910 return new CompositorOutputSurface(routing_id(), NULL,
1911 new CompositorSoftwareOutputDeviceGLAdapter(context));
1912 } else
1913 return new CompositorOutputSurface(routing_id(), context, NULL);
1916 void RenderViewImpl::didAddMessageToConsole(
1917 const WebConsoleMessage& message, const WebString& source_name,
1918 unsigned source_line) {
1919 logging::LogSeverity log_severity = logging::LOG_VERBOSE;
1920 switch (message.level) {
1921 case WebConsoleMessage::LevelTip:
1922 log_severity = logging::LOG_VERBOSE;
1923 break;
1924 case WebConsoleMessage::LevelLog:
1925 log_severity = logging::LOG_INFO;
1926 break;
1927 case WebConsoleMessage::LevelWarning:
1928 log_severity = logging::LOG_WARNING;
1929 break;
1930 case WebConsoleMessage::LevelError:
1931 log_severity = logging::LOG_ERROR;
1932 break;
1933 default:
1934 NOTREACHED();
1937 Send(new ViewHostMsg_AddMessageToConsole(routing_id_,
1938 static_cast<int32>(log_severity),
1939 message.text,
1940 static_cast<int32>(source_line),
1941 source_name));
1944 void RenderViewImpl::printPage(WebFrame* frame) {
1945 FOR_EACH_OBSERVER(RenderViewObserver, observers_,
1946 PrintPage(frame, handling_input_event_));
1949 WebKit::WebNotificationPresenter* RenderViewImpl::notificationPresenter() {
1950 return notification_provider_;
1953 bool RenderViewImpl::enumerateChosenDirectory(
1954 const WebString& path,
1955 WebFileChooserCompletion* chooser_completion) {
1956 int id = enumeration_completion_id_++;
1957 enumeration_completions_[id] = chooser_completion;
1958 return Send(new ViewHostMsg_EnumerateDirectory(
1959 routing_id_,
1961 webkit_base::WebStringToFilePath(path)));
1964 void RenderViewImpl::initializeHelperPluginWebFrame(
1965 WebKit::WebHelperPlugin* plugin) {
1966 plugin->initializeFrame(this);
1969 void RenderViewImpl::didStartLoading() {
1970 if (is_loading_) {
1971 DVLOG(1) << "didStartLoading called while loading";
1972 return;
1975 is_loading_ = true;
1977 Send(new ViewHostMsg_DidStartLoading(routing_id_));
1979 FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidStartLoading());
1982 void RenderViewImpl::didStopLoading() {
1983 if (!is_loading_) {
1984 DVLOG(1) << "DidStopLoading called while not loading";
1985 return;
1988 is_loading_ = false;
1990 if (pending_frame_tree_update_) {
1991 pending_frame_tree_update_ = false;
1992 SendUpdatedFrameTree(NULL);
1995 // NOTE: For now we're doing the safest thing, and sending out notification
1996 // when done loading. This currently isn't an issue as the favicon is only
1997 // displayed when done loading. Ideally we would send notification when
1998 // finished parsing the head, but webkit doesn't support that yet.
1999 // The feed discovery code would also benefit from access to the head.
2000 Send(new ViewHostMsg_DidStopLoading(routing_id_));
2002 if (load_progress_tracker_ != NULL)
2003 load_progress_tracker_->DidStopLoading();
2005 FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidStopLoading());
2008 void RenderViewImpl::didChangeLoadProgress(WebFrame* frame,
2009 double load_progress) {
2010 if (load_progress_tracker_ != NULL)
2011 load_progress_tracker_->DidChangeLoadProgress(frame, load_progress);
2014 bool RenderViewImpl::isSmartInsertDeleteEnabled() {
2015 #if defined(OS_MACOSX)
2016 return true;
2017 #else
2018 return false;
2019 #endif
2022 bool RenderViewImpl::isSelectTrailingWhitespaceEnabled() {
2023 #if defined(OS_WIN)
2024 return true;
2025 #else
2026 return false;
2027 #endif
2030 void RenderViewImpl::didChangeSelection(bool is_empty_selection) {
2031 if (!handling_input_event_ && !handling_select_range_)
2032 return;
2033 handling_select_range_ = false;
2035 if (is_empty_selection)
2036 selection_text_.clear();
2038 SyncSelectionIfRequired();
2041 void RenderViewImpl::didExecuteCommand(const WebString& command_name) {
2042 const std::string& name = UTF16ToUTF8(command_name);
2043 if (StartsWithASCII(name, "Move", true) ||
2044 StartsWithASCII(name, "Insert", true) ||
2045 StartsWithASCII(name, "Delete", true))
2046 return;
2047 RenderThreadImpl::current()->RecordUserMetrics(name);
2050 bool RenderViewImpl::handleCurrentKeyboardEvent() {
2051 if (edit_commands_.empty())
2052 return false;
2054 WebFrame* frame = webview()->focusedFrame();
2055 if (!frame)
2056 return false;
2058 EditCommands::iterator it = edit_commands_.begin();
2059 EditCommands::iterator end = edit_commands_.end();
2061 bool did_execute_command = false;
2062 for (; it != end; ++it) {
2063 // In gtk and cocoa, it's possible to bind multiple edit commands to one
2064 // key (but it's the exception). Once one edit command is not executed, it
2065 // seems safest to not execute the rest.
2066 if (!frame->executeCommand(WebString::fromUTF8(it->name),
2067 WebString::fromUTF8(it->value)))
2068 break;
2069 did_execute_command = true;
2072 return did_execute_command;
2075 void RenderViewImpl::didHandleGestureEvent(const WebGestureEvent& event,
2076 bool event_swallowed) {
2077 #if defined(OS_ANDROID)
2078 if (event.type == WebInputEvent::GestureTap ||
2079 event.type == WebInputEvent::GestureLongPress) {
2080 UpdateTextInputState(SHOW_IME_IF_NEEDED);
2082 #endif
2083 FOR_EACH_OBSERVER(RenderViewObserver, observers_,
2084 DidHandleGestureEvent(event));
2087 WebKit::WebColorChooser* RenderViewImpl::createColorChooser(
2088 WebKit::WebColorChooserClient* client,
2089 const WebKit::WebColor& initial_color) {
2090 RendererWebColorChooserImpl* color_chooser =
2091 new RendererWebColorChooserImpl(this, client);
2092 color_chooser->Open(static_cast<SkColor>(initial_color));
2093 return color_chooser;
2096 bool RenderViewImpl::runFileChooser(
2097 const WebKit::WebFileChooserParams& params,
2098 WebFileChooserCompletion* chooser_completion) {
2099 // Do not open the file dialog in a hidden RenderView.
2100 if (is_hidden())
2101 return false;
2102 FileChooserParams ipc_params;
2103 if (params.directory)
2104 ipc_params.mode = FileChooserParams::OpenFolder;
2105 else if (params.multiSelect)
2106 ipc_params.mode = FileChooserParams::OpenMultiple;
2107 else if (params.saveAs)
2108 ipc_params.mode = FileChooserParams::Save;
2109 else
2110 ipc_params.mode = FileChooserParams::Open;
2111 ipc_params.title = params.title;
2112 ipc_params.default_file_name =
2113 webkit_base::WebStringToFilePath(params.initialValue);
2114 ipc_params.accept_types.reserve(params.acceptTypes.size());
2115 for (size_t i = 0; i < params.acceptTypes.size(); ++i)
2116 ipc_params.accept_types.push_back(params.acceptTypes[i]);
2117 #if defined(OS_ANDROID)
2118 ipc_params.capture = params.capture;
2119 #endif
2121 return ScheduleFileChooser(ipc_params, chooser_completion);
2124 void RenderViewImpl::runModalAlertDialog(WebFrame* frame,
2125 const WebString& message) {
2126 RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_ALERT,
2127 message,
2128 string16(),
2129 frame->document().url(),
2130 NULL);
2133 bool RenderViewImpl::runModalConfirmDialog(WebFrame* frame,
2134 const WebString& message) {
2135 return RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_CONFIRM,
2136 message,
2137 string16(),
2138 frame->document().url(),
2139 NULL);
2142 bool RenderViewImpl::runModalPromptDialog(WebFrame* frame,
2143 const WebString& message,
2144 const WebString& default_value,
2145 WebString* actual_value) {
2146 string16 result;
2147 bool ok = RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_PROMPT,
2148 message,
2149 default_value,
2150 frame->document().url(),
2151 &result);
2152 if (ok)
2153 actual_value->assign(result);
2154 return ok;
2157 bool RenderViewImpl::runModalBeforeUnloadDialog(
2158 WebFrame* frame, const WebString& message) {
2159 // If we are swapping out, we have already run the beforeunload handler.
2160 // TODO(creis): Fix OnSwapOut to clear the frame without running beforeunload
2161 // at all, to avoid running it twice.
2162 if (is_swapped_out_)
2163 return true;
2165 bool is_reload = false;
2166 WebDataSource* ds = frame->provisionalDataSource();
2167 if (ds)
2168 is_reload = (ds->navigationType() == WebKit::WebNavigationTypeReload);
2170 bool success = false;
2171 // This is an ignored return value, but is included so we can accept the same
2172 // response as RunJavaScriptMessage.
2173 string16 ignored_result;
2174 SendAndRunNestedMessageLoop(new ViewHostMsg_RunBeforeUnloadConfirm(
2175 routing_id_, frame->document().url(), message, is_reload,
2176 &success, &ignored_result));
2177 return success;
2180 void RenderViewImpl::showContextMenu(
2181 WebFrame* frame, const WebContextMenuData& data) {
2182 ContextMenuParams params(data);
2184 // Plugins, e.g. PDF, don't currently update the render view when their
2185 // selected text changes, but the context menu params do contain the updated
2186 // selection. If that's the case, update the render view's state just prior
2187 // to showing the context menu.
2188 // TODO(asvitkine): http://crbug.com/152432
2189 string16 selection_text;
2190 if (!selection_text_.empty() && !selection_range_.is_empty()) {
2191 const int start = selection_range_.GetMin() - selection_text_offset_;
2192 const size_t length = selection_range_.length();
2193 if (start >= 0 && start + length <= selection_text_.length())
2194 selection_text = selection_text_.substr(start, length);
2196 if (params.selection_text != selection_text) {
2197 selection_text_ = params.selection_text;
2198 // TODO(asvitkine): Text offset and range is not available in this case.
2199 selection_text_offset_ = 0;
2200 selection_range_ = ui::Range(0, selection_text_.length());
2201 Send(new ViewHostMsg_SelectionChanged(routing_id_,
2202 selection_text_,
2203 selection_text_offset_,
2204 selection_range_));
2207 // frame is NULL if invoked by BlockedPlugin.
2208 if (frame)
2209 params.frame_id = frame->identifier();
2211 // Serializing a GURL longer than kMaxURLChars will fail, so don't do
2212 // it. We replace it with an empty GURL so the appropriate items are disabled
2213 // in the context menu.
2214 // TODO(jcivelli): http://crbug.com/45160 This prevents us from saving large
2215 // data encoded images. We should have a way to save them.
2216 if (params.src_url.spec().size() > kMaxURLChars)
2217 params.src_url = GURL();
2218 context_menu_node_ = data.node;
2220 #if defined(OS_ANDROID)
2221 gfx::Rect start_rect;
2222 gfx::Rect end_rect;
2223 GetSelectionBounds(&start_rect, &end_rect);
2224 params.selection_start =
2225 gfx::Point(start_rect.x(), start_rect.bottom()) + GetScrollOffset();
2226 params.selection_end =
2227 gfx::Point(end_rect.right(), end_rect.bottom()) + GetScrollOffset();
2228 #endif
2230 Send(new ViewHostMsg_ContextMenu(routing_id_, params));
2232 FOR_EACH_OBSERVER(
2233 RenderViewObserver, observers_, DidRequestShowContextMenu(frame, data));
2236 void RenderViewImpl::setStatusText(const WebString& text) {
2239 void RenderViewImpl::UpdateTargetURL(const GURL& url,
2240 const GURL& fallback_url) {
2241 GURL latest_url = url.is_empty() ? fallback_url : url;
2242 if (latest_url == target_url_)
2243 return;
2245 // Tell the browser to display a destination link.
2246 if (target_url_status_ == TARGET_INFLIGHT ||
2247 target_url_status_ == TARGET_PENDING) {
2248 // If we have a request in-flight, save the URL to be sent when we
2249 // receive an ACK to the in-flight request. We can happily overwrite
2250 // any existing pending sends.
2251 pending_target_url_ = latest_url;
2252 target_url_status_ = TARGET_PENDING;
2253 } else {
2254 // URLs larger than |kMaxURLChars| cannot be sent through IPC -
2255 // see |ParamTraits<GURL>|.
2256 if (latest_url.possibly_invalid_spec().size() > kMaxURLChars)
2257 latest_url = GURL();
2258 Send(new ViewHostMsg_UpdateTargetURL(routing_id_, page_id_, latest_url));
2259 target_url_ = latest_url;
2260 target_url_status_ = TARGET_INFLIGHT;
2264 void RenderViewImpl::StartNavStateSyncTimerIfNecessary() {
2265 // No need to update state if no page has committed yet.
2266 if (page_id_ == -1)
2267 return;
2269 int delay;
2270 if (send_content_state_immediately_)
2271 delay = 0;
2272 else if (is_hidden())
2273 delay = kDelaySecondsForContentStateSyncHidden;
2274 else
2275 delay = kDelaySecondsForContentStateSync;
2277 if (nav_state_sync_timer_.IsRunning()) {
2278 // The timer is already running. If the delay of the timer maches the amount
2279 // we want to delay by, then return. Otherwise stop the timer so that it
2280 // gets started with the right delay.
2281 if (nav_state_sync_timer_.GetCurrentDelay().InSeconds() == delay)
2282 return;
2283 nav_state_sync_timer_.Stop();
2286 nav_state_sync_timer_.Start(FROM_HERE, TimeDelta::FromSeconds(delay), this,
2287 &RenderViewImpl::SyncNavigationState);
2290 void RenderViewImpl::setMouseOverURL(const WebURL& url) {
2291 mouse_over_url_ = GURL(url);
2292 UpdateTargetURL(mouse_over_url_, focus_url_);
2295 void RenderViewImpl::setKeyboardFocusURL(const WebURL& url) {
2296 focus_url_ = GURL(url);
2297 UpdateTargetURL(focus_url_, mouse_over_url_);
2300 void RenderViewImpl::startDragging(WebFrame* frame,
2301 const WebDragData& data,
2302 WebDragOperationsMask mask,
2303 const WebImage& image,
2304 const WebPoint& webImageOffset) {
2305 WebDropData drop_data(data);
2306 drop_data.referrer_policy = frame->document().referrerPolicy();
2307 gfx::Vector2d imageOffset(webImageOffset.x, webImageOffset.y);
2308 Send(new DragHostMsg_StartDragging(routing_id_,
2309 drop_data,
2310 mask,
2311 image.getSkBitmap(),
2312 imageOffset,
2313 possible_drag_event_info_));
2316 bool RenderViewImpl::acceptsLoadDrops() {
2317 return renderer_preferences_.can_accept_load_drops;
2320 void RenderViewImpl::focusNext() {
2321 Send(new ViewHostMsg_TakeFocus(routing_id_, false));
2324 void RenderViewImpl::focusPrevious() {
2325 Send(new ViewHostMsg_TakeFocus(routing_id_, true));
2328 void RenderViewImpl::focusedNodeChanged(const WebNode& node) {
2329 Send(new ViewHostMsg_FocusedNodeChanged(routing_id_, IsEditableNode(node)));
2331 FOR_EACH_OBSERVER(RenderViewObserver, observers_, FocusedNodeChanged(node));
2334 void RenderViewImpl::numberOfWheelEventHandlersChanged(unsigned num_handlers) {
2335 Send(new ViewHostMsg_DidChangeNumWheelEvents(routing_id_, num_handlers));
2338 void RenderViewImpl::hasTouchEventHandlers(bool has_handlers) {
2339 Send(new ViewHostMsg_HasTouchEventHandlers(routing_id_, has_handlers));
2342 void RenderViewImpl::didUpdateLayout() {
2343 // We don't always want to set up a timer, only if we've been put in that
2344 // mode by getting a |ViewMsg_EnablePreferredSizeChangedMode|
2345 // message.
2346 if (!send_preferred_size_changes_ || !webview())
2347 return;
2349 if (check_preferred_size_timer_.IsRunning())
2350 return;
2351 check_preferred_size_timer_.Start(FROM_HERE,
2352 TimeDelta::FromMilliseconds(0), this,
2353 &RenderViewImpl::CheckPreferredSize);
2356 void RenderViewImpl::navigateBackForwardSoon(int offset) {
2357 Send(new ViewHostMsg_GoToEntryAtOffset(routing_id_, offset));
2360 int RenderViewImpl::historyBackListCount() {
2361 return history_list_offset_ < 0 ? 0 : history_list_offset_;
2364 int RenderViewImpl::historyForwardListCount() {
2365 return history_list_length_ - historyBackListCount() - 1;
2368 void RenderViewImpl::postAccessibilityNotification(
2369 const WebAccessibilityObject& obj,
2370 WebAccessibilityNotification notification) {
2371 if (renderer_accessibility_) {
2372 renderer_accessibility_->HandleWebAccessibilityNotification(
2373 obj, notification);
2377 void RenderViewImpl::didUpdateInspectorSetting(const WebString& key,
2378 const WebString& value) {
2379 Send(new ViewHostMsg_UpdateInspectorSetting(routing_id_,
2380 key.utf8(),
2381 value.utf8()));
2384 // WebKit::WebWidgetClient ----------------------------------------------------
2386 void RenderViewImpl::didFocus() {
2387 // TODO(jcivelli): when https://bugs.webkit.org/show_bug.cgi?id=33389 is fixed
2388 // we won't have to test for user gesture anymore and we can
2389 // move that code back to render_widget.cc
2390 if (webview() && webview()->mainFrame() &&
2391 webview()->mainFrame()->isProcessingUserGesture()) {
2392 Send(new ViewHostMsg_Focus(routing_id_));
2396 void RenderViewImpl::didBlur() {
2397 // TODO(jcivelli): see TODO above in didFocus().
2398 if (webview() && webview()->mainFrame() &&
2399 webview()->mainFrame()->isProcessingUserGesture()) {
2400 Send(new ViewHostMsg_Blur(routing_id_));
2404 // We are supposed to get a single call to Show for a newly created RenderView
2405 // that was created via RenderViewImpl::CreateWebView. So, we wait until this
2406 // point to dispatch the ShowView message.
2408 // This method provides us with the information about how to display the newly
2409 // created RenderView (i.e., as a blocked popup or as a new tab).
2411 void RenderViewImpl::show(WebNavigationPolicy policy) {
2412 if (did_show_) {
2413 #if defined(OS_ANDROID)
2414 // When supports_multiple_windows is disabled, popups are reusing
2415 // the same view. In some scenarios, this makes WebKit to call show() twice.
2416 if (!webkit_preferences_.supports_multiple_windows)
2417 return;
2418 #endif
2419 NOTREACHED() << "received extraneous Show call";
2420 return;
2422 did_show_ = true;
2424 DCHECK(opener_id_ != MSG_ROUTING_NONE);
2426 if (GetContentClient()->renderer()->AllowPopup())
2427 opened_by_user_gesture_ = true;
2429 // Force new windows to a popup if they were not opened with a user gesture.
2430 if (!opened_by_user_gesture_) {
2431 // We exempt background tabs for compat with older versions of Chrome.
2432 // TODO(darin): This seems bogus. These should have a user gesture, so
2433 // we probably don't need this check.
2434 if (policy != WebKit::WebNavigationPolicyNewBackgroundTab)
2435 policy = WebKit::WebNavigationPolicyNewPopup;
2438 // NOTE: initial_pos_ may still have its default values at this point, but
2439 // that's okay. It'll be ignored if disposition is not NEW_POPUP, or the
2440 // browser process will impose a default position otherwise.
2441 Send(new ViewHostMsg_ShowView(opener_id_, routing_id_,
2442 NavigationPolicyToDisposition(policy), initial_pos_,
2443 opened_by_user_gesture_));
2444 SetPendingWindowRect(initial_pos_);
2447 void RenderViewImpl::runModal() {
2448 DCHECK(did_show_) << "should already have shown the view";
2450 // We must keep WebKit's shared timer running in this case in order to allow
2451 // showModalDialog to function properly.
2453 // TODO(darin): WebKit should really be smarter about suppressing events and
2454 // timers so that we do not need to manage the shared timer in such a heavy
2455 // handed manner.
2457 if (RenderThreadImpl::current()) // Will be NULL during unit tests.
2458 RenderThreadImpl::current()->DoNotSuspendWebKitSharedTimer();
2460 SendAndRunNestedMessageLoop(new ViewHostMsg_RunModal(
2461 routing_id_, opener_id_));
2464 bool RenderViewImpl::enterFullScreen() {
2465 Send(new ViewHostMsg_ToggleFullscreen(routing_id_, true));
2466 return true;
2469 void RenderViewImpl::exitFullScreen() {
2470 Send(new ViewHostMsg_ToggleFullscreen(routing_id_, false));
2473 bool RenderViewImpl::requestPointerLock() {
2474 return mouse_lock_dispatcher_->LockMouse(webwidget_mouse_lock_target_.get());
2477 void RenderViewImpl::requestPointerUnlock() {
2478 mouse_lock_dispatcher_->UnlockMouse(webwidget_mouse_lock_target_.get());
2481 bool RenderViewImpl::isPointerLocked() {
2482 return mouse_lock_dispatcher_->IsMouseLockedTo(
2483 webwidget_mouse_lock_target_.get());
2486 void RenderViewImpl::didActivateCompositor(int input_handler_identifier) {
2487 CompositorThread* compositor_thread =
2488 RenderThreadImpl::current()->compositor_thread();
2489 if (compositor_thread)
2490 compositor_thread->AddInputHandler(
2491 routing_id_, input_handler_identifier, AsWeakPtr());
2493 RenderWidget::didActivateCompositor(input_handler_identifier);
2495 ProcessAcceleratedPinchZoomFlags(*CommandLine::ForCurrentProcess());
2498 // WebKit::WebFrameClient -----------------------------------------------------
2500 WebPlugin* RenderViewImpl::createPlugin(WebFrame* frame,
2501 const WebPluginParams& params) {
2502 WebPlugin* plugin = NULL;
2503 if (GetContentClient()->renderer()->OverrideCreatePlugin(
2504 this, frame, params, &plugin)) {
2505 return plugin;
2508 if (UTF16ToASCII(params.mimeType) == kBrowserPluginMimeType) {
2509 return browser_plugin_manager()->CreateBrowserPlugin(this, frame, params);
2512 webkit::WebPluginInfo info;
2513 std::string mime_type;
2514 bool found = GetPluginInfo(params.url, frame->top()->document().url(),
2515 params.mimeType.utf8(), &info, &mime_type);
2516 if (!found)
2517 return NULL;
2519 WebPluginParams params_to_use = params;
2520 params_to_use.mimeType = WebString::fromUTF8(mime_type);
2521 return CreatePlugin(frame, info, params_to_use);
2524 WebSharedWorker* RenderViewImpl::createSharedWorker(
2525 WebFrame* frame, const WebURL& url, const WebString& name,
2526 unsigned long long document_id) {
2528 int route_id = MSG_ROUTING_NONE;
2529 bool exists = false;
2530 bool url_mismatch = false;
2531 ViewHostMsg_CreateWorker_Params params;
2532 params.url = url;
2533 params.name = name;
2534 params.document_id = document_id;
2535 params.render_view_route_id = routing_id_;
2536 params.route_id = MSG_ROUTING_NONE;
2537 params.script_resource_appcache_id = 0;
2538 Send(new ViewHostMsg_LookupSharedWorker(
2539 params, &exists, &route_id, &url_mismatch));
2540 if (url_mismatch) {
2541 return NULL;
2542 } else {
2543 return new WebSharedWorkerProxy(RenderThreadImpl::current(),
2544 document_id,
2545 exists,
2546 route_id,
2547 routing_id_);
2551 WebMediaPlayer* RenderViewImpl::createMediaPlayer(
2552 WebFrame* frame, const WebKit::WebURL& url, WebMediaPlayerClient* client) {
2553 FOR_EACH_OBSERVER(
2554 RenderViewObserver, observers_, WillCreateMediaPlayer(frame, client));
2556 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
2557 #if defined(ENABLE_WEBRTC)
2558 // TODO(wjia): when all patches related to WebMediaPlayerMS have been
2559 // landed, remove the switch. Refer to crbug.com/142988.
2560 if (!cmd_line->HasSwitch(switches::kDisableWebMediaPlayerMS) &&
2561 MediaStreamImpl::CheckMediaStream(url)) {
2562 EnsureMediaStreamImpl();
2563 return new webkit_media::WebMediaPlayerMS(
2564 frame, client, AsWeakPtr(), media_stream_impl_, new RenderMediaLog());
2566 #endif
2568 #if defined(OS_ANDROID)
2569 WebGraphicsContext3D* resource_context =
2570 GetWebView()->sharedGraphicsContext3D();
2572 GpuChannelHost* gpu_channel_host =
2573 RenderThreadImpl::current()->EstablishGpuChannelSync(
2574 CAUSE_FOR_GPU_LAUNCH_VIDEODECODEACCELERATOR_INITIALIZE);
2575 if (!gpu_channel_host) {
2576 LOG(ERROR) << "Failed to establish GPU channel for media player";
2577 return NULL;
2580 if (cmd_line->HasSwitch(switches::kMediaPlayerInRenderProcess)) {
2581 if (!media_bridge_manager_.get()) {
2582 media_bridge_manager_.reset(
2583 new webkit_media::MediaPlayerBridgeManagerImpl(1));
2585 return new webkit_media::WebMediaPlayerInProcessAndroid(
2586 frame,
2587 client,
2588 cookieJar(frame),
2589 media_player_manager_.get(),
2590 media_bridge_manager_.get(),
2591 new StreamTextureFactoryImpl(
2592 resource_context, gpu_channel_host, routing_id_),
2593 cmd_line->HasSwitch(switches::kDisableMediaHistoryLogging));
2595 if (!media_player_proxy_) {
2596 media_player_proxy_ = new WebMediaPlayerProxyImplAndroid(
2597 this, media_player_manager_.get());
2599 return new webkit_media::WebMediaPlayerImplAndroid(
2600 frame,
2601 client,
2602 media_player_manager_.get(),
2603 media_player_proxy_,
2604 new StreamTextureFactoryImpl(
2605 resource_context, gpu_channel_host, routing_id_));
2606 #endif
2608 media::MessageLoopFactory* message_loop_factory =
2609 new media::MessageLoopFactory();
2610 media::FilterCollection* collection = new media::FilterCollection();
2611 RenderMediaLog* render_media_log = new RenderMediaLog();
2613 RenderAudioSourceProvider* audio_source_provider = NULL;
2615 // |audio_source_provider| "provides" audio to WebKit and is a sink from the
2616 // perspective of the audio renderer.
2617 if (!cmd_line->HasSwitch(switches::kDisableAudio)) {
2618 audio_source_provider = new RenderAudioSourceProvider(routing_id_);
2621 WebGraphicsContext3DCommandBufferImpl* context3d = NULL;
2622 if (!cmd_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
2623 context3d = RenderThreadImpl::current()->GetGpuVDAContext3D();
2624 if (context3d) {
2625 scoped_refptr<base::MessageLoopProxy> factories_loop =
2626 RenderThreadImpl::current()->compositor_thread() ?
2627 RenderThreadImpl::current()->compositor_thread()->GetWebThread()
2628 ->message_loop()->message_loop_proxy() :
2629 base::MessageLoopProxy::current();
2630 GpuChannelHost* gpu_channel_host =
2631 RenderThreadImpl::current()->EstablishGpuChannelSync(
2632 CAUSE_FOR_GPU_LAUNCH_VIDEODECODEACCELERATOR_INITIALIZE);
2633 collection->GetVideoDecoders()->push_back(new media::GpuVideoDecoder(
2634 message_loop_factory->GetMessageLoop(
2635 media::MessageLoopFactory::kPipeline),
2636 factories_loop,
2637 new RendererGpuVideoDecoderFactories(
2638 gpu_channel_host, factories_loop, context3d)));
2641 WebMediaPlayer* media_player =
2642 GetContentClient()->renderer()->OverrideCreateWebMediaPlayer(
2643 this, frame, client, AsWeakPtr(), collection, audio_source_provider,
2644 audio_source_provider, message_loop_factory, media_stream_impl_,
2645 render_media_log);
2646 if (!media_player) {
2647 media_player = new webkit_media::WebMediaPlayerImpl(
2648 frame, client, AsWeakPtr(), collection, audio_source_provider,
2649 audio_source_provider, message_loop_factory, media_stream_impl_,
2650 render_media_log);
2652 return media_player;
2655 WebApplicationCacheHost* RenderViewImpl::createApplicationCacheHost(
2656 WebFrame* frame, WebApplicationCacheHostClient* client) {
2657 if (!frame || !frame->view())
2658 return NULL;
2659 return new RendererWebApplicationCacheHostImpl(
2660 FromWebView(frame->view()), client,
2661 RenderThreadImpl::current()->appcache_dispatcher()->backend_proxy());
2664 WebCookieJar* RenderViewImpl::cookieJar(WebFrame* frame) {
2665 return &cookie_jar_;
2668 void RenderViewImpl::didCreateFrame(WebFrame* parent, WebFrame* child) {
2669 if (!updating_frame_tree_)
2670 SendUpdatedFrameTree(NULL);
2673 void RenderViewImpl::didDisownOpener(WebKit::WebFrame* frame) {
2674 // We should only hear this from the top-level frame, because subframes do not
2675 // have openers.
2676 CHECK(!frame->parent());
2678 // We only need to notify the browser if the active frame clears its opener.
2679 // We can ignore cases where a swapped out frame clears its opener after
2680 // hearing about it from the browser.
2681 if (is_swapped_out_)
2682 return;
2684 // Notify WebContents and all its swapped out RenderViews.
2685 Send(new ViewHostMsg_DidDisownOpener(routing_id_));
2688 void RenderViewImpl::frameDetached(WebFrame* frame) {
2689 if (is_loading_) {
2690 pending_frame_tree_update_ = true;
2691 // Make sure observers are notified, even if we return right away.
2692 FOR_EACH_OBSERVER(RenderViewObserver, observers_, FrameDetached(frame));
2693 return;
2695 if (!updating_frame_tree_)
2696 SendUpdatedFrameTree(frame);
2698 FOR_EACH_OBSERVER(RenderViewObserver, observers_, FrameDetached(frame));
2701 void RenderViewImpl::willClose(WebFrame* frame) {
2702 FOR_EACH_OBSERVER(RenderViewObserver, observers_, FrameWillClose(frame));
2705 void RenderViewImpl::loadURLExternally(
2706 WebFrame* frame, const WebURLRequest& request,
2707 WebNavigationPolicy policy) {
2708 loadURLExternally(frame, request, policy, WebString());
2711 void RenderViewImpl::Repaint(const gfx::Size& size) {
2712 OnMsgRepaint(size);
2715 void RenderViewImpl::SetEditCommandForNextKeyEvent(const std::string& name,
2716 const std::string& value) {
2717 EditCommands edit_commands;
2718 edit_commands.push_back(EditCommand(name, value));
2719 OnSetEditCommandsForNextKeyEvent(edit_commands);
2722 void RenderViewImpl::ClearEditCommands() {
2723 edit_commands_.clear();
2726 SSLStatus RenderViewImpl::GetSSLStatusOfFrame(WebKit::WebFrame* frame) const {
2727 SSLStatus ssl_status;
2729 DocumentState* doc_state = DocumentState::FromDataSource(frame->dataSource());
2730 if (doc_state && !doc_state->security_info().empty()) {
2731 DeserializeSecurityInfo(doc_state->security_info(),
2732 &ssl_status.cert_id,
2733 &ssl_status.cert_status,
2734 &ssl_status.security_bits,
2735 &ssl_status.connection_status);
2738 return ssl_status;
2741 void RenderViewImpl::loadURLExternally(
2742 WebFrame* frame, const WebURLRequest& request,
2743 WebNavigationPolicy policy,
2744 const WebString& suggested_name) {
2745 Referrer referrer(
2746 GURL(request.httpHeaderField(WebString::fromUTF8("Referer"))),
2747 GetReferrerPolicyFromRequest(frame, request));
2748 if (policy == WebKit::WebNavigationPolicyDownload) {
2749 Send(new ViewHostMsg_DownloadUrl(routing_id_, request.url(), referrer,
2750 suggested_name));
2751 } else {
2752 OpenURL(frame, request.url(), referrer, policy);
2756 WebNavigationPolicy RenderViewImpl::decidePolicyForNavigation(
2757 WebFrame* frame, const WebURLRequest& request, WebNavigationType type,
2758 const WebNode&, WebNavigationPolicy default_policy, bool is_redirect) {
2759 if (request.url() != GURL(kSwappedOutURL) &&
2760 GetContentClient()->renderer()->HandleNavigation(frame, request, type,
2761 default_policy,
2762 is_redirect)) {
2763 return WebKit::WebNavigationPolicyIgnore;
2766 Referrer referrer(
2767 GURL(request.httpHeaderField(WebString::fromUTF8("Referer"))),
2768 GetReferrerPolicyFromRequest(frame, request));
2770 if (is_swapped_out_) {
2771 if (request.url() != GURL(kSwappedOutURL)) {
2772 // Targeted links may try to navigate a swapped out frame. Allow the
2773 // browser process to navigate the tab instead. Note that it is also
2774 // possible for non-targeted navigations (from this view) to arrive
2775 // here just after we are swapped out. It's ok to send them to the
2776 // browser, as long as they're for the top level frame.
2777 // TODO(creis): Ensure this supports targeted form submissions when
2778 // fixing http://crbug.com/101395.
2779 if (frame->parent() == NULL) {
2780 OpenURL(frame, request.url(), referrer, default_policy);
2781 return WebKit::WebNavigationPolicyIgnore; // Suppress the load here.
2784 // We should otherwise ignore in-process iframe navigations, if they
2785 // arrive just after we are swapped out.
2786 return WebKit::WebNavigationPolicyIgnore;
2789 // Allow kSwappedOutURL to complete.
2790 return default_policy;
2793 // Webkit is asking whether to navigate to a new URL.
2794 // This is fine normally, except if we're showing UI from one security
2795 // context and they're trying to navigate to a different context.
2796 const GURL& url = request.url();
2798 // A content initiated navigation may have originated from a link-click,
2799 // script, drag-n-drop operation, etc.
2800 bool is_content_initiated =
2801 DocumentState::FromDataSource(frame->provisionalDataSource())->
2802 navigation_state()->is_content_initiated();
2804 // Experimental:
2805 // If --enable-strict-site-isolation or --site-per-process is enabled, send
2806 // all top-level navigations to the browser to let it swap processes when
2807 // crossing site boundaries. This is currently expected to break some script
2808 // calls and navigations, such as form submissions.
2809 const CommandLine& command_line = *CommandLine::ForCurrentProcess();
2810 bool force_swap_due_to_flag =
2811 command_line.HasSwitch(switches::kEnableStrictSiteIsolation) ||
2812 command_line.HasSwitch(switches::kSitePerProcess);
2813 if (force_swap_due_to_flag &&
2814 !frame->parent() && (is_content_initiated || is_redirect)) {
2815 WebString origin_str = frame->document().securityOrigin().toString();
2816 GURL frame_url(origin_str.utf8().data());
2817 // TODO(cevans): revisit whether this site check is still necessary once
2818 // crbug.com/101395 is fixed.
2819 if (!net::RegistryControlledDomainService::SameDomainOrHost(frame_url,
2820 url) ||
2821 frame_url.scheme() != url.scheme()) {
2822 OpenURL(frame, url, referrer, default_policy);
2823 return WebKit::WebNavigationPolicyIgnore;
2827 // If the browser is interested, then give it a chance to look at the request.
2828 if (is_content_initiated) {
2829 bool browser_handles_request =
2830 renderer_preferences_.browser_handles_non_local_top_level_requests &&
2831 IsNonLocalTopLevelNavigation(url, frame, type);
2832 if (!browser_handles_request) {
2833 browser_handles_request =
2834 renderer_preferences_.browser_handles_all_top_level_requests &&
2835 IsTopLevelNavigation(frame);
2838 if (browser_handles_request) {
2839 // Reset these counters as the RenderView could be reused for the next
2840 // navigation.
2841 page_id_ = -1;
2842 last_page_id_sent_to_browser_ = -1;
2843 OpenURL(frame, url, referrer, default_policy);
2844 return WebKit::WebNavigationPolicyIgnore; // Suppress the load here.
2848 // Use the frame's original request's URL rather than the document's URL for
2849 // subsequent checks. For a popup, the document's URL may become the opener
2850 // window's URL if the opener has called document.write().
2851 // See http://crbug.com/93517.
2852 GURL old_url(frame->dataSource()->request().url());
2854 // Detect when we're crossing a permission-based boundary (e.g. into or out of
2855 // an extension or app origin, leaving a WebUI page, etc). We only care about
2856 // top-level navigations (not iframes). But we sometimes navigate to
2857 // about:blank to clear a tab, and we want to still allow that.
2859 // Note: this is known to break POST submissions when crossing process
2860 // boundaries until http://crbug.com/101395 is fixed. This is better for
2861 // security than loading a WebUI, extension or app page in the wrong process.
2862 // POST requests don't work because this mechanism does not preserve form
2863 // POST data. We will need to send the request's httpBody data up to the
2864 // browser process, and issue a special POST navigation in WebKit (via
2865 // FrameLoader::loadFrameRequest). See ResourceDispatcher and WebURLLoaderImpl
2866 // for examples of how to send the httpBody data.
2867 if (!frame->parent() && is_content_initiated &&
2868 !url.SchemeIs(chrome::kAboutScheme)) {
2869 bool send_referrer = false;
2871 // All navigations to WebUI URLs or within WebUI-enabled RenderProcesses
2872 // must be handled by the browser process so that the correct bindings and
2873 // data sources can be registered.
2874 // Similarly, navigations to view-source URLs or within ViewSource mode
2875 // must be handled by the browser process (except for reloads - those are
2876 // safe to leave within the renderer).
2877 // Lastly, access to file:// URLs from non-file:// URL pages must be
2878 // handled by the browser so that ordinary renderer processes don't get
2879 // blessed with file permissions.
2880 int cumulative_bindings = RenderProcess::current()->GetEnabledBindings();
2881 bool is_initial_navigation = page_id_ == -1;
2882 bool should_fork =
2883 GetContentClient()->HasWebUIScheme(url) ||
2884 (cumulative_bindings & BINDINGS_POLICY_WEB_UI) ||
2885 url.SchemeIs(chrome::kViewSourceScheme) ||
2886 (frame->isViewSourceModeEnabled() &&
2887 type != WebKit::WebNavigationTypeReload);
2889 if (!should_fork && url.SchemeIs(chrome::kFileScheme)) {
2890 // Fork non-file to file opens. Check the opener URL if this is the
2891 // initial navigation in a newly opened window.
2892 GURL source_url(old_url);
2893 if (is_initial_navigation && source_url.is_empty() && frame->opener())
2894 source_url = frame->opener()->top()->document().url();
2895 DCHECK(!source_url.is_empty());
2896 should_fork = !source_url.SchemeIs(chrome::kFileScheme);
2899 if (!should_fork) {
2900 // Give the embedder a chance.
2901 // For now, we skip this for POST submissions. This is because
2902 // http://crbug.com/101395 is more likely to cause compatibility issues
2903 // with hosted apps and extensions than WebUI pages. We will remove this
2904 // check when cross-process POST submissions are supported.
2905 if (request.httpMethod() == "GET") {
2906 should_fork = GetContentClient()->renderer()->ShouldFork(
2907 frame, url, is_initial_navigation, &send_referrer);
2911 if (should_fork) {
2912 OpenURL(
2913 frame, url, send_referrer ? referrer : Referrer(), default_policy);
2914 return WebKit::WebNavigationPolicyIgnore; // Suppress the load here.
2918 // Detect when a page is "forking" a new tab that can be safely rendered in
2919 // its own process. This is done by sites like Gmail that try to open links
2920 // in new windows without script connections back to the original page. We
2921 // treat such cases as browser navigations (in which we will create a new
2922 // renderer for a cross-site navigation), rather than WebKit navigations.
2924 // We use the following heuristic to decide whether to fork a new page in its
2925 // own process:
2926 // The parent page must open a new tab to about:blank, set the new tab's
2927 // window.opener to null, and then redirect the tab to a cross-site URL using
2928 // JavaScript.
2930 // TODO(creis): Deprecate this logic once we can rely on rel=noreferrer
2931 // (see below).
2932 bool is_fork =
2933 // Must start from a tab showing about:blank, which is later redirected.
2934 old_url == GURL(chrome::kAboutBlankURL) &&
2935 // Must be the first real navigation of the tab.
2936 historyBackListCount() < 1 &&
2937 historyForwardListCount() < 1 &&
2938 // The parent page must have set the child's window.opener to null before
2939 // redirecting to the desired URL.
2940 frame->opener() == NULL &&
2941 // Must be a top-level frame.
2942 frame->parent() == NULL &&
2943 // Must not have issued the request from this page.
2944 is_content_initiated &&
2945 // Must be targeted at the current tab.
2946 default_policy == WebKit::WebNavigationPolicyCurrentTab &&
2947 // Must be a JavaScript navigation, which appears as "other".
2948 type == WebKit::WebNavigationTypeOther;
2950 if (is_fork) {
2951 // Open the URL via the browser, not via WebKit.
2952 OpenURL(frame, url, Referrer(), default_policy);
2953 return WebKit::WebNavigationPolicyIgnore;
2956 return default_policy;
2959 bool RenderViewImpl::canHandleRequest(
2960 WebFrame* frame, const WebURLRequest& request) {
2961 // We allow WebKit to think that everything can be handled even though
2962 // browser-side we limit what we load.
2963 return true;
2966 WebURLError RenderViewImpl::cannotHandleRequestError(
2967 WebFrame* frame, const WebURLRequest& request) {
2968 NOTREACHED(); // Since we said we can handle all requests.
2969 return WebURLError();
2972 WebURLError RenderViewImpl::cancelledError(
2973 WebFrame* frame, const WebURLRequest& request) {
2974 WebURLError error;
2975 error.domain = WebString::fromUTF8(net::kErrorDomain);
2976 error.reason = net::ERR_ABORTED;
2977 error.unreachableURL = request.url();
2978 return error;
2981 void RenderViewImpl::unableToImplementPolicyWithError(
2982 WebFrame*, const WebURLError&) {
2983 NOTREACHED(); // Since we said we can handle all requests.
2986 void RenderViewImpl::willSendSubmitEvent(WebKit::WebFrame* frame,
2987 const WebKit::WebFormElement& form) {
2988 // Some login forms have onSubmit handlers that put a hash of the password
2989 // into a hidden field and then clear the password. (Issue 28910.)
2990 // This method gets called before any of those handlers run, so save away
2991 // a copy of the password in case it gets lost.
2992 DocumentState* document_state =
2993 DocumentState::FromDataSource(frame->dataSource());
2994 document_state->set_password_form_data(CreatePasswordForm(form));
2997 void RenderViewImpl::willSubmitForm(WebFrame* frame,
2998 const WebFormElement& form) {
2999 DocumentState* document_state =
3000 DocumentState::FromDataSource(frame->provisionalDataSource());
3001 NavigationState* navigation_state = document_state->navigation_state();
3003 if (navigation_state->transition_type() == PAGE_TRANSITION_LINK)
3004 navigation_state->set_transition_type(PAGE_TRANSITION_FORM_SUBMIT);
3006 // Save these to be processed when the ensuing navigation is committed.
3007 WebSearchableFormData web_searchable_form_data(form);
3008 document_state->set_searchable_form_url(web_searchable_form_data.url());
3009 document_state->set_searchable_form_encoding(
3010 web_searchable_form_data.encoding().utf8());
3011 scoped_ptr<PasswordForm> password_form_data =
3012 CreatePasswordForm(form);
3014 // In order to save the password that the user actually typed and not one
3015 // that may have gotten transformed by the site prior to submit, recover it
3016 // from the form contents already stored by |willSendSubmitEvent| into the
3017 // dataSource's NavigationState (as opposed to the provisionalDataSource's,
3018 // which is what we're storing into now.)
3019 if (password_form_data.get()) {
3020 DocumentState* old_document_state =
3021 DocumentState::FromDataSource(frame->dataSource());
3022 if (old_document_state) {
3023 PasswordForm* old_form_data = old_document_state->password_form_data();
3024 if (old_form_data && old_form_data->action == password_form_data->action)
3025 password_form_data->password_value = old_form_data->password_value;
3029 document_state->set_password_form_data(password_form_data.Pass());
3031 FOR_EACH_OBSERVER(
3032 RenderViewObserver, observers_, WillSubmitForm(frame, form));
3035 void RenderViewImpl::willPerformClientRedirect(
3036 WebFrame* frame, const WebURL& from, const WebURL& to, double interval,
3037 double fire_time) {
3038 // Replace any occurrences of swappedout:// with about:blank.
3039 const WebURL& blank_url = GURL(chrome::kAboutBlankURL);
3041 FOR_EACH_OBSERVER(
3042 RenderViewObserver, observers_,
3043 WillPerformClientRedirect(frame,
3044 from == GURL(kSwappedOutURL) ? blank_url : from,
3045 to, interval, fire_time));
3048 void RenderViewImpl::didCancelClientRedirect(WebFrame* frame) {
3049 FOR_EACH_OBSERVER(
3050 RenderViewObserver, observers_, DidCancelClientRedirect(frame));
3053 void RenderViewImpl::didCompleteClientRedirect(
3054 WebFrame* frame, const WebURL& from) {
3055 // Replace any occurrences of swappedout:// with about:blank.
3056 const WebURL& blank_url = GURL(chrome::kAboutBlankURL);
3057 if (!frame->parent()) {
3058 WebDataSource* ds = frame->provisionalDataSource();
3059 // If there's no provisional data source, it's a reference fragment
3060 // navigation.
3061 completed_client_redirect_src_ = Referrer(
3062 from == GURL(kSwappedOutURL) ? blank_url : from,
3063 ds ? GetReferrerPolicyFromRequest(frame, ds->request()) :
3064 frame->document().referrerPolicy());
3066 FOR_EACH_OBSERVER(
3067 RenderViewObserver, observers_, DidCompleteClientRedirect(
3068 frame, from == GURL(kSwappedOutURL) ? blank_url : from));
3071 void RenderViewImpl::didCreateDataSource(WebFrame* frame, WebDataSource* ds) {
3072 bool content_initiated = !pending_navigation_params_.get();
3074 DocumentState* document_state = DocumentState::FromDataSource(ds);
3075 if (!document_state) {
3076 document_state = new DocumentState;
3077 ds->setExtraData(document_state);
3078 if (!content_initiated)
3079 PopulateDocumentStateFromPending(document_state);
3082 // Carry over the user agent override flag, if it exists.
3083 if (content_initiated && webview() && webview()->mainFrame() &&
3084 webview()->mainFrame()->dataSource()) {
3085 DocumentState* old_document_state =
3086 DocumentState::FromDataSource(webview()->mainFrame()->dataSource());
3087 if (old_document_state) {
3088 document_state->set_is_overriding_user_agent(
3089 old_document_state->is_overriding_user_agent());
3093 // The rest of RenderView assumes that a WebDataSource will always have a
3094 // non-null NavigationState.
3095 if (content_initiated) {
3096 document_state->set_navigation_state(
3097 NavigationState::CreateContentInitiated());
3098 } else {
3099 document_state->set_navigation_state(CreateNavigationStateFromPending());
3100 pending_navigation_params_.reset();
3103 // DocumentState::referred_by_prefetcher_ is true if we are
3104 // navigating from a page that used prefetching using a link on that
3105 // page. We are early enough in the request process here that we
3106 // can still see the DocumentState of the previous page and set
3107 // this value appropriately.
3108 // TODO(gavinp): catch the important case of navigation in a new
3109 // renderer process.
3110 if (webview()) {
3111 if (WebFrame* old_frame = webview()->mainFrame()) {
3112 const WebURLRequest& original_request = ds->originalRequest();
3113 const GURL referrer(
3114 original_request.httpHeaderField(WebString::fromUTF8("Referer")));
3115 if (!referrer.is_empty() &&
3116 DocumentState::FromDataSource(
3117 old_frame->dataSource())->was_prefetcher()) {
3118 for (; old_frame; old_frame = old_frame->traverseNext(false)) {
3119 WebDataSource* old_frame_ds = old_frame->dataSource();
3120 if (old_frame_ds && referrer == GURL(old_frame_ds->request().url())) {
3121 document_state->set_was_referred_by_prefetcher(true);
3122 break;
3129 if (content_initiated) {
3130 const WebURLRequest& request = ds->request();
3131 switch (request.cachePolicy()) {
3132 case WebURLRequest::UseProtocolCachePolicy: // normal load.
3133 document_state->set_load_type(DocumentState::LINK_LOAD_NORMAL);
3134 break;
3135 case WebURLRequest::ReloadIgnoringCacheData: // reload.
3136 document_state->set_load_type(DocumentState::LINK_LOAD_RELOAD);
3137 break;
3138 case WebURLRequest::ReturnCacheDataElseLoad: // allow stale data.
3139 document_state->set_load_type(
3140 DocumentState::LINK_LOAD_CACHE_STALE_OK);
3141 break;
3142 case WebURLRequest::ReturnCacheDataDontLoad: // Don't re-post.
3143 document_state->set_load_type(DocumentState::LINK_LOAD_CACHE_ONLY);
3144 break;
3148 FOR_EACH_OBSERVER(
3149 RenderViewObserver, observers_, DidCreateDataSource(frame, ds));
3152 void RenderViewImpl::PopulateDocumentStateFromPending(
3153 DocumentState* document_state) {
3154 const ViewMsg_Navigate_Params& params = *pending_navigation_params_.get();
3155 document_state->set_request_time(params.request_time);
3157 if (!params.url.SchemeIs(chrome::kJavaScriptScheme) &&
3158 params.navigation_type == ViewMsg_Navigate_Type::RESTORE) {
3159 // We're doing a load of a page that was restored from the last session. By
3160 // default this prefers the cache over loading (LOAD_PREFERRING_CACHE) which
3161 // can result in stale data for pages that are set to expire. We explicitly
3162 // override that by setting the policy here so that as necessary we load
3163 // from the network.
3164 document_state->set_cache_policy_override(
3165 WebURLRequest::UseProtocolCachePolicy);
3168 if (IsReload(params))
3169 document_state->set_load_type(DocumentState::RELOAD);
3170 else if (!params.state.empty())
3171 document_state->set_load_type(DocumentState::HISTORY_LOAD);
3172 else
3173 document_state->set_load_type(DocumentState::NORMAL_LOAD);
3175 document_state->set_referrer_policy(params.referrer.policy);
3176 document_state->set_is_overriding_user_agent(params.is_overriding_user_agent);
3177 document_state->set_must_reset_scroll_and_scale_state(
3178 params.navigation_type ==
3179 ViewMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL);
3180 document_state->set_can_load_local_resources(params.can_load_local_resources);
3183 NavigationState* RenderViewImpl::CreateNavigationStateFromPending() {
3184 const ViewMsg_Navigate_Params& params = *pending_navigation_params_.get();
3185 NavigationState* navigation_state = NULL;
3187 // A navigation resulting from loading a javascript URL should not be treated
3188 // as a browser initiated event. Instead, we want it to look as if the page
3189 // initiated any load resulting from JS execution.
3190 if (!params.url.SchemeIs(chrome::kJavaScriptScheme)) {
3191 navigation_state = NavigationState::CreateBrowserInitiated(
3192 params.page_id,
3193 params.pending_history_list_offset,
3194 params.transition);
3195 navigation_state->set_transferred_request_child_id(
3196 params.transferred_request_child_id);
3197 navigation_state->set_transferred_request_request_id(
3198 params.transferred_request_request_id);
3199 navigation_state->set_allow_download(params.allow_download);
3200 } else {
3201 navigation_state = NavigationState::CreateContentInitiated();
3203 return navigation_state;
3206 void RenderViewImpl::ProcessViewLayoutFlags(const CommandLine& command_line) {
3207 bool enable_viewport =
3208 command_line.HasSwitch(switches::kEnableViewport);
3209 bool enable_fixed_layout =
3210 command_line.HasSwitch(switches::kEnableFixedLayout);
3212 webview()->enableFixedLayoutMode(enable_fixed_layout || enable_viewport);
3213 webview()->settings()->setFixedElementsLayoutRelativeToFrame(true);
3215 if (enable_viewport) {
3216 webview()->settings()->setViewportEnabled(true);
3217 } else if (enable_fixed_layout) {
3218 std::string str =
3219 command_line.GetSwitchValueASCII(switches::kEnableFixedLayout);
3220 std::vector<std::string> tokens;
3221 base::SplitString(str, ',', &tokens);
3222 if (tokens.size() == 2) {
3223 int width, height;
3224 if (base::StringToInt(tokens[0], &width) &&
3225 base::StringToInt(tokens[1], &height))
3226 webview()->setFixedLayoutSize(WebSize(width, height));
3230 ProcessAcceleratedPinchZoomFlags(command_line);
3233 void RenderViewImpl::ProcessAcceleratedPinchZoomFlags(
3234 const CommandLine& command_line) {
3235 if (!webview()->isAcceleratedCompositingActive())
3236 return;
3238 bool enable_viewport = command_line.HasSwitch(switches::kEnableViewport);
3239 bool enable_pinch = command_line.HasSwitch(switches::kEnablePinch);
3241 if (enable_viewport)
3242 return;
3244 if (enable_pinch)
3245 webview()->setPageScaleFactorLimits(1, 4);
3246 else
3247 webview()->setPageScaleFactorLimits(1, 1);
3250 void RenderViewImpl::didStartProvisionalLoad(WebFrame* frame) {
3251 WebDataSource* ds = frame->provisionalDataSource();
3252 DocumentState* document_state = DocumentState::FromDataSource(ds);
3254 // We should only navigate to swappedout:// when is_swapped_out_ is true.
3255 CHECK((ds->request().url() != GURL(kSwappedOutURL)) ||
3256 is_swapped_out_) << "Heard swappedout:// when not swapped out.";
3258 // Update the request time if WebKit has better knowledge of it.
3259 if (document_state->request_time().is_null()) {
3260 double event_time = ds->triggeringEventTime();
3261 if (event_time != 0.0)
3262 document_state->set_request_time(Time::FromDoubleT(event_time));
3265 // Start time is only set after request time.
3266 document_state->set_start_load_time(Time::Now());
3268 bool is_top_most = !frame->parent();
3269 if (is_top_most) {
3270 navigation_gesture_ = frame->isProcessingUserGesture() ?
3271 NavigationGestureUser : NavigationGestureAuto;
3273 // Make sure redirect tracking state is clear for the new load.
3274 completed_client_redirect_src_ = Referrer();
3275 } else if (frame->parent()->isLoading()) {
3276 // Take note of AUTO_SUBFRAME loads here, so that we can know how to
3277 // load an error page. See didFailProvisionalLoad.
3278 document_state->navigation_state()->set_transition_type(
3279 PAGE_TRANSITION_AUTO_SUBFRAME);
3282 FOR_EACH_OBSERVER(
3283 RenderViewObserver, observers_, DidStartProvisionalLoad(frame));
3285 Send(new ViewHostMsg_DidStartProvisionalLoadForFrame(
3286 routing_id_, frame->identifier(),
3287 frame->parent() ? frame->parent()->identifier() : -1,
3288 is_top_most, ds->request().url()));
3291 void RenderViewImpl::didReceiveServerRedirectForProvisionalLoad(
3292 WebFrame* frame) {
3293 if (frame->parent())
3294 return;
3295 // Received a redirect on the main frame.
3296 WebDataSource* data_source = frame->provisionalDataSource();
3297 if (!data_source) {
3298 // Should only be invoked when we have a data source.
3299 NOTREACHED();
3300 return;
3302 std::vector<GURL> redirects;
3303 GetRedirectChain(data_source, &redirects);
3304 if (redirects.size() >= 2) {
3305 Send(new ViewHostMsg_DidRedirectProvisionalLoad(routing_id_, page_id_,
3306 redirects[redirects.size() - 2], redirects.back()));
3310 void RenderViewImpl::didFailProvisionalLoad(WebFrame* frame,
3311 const WebURLError& error) {
3312 // Notify the browser that we failed a provisional load with an error.
3314 // Note: It is important this notification occur before DidStopLoading so the
3315 // SSL manager can react to the provisional load failure before being
3316 // notified the load stopped.
3318 WebDataSource* ds = frame->provisionalDataSource();
3319 DCHECK(ds);
3321 const WebURLRequest& failed_request = ds->request();
3323 FOR_EACH_OBSERVER(
3324 RenderViewObserver, observers_, DidFailProvisionalLoad(frame, error));
3326 bool show_repost_interstitial =
3327 (error.reason == net::ERR_CACHE_MISS &&
3328 EqualsASCII(failed_request.httpMethod(), "POST"));
3330 ViewHostMsg_DidFailProvisionalLoadWithError_Params params;
3331 params.frame_id = frame->identifier();
3332 params.is_main_frame = !frame->parent();
3333 params.error_code = error.reason;
3334 GetContentClient()->renderer()->GetNavigationErrorStrings(
3335 failed_request,
3336 error,
3337 NULL,
3338 &params.error_description);
3339 params.url = error.unreachableURL;
3340 params.showing_repost_interstitial = show_repost_interstitial;
3341 Send(new ViewHostMsg_DidFailProvisionalLoadWithError(
3342 routing_id_, params));
3344 // Don't display an error page if this is simply a cancelled load. Aside
3345 // from being dumb, WebCore doesn't expect it and it will cause a crash.
3346 if (error.reason == net::ERR_ABORTED)
3347 return;
3349 // Make sure we never show errors in view source mode.
3350 frame->enableViewSourceMode(false);
3352 DocumentState* document_state = DocumentState::FromDataSource(ds);
3353 NavigationState* navigation_state = document_state->navigation_state();
3355 // If this is a failed back/forward/reload navigation, then we need to do a
3356 // 'replace' load. This is necessary to avoid messing up session history.
3357 // Otherwise, we do a normal load, which simulates a 'go' navigation as far
3358 // as session history is concerned.
3360 // AUTO_SUBFRAME loads should always be treated as loads that do not advance
3361 // the page id.
3363 bool replace =
3364 navigation_state->pending_page_id() != -1 ||
3365 navigation_state->transition_type() ==
3366 PAGE_TRANSITION_AUTO_SUBFRAME;
3368 // If we failed on a browser initiated request, then make sure that our error
3369 // page load is regarded as the same browser initiated request.
3370 if (!navigation_state->is_content_initiated()) {
3371 pending_navigation_params_.reset(new ViewMsg_Navigate_Params);
3372 pending_navigation_params_->page_id =
3373 navigation_state->pending_page_id();
3374 pending_navigation_params_->pending_history_list_offset =
3375 navigation_state->pending_history_list_offset();
3376 pending_navigation_params_->transition =
3377 navigation_state->transition_type();
3378 pending_navigation_params_->request_time =
3379 document_state->request_time();
3382 // Provide the user with a more helpful error page?
3383 if (MaybeLoadAlternateErrorPage(frame, error, replace))
3384 return;
3386 // Fallback to a local error page.
3387 LoadNavigationErrorPage(frame, failed_request, error, std::string(), replace);
3390 void RenderViewImpl::didReceiveDocumentData(
3391 WebFrame* frame, const char* data, size_t data_len,
3392 bool& prevent_default) {
3393 DocumentState* document_state =
3394 DocumentState::FromDataSource(frame->dataSource());
3395 document_state->set_use_error_page(false);
3398 void RenderViewImpl::didCommitProvisionalLoad(WebFrame* frame,
3399 bool is_new_navigation) {
3400 DocumentState* document_state =
3401 DocumentState::FromDataSource(frame->dataSource());
3402 NavigationState* navigation_state = document_state->navigation_state();
3404 if (document_state->commit_load_time().is_null())
3405 document_state->set_commit_load_time(Time::Now());
3407 if (document_state->must_reset_scroll_and_scale_state()) {
3408 #if defined(OS_ANDROID) // crbug.com/153907
3409 webview()->resetScrollAndScaleState();
3410 #endif
3411 document_state->set_must_reset_scroll_and_scale_state(false);
3414 if (is_new_navigation) {
3415 // When we perform a new navigation, we need to update the last committed
3416 // session history entry with state for the page we are leaving.
3417 UpdateSessionHistory(frame);
3419 // We bump our Page ID to correspond with the new session history entry.
3420 page_id_ = next_page_id_++;
3422 // Don't update history_page_ids_ (etc) for kSwappedOutURL, since
3423 // we don't want to forget the entry that was there, and since we will
3424 // never come back to kSwappedOutURL. Note that we have to call
3425 // UpdateSessionHistory and update page_id_ even in this case, so that
3426 // the current entry gets a state update and so that we don't send a
3427 // state update to the wrong entry when we swap back in.
3428 if (GetLoadingUrl(frame) != GURL(kSwappedOutURL)) {
3429 // Advance our offset in session history, applying the length limit.
3430 // There is now no forward history.
3431 history_list_offset_++;
3432 if (history_list_offset_ >= kMaxSessionHistoryEntries)
3433 history_list_offset_ = kMaxSessionHistoryEntries - 1;
3434 history_list_length_ = history_list_offset_ + 1;
3435 history_page_ids_.resize(history_list_length_, -1);
3436 history_page_ids_[history_list_offset_] = page_id_;
3438 } else {
3439 // Inspect the navigation_state on this frame to see if the navigation
3440 // corresponds to a session history navigation... Note: |frame| may or
3441 // may not be the toplevel frame, but for the case of capturing session
3442 // history, the first committed frame suffices. We keep track of whether
3443 // we've seen this commit before so that only capture session history once
3444 // per navigation.
3446 // Note that we need to check if the page ID changed. In the case of a
3447 // reload, the page ID doesn't change, and UpdateSessionHistory gets the
3448 // previous URL and the current page ID, which would be wrong.
3449 if (navigation_state->pending_page_id() != -1 &&
3450 navigation_state->pending_page_id() != page_id_ &&
3451 !navigation_state->request_committed()) {
3452 // This is a successful session history navigation!
3453 UpdateSessionHistory(frame);
3454 page_id_ = navigation_state->pending_page_id();
3456 history_list_offset_ = navigation_state->pending_history_list_offset();
3458 // If the history list is valid, our list of page IDs should be correct.
3459 DCHECK(history_list_length_ <= 0 ||
3460 history_list_offset_ < 0 ||
3461 history_list_offset_ >= history_list_length_ ||
3462 history_page_ids_[history_list_offset_] == page_id_);
3466 FOR_EACH_OBSERVER(RenderViewObserver, observers_,
3467 DidCommitProvisionalLoad(frame, is_new_navigation));
3469 // Remember that we've already processed this request, so we don't update
3470 // the session history again. We do this regardless of whether this is
3471 // a session history navigation, because if we attempted a session history
3472 // navigation without valid HistoryItem state, WebCore will think it is a
3473 // new navigation.
3474 navigation_state->set_request_committed(true);
3476 UpdateURL(frame);
3478 // If this committed load was initiated by a client redirect, we're
3479 // at the last stop now, so clear it.
3480 completed_client_redirect_src_ = Referrer();
3482 // Check whether we have new encoding name.
3483 UpdateEncoding(frame, frame->view()->pageEncoding().utf8());
3485 if (!frame->parent()) { // Only for top frames.
3486 RenderThreadImpl* render_thread_impl = RenderThreadImpl::current();
3487 if (render_thread_impl) { // Can be NULL in tests.
3488 render_thread_impl->histogram_customizer()->
3489 RenderViewNavigatedToHost(GURL(GetLoadingUrl(frame)).host(),
3490 g_view_map.Get().size());
3495 void RenderViewImpl::didClearWindowObject(WebFrame* frame) {
3496 FOR_EACH_OBSERVER(RenderViewObserver, observers_,
3497 DidClearWindowObject(frame));
3499 if (enabled_bindings_ & BINDINGS_POLICY_DOM_AUTOMATION) {
3500 if (!dom_automation_controller_.get())
3501 dom_automation_controller_.reset(new DomAutomationController());
3502 dom_automation_controller_->set_message_sender(
3503 static_cast<RenderView*>(this));
3504 dom_automation_controller_->set_routing_id(routing_id());
3505 dom_automation_controller_->BindToJavascript(frame,
3506 "domAutomationController");
3509 InjectDoNotTrackBindings(frame);
3512 void RenderViewImpl::didCreateDocumentElement(WebFrame* frame) {
3513 // Notify the browser about non-blank documents loading in the top frame.
3514 GURL url = frame->document().url();
3515 if (url.is_valid() && url.spec() != chrome::kAboutBlankURL) {
3516 if (frame == webview()->mainFrame())
3517 Send(new ViewHostMsg_DocumentAvailableInMainFrame(routing_id_));
3520 FOR_EACH_OBSERVER(RenderViewObserver, observers_,
3521 DidCreateDocumentElement(frame));
3524 void RenderViewImpl::didReceiveTitle(WebFrame* frame, const WebString& title,
3525 WebTextDirection direction) {
3526 UpdateTitle(frame, title, direction);
3528 // Also check whether we have new encoding name.
3529 UpdateEncoding(frame, frame->view()->pageEncoding().utf8());
3532 void RenderViewImpl::didChangeIcon(WebFrame* frame, WebIconURL::Type type) {
3533 favicon_helper_->DidChangeIcon(frame, type);
3536 void RenderViewImpl::didFinishDocumentLoad(WebFrame* frame) {
3537 WebDataSource* ds = frame->dataSource();
3538 DocumentState* document_state = DocumentState::FromDataSource(ds);
3539 document_state->set_finish_document_load_time(Time::Now());
3541 Send(new ViewHostMsg_DocumentLoadedInFrame(routing_id_, frame->identifier()));
3543 FOR_EACH_OBSERVER(RenderViewObserver, observers_,
3544 DidFinishDocumentLoad(frame));
3546 // Check whether we have new encoding name.
3547 UpdateEncoding(frame, frame->view()->pageEncoding().utf8());
3550 void RenderViewImpl::didHandleOnloadEvents(WebFrame* frame) {
3551 if (webview()->mainFrame() == frame) {
3552 Send(new ViewHostMsg_DocumentOnLoadCompletedInMainFrame(routing_id_,
3553 page_id_));
3557 void RenderViewImpl::didFailLoad(WebFrame* frame, const WebURLError& error) {
3558 WebDataSource* ds = frame->dataSource();
3559 DCHECK(ds);
3562 FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidFailLoad(frame, error));
3564 const WebURLRequest& failed_request = ds->request();
3565 string16 error_description;
3566 GetContentClient()->renderer()->GetNavigationErrorStrings(
3567 failed_request,
3568 error,
3569 NULL,
3570 &error_description);
3571 Send(new ViewHostMsg_DidFailLoadWithError(routing_id_,
3572 frame->identifier(),
3573 failed_request.url(),
3574 !frame->parent(),
3575 error.reason,
3576 error_description));
3579 void RenderViewImpl::didFinishLoad(WebFrame* frame) {
3580 WebDataSource* ds = frame->dataSource();
3581 DocumentState* document_state = DocumentState::FromDataSource(ds);
3582 if (document_state->finish_load_time().is_null())
3583 document_state->set_finish_load_time(Time::Now());
3585 FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidFinishLoad(frame));
3587 Send(new ViewHostMsg_DidFinishLoad(routing_id_,
3588 frame->identifier(),
3589 ds->request().url(),
3590 !frame->parent()));
3593 void RenderViewImpl::didNavigateWithinPage(
3594 WebFrame* frame, bool is_new_navigation) {
3595 // If this was a reference fragment navigation that we initiated, then we
3596 // could end up having a non-null pending navigation params. We just need to
3597 // update the ExtraData on the datasource so that others who read the
3598 // ExtraData will get the new NavigationState. Similarly, if we did not
3599 // initiate this navigation, then we need to take care to reset any pre-
3600 // existing navigation state to a content-initiated navigation state.
3601 // DidCreateDataSource conveniently takes care of this for us.
3602 didCreateDataSource(frame, frame->dataSource());
3604 DocumentState* document_state =
3605 DocumentState::FromDataSource(frame->dataSource());
3606 NavigationState* new_state = document_state->navigation_state();
3607 new_state->set_was_within_same_page(true);
3609 didCommitProvisionalLoad(frame, is_new_navigation);
3611 WebDataSource* datasource = frame->view()->mainFrame()->dataSource();
3612 UpdateTitle(frame, datasource->pageTitle(), datasource->pageTitleDirection());
3615 void RenderViewImpl::didUpdateCurrentHistoryItem(WebFrame* frame) {
3616 StartNavStateSyncTimerIfNecessary();
3619 void RenderViewImpl::assignIdentifierToRequest(
3620 WebFrame* frame, unsigned identifier, const WebURLRequest& request) {
3621 // Ignore
3624 void RenderViewImpl::willSendRequest(WebFrame* frame,
3625 unsigned identifier,
3626 WebURLRequest& request,
3627 const WebURLResponse& redirect_response) {
3628 WebFrame* top_frame = frame->top();
3629 if (!top_frame)
3630 top_frame = frame;
3631 WebDataSource* provisional_data_source = top_frame->provisionalDataSource();
3632 WebDataSource* top_data_source = top_frame->dataSource();
3633 WebDataSource* data_source =
3634 provisional_data_source ? provisional_data_source : top_data_source;
3636 PageTransition transition_type = PAGE_TRANSITION_LINK;
3637 DocumentState* document_state = DocumentState::FromDataSource(data_source);
3638 DCHECK(document_state);
3639 NavigationState* navigation_state = document_state->navigation_state();
3640 transition_type = navigation_state->transition_type();
3642 GURL request_url(request.url());
3643 GURL new_url;
3644 if (GetContentClient()->renderer()->WillSendRequest(
3645 frame,
3646 transition_type,
3647 request_url,
3648 request.firstPartyForCookies(),
3649 &new_url)) {
3650 request.setURL(WebURL(new_url));
3653 if (document_state->is_cache_policy_override_set())
3654 request.setCachePolicy(document_state->cache_policy_override());
3656 WebKit::WebReferrerPolicy referrer_policy;
3657 if (document_state && document_state->is_referrer_policy_set()) {
3658 referrer_policy = document_state->referrer_policy();
3659 document_state->clear_referrer_policy();
3660 } else {
3661 referrer_policy = frame->document().referrerPolicy();
3664 // The request's extra data may indicate that we should set a custom user
3665 // agent. This needs to be done here, after WebKit is through with setting the
3666 // user agent on its own.
3667 WebString custom_user_agent;
3668 if (request.extraData()) {
3669 webkit_glue::WebURLRequestExtraDataImpl* old_extra_data =
3670 static_cast<webkit_glue::WebURLRequestExtraDataImpl*>(
3671 request.extraData());
3672 custom_user_agent = old_extra_data->custom_user_agent();
3674 if (!custom_user_agent.isNull()) {
3675 if (custom_user_agent.isEmpty())
3676 request.clearHTTPHeaderField("User-Agent");
3677 else
3678 request.setHTTPHeaderField("User-Agent", custom_user_agent);
3682 request.setExtraData(
3683 new RequestExtraData(referrer_policy,
3684 custom_user_agent,
3685 (frame == top_frame),
3686 frame->identifier(),
3687 frame->parent() == top_frame,
3688 frame->parent() ? frame->parent()->identifier() : -1,
3689 navigation_state->allow_download(),
3690 transition_type,
3691 navigation_state->transferred_request_child_id(),
3692 navigation_state->transferred_request_request_id()));
3694 DocumentState* top_document_state =
3695 DocumentState::FromDataSource(top_data_source);
3696 // TODO(gavinp): separate out prefetching and prerender field trials
3697 // if the rel=prerender rel type is sticking around.
3698 if (top_document_state &&
3699 request.targetType() == WebURLRequest::TargetIsPrefetch)
3700 top_document_state->set_was_prefetcher(true);
3702 request.setRequestorID(routing_id_);
3703 request.setHasUserGesture(frame->isProcessingUserGesture());
3705 if (!renderer_preferences_.enable_referrers)
3706 request.clearHTTPHeaderField("Referer");
3709 void RenderViewImpl::didReceiveResponse(
3710 WebFrame* frame, unsigned identifier, const WebURLResponse& response) {
3712 // Only do this for responses that correspond to a provisional data source
3713 // of the top-most frame. If we have a provisional data source, then we
3714 // can't have any sub-resources yet, so we know that this response must
3715 // correspond to a frame load.
3716 if (!frame->provisionalDataSource() || frame->parent())
3717 return;
3719 // If we are in view source mode, then just let the user see the source of
3720 // the server's error page.
3721 if (frame->isViewSourceModeEnabled())
3722 return;
3724 DocumentState* document_state =
3725 DocumentState::FromDataSource(frame->provisionalDataSource());
3726 int http_status_code = response.httpStatusCode();
3728 // Record page load flags.
3729 document_state->set_was_fetched_via_spdy(response.wasFetchedViaSPDY());
3730 document_state->set_was_npn_negotiated(response.wasNpnNegotiated());
3731 WebURLResponseExtraDataImpl* extra_data = GetExtraDataFromResponse(response);
3732 if (extra_data) {
3733 document_state->set_npn_negotiated_protocol(
3734 extra_data->npn_negotiated_protocol());
3736 document_state->set_was_alternate_protocol_available(
3737 response.wasAlternateProtocolAvailable());
3738 document_state->set_was_fetched_via_proxy(response.wasFetchedViaProxy());
3739 document_state->set_http_status_code(http_status_code);
3740 // Whether or not the http status code actually corresponds to an error is
3741 // only checked when the page is done loading, if |use_error_page| is
3742 // still true.
3743 document_state->set_use_error_page(true);
3746 void RenderViewImpl::didFinishResourceLoad(
3747 WebFrame* frame, unsigned identifier) {
3748 DocumentState* document_state =
3749 DocumentState::FromDataSource(frame->dataSource());
3750 if (!document_state->use_error_page())
3751 return;
3753 // Do not show error page when DevTools is attached.
3754 if (devtools_agent_->IsAttached())
3755 return;
3757 // Display error page, if appropriate.
3758 int http_status_code = document_state->http_status_code();
3759 if (http_status_code == 404) {
3760 // On 404s, try a remote search page as a fallback.
3761 const GURL& document_url = frame->document().url();
3763 const GURL& error_page_url =
3764 GetAlternateErrorPageURL(document_url, HTTP_404);
3765 if (error_page_url.is_valid()) {
3766 WebURLError original_error;
3767 original_error.domain = "http";
3768 original_error.reason = 404;
3769 original_error.unreachableURL = document_url;
3771 document_state->set_alt_error_page_fetcher(
3772 new AltErrorPageResourceFetcher(
3773 error_page_url, frame, original_error,
3774 base::Bind(&RenderViewImpl::AltErrorPageFinished,
3775 base::Unretained(this))));
3776 return;
3780 std::string error_domain;
3781 if (GetContentClient()->renderer()->HasErrorPage(
3782 http_status_code, &error_domain)) {
3783 WebURLError error;
3784 error.unreachableURL = frame->document().url();
3785 error.domain = WebString::fromUTF8(error_domain);
3786 error.reason = http_status_code;
3788 LoadNavigationErrorPage(
3789 frame, frame->dataSource()->request(), error, std::string(), true);
3793 void RenderViewImpl::didFailResourceLoad(
3794 WebFrame* frame, unsigned identifier, const WebURLError& error) {
3795 // Ignore
3798 void RenderViewImpl::didLoadResourceFromMemoryCache(
3799 WebFrame* frame, const WebURLRequest& request,
3800 const WebURLResponse& response) {
3801 // The recipients of this message have no use for data: URLs: they don't
3802 // affect the page's insecure content list and are not in the disk cache. To
3803 // prevent large (1M+) data: URLs from crashing in the IPC system, we simply
3804 // filter them out here.
3805 GURL url(request.url());
3806 if (url.SchemeIs("data"))
3807 return;
3809 // Let the browser know we loaded a resource from the memory cache. This
3810 // message is needed to display the correct SSL indicators.
3811 Send(new ViewHostMsg_DidLoadResourceFromMemoryCache(
3812 routing_id_,
3813 url,
3814 response.securityInfo(),
3815 request.httpMethod().utf8(),
3816 response.mimeType().utf8(),
3817 ResourceType::FromTargetType(request.targetType())));
3820 void RenderViewImpl::didDisplayInsecureContent(WebFrame* frame) {
3821 Send(new ViewHostMsg_DidDisplayInsecureContent(routing_id_));
3824 void RenderViewImpl::didRunInsecureContent(
3825 WebFrame* frame, const WebSecurityOrigin& origin, const WebURL& target) {
3826 Send(new ViewHostMsg_DidRunInsecureContent(
3827 routing_id_,
3828 origin.toString().utf8(),
3829 target));
3832 void RenderViewImpl::didExhaustMemoryAvailableForScript(WebFrame* frame) {
3833 Send(new ViewHostMsg_JSOutOfMemory(routing_id_));
3836 void RenderViewImpl::didCreateScriptContext(WebFrame* frame,
3837 v8::Handle<v8::Context> context,
3838 int extension_group,
3839 int world_id) {
3840 GetContentClient()->renderer()->DidCreateScriptContext(
3841 frame, context, extension_group, world_id);
3843 intents_host_->DidCreateScriptContext(
3844 frame, context, extension_group, world_id);
3847 void RenderViewImpl::willReleaseScriptContext(WebFrame* frame,
3848 v8::Handle<v8::Context> context,
3849 int world_id) {
3850 GetContentClient()->renderer()->WillReleaseScriptContext(
3851 frame, context, world_id);
3854 void RenderViewImpl::CheckPreferredSize() {
3855 // We don't always want to send the change messages over IPC, only if we've
3856 // been put in that mode by getting a |ViewMsg_EnablePreferredSizeChangedMode|
3857 // message.
3858 if (!send_preferred_size_changes_ || !webview())
3859 return;
3861 gfx::Size size(webview()->mainFrame()->contentsPreferredWidth(),
3862 webview()->mainFrame()->documentElementScrollHeight());
3864 // In the presence of zoom, these sizes are still reported as if unzoomed,
3865 // so we need to adjust.
3866 double zoom_factor = WebView::zoomLevelToZoomFactor(webview()->zoomLevel());
3867 size.set_width(static_cast<int>(size.width() * zoom_factor));
3868 size.set_height(static_cast<int>(size.height() * zoom_factor));
3870 if (size == preferred_size_)
3871 return;
3873 preferred_size_ = size;
3874 Send(new ViewHostMsg_DidContentsPreferredSizeChange(routing_id_,
3875 preferred_size_));
3878 WebGraphicsContext3D* RenderViewImpl::CreateGraphicsContext3D(
3879 const WebGraphicsContext3D::Attributes& attributes) {
3880 if (!webview())
3881 return NULL;
3883 // The WebGraphicsContext3DInProcessImpl code path is used for
3884 // layout tests (though not through this code) as well as for
3885 // debugging and bringing up new ports.
3886 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessWebGL)) {
3887 return webkit::gpu::WebGraphicsContext3DInProcessImpl::CreateForWebView(
3888 attributes, true);
3889 } else {
3890 GURL url;
3891 if (webview()->mainFrame())
3892 url = GURL(webview()->mainFrame()->document().url());
3893 else
3894 url = GURL("chrome://gpu/RenderViewImpl::CreateGraphicsContext3D");
3896 scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
3897 new WebGraphicsContext3DCommandBufferImpl(
3898 surface_id(),
3899 url,
3900 RenderThreadImpl::current(),
3901 AsWeakPtr()));
3903 if (!context->Initialize(
3904 attributes,
3905 false /* bind generates resources */,
3906 CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE))
3907 return NULL;
3908 return context.release();
3912 // The browser process needs to know the shape of the tree, as well as the names
3913 // and ids of all frames. This allows it to properly route JavaScript messages
3914 // across processes and frames. The serialization format is described in the
3915 // comments of the ViewMsg_FrameTreeUpdated message.
3916 // This function sends those updates to the browser and updates the RVH
3917 // corresponding to this object. It must be called on any events that modify
3918 // the tree structure or the names of any frames.
3919 void RenderViewImpl::SendUpdatedFrameTree(
3920 WebKit::WebFrame* exclude_frame_subtree) {
3921 // TODO(nasko): Frame tree updates are causing issues with postMessage, as
3922 // described in http://crbug.com/153701. Disable them until a proper fix is
3923 // in place.
3926 BrowserPluginManager* RenderViewImpl::browser_plugin_manager() {
3927 if (!browser_plugin_manager_)
3928 browser_plugin_manager_ = BrowserPluginManager::Create(this);
3929 return browser_plugin_manager_;
3932 void RenderViewImpl::CreateFrameTree(WebKit::WebFrame* frame,
3933 DictionaryValue* frame_tree) {
3934 // TODO(nasko): Remove once http://crbug.com/153701 is fixed.
3935 DCHECK(false);
3936 NavigateToSwappedOutURL(frame);
3938 string16 name;
3939 if (frame_tree->GetString(kFrameTreeNodeNameKey, &name) && !name.empty())
3940 frame->setName(name);
3942 int remote_id;
3943 if (frame_tree->GetInteger(kFrameTreeNodeIdKey, &remote_id))
3944 active_frame_id_map_.insert(std::pair<int, int>(frame->identifier(),
3945 remote_id));
3947 ListValue* children;
3948 if (!frame_tree->GetList(kFrameTreeNodeSubtreeKey, &children))
3949 return;
3951 // Create an invisible iframe tree in the swapped out page.
3952 base::DictionaryValue* child;
3953 for (size_t i = 0; i < children->GetSize(); ++i) {
3954 if (!children->GetDictionary(i, &child))
3955 continue;
3956 WebElement element = frame->document().createElement("iframe");
3957 element.setAttribute("width", "0");
3958 element.setAttribute("height", "0");
3959 element.setAttribute("frameBorder", "0");
3960 if (frame->document().body().appendChild(element)) {
3961 WebFrame* subframe = WebFrame::fromFrameOwnerElement(element);
3962 if (subframe)
3963 CreateFrameTree(subframe, child);
3964 } else {
3965 LOG(ERROR) << "Failed to append created iframe element.";
3970 WebKit::WebFrame* RenderViewImpl::GetFrameByRemoteID(int remote_frame_id) {
3971 std::map<int, int>::const_iterator it = active_frame_id_map_.begin();
3972 for (; it != active_frame_id_map_.end(); ++it) {
3973 if (it->second == remote_frame_id)
3974 return FindFrameByID(webview()->mainFrame(), it->first);
3976 return NULL;
3979 void RenderViewImpl::EnsureMediaStreamImpl() {
3980 if (!RenderThreadImpl::current()) // Will be NULL during unit tests.
3981 return;
3983 #if defined(ENABLE_WEBRTC)
3984 if (!media_stream_dispatcher_)
3985 media_stream_dispatcher_ = new MediaStreamDispatcher(this);
3987 if (!media_stream_impl_) {
3988 media_stream_impl_ = new MediaStreamImpl(
3989 this,
3990 media_stream_dispatcher_,
3991 RenderThreadImpl::current()->video_capture_impl_manager(),
3992 RenderThreadImpl::current()->GetMediaStreamDependencyFactory());
3994 #endif
3997 void RenderViewImpl::didChangeContentsSize(WebFrame* frame,
3998 const WebSize& size) {
3999 if (webview()->mainFrame() != frame)
4000 return;
4001 WebView* frameView = frame->view();
4002 if (!frameView)
4003 return;
4005 bool has_horizontal_scrollbar = frame->hasHorizontalScrollbar();
4006 bool has_vertical_scrollbar = frame->hasVerticalScrollbar();
4008 if (has_horizontal_scrollbar != cached_has_main_frame_horizontal_scrollbar_ ||
4009 has_vertical_scrollbar != cached_has_main_frame_vertical_scrollbar_) {
4010 Send(new ViewHostMsg_DidChangeScrollbarsForMainFrame(
4011 routing_id_, has_horizontal_scrollbar, has_vertical_scrollbar));
4013 cached_has_main_frame_horizontal_scrollbar_ = has_horizontal_scrollbar;
4014 cached_has_main_frame_vertical_scrollbar_ = has_vertical_scrollbar;
4017 #if defined(OS_ANDROID)
4018 ScheduleUpdateFrameInfo();
4019 #endif
4022 void RenderViewImpl::UpdateScrollState(WebFrame* frame) {
4023 WebSize offset = frame->scrollOffset();
4024 WebSize minimum_offset = frame->minimumScrollOffset();
4025 WebSize maximum_offset = frame->maximumScrollOffset();
4027 bool is_pinned_to_left = offset.width <= minimum_offset.width;
4028 bool is_pinned_to_right = offset.width >= maximum_offset.width;
4030 if (is_pinned_to_left != cached_is_main_frame_pinned_to_left_ ||
4031 is_pinned_to_right != cached_is_main_frame_pinned_to_right_) {
4032 Send(new ViewHostMsg_DidChangeScrollOffsetPinningForMainFrame(
4033 routing_id_, is_pinned_to_left, is_pinned_to_right));
4035 cached_is_main_frame_pinned_to_left_ = is_pinned_to_left;
4036 cached_is_main_frame_pinned_to_right_ = is_pinned_to_right;
4040 void RenderViewImpl::didChangeScrollOffset(WebFrame* frame) {
4041 StartNavStateSyncTimerIfNecessary();
4043 if (webview()->mainFrame() == frame)
4044 UpdateScrollState(frame);
4046 FOR_EACH_OBSERVER(
4047 RenderViewObserver, observers_, DidChangeScrollOffset(frame));
4049 #if defined(OS_ANDROID)
4050 if (webview()->mainFrame() == frame)
4051 ScheduleUpdateFrameInfo();
4052 #endif
4055 #if defined(OS_ANDROID)
4056 void RenderViewImpl::didFirstVisuallyNonEmptyLayout(WebFrame* frame) {
4057 if (frame != webview()->mainFrame())
4058 return;
4060 // Update body background color if necessary.
4061 SkColor bg_color = webwidget_->backgroundColor();
4063 // If not initialized, default to white. Note that 0 is different from black
4064 // as black still has alpha 0xFF.
4065 if (!bg_color)
4066 bg_color = SK_ColorWHITE;
4068 if (bg_color != body_background_color_) {
4069 body_background_color_ = bg_color;
4070 Send(new ViewHostMsg_DidChangeBodyBackgroundColor(routing_id_, bg_color));
4073 #endif
4075 void RenderViewImpl::SendFindReply(int request_id,
4076 int match_count,
4077 int ordinal,
4078 const WebRect& selection_rect,
4079 bool final_status_update) {
4080 #if defined(OS_ANDROID)
4081 if (synchronous_find_reply_message_.get()) {
4082 if (final_status_update) {
4083 ViewMsg_SynchronousFind::WriteReplyParams(
4084 synchronous_find_reply_message_.get(),
4085 match_count,
4086 match_count ? synchronous_find_active_match_ordinal_ : 0);
4087 Send(synchronous_find_reply_message_.release());
4089 return;
4091 #endif
4093 Send(new ViewHostMsg_Find_Reply(routing_id_,
4094 request_id,
4095 match_count,
4096 selection_rect,
4097 ordinal,
4098 final_status_update));
4101 void RenderViewImpl::reportFindInPageMatchCount(int request_id,
4102 int count,
4103 bool final_update) {
4104 int active_match_ordinal = -1; // -1 = don't update active match ordinal
4105 if (!count)
4106 active_match_ordinal = 0;
4108 // Send the search result over to the browser process.
4109 SendFindReply(request_id,
4110 count,
4111 active_match_ordinal,
4112 gfx::Rect(),
4113 final_update);
4116 void RenderViewImpl::reportFindInPageSelection(int request_id,
4117 int active_match_ordinal,
4118 const WebRect& selection_rect) {
4119 #if defined(OS_ANDROID)
4120 // If this was a SynchronousFind request, we need to remember the ordinal
4121 // value here for replying when reportFindInPageMatchCount is called.
4122 if (synchronous_find_reply_message_.get()) {
4123 synchronous_find_active_match_ordinal_ = active_match_ordinal;
4124 return;
4126 #endif
4128 SendFindReply(request_id,
4130 active_match_ordinal,
4131 selection_rect,
4132 false);
4135 void RenderViewImpl::openFileSystem(
4136 WebFrame* frame,
4137 WebFileSystem::Type type,
4138 long long size,
4139 bool create,
4140 WebFileSystemCallbacks* callbacks) {
4141 DCHECK(callbacks);
4143 WebSecurityOrigin origin = frame->document().securityOrigin();
4144 if (origin.isUnique()) {
4145 // Unique origins cannot store persistent state.
4146 callbacks->didFail(WebKit::WebFileErrorAbort);
4147 return;
4150 ChildThread::current()->file_system_dispatcher()->OpenFileSystem(
4151 GURL(origin.toString()), static_cast<fileapi::FileSystemType>(type),
4152 size, create, new WebFileSystemCallbackDispatcher(callbacks));
4155 void RenderViewImpl::deleteFileSystem(
4156 WebFrame* frame,
4157 WebFileSystem::Type type ,
4158 WebFileSystemCallbacks* callbacks) {
4159 DCHECK(callbacks);
4161 WebSecurityOrigin origin = frame->document().securityOrigin();
4162 if (origin.isUnique()) {
4163 // Unique origins cannot store persistent state.
4164 callbacks->didSucceed();
4165 return;
4168 ChildThread::current()->file_system_dispatcher()->DeleteFileSystem(
4169 GURL(origin.toString()),
4170 static_cast<fileapi::FileSystemType>(type),
4171 new WebFileSystemCallbackDispatcher(callbacks));
4174 void RenderViewImpl::queryStorageUsageAndQuota(
4175 WebFrame* frame,
4176 WebStorageQuotaType type,
4177 WebStorageQuotaCallbacks* callbacks) {
4178 DCHECK(frame);
4179 WebSecurityOrigin origin = frame->document().securityOrigin();
4180 if (origin.isUnique()) {
4181 // Unique origins cannot store persistent state.
4182 callbacks->didFail(WebKit::WebStorageQuotaErrorAbort);
4183 return;
4185 ChildThread::current()->quota_dispatcher()->QueryStorageUsageAndQuota(
4186 GURL(origin.toString()),
4187 static_cast<quota::StorageType>(type),
4188 QuotaDispatcher::CreateWebStorageQuotaCallbacksWrapper(callbacks));
4191 void RenderViewImpl::requestStorageQuota(
4192 WebFrame* frame,
4193 WebStorageQuotaType type,
4194 unsigned long long requested_size,
4195 WebStorageQuotaCallbacks* callbacks) {
4196 DCHECK(frame);
4197 WebSecurityOrigin origin = frame->document().securityOrigin();
4198 if (origin.isUnique()) {
4199 // Unique origins cannot store persistent state.
4200 callbacks->didFail(WebKit::WebStorageQuotaErrorAbort);
4201 return;
4203 ChildThread::current()->quota_dispatcher()->RequestStorageQuota(
4204 routing_id(), GURL(origin.toString()),
4205 static_cast<quota::StorageType>(type), requested_size,
4206 QuotaDispatcher::CreateWebStorageQuotaCallbacksWrapper(callbacks));
4209 void RenderViewImpl::registerIntentService(
4210 WebFrame* frame, const WebIntentServiceInfo& service) {
4211 webkit_glue::WebIntentServiceData data(service);
4212 if (data.title.empty())
4213 data.title = webview()->mainFrame()->document().title();
4214 bool user_gesture = frame->isProcessingUserGesture();
4215 Send(new IntentsHostMsg_RegisterIntentService(routing_id_,
4216 data,
4217 user_gesture));
4220 void RenderViewImpl::dispatchIntent(
4221 WebFrame* frame, const WebIntentRequest& intentRequest) {
4222 webkit_glue::WebIntentData intent_data(intentRequest.intent());
4224 // See WebMessagePortChannelImpl::postMessage() and ::OnMessagedQueued()
4225 WebKit::WebMessagePortChannelArray* channels =
4226 intentRequest.intent().messagePortChannelsRelease();
4227 if (channels) {
4228 for (size_t i = 0; i < channels->size(); ++i) {
4229 WebMessagePortChannelImpl* webchannel =
4230 static_cast<WebMessagePortChannelImpl*>((*channels)[i]);
4231 intent_data.message_port_ids.push_back(webchannel->message_port_id());
4232 DCHECK(intent_data.message_port_ids[i] != MSG_ROUTING_NONE);
4234 delete channels;
4237 int id = intents_host_->RegisterWebIntent(intentRequest);
4238 Send(new IntentsHostMsg_WebIntentDispatch(
4239 routing_id_, intent_data, id));
4242 bool RenderViewImpl::willCheckAndDispatchMessageEvent(
4243 WebKit::WebFrame* sourceFrame,
4244 WebKit::WebFrame* targetFrame,
4245 WebKit::WebSecurityOrigin target_origin,
4246 WebKit::WebDOMMessageEvent event) {
4247 if (!is_swapped_out_)
4248 return false;
4250 ViewMsg_PostMessage_Params params;
4251 params.data = event.data().toString();
4252 params.source_origin = event.origin();
4253 if (!target_origin.isNull())
4254 params.target_origin = target_origin.toString();
4256 // Include the routing ID for the source frame, which the browser process
4257 // will translate into the routing ID for the equivalent frame in the target
4258 // process.
4259 params.source_routing_id = MSG_ROUTING_NONE;
4260 RenderViewImpl* source_view = FromWebView(sourceFrame->view());
4261 if (source_view)
4262 params.source_routing_id = source_view->routing_id();
4263 params.source_frame_id = sourceFrame->identifier();
4265 // Include the process, route, and frame IDs of the target frame. This allows
4266 // the browser to detect races between this message being sent and the target
4267 // frame no longer being valid.
4268 params.target_process_id = target_process_id_;
4269 params.target_routing_id = target_routing_id_;
4271 std::map<int,int>::iterator it = active_frame_id_map_.find(
4272 targetFrame->identifier());
4273 if (it != active_frame_id_map_.end()) {
4274 params.target_frame_id = it->second;
4275 } else {
4276 params.target_frame_id = 0;
4279 Send(new ViewHostMsg_RouteMessageEvent(routing_id_, params));
4280 return true;
4283 void RenderViewImpl::willOpenSocketStream(
4284 WebSocketStreamHandle* handle) {
4285 SocketStreamHandleData::AddToHandle(handle, routing_id_);
4288 void RenderViewImpl::willStartUsingPeerConnectionHandler(
4289 WebKit::WebFrame* frame, WebKit::WebRTCPeerConnectionHandler* handler) {
4290 #if defined(ENABLE_WEBRTC)
4291 static_cast<RTCPeerConnectionHandler*>(handler)->associateWithFrame(frame);
4292 #endif
4295 WebKit::WebString RenderViewImpl::userAgentOverride(
4296 WebKit::WebFrame* frame,
4297 const WebKit::WebURL& url) {
4298 if (!webview() || !webview()->mainFrame() ||
4299 renderer_preferences_.user_agent_override.empty()) {
4300 return WebKit::WebString();
4303 // If we're in the middle of committing a load, the data source we need
4304 // will still be provisional.
4305 WebFrame* main_frame = webview()->mainFrame();
4306 WebDataSource* data_source = NULL;
4307 if (main_frame->provisionalDataSource())
4308 data_source = main_frame->provisionalDataSource();
4309 else
4310 data_source = main_frame->dataSource();
4312 DocumentState* document_state =
4313 data_source ? DocumentState::FromDataSource(data_source) : NULL;
4314 if (document_state && document_state->is_overriding_user_agent())
4315 return WebString::fromUTF8(renderer_preferences_.user_agent_override);
4316 else
4317 return WebKit::WebString();
4320 bool RenderViewImpl::allowWebGL(WebFrame* frame, bool default_value) {
4321 if (!default_value)
4322 return false;
4324 bool blocked = true;
4325 Send(new ViewHostMsg_Are3DAPIsBlocked(
4326 routing_id_,
4327 GURL(frame->top()->document().securityOrigin().toString()),
4328 THREE_D_API_TYPE_WEBGL,
4329 &blocked));
4330 return !blocked;
4333 void RenderViewImpl::didLoseWebGLContext(
4334 WebKit::WebFrame* frame,
4335 int arb_robustness_status_code) {
4336 Send(new ViewHostMsg_DidLose3DContext(
4337 GURL(frame->top()->document().securityOrigin().toString()),
4338 THREE_D_API_TYPE_WEBGL,
4339 arb_robustness_status_code));
4342 // WebKit::WebPageSerializerClient implementation ------------------------------
4344 void RenderViewImpl::didSerializeDataForFrame(
4345 const WebURL& frame_url,
4346 const WebCString& data,
4347 WebPageSerializerClient::PageSerializationStatus status) {
4348 Send(new ViewHostMsg_SendSerializedHtmlData(
4349 routing_id(),
4350 frame_url,
4351 data.data(),
4352 static_cast<int32>(status)));
4355 // RenderView implementation ---------------------------------------------------
4357 bool RenderViewImpl::Send(IPC::Message* message) {
4358 return RenderWidget::Send(message);
4361 int RenderViewImpl::GetRoutingID() const {
4362 return routing_id_;
4365 int RenderViewImpl::GetPageId() const {
4366 return page_id_;
4369 gfx::Size RenderViewImpl::GetSize() const {
4370 return size();
4373 WebPreferences& RenderViewImpl::GetWebkitPreferences() {
4374 return webkit_preferences_;
4377 void RenderViewImpl::SetWebkitPreferences(const WebPreferences& preferences) {
4378 OnUpdateWebPreferences(preferences);
4381 WebKit::WebView* RenderViewImpl::GetWebView() {
4382 return webview();
4385 WebKit::WebNode RenderViewImpl::GetFocusedNode() const {
4386 if (!webview())
4387 return WebNode();
4388 WebFrame* focused_frame = webview()->focusedFrame();
4389 if (focused_frame) {
4390 WebDocument doc = focused_frame->document();
4391 if (!doc.isNull())
4392 return doc.focusedNode();
4395 return WebNode();
4398 WebKit::WebNode RenderViewImpl::GetContextMenuNode() const {
4399 return context_menu_node_;
4402 bool RenderViewImpl::IsEditableNode(const WebNode& node) const {
4403 if (node.isNull())
4404 return false;
4406 if (node.isContentEditable())
4407 return true;
4409 if (node.isElementNode()) {
4410 const WebElement& element = node.toConst<WebElement>();
4411 if (element.isTextFormControlElement())
4412 return true;
4414 // Also return true if it has an ARIA role of 'textbox'.
4415 for (unsigned i = 0; i < element.attributeCount(); ++i) {
4416 if (LowerCaseEqualsASCII(element.attributeLocalName(i), "role")) {
4417 if (LowerCaseEqualsASCII(element.attributeValue(i), "textbox"))
4418 return true;
4419 break;
4424 return false;
4427 WebKit::WebPlugin* RenderViewImpl::CreatePlugin(
4428 WebKit::WebFrame* frame,
4429 const webkit::WebPluginInfo& info,
4430 const WebKit::WebPluginParams& params) {
4431 WebKit::WebPlugin* pepper_webplugin =
4432 pepper_helper_->CreatePepperWebPlugin(info, params);
4434 if (pepper_webplugin)
4435 return pepper_webplugin;
4437 #if defined(USE_AURA) && !defined(OS_WIN)
4438 return NULL;
4439 #else
4440 return new webkit::npapi::WebPluginImpl(
4441 frame, params, info.path, AsWeakPtr());
4442 #endif
4445 void RenderViewImpl::EvaluateScript(const string16& frame_xpath,
4446 const string16& jscript,
4447 int id,
4448 bool notify_result) {
4449 v8::Handle<v8::Value> result;
4450 WebFrame* web_frame = GetChildFrame(frame_xpath);
4451 if (web_frame)
4452 result = web_frame->executeScriptAndReturnValue(WebScriptSource(jscript));
4453 if (notify_result) {
4454 ListValue list;
4455 if (!result.IsEmpty() && web_frame) {
4456 v8::HandleScope handle_scope;
4457 v8::Local<v8::Context> context = web_frame->mainWorldScriptContext();
4458 v8::Context::Scope context_scope(context);
4459 V8ValueConverterImpl converter;
4460 converter.SetDateAllowed(true);
4461 converter.SetRegExpAllowed(true);
4462 base::Value* result_value = converter.FromV8Value(result, context);
4463 list.Set(0, result_value ? result_value :
4464 base::Value::CreateNullValue());
4465 } else {
4466 list.Set(0, Value::CreateNullValue());
4468 Send(new ViewHostMsg_ScriptEvalResponse(routing_id_, id, list));
4472 bool RenderViewImpl::ShouldDisplayScrollbars(int width, int height) const {
4473 return (!send_preferred_size_changes_ ||
4474 (disable_scrollbars_size_limit_.width() <= width ||
4475 disable_scrollbars_size_limit_.height() <= height));
4478 int RenderViewImpl::GetEnabledBindings() const {
4479 return enabled_bindings_;
4482 bool RenderViewImpl::GetContentStateImmediately() const {
4483 return send_content_state_immediately_;
4486 float RenderViewImpl::GetFilteredTimePerFrame() const {
4487 return filtered_time_per_frame();
4490 int RenderViewImpl::ShowContextMenu(ContextMenuClient* client,
4491 const ContextMenuParams& params) {
4492 DCHECK(client); // A null client means "internal" when we issue callbacks.
4493 ContextMenuParams our_params(params);
4494 our_params.custom_context.request_id = pending_context_menus_.Add(client);
4495 Send(new ViewHostMsg_ContextMenu(routing_id_, our_params));
4496 return our_params.custom_context.request_id;
4499 void RenderViewImpl::CancelContextMenu(int request_id) {
4500 DCHECK(pending_context_menus_.Lookup(request_id));
4501 pending_context_menus_.Remove(request_id);
4504 WebKit::WebPageVisibilityState RenderViewImpl::GetVisibilityState() const {
4505 return visibilityState();
4508 void RenderViewImpl::RunModalAlertDialog(WebKit::WebFrame* frame,
4509 const WebKit::WebString& message) {
4510 return runModalAlertDialog(frame, message);
4513 void RenderViewImpl::LoadURLExternally(
4514 WebKit::WebFrame* frame,
4515 const WebKit::WebURLRequest& request,
4516 WebKit::WebNavigationPolicy policy) {
4517 loadURLExternally(frame, request, policy);
4520 // webkit_glue::WebPluginPageDelegate ------------------------------------------
4522 webkit::npapi::WebPluginDelegate* RenderViewImpl::CreatePluginDelegate(
4523 const FilePath& file_path,
4524 const std::string& mime_type) {
4525 if (!PluginChannelHost::IsListening()) {
4526 LOG(ERROR) << "PluginChannelHost isn't listening";
4527 return NULL;
4530 bool in_process_plugin = RenderProcess::current()->UseInProcessPlugins();
4531 if (in_process_plugin) {
4532 #if defined(OS_WIN) && !defined(USE_AURA)
4533 return webkit::npapi::WebPluginDelegateImpl::Create(file_path, mime_type);
4534 #else
4535 // In-proc plugins aren't supported on non-Windows.
4536 NOTIMPLEMENTED();
4537 return NULL;
4538 #endif
4541 return new WebPluginDelegateProxy(mime_type, AsWeakPtr());
4544 WebKit::WebPlugin* RenderViewImpl::CreatePluginReplacement(
4545 const FilePath& file_path) {
4546 return GetContentClient()->renderer()->CreatePluginReplacement(
4547 this, file_path);
4550 void RenderViewImpl::CreatedPluginWindow(gfx::PluginWindowHandle window) {
4551 #if defined(USE_X11)
4552 Send(new ViewHostMsg_CreatePluginContainer(routing_id(), window));
4553 #endif
4556 void RenderViewImpl::WillDestroyPluginWindow(gfx::PluginWindowHandle window) {
4557 #if defined(USE_X11)
4558 Send(new ViewHostMsg_DestroyPluginContainer(routing_id(), window));
4559 #endif
4560 CleanupWindowInPluginMoves(window);
4563 void RenderViewImpl::DidMovePlugin(
4564 const webkit::npapi::WebPluginGeometry& move) {
4565 SchedulePluginMove(move);
4568 void RenderViewImpl::DidStartLoadingForPlugin() {
4569 // TODO(darin): Make is_loading_ be a counter!
4570 didStartLoading();
4573 void RenderViewImpl::DidStopLoadingForPlugin() {
4574 // TODO(darin): Make is_loading_ be a counter!
4575 didStopLoading();
4578 WebCookieJar* RenderViewImpl::GetCookieJar() {
4579 return &cookie_jar_;
4582 void RenderViewImpl::DidPlay(WebKit::WebMediaPlayer* player) {
4583 Send(new ViewHostMsg_MediaNotification(routing_id_,
4584 reinterpret_cast<int64>(player),
4585 player->hasVideo(),
4586 player->hasAudio(),
4587 true));
4590 void RenderViewImpl::DidPause(WebKit::WebMediaPlayer* player) {
4591 Send(new ViewHostMsg_MediaNotification(routing_id_,
4592 reinterpret_cast<int64>(player),
4593 player->hasVideo(),
4594 player->hasAudio(),
4595 false));
4598 void RenderViewImpl::PlayerGone(WebKit::WebMediaPlayer* player) {
4599 DidPause(player);
4602 void RenderViewImpl::SyncNavigationState() {
4603 if (!webview())
4604 return;
4606 const WebHistoryItem& item = webview()->mainFrame()->currentHistoryItem();
4607 SendUpdateState(item);
4610 void RenderViewImpl::SyncSelectionIfRequired() {
4611 WebFrame* frame = webview()->focusedFrame();
4612 if (!frame)
4613 return;
4615 string16 text;
4616 size_t offset;
4617 ui::Range range;
4618 if (pepper_helper_->IsPluginFocused()) {
4619 pepper_helper_->GetSurroundingText(&text, &range);
4620 offset = 0; // Pepper API does not support offset reporting.
4621 // TODO(kinaba): cut as needed.
4622 } else {
4623 size_t location, length;
4624 if (!webview()->caretOrSelectionRange(&location, &length))
4625 return;
4627 range = ui::Range(location, location + length);
4629 if (webview()->textInputType() != WebKit::WebTextInputTypeNone) {
4630 // If current focused element is editable, we will send 100 more chars
4631 // before and after selection. It is for input method surrounding text
4632 // feature.
4633 if (location > kExtraCharsBeforeAndAfterSelection)
4634 offset = location - kExtraCharsBeforeAndAfterSelection;
4635 else
4636 offset = 0;
4637 length = location + length - offset + kExtraCharsBeforeAndAfterSelection;
4638 WebRange webrange = WebRange::fromDocumentRange(frame, offset, length);
4639 if (!webrange.isNull())
4640 text = WebRange::fromDocumentRange(frame, offset, length).toPlainText();
4641 } else {
4642 offset = location;
4643 text = frame->selectionAsText();
4644 // http://crbug.com/101435
4645 // In some case, frame->selectionAsText() returned text's length is not
4646 // equal to the length returned from webview()->caretOrSelectionRange().
4647 // So we have to set the range according to text.length().
4648 range.set_end(range.start() + text.length());
4652 // Sometimes we get repeated didChangeSelection calls from webkit when
4653 // the selection hasn't actually changed. We don't want to report these
4654 // because it will cause us to continually claim the X clipboard.
4655 if (selection_text_offset_ != offset ||
4656 selection_range_ != range ||
4657 selection_text_ != text) {
4658 selection_text_ = text;
4659 selection_text_offset_ = offset;
4660 selection_range_ = range;
4661 Send(new ViewHostMsg_SelectionChanged(routing_id_, text, offset, range));
4665 GURL RenderViewImpl::GetAlternateErrorPageURL(const GURL& failed_url,
4666 ErrorPageType error_type) {
4667 if (failed_url.SchemeIsSecure()) {
4668 // If the URL that failed was secure, then the embedding web page was not
4669 // expecting a network attacker to be able to manipulate its contents. As
4670 // we fetch alternate error pages over HTTP, we would be allowing a network
4671 // attacker to manipulate the contents of the response if we tried to use
4672 // the link doctor here.
4673 return GURL();
4676 // Grab the base URL from the browser process.
4677 if (!alternate_error_page_url_.is_valid())
4678 return GURL();
4680 // Strip query params from the failed URL.
4681 GURL::Replacements remove_params;
4682 remove_params.ClearUsername();
4683 remove_params.ClearPassword();
4684 remove_params.ClearQuery();
4685 remove_params.ClearRef();
4686 const GURL url_to_send = failed_url.ReplaceComponents(remove_params);
4687 std::string spec_to_send = url_to_send.spec();
4688 // Notify link doctor of the url truncation by sending of "?" at the end.
4689 if (failed_url.has_query())
4690 spec_to_send.append("?");
4692 // Construct the query params to send to link doctor.
4693 std::string params(alternate_error_page_url_.query());
4694 params.append("&url=");
4695 params.append(net::EscapeQueryParamValue(spec_to_send, true));
4696 params.append("&sourceid=chrome");
4697 params.append("&error=");
4698 switch (error_type) {
4699 case DNS_ERROR:
4700 params.append("dnserror");
4701 break;
4703 case HTTP_404:
4704 params.append("http404");
4705 break;
4707 case CONNECTION_ERROR:
4708 params.append("connectionfailure");
4709 break;
4711 default:
4712 NOTREACHED() << "unknown ErrorPageType";
4715 // OK, build the final url to return.
4716 GURL::Replacements link_doctor_params;
4717 link_doctor_params.SetQueryStr(params);
4718 GURL url = alternate_error_page_url_.ReplaceComponents(link_doctor_params);
4719 return url;
4722 GURL RenderViewImpl::GetLoadingUrl(WebKit::WebFrame* frame) const {
4723 WebDataSource* ds = frame->dataSource();
4724 if (ds->hasUnreachableURL())
4725 return ds->unreachableURL();
4727 const WebURLRequest& request = ds->request();
4728 return request.url();
4731 WebKit::WebPlugin* RenderViewImpl::GetWebPluginFromPluginDocument() {
4732 return webview()->mainFrame()->document().to<WebPluginDocument>().plugin();
4735 void RenderViewImpl::OnFind(int request_id,
4736 const string16& search_text,
4737 const WebFindOptions& options) {
4738 #if defined(OS_ANDROID)
4739 // Make sure any asynchronous messages do not disrupt an ongoing synchronous
4740 // find request as it might lead to deadlocks. Also, these should be safe to
4741 // ignore since they would belong to a previous find request.
4742 if (synchronous_find_reply_message_.get())
4743 return;
4744 #endif
4745 Find(request_id, search_text, options);
4748 void RenderViewImpl::Find(int request_id,
4749 const string16& search_text,
4750 const WebFindOptions& options) {
4751 WebFrame* main_frame = webview()->mainFrame();
4753 // Check if the plugin still exists in the document.
4754 if (main_frame->document().isPluginDocument() &&
4755 GetWebPluginFromPluginDocument()) {
4756 if (options.findNext) {
4757 // Just navigate back/forward.
4758 GetWebPluginFromPluginDocument()->selectFindResult(options.forward);
4759 } else {
4760 if (!GetWebPluginFromPluginDocument()->startFind(
4761 search_text, options.matchCase, request_id)) {
4762 // Send "no results".
4763 SendFindReply(request_id, 0, 0, gfx::Rect(), true);
4766 return;
4769 WebFrame* frame_after_main = main_frame->traverseNext(true);
4770 WebFrame* focused_frame = webview()->focusedFrame();
4771 WebFrame* search_frame = focused_frame; // start searching focused frame.
4773 bool multi_frame = (frame_after_main != main_frame);
4775 // If we have multiple frames, we don't want to wrap the search within the
4776 // frame, so we check here if we only have main_frame in the chain.
4777 bool wrap_within_frame = !multi_frame;
4779 WebRect selection_rect;
4780 bool result = false;
4782 // If something is selected when we start searching it means we cannot just
4783 // increment the current match ordinal; we need to re-generate it.
4784 WebRange current_selection = focused_frame->selectionRange();
4786 do {
4787 result = search_frame->find(
4788 request_id, search_text, options, wrap_within_frame, &selection_rect);
4790 if (!result) {
4791 // don't leave text selected as you move to the next frame.
4792 search_frame->executeCommand(WebString::fromUTF8("Unselect"));
4794 // Find the next frame, but skip the invisible ones.
4795 do {
4796 // What is the next frame to search? (we might be going backwards). Note
4797 // that we specify wrap=true so that search_frame never becomes NULL.
4798 search_frame = options.forward ?
4799 search_frame->traverseNext(true) :
4800 search_frame->traversePrevious(true);
4801 } while (!search_frame->hasVisibleContent() &&
4802 search_frame != focused_frame);
4804 // Make sure selection doesn't affect the search operation in new frame.
4805 search_frame->executeCommand(WebString::fromUTF8("Unselect"));
4807 // If we have multiple frames and we have wrapped back around to the
4808 // focused frame, we need to search it once more allowing wrap within
4809 // the frame, otherwise it will report 'no match' if the focused frame has
4810 // reported matches, but no frames after the focused_frame contain a
4811 // match for the search word(s).
4812 if (multi_frame && search_frame == focused_frame) {
4813 result = search_frame->find(
4814 request_id, search_text, options, true, // Force wrapping.
4815 &selection_rect);
4819 webview()->setFocusedFrame(search_frame);
4820 } while (!result && search_frame != focused_frame);
4822 if (options.findNext && current_selection.isNull()) {
4823 // Force the main_frame to report the actual count.
4824 main_frame->increaseMatchCount(0, request_id);
4825 } else {
4826 // If nothing is found, set result to "0 of 0", otherwise, set it to
4827 // "-1 of 1" to indicate that we found at least one item, but we don't know
4828 // yet what is active.
4829 int ordinal = result ? -1 : 0; // -1 here means, we might know more later.
4830 int match_count = result ? 1 : 0; // 1 here means possibly more coming.
4832 // If we find no matches then this will be our last status update.
4833 // Otherwise the scoping effort will send more results.
4834 bool final_status_update = !result;
4836 SendFindReply(request_id, match_count, ordinal, selection_rect,
4837 final_status_update);
4839 // Scoping effort begins, starting with the mainframe.
4840 search_frame = main_frame;
4842 main_frame->resetMatchCount();
4844 do {
4845 // Cancel all old scoping requests before starting a new one.
4846 search_frame->cancelPendingScopingEffort();
4848 // We don't start another scoping effort unless at least one match has
4849 // been found.
4850 if (result) {
4851 // Start new scoping request. If the scoping function determines that it
4852 // needs to scope, it will defer until later.
4853 search_frame->scopeStringMatches(request_id,
4854 search_text,
4855 options,
4856 true); // reset the tickmarks
4859 // Iterate to the next frame. The frame will not necessarily scope, for
4860 // example if it is not visible.
4861 search_frame = search_frame->traverseNext(true);
4862 } while (search_frame != main_frame);
4866 void RenderViewImpl::OnStopFinding(StopFindAction action) {
4867 #if defined(OS_ANDROID)
4868 // Make sure any asynchronous messages do not disrupt an ongoing synchronous
4869 // find request as it might lead to deadlocks. Also, these should be safe to
4870 // ignore since they would belong to a previous find request.
4871 if (synchronous_find_reply_message_.get())
4872 return;
4873 #endif
4875 StopFinding(action);
4878 void RenderViewImpl::StopFinding(StopFindAction action) {
4879 WebView* view = webview();
4880 if (!view)
4881 return;
4883 WebDocument doc = view->mainFrame()->document();
4884 if (doc.isPluginDocument() && GetWebPluginFromPluginDocument()) {
4885 GetWebPluginFromPluginDocument()->stopFind();
4886 return;
4889 bool clear_selection = action == STOP_FIND_ACTION_CLEAR_SELECTION;
4890 if (clear_selection)
4891 view->focusedFrame()->executeCommand(WebString::fromUTF8("Unselect"));
4893 WebFrame* frame = view->mainFrame();
4894 while (frame) {
4895 frame->stopFinding(clear_selection);
4896 frame = frame->traverseNext(false);
4899 if (action == STOP_FIND_ACTION_ACTIVATE_SELECTION) {
4900 WebFrame* focused_frame = view->focusedFrame();
4901 if (focused_frame) {
4902 WebDocument doc = focused_frame->document();
4903 if (!doc.isNull()) {
4904 WebNode node = doc.focusedNode();
4905 if (!node.isNull())
4906 node.simulateClick();
4912 #if defined(OS_ANDROID)
4913 void RenderViewImpl::OnSynchronousFind(int request_id,
4914 const string16& search_string,
4915 const WebFindOptions& options,
4916 IPC::Message* reply_msg) {
4917 // It is impossible for simultaneous blocking finds to occur.
4918 CHECK(!synchronous_find_reply_message_.get());
4919 synchronous_find_reply_message_.reset(reply_msg);
4921 // Find next should be asynchronous in order to minimize blocking
4922 // the UI thread as much as possible.
4923 DCHECK(!options.findNext);
4924 StopFinding(STOP_FIND_ACTION_KEEP_SELECTION);
4925 synchronous_find_active_match_ordinal_ = -1;
4927 Find(request_id, search_string, options);
4930 void RenderViewImpl::OnActivateNearestFindResult(int request_id,
4931 float x, float y) {
4932 if (!webview())
4933 return;
4935 WebFrame* main_frame = webview()->mainFrame();
4936 WebRect selection_rect;
4937 int ordinal = main_frame->selectNearestFindMatch(WebFloatPoint(x, y),
4938 &selection_rect);
4939 if (ordinal == -1) {
4940 // Something went wrong, so send a no-op reply (force the main_frame to
4941 // report the current match count) in case the host is waiting for a
4942 // response due to rate-limiting).
4943 main_frame->increaseMatchCount(0, request_id);
4944 return;
4947 SendFindReply(request_id,
4948 -1 /* number_of_matches */,
4949 ordinal,
4950 selection_rect,
4951 true /* final_update */);
4954 void RenderViewImpl::OnFindMatchRects(int current_version) {
4955 if (!webview())
4956 return;
4958 WebFrame* main_frame = webview()->mainFrame();
4959 std::vector<gfx::RectF> match_rects;
4961 int rects_version = main_frame->findMatchMarkersVersion();
4962 if (current_version != rects_version) {
4963 WebVector<WebFloatRect> web_match_rects;
4964 main_frame->findMatchRects(web_match_rects);
4965 match_rects.reserve(web_match_rects.size());
4966 for (size_t i = 0; i < web_match_rects.size(); ++i)
4967 match_rects.push_back(gfx::RectF(web_match_rects[i]));
4970 gfx::RectF active_rect = main_frame->activeFindMatchRect();
4971 Send(new ViewHostMsg_FindMatchRects_Reply(routing_id_,
4972 rects_version,
4973 match_rects,
4974 active_rect));
4976 #endif
4978 void RenderViewImpl::OnZoom(PageZoom zoom) {
4979 if (!webview()) // Not sure if this can happen, but no harm in being safe.
4980 return;
4982 webview()->hidePopups();
4984 double old_zoom_level = webview()->zoomLevel();
4985 double zoom_level;
4986 if (zoom == PAGE_ZOOM_RESET) {
4987 zoom_level = 0;
4988 } else if (static_cast<int>(old_zoom_level) == old_zoom_level) {
4989 // Previous zoom level is a whole number, so just increment/decrement.
4990 zoom_level = old_zoom_level + zoom;
4991 } else {
4992 // Either the user hit the zoom factor limit and thus the zoom level is now
4993 // not a whole number, or a plugin changed it to a custom value. We want
4994 // to go to the next whole number so that the user can always get back to
4995 // 100% with the keyboard/menu.
4996 if ((old_zoom_level > 1 && zoom > 0) ||
4997 (old_zoom_level < 1 && zoom < 0)) {
4998 zoom_level = static_cast<int>(old_zoom_level + zoom);
4999 } else {
5000 // We're going towards 100%, so first go to the next whole number.
5001 zoom_level = static_cast<int>(old_zoom_level);
5004 webview()->setZoomLevel(false, zoom_level);
5005 zoomLevelChanged();
5008 void RenderViewImpl::OnZoomFactor(PageZoom zoom, int zoom_center_x,
5009 int zoom_center_y) {
5010 ZoomFactorHelper(zoom, zoom_center_x, zoom_center_y,
5011 kScalingIncrementForGesture);
5014 void RenderViewImpl::ZoomFactorHelper(PageZoom zoom,
5015 int zoom_center_x,
5016 int zoom_center_y,
5017 float scaling_increment) {
5018 if (!webview()) // Not sure if this can happen, but no harm in being safe.
5019 return;
5021 double old_page_scale_factor = webview()->pageScaleFactor();
5022 double page_scale_factor;
5023 if (zoom == PAGE_ZOOM_RESET) {
5024 page_scale_factor = 1.0;
5025 } else {
5026 page_scale_factor = old_page_scale_factor +
5027 (zoom > 0 ? scaling_increment : -scaling_increment);
5029 if (page_scale_factor > 0) {
5030 webview()->setPageScaleFactor(page_scale_factor,
5031 WebPoint(zoom_center_x, zoom_center_y));
5035 void RenderViewImpl::OnSetZoomLevel(double zoom_level) {
5036 webview()->hidePopups();
5037 webview()->setZoomLevel(false, zoom_level);
5038 zoomLevelChanged();
5041 void RenderViewImpl::OnSetZoomLevelForLoadingURL(const GURL& url,
5042 double zoom_level) {
5043 host_zoom_levels_[url] = zoom_level;
5046 void RenderViewImpl::OnSetPageEncoding(const std::string& encoding_name) {
5047 webview()->setPageEncoding(WebString::fromUTF8(encoding_name));
5050 void RenderViewImpl::OnResetPageEncodingToDefault() {
5051 WebString no_encoding;
5052 webview()->setPageEncoding(no_encoding);
5055 WebFrame* RenderViewImpl::GetChildFrame(const string16& xpath) const {
5056 if (xpath.empty())
5057 return webview()->mainFrame();
5059 // xpath string can represent a frame deep down the tree (across multiple
5060 // frame DOMs).
5061 // Example, /html/body/table/tbody/tr/td/iframe\n/frameset/frame[0]
5062 // should break into 2 xpaths
5063 // /html/body/table/tbody/tr/td/iframe & /frameset/frame[0]
5064 std::vector<string16> xpaths;
5065 base::SplitString(xpath, '\n', &xpaths);
5067 WebFrame* frame = webview()->mainFrame();
5068 for (std::vector<string16>::const_iterator i = xpaths.begin();
5069 frame && i != xpaths.end(); ++i) {
5070 frame = frame->findChildByExpression(*i);
5073 return frame;
5076 void RenderViewImpl::OnScriptEvalRequest(const string16& frame_xpath,
5077 const string16& jscript,
5078 int id,
5079 bool notify_result) {
5080 TRACE_EVENT_INSTANT0("test_tracing", "OnScriptEvalRequest");
5081 EvaluateScript(frame_xpath, jscript, id, notify_result);
5084 void RenderViewImpl::OnPostMessageEvent(
5085 const ViewMsg_PostMessage_Params& params) {
5086 // Find the target frame of this message. The source tags the message with
5087 // |target_frame_id|, so use it to locate the frame.
5088 // TODO(nasko): Lookup based on the frame id, once http://crbug.com/153701
5089 // is fixed and we can rely on having frame tree updates again.
5090 WebFrame* frame = webview()->mainFrame();
5092 // Find the source frame if it exists.
5093 WebFrame* source_frame = NULL;
5094 if (params.source_routing_id != MSG_ROUTING_NONE) {
5095 RenderViewImpl* source_view = FromRoutingID(params.source_routing_id);
5096 // TODO(nasko): Lookup based on the frame id, once http://crbug.com/153701
5097 // is fixed and we can rely on having frame tree updates again.
5098 if (source_view)
5099 source_frame = source_view->webview()->mainFrame();
5102 // Create an event with the message. The final parameter to initMessageEvent
5103 // is the last event ID, which is not used with postMessage.
5104 WebDOMEvent event = frame->document().createEvent("MessageEvent");
5105 WebDOMMessageEvent msg_event = event.to<WebDOMMessageEvent>();
5106 msg_event.initMessageEvent("message",
5107 // |canBubble| and |cancellable| are always false
5108 false, false,
5109 WebSerializedScriptValue::fromString(params.data),
5110 params.source_origin, source_frame, "");
5112 // We must pass in the target_origin to do the security check on this side,
5113 // since it may have changed since the original postMessage call was made.
5114 WebSecurityOrigin target_origin;
5115 if (!params.target_origin.empty()) {
5116 target_origin =
5117 WebSecurityOrigin::createFromString(WebString(params.target_origin));
5119 frame->dispatchMessageEventWithOriginCheck(target_origin, msg_event);
5122 void RenderViewImpl::OnCSSInsertRequest(const string16& frame_xpath,
5123 const std::string& css) {
5124 WebFrame* frame = GetChildFrame(frame_xpath);
5125 if (!frame)
5126 return;
5128 frame->document().insertUserStyleSheet(
5129 WebString::fromUTF8(css),
5130 WebDocument::UserStyleAuthorLevel);
5133 void RenderViewImpl::OnAllowBindings(int enabled_bindings_flags) {
5134 if ((enabled_bindings_flags & BINDINGS_POLICY_WEB_UI) &&
5135 !(enabled_bindings_ & BINDINGS_POLICY_WEB_UI)) {
5136 RenderThread::Get()->RegisterExtension(content::WebUIExtension::Get());
5137 new WebUIExtensionData(this);
5140 enabled_bindings_ |= enabled_bindings_flags;
5142 // Keep track of the total bindings accumulated in this process.
5143 RenderProcess::current()->AddBindings(enabled_bindings_flags);
5146 void RenderViewImpl::OnDragTargetDragEnter(const WebDropData& drop_data,
5147 const gfx::Point& client_point,
5148 const gfx::Point& screen_point,
5149 WebDragOperationsMask ops,
5150 int key_modifiers) {
5151 WebDragOperation operation = webview()->dragTargetDragEnter(
5152 drop_data.ToDragData(),
5153 client_point,
5154 screen_point,
5155 ops,
5156 key_modifiers);
5158 Send(new DragHostMsg_UpdateDragCursor(routing_id_, operation));
5161 void RenderViewImpl::OnDragTargetDragOver(const gfx::Point& client_point,
5162 const gfx::Point& screen_point,
5163 WebDragOperationsMask ops,
5164 int key_modifiers) {
5165 WebDragOperation operation = webview()->dragTargetDragOver(
5166 client_point,
5167 screen_point,
5168 ops,
5169 key_modifiers);
5171 Send(new DragHostMsg_UpdateDragCursor(routing_id_, operation));
5174 void RenderViewImpl::OnDragTargetDragLeave() {
5175 webview()->dragTargetDragLeave();
5178 void RenderViewImpl::OnDragTargetDrop(const gfx::Point& client_point,
5179 const gfx::Point& screen_point,
5180 int key_modifiers) {
5181 webview()->dragTargetDrop(client_point, screen_point, key_modifiers);
5183 Send(new DragHostMsg_TargetDrop_ACK(routing_id_));
5186 void RenderViewImpl::OnDragSourceEndedOrMoved(const gfx::Point& client_point,
5187 const gfx::Point& screen_point,
5188 bool ended,
5189 WebDragOperation op) {
5190 if (ended) {
5191 webview()->dragSourceEndedAt(client_point, screen_point, op);
5192 } else {
5193 webview()->dragSourceMovedTo(client_point, screen_point, op);
5197 void RenderViewImpl::OnDragSourceSystemDragEnded() {
5198 webview()->dragSourceSystemDragEnded();
5201 void RenderViewImpl::OnUpdateWebPreferences(const WebPreferences& prefs) {
5202 webkit_preferences_ = prefs;
5203 webkit_preferences_.Apply(webview());
5206 void RenderViewImpl::OnUpdateTimezone() {
5207 if (webview())
5208 NotifyTimezoneChange(webview()->mainFrame());
5211 void RenderViewImpl::OnSetAltErrorPageURL(const GURL& url) {
5212 alternate_error_page_url_ = url;
5215 void RenderViewImpl::OnCustomContextMenuAction(
5216 const CustomContextMenuContext& custom_context,
5217 unsigned action) {
5218 if (custom_context.request_id) {
5219 // External context menu request, look in our map.
5220 ContextMenuClient* client =
5221 pending_context_menus_.Lookup(custom_context.request_id);
5222 if (client)
5223 client->OnMenuAction(custom_context.request_id, action);
5224 } else {
5225 // Internal request, forward to WebKit.
5226 webview()->performCustomContextMenuAction(action);
5230 void RenderViewImpl::OnEnumerateDirectoryResponse(
5231 int id,
5232 const std::vector<FilePath>& paths) {
5233 if (!enumeration_completions_[id])
5234 return;
5236 WebVector<WebString> ws_file_names(paths.size());
5237 for (size_t i = 0; i < paths.size(); ++i)
5238 ws_file_names[i] = webkit_base::FilePathToWebString(paths[i]);
5240 enumeration_completions_[id]->didChooseFile(ws_file_names);
5241 enumeration_completions_.erase(id);
5244 void RenderViewImpl::OnFileChooserResponse(
5245 const std::vector<ui::SelectedFileInfo>& files) {
5246 // This could happen if we navigated to a different page before the user
5247 // closed the chooser.
5248 if (file_chooser_completions_.empty())
5249 return;
5251 // Convert Chrome's SelectedFileInfo list to WebKit's.
5252 WebVector<WebFileChooserCompletion::SelectedFileInfo> selected_files(
5253 files.size());
5254 for (size_t i = 0; i < files.size(); ++i) {
5255 WebFileChooserCompletion::SelectedFileInfo selected_file;
5256 selected_file.path = webkit_base::FilePathToWebString(files[i].local_path);
5257 selected_file.displayName = webkit_base::FilePathStringToWebString(
5258 files[i].display_name);
5259 selected_files[i] = selected_file;
5262 if (file_chooser_completions_.front()->completion)
5263 file_chooser_completions_.front()->completion->didChooseFile(
5264 selected_files);
5265 file_chooser_completions_.pop_front();
5267 // If there are more pending file chooser requests, schedule one now.
5268 if (!file_chooser_completions_.empty()) {
5269 Send(new ViewHostMsg_RunFileChooser(routing_id_,
5270 file_chooser_completions_.front()->params));
5274 void RenderViewImpl::OnEnableAutoResize(const gfx::Size& min_size,
5275 const gfx::Size& max_size) {
5276 DCHECK(disable_scrollbars_size_limit_.IsEmpty());
5277 if (!webview())
5278 return;
5279 webview()->enableAutoResizeMode(min_size, max_size);
5282 void RenderViewImpl::OnDisableAutoResize(const gfx::Size& new_size) {
5283 DCHECK(disable_scrollbars_size_limit_.IsEmpty());
5284 if (!webview())
5285 return;
5286 webview()->disableAutoResizeMode();
5288 Resize(new_size, resizer_rect_, is_fullscreen_, NO_RESIZE_ACK);
5291 void RenderViewImpl::OnEnablePreferredSizeChangedMode() {
5292 if (send_preferred_size_changes_)
5293 return;
5294 send_preferred_size_changes_ = true;
5296 // Start off with an initial preferred size notification (in case
5297 // |didUpdateLayout| was already called).
5298 didUpdateLayout();
5301 void RenderViewImpl::OnDisableScrollbarsForSmallWindows(
5302 const gfx::Size& disable_scrollbar_size_limit) {
5303 disable_scrollbars_size_limit_ = disable_scrollbar_size_limit;
5306 void RenderViewImpl::OnSetRendererPrefs(
5307 const RendererPreferences& renderer_prefs) {
5308 double old_zoom_level = renderer_preferences_.default_zoom_level;
5309 renderer_preferences_ = renderer_prefs;
5310 UpdateFontRenderingFromRendererPrefs();
5311 #if defined(TOOLKIT_GTK)
5312 WebColorName name = WebKit::WebColorWebkitFocusRingColor;
5313 WebKit::setNamedColors(&name, &renderer_prefs.focus_ring_color, 1);
5314 WebKit::setCaretBlinkInterval(renderer_prefs.caret_blink_interval);
5315 ui::NativeTheme::instance()->SetScrollbarColors(
5316 renderer_prefs.thumb_inactive_color,
5317 renderer_prefs.thumb_active_color,
5318 renderer_prefs.track_color);
5319 #endif
5321 #if defined(USE_DEFAULT_RENDER_THEME) || defined(TOOLKIT_GTK)
5322 if (webview()) {
5323 #if defined(TOOLKIT_GTK)
5324 webview()->setScrollbarColors(
5325 renderer_prefs.thumb_inactive_color,
5326 renderer_prefs.thumb_active_color,
5327 renderer_prefs.track_color);
5328 #endif
5329 webview()->setSelectionColors(
5330 renderer_prefs.active_selection_bg_color,
5331 renderer_prefs.active_selection_fg_color,
5332 renderer_prefs.inactive_selection_bg_color,
5333 renderer_prefs.inactive_selection_fg_color);
5334 webview()->themeChanged();
5336 #endif
5338 // If the zoom level for this page matches the old zoom default, and this
5339 // is not a plugin, update the zoom level to match the new default.
5340 if (webview() && !webview()->mainFrame()->document().isPluginDocument() &&
5341 ZoomValuesEqual(webview()->zoomLevel(), old_zoom_level)) {
5342 webview()->setZoomLevel(false, renderer_preferences_.default_zoom_level);
5343 zoomLevelChanged();
5347 void RenderViewImpl::OnMediaPlayerActionAt(const gfx::Point& location,
5348 const WebMediaPlayerAction& action) {
5349 if (webview())
5350 webview()->performMediaPlayerAction(action, location);
5353 void RenderViewImpl::OnOrientationChangeEvent(int orientation) {
5354 webview()->mainFrame()->sendOrientationChangeEvent(orientation);
5357 void RenderViewImpl::OnPluginActionAt(const gfx::Point& location,
5358 const WebPluginAction& action) {
5359 if (webview())
5360 webview()->performPluginAction(action, location);
5363 void RenderViewImpl::OnGetAllSavableResourceLinksForCurrentPage(
5364 const GURL& page_url) {
5365 // Prepare list to storage all savable resource links.
5366 std::vector<GURL> resources_list;
5367 std::vector<GURL> referrer_urls_list;
5368 std::vector<WebKit::WebReferrerPolicy> referrer_policies_list;
5369 std::vector<GURL> frames_list;
5370 webkit_glue::SavableResourcesResult result(&resources_list,
5371 &referrer_urls_list,
5372 &referrer_policies_list,
5373 &frames_list);
5375 // webkit/ doesn't know about Referrer.
5376 if (!webkit_glue::GetAllSavableResourceLinksForCurrentPage(
5377 webview(),
5378 page_url,
5379 &result,
5380 const_cast<const char**>(GetSavableSchemes()))) {
5381 // If something is wrong when collecting all savable resource links,
5382 // send empty list to embedder(browser) to tell it failed.
5383 referrer_urls_list.clear();
5384 referrer_policies_list.clear();
5385 resources_list.clear();
5386 frames_list.clear();
5389 std::vector<Referrer> referrers_list;
5390 CHECK_EQ(referrer_urls_list.size(), referrer_policies_list.size());
5391 for (unsigned i = 0; i < referrer_urls_list.size(); ++i) {
5392 referrers_list.push_back(
5393 Referrer(referrer_urls_list[i], referrer_policies_list[i]));
5396 // Send result of all savable resource links to embedder.
5397 Send(new ViewHostMsg_SendCurrentPageAllSavableResourceLinks(routing_id(),
5398 resources_list,
5399 referrers_list,
5400 frames_list));
5403 void RenderViewImpl::OnGetSerializedHtmlDataForCurrentPageWithLocalLinks(
5404 const std::vector<GURL>& links,
5405 const std::vector<FilePath>& local_paths,
5406 const FilePath& local_directory_name) {
5408 // Convert std::vector of GURLs to WebVector<WebURL>
5409 WebVector<WebURL> weburl_links(links);
5411 // Convert std::vector of std::strings to WebVector<WebString>
5412 WebVector<WebString> webstring_paths(local_paths.size());
5413 for (size_t i = 0; i < local_paths.size(); i++)
5414 webstring_paths[i] = webkit_base::FilePathToWebString(local_paths[i]);
5416 WebPageSerializer::serialize(webview()->mainFrame(), true, this, weburl_links,
5417 webstring_paths,
5418 webkit_base::FilePathToWebString(
5419 local_directory_name));
5422 void RenderViewImpl::OnShouldClose() {
5423 base::TimeTicks before_unload_start_time = base::TimeTicks::Now();
5424 bool should_close = webview()->dispatchBeforeUnloadEvent();
5425 base::TimeTicks before_unload_end_time = base::TimeTicks::Now();
5426 Send(new ViewHostMsg_ShouldClose_ACK(routing_id_, should_close,
5427 before_unload_start_time,
5428 before_unload_end_time));
5431 void RenderViewImpl::OnSwapOut(const ViewMsg_SwapOut_Params& params) {
5432 // Ensure that no other in-progress navigation continues.
5433 OnStop();
5435 // Only run unload if we're not swapped out yet, but send the ack either way.
5436 if (!is_swapped_out_) {
5437 // Swap this RenderView out so the tab can navigate to a page rendered by a
5438 // different process. This involves running the unload handler and clearing
5439 // the page. Once WasSwappedOut is called, we also allow this process to
5440 // exit if there are no other active RenderViews in it.
5442 // Send an UpdateState message before we get swapped out.
5443 SyncNavigationState();
5445 // Synchronously run the unload handler before sending the ACK.
5446 webview()->dispatchUnloadEvent();
5448 // Swap out and stop sending any IPC messages that are not ACKs.
5449 SetSwappedOut(true);
5451 // Replace the page with a blank dummy URL. The unload handler will not be
5452 // run a second time, thanks to a check in FrameLoader::stopLoading.
5453 // TODO(creis): Need to add a better way to do this that avoids running the
5454 // beforeunload handler. For now, we just run it a second time silently.
5455 NavigateToSwappedOutURL(webview()->mainFrame());
5457 // Let WebKit know that this view is hidden so it can drop resources and
5458 // stop compositing.
5459 webview()->setVisibilityState(WebKit::WebPageVisibilityStateHidden, false);
5462 // Just echo back the params in the ACK.
5463 Send(new ViewHostMsg_SwapOut_ACK(routing_id_, params));
5466 void RenderViewImpl::NavigateToSwappedOutURL(WebKit::WebFrame* frame) {
5467 // We use loadRequest instead of loadHTMLString because the former commits
5468 // synchronously. Otherwise a new navigation can interrupt the navigation
5469 // to kSwappedOutURL. If that happens to be to the page we had been
5470 // showing, then WebKit will never send a commit and we'll be left spinning.
5471 CHECK(is_swapped_out_);
5472 GURL swappedOutURL(kSwappedOutURL);
5473 WebURLRequest request(swappedOutURL);
5474 frame->loadRequest(request);
5477 void RenderViewImpl::OnClosePage() {
5478 FOR_EACH_OBSERVER(RenderViewObserver, observers_, ClosePage());
5479 // TODO(creis): We'd rather use webview()->Close() here, but that currently
5480 // sets the WebView's delegate_ to NULL, preventing any JavaScript dialogs
5481 // in the onunload handler from appearing. For now, we're bypassing that and
5482 // calling the FrameLoader's CloseURL method directly. This should be
5483 // revisited to avoid having two ways to close a page. Having a single way
5484 // to close that can run onunload is also useful for fixing
5485 // http://b/issue?id=753080.
5486 webview()->dispatchUnloadEvent();
5488 Send(new ViewHostMsg_ClosePage_ACK(routing_id_));
5491 void RenderViewImpl::OnThemeChanged() {
5492 #if defined(USE_AURA)
5493 // Aura doesn't care if we switch themes.
5494 #elif defined(OS_WIN)
5495 ui::NativeThemeWin::instance()->CloseHandles();
5496 if (webview())
5497 webview()->themeChanged();
5498 #else // defined(OS_WIN)
5499 // TODO(port): we don't support theming on non-Windows platforms yet
5500 NOTIMPLEMENTED();
5501 #endif
5504 void RenderViewImpl::OnDisassociateFromPopupCount() {
5505 if (decrement_shared_popup_at_destruction_)
5506 shared_popup_counter_->data--;
5507 shared_popup_counter_ = new SharedRenderViewCounter(0);
5508 decrement_shared_popup_at_destruction_ = false;
5511 bool RenderViewImpl::MaybeLoadAlternateErrorPage(WebFrame* frame,
5512 const WebURLError& error,
5513 bool replace) {
5514 // We only show alternate error pages in the main frame. They are
5515 // intended to assist the user when navigating, so there is not much
5516 // value in showing them for failed subframes. Ideally, we would be
5517 // able to use the TYPED transition type for this, but that flag is
5518 // not preserved across page reloads.
5519 if (frame->parent())
5520 return false;
5522 // Use the alternate error page service if this is a DNS failure or
5523 // connection failure.
5524 int ec = error.reason;
5525 if (ec != net::ERR_NAME_NOT_RESOLVED &&
5526 ec != net::ERR_CONNECTION_FAILED &&
5527 ec != net::ERR_CONNECTION_REFUSED &&
5528 ec != net::ERR_ADDRESS_UNREACHABLE &&
5529 ec != net::ERR_CONNECTION_TIMED_OUT) {
5530 return false;
5533 const GURL& error_page_url = GetAlternateErrorPageURL(error.unreachableURL,
5534 ec == net::ERR_NAME_NOT_RESOLVED ? DNS_ERROR : CONNECTION_ERROR);
5535 if (!error_page_url.is_valid())
5536 return false;
5538 // Load an empty page first so there is an immediate response to the error,
5539 // and then kick off a request for the alternate error page.
5540 frame->loadHTMLString(std::string(),
5541 GURL(kUnreachableWebDataURL),
5542 error.unreachableURL,
5543 replace);
5545 // Now, create a fetcher for the error page and associate it with the data
5546 // source we just created via the LoadHTMLString call. That way if another
5547 // navigation occurs, the fetcher will get destroyed.
5548 DocumentState* document_state =
5549 DocumentState::FromDataSource(frame->provisionalDataSource());
5550 document_state->set_alt_error_page_fetcher(
5551 new AltErrorPageResourceFetcher(
5552 error_page_url, frame, error,
5553 base::Bind(&RenderViewImpl::AltErrorPageFinished,
5554 base::Unretained(this))));
5555 return true;
5558 void RenderViewImpl::AltErrorPageFinished(WebFrame* frame,
5559 const WebURLError& original_error,
5560 const std::string& html) {
5561 // Here, we replace the blank page we loaded previously.
5562 // If we failed to download the alternate error page, LoadNavigationErrorPage
5563 // will simply display a default error page.
5564 LoadNavigationErrorPage(frame, WebURLRequest(), original_error, html, true);
5567 void RenderViewImpl::OnMoveOrResizeStarted() {
5568 if (webview())
5569 webview()->hidePopups();
5572 void RenderViewImpl::OnResize(const gfx::Size& new_size,
5573 const gfx::Rect& resizer_rect,
5574 bool is_fullscreen) {
5575 if (webview()) {
5576 webview()->hidePopups();
5577 if (send_preferred_size_changes_) {
5578 webview()->mainFrame()->setCanHaveScrollbars(
5579 ShouldDisplayScrollbars(new_size.width(), new_size.height()));
5581 UpdateScrollState(webview()->mainFrame());
5584 RenderWidget::OnResize(new_size, resizer_rect, is_fullscreen);
5587 void RenderViewImpl::WillInitiatePaint() {
5588 // Notify the pepper plugins that we're about to paint.
5589 pepper_helper_->ViewWillInitiatePaint();
5592 void RenderViewImpl::DidInitiatePaint() {
5593 // Notify the pepper plugins that we've painted, and are waiting to flush.
5594 pepper_helper_->ViewInitiatedPaint();
5597 void RenderViewImpl::DidFlushPaint() {
5598 // Notify any pepper plugins that we painted. This will call into the plugin,
5599 // and we it may ask to close itself as a result. This will, in turn, modify
5600 // our set, possibly invalidating the iterator. So we iterate on a copy that
5601 // won't change out from under us.
5602 pepper_helper_->ViewFlushedPaint();
5604 // If the RenderWidget is closing down then early-exit, otherwise we'll crash.
5605 // See crbug.com/112921.
5606 if (!webview())
5607 return;
5609 WebFrame* main_frame = webview()->mainFrame();
5611 // If we have a provisional frame we are between the start and commit stages
5612 // of loading and we don't want to save stats.
5613 if (!main_frame->provisionalDataSource()) {
5614 WebDataSource* ds = main_frame->dataSource();
5615 DocumentState* document_state = DocumentState::FromDataSource(ds);
5617 // TODO(jar): The following code should all be inside a method, probably in
5618 // NavigatorState.
5619 Time now = Time::Now();
5620 if (document_state->first_paint_time().is_null()) {
5621 document_state->set_first_paint_time(now);
5623 if (document_state->first_paint_after_load_time().is_null() &&
5624 !document_state->finish_load_time().is_null()) {
5625 document_state->set_first_paint_after_load_time(now);
5630 void RenderViewImpl::OnViewContextSwapBuffersPosted() {
5631 RenderWidget::OnSwapBuffersPosted();
5634 void RenderViewImpl::OnViewContextSwapBuffersComplete() {
5635 RenderWidget::OnSwapBuffersComplete();
5638 void RenderViewImpl::OnViewContextSwapBuffersAborted() {
5639 RenderWidget::OnSwapBuffersAborted();
5642 webkit::ppapi::PluginInstance* RenderViewImpl::GetBitmapForOptimizedPluginPaint(
5643 const gfx::Rect& paint_bounds,
5644 TransportDIB** dib,
5645 gfx::Rect* location,
5646 gfx::Rect* clip,
5647 float* scale_factor) {
5648 return pepper_helper_->GetBitmapForOptimizedPluginPaint(
5649 paint_bounds, dib, location, clip, scale_factor);
5652 gfx::Vector2d RenderViewImpl::GetScrollOffset() {
5653 WebSize scroll_offset = webview()->mainFrame()->scrollOffset();
5654 return gfx::Vector2d(scroll_offset.width, scroll_offset.height);
5657 void RenderViewImpl::OnClearFocusedNode() {
5658 if (webview())
5659 webview()->clearFocusedNode();
5662 void RenderViewImpl::OnSetBackground(const SkBitmap& background) {
5663 if (webview())
5664 webview()->setIsTransparent(!background.empty());
5666 SetBackground(background);
5669 void RenderViewImpl::OnSetAccessibilityMode(AccessibilityMode new_mode) {
5670 if (accessibility_mode_ == new_mode)
5671 return;
5672 accessibility_mode_ = new_mode;
5673 if (renderer_accessibility_) {
5674 delete renderer_accessibility_;
5675 renderer_accessibility_ = NULL;
5677 if (accessibility_mode_ == AccessibilityModeComplete)
5678 renderer_accessibility_ = new RendererAccessibilityComplete(this);
5679 else if (accessibility_mode_ == AccessibilityModeEditableTextOnly)
5680 renderer_accessibility_ = new RendererAccessibilityFocusOnly(this);
5683 void RenderViewImpl::OnSetActive(bool active) {
5684 if (webview())
5685 webview()->setIsActive(active);
5687 #if defined(OS_MACOSX)
5688 std::set<WebPluginDelegateProxy*>::iterator plugin_it;
5689 for (plugin_it = plugin_delegates_.begin();
5690 plugin_it != plugin_delegates_.end(); ++plugin_it) {
5691 (*plugin_it)->SetWindowFocus(active);
5693 #endif
5696 void RenderViewImpl::OnSetNavigationStartTime(
5697 const base::TimeTicks& browser_navigation_start) {
5698 if (!webview())
5699 return;
5701 // Only the initial navigation can be a cross-renderer navigation. If we've
5702 // already navigated away from that page, we can ignore this message.
5703 if (page_id_ != -1)
5704 return;
5706 // browser_navigation_start is likely before this process existed, so we can't
5707 // use InterProcessTimeTicksConverter. Instead, the best we can do is just
5708 // ensure we don't report a bogus value in the future.
5709 base::TimeTicks navigation_start = std::min(base::TimeTicks::Now(),
5710 browser_navigation_start);
5711 webview()->mainFrame()->provisionalDataSource()->setNavigationStartTime(
5712 (navigation_start - base::TimeTicks()).InSecondsF());
5715 #if defined(OS_MACOSX)
5716 void RenderViewImpl::OnSetWindowVisibility(bool visible) {
5717 // Inform plugins that their container has changed visibility.
5718 std::set<WebPluginDelegateProxy*>::iterator plugin_it;
5719 for (plugin_it = plugin_delegates_.begin();
5720 plugin_it != plugin_delegates_.end(); ++plugin_it) {
5721 (*plugin_it)->SetContainerVisibility(visible);
5725 void RenderViewImpl::OnWindowFrameChanged(const gfx::Rect& window_frame,
5726 const gfx::Rect& view_frame) {
5727 // Inform plugins that their window's frame has changed.
5728 std::set<WebPluginDelegateProxy*>::iterator plugin_it;
5729 for (plugin_it = plugin_delegates_.begin();
5730 plugin_it != plugin_delegates_.end(); ++plugin_it) {
5731 (*plugin_it)->WindowFrameChanged(window_frame, view_frame);
5735 void RenderViewImpl::OnPluginImeCompositionCompleted(const string16& text,
5736 int plugin_id) {
5737 // WebPluginDelegateProxy is responsible for figuring out if this event
5738 // applies to it or not, so inform all the delegates.
5739 std::set<WebPluginDelegateProxy*>::iterator plugin_it;
5740 for (plugin_it = plugin_delegates_.begin();
5741 plugin_it != plugin_delegates_.end(); ++plugin_it) {
5742 (*plugin_it)->ImeCompositionCompleted(text, plugin_id);
5745 #endif // OS_MACOSX
5747 void RenderViewImpl::OnSetEditCommandsForNextKeyEvent(
5748 const EditCommands& edit_commands) {
5749 edit_commands_ = edit_commands;
5752 void RenderViewImpl::Close() {
5753 // We need to grab a pointer to the doomed WebView before we destroy it.
5754 WebView* doomed = webview();
5755 RenderWidget::Close();
5756 g_view_map.Get().erase(doomed);
5757 g_routing_id_view_map.Get().erase(routing_id_);
5760 void RenderViewImpl::DidHandleKeyEvent() {
5761 ClearEditCommands();
5764 bool RenderViewImpl::WillHandleMouseEvent(const WebKit::WebMouseEvent& event) {
5765 possible_drag_event_info_.event_source =
5766 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE;
5767 possible_drag_event_info_.event_location =
5768 gfx::Point(event.globalX, event.globalY);
5769 pepper_helper_->WillHandleMouseEvent();
5771 // If the mouse is locked, only the current owner of the mouse lock can
5772 // process mouse events.
5773 return mouse_lock_dispatcher_->WillHandleMouseEvent(event);
5776 bool RenderViewImpl::WillHandleGestureEvent(
5777 const WebKit::WebGestureEvent& event) {
5778 possible_drag_event_info_.event_source =
5779 ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH;
5780 possible_drag_event_info_.event_location =
5781 gfx::Point(event.globalX, event.globalY);
5782 return false;
5785 void RenderViewImpl::DidHandleMouseEvent(const WebMouseEvent& event) {
5786 FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidHandleMouseEvent(event));
5789 void RenderViewImpl::DidHandleTouchEvent(const WebTouchEvent& event) {
5790 FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidHandleTouchEvent(event));
5793 bool RenderViewImpl::HasTouchEventHandlersAt(const gfx::Point& point) const {
5794 if (!webview())
5795 return false;
5796 return webview()->hasTouchEventHandlersAt(point);
5799 void RenderViewImpl::OnWasHidden() {
5800 RenderWidget::OnWasHidden();
5802 #if defined(OS_ANDROID)
5803 // Inform WebMediaPlayerManagerAndroid to release all media player resources.
5804 // unless some audio is playing.
5805 // If something is in progress the resource will not be freed, it will
5806 // only be freed once the tab is destroyed or if the user navigates away
5807 // via WebMediaPlayerAndroid::Destroy
5808 media_player_manager_->ReleaseMediaResources();
5809 #endif
5811 if (webview()) {
5812 webview()->settings()->setMinimumTimerInterval(
5813 webkit_glue::kBackgroundTabTimerInterval);
5814 webview()->setVisibilityState(visibilityState(), false);
5817 // Inform PPAPI plugins that their page is no longer visible.
5818 pepper_helper_->PageVisibilityChanged(false);
5820 #if defined(OS_MACOSX)
5821 // Inform NPAPI plugins that their container is no longer visible.
5822 std::set<WebPluginDelegateProxy*>::iterator plugin_it;
5823 for (plugin_it = plugin_delegates_.begin();
5824 plugin_it != plugin_delegates_.end(); ++plugin_it) {
5825 (*plugin_it)->SetContainerVisibility(false);
5827 #endif // OS_MACOSX
5830 void RenderViewImpl::OnWasShown(bool needs_repainting) {
5831 RenderWidget::OnWasShown(needs_repainting);
5833 if (webview()) {
5834 webview()->settings()->setMinimumTimerInterval(
5835 webkit_glue::kForegroundTabTimerInterval);
5836 webview()->setVisibilityState(visibilityState(), false);
5839 // Inform PPAPI plugins that their page is visible.
5840 pepper_helper_->PageVisibilityChanged(true);
5842 #if defined(OS_MACOSX)
5843 // Inform NPAPI plugins that their container is now visible.
5844 std::set<WebPluginDelegateProxy*>::iterator plugin_it;
5845 for (plugin_it = plugin_delegates_.begin();
5846 plugin_it != plugin_delegates_.end(); ++plugin_it) {
5847 (*plugin_it)->SetContainerVisibility(true);
5849 #endif // OS_MACOSX
5852 bool RenderViewImpl::SupportsAsynchronousSwapBuffers() {
5853 // Contexts using the command buffer support asynchronous swapbuffers.
5854 // See RenderViewImpl::createOutputSurface().
5855 if (WebWidgetHandlesCompositorScheduling() ||
5856 CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessWebGL))
5857 return false;
5859 return true;
5862 bool RenderViewImpl::ForceCompositingModeEnabled() {
5863 return webkit_preferences_.force_compositing_mode;
5866 void RenderViewImpl::OnSetFocus(bool enable) {
5867 RenderWidget::OnSetFocus(enable);
5869 if (webview() && webview()->isActive()) {
5870 // Notify all NPAPI plugins.
5871 std::set<WebPluginDelegateProxy*>::iterator plugin_it;
5872 for (plugin_it = plugin_delegates_.begin();
5873 plugin_it != plugin_delegates_.end(); ++plugin_it) {
5874 #if defined(OS_MACOSX)
5875 // RenderWidget's call to setFocus can cause the underlying webview's
5876 // activation state to change just like a call to setIsActive.
5877 if (enable)
5878 (*plugin_it)->SetWindowFocus(true);
5879 #endif
5880 (*plugin_it)->SetContentAreaFocus(enable);
5883 // Notify all Pepper plugins.
5884 pepper_helper_->OnSetFocus(enable);
5885 // Notify all BrowserPlugins of the RenderView's focus state.
5886 if (browser_plugin_manager_)
5887 browser_plugin_manager()->SetEmbedderFocus(this, enable);
5890 void RenderViewImpl::PpapiPluginFocusChanged() {
5891 UpdateTextInputState(DO_NOT_SHOW_IME);
5892 UpdateSelectionBounds();
5895 void RenderViewImpl::PpapiPluginTextInputTypeChanged() {
5896 UpdateTextInputState(DO_NOT_SHOW_IME);
5897 if (renderer_accessibility_)
5898 renderer_accessibility_->FocusedNodeChanged(WebNode());
5901 void RenderViewImpl::PpapiPluginCaretPositionChanged() {
5902 UpdateSelectionBounds();
5905 bool RenderViewImpl::GetPpapiPluginCaretBounds(gfx::Rect* rect) {
5906 if (!pepper_helper_->IsPluginFocused())
5907 return false;
5908 *rect = pepper_helper_->GetCaretBounds();
5909 return true;
5912 void RenderViewImpl::SimulateImeSetComposition(
5913 const string16& text,
5914 const std::vector<WebKit::WebCompositionUnderline>& underlines,
5915 int selection_start,
5916 int selection_end) {
5917 OnImeSetComposition(text, underlines, selection_start, selection_end);
5920 void RenderViewImpl::SimulateImeConfirmComposition(
5921 const string16& text,
5922 const ui::Range& replacement_range) {
5923 OnImeConfirmComposition(text, replacement_range);
5926 void RenderViewImpl::PpapiPluginCancelComposition() {
5927 Send(new ViewHostMsg_ImeCancelComposition(routing_id()));
5928 const ui::Range range(ui::Range::InvalidRange());
5929 const std::vector<gfx::Rect> empty_bounds;
5930 UpdateCompositionInfo(range, empty_bounds);
5933 void RenderViewImpl::PpapiPluginSelectionChanged() {
5934 SyncSelectionIfRequired();
5937 void RenderViewImpl::PpapiPluginCreated(RendererPpapiHost* host) {
5938 FOR_EACH_OBSERVER(RenderViewObserver, observers_,
5939 DidCreatePepperPlugin(host));
5942 void RenderViewImpl::OnImeSetComposition(
5943 const string16& text,
5944 const std::vector<WebKit::WebCompositionUnderline>& underlines,
5945 int selection_start,
5946 int selection_end) {
5947 if (pepper_helper_->IsPluginFocused()) {
5948 // When a PPAPI plugin has focus, we bypass WebKit.
5949 pepper_helper_->OnImeSetComposition(text,
5950 underlines,
5951 selection_start,
5952 selection_end);
5953 } else {
5954 #if defined(OS_WIN)
5955 // When a plug-in has focus, we create platform-specific IME data used by
5956 // our IME emulator and send it directly to the focused plug-in, i.e. we
5957 // bypass WebKit. (WebPluginDelegate dispatches this IME data only when its
5958 // instance ID is the same one as the specified ID.)
5959 if (focused_plugin_id_ >= 0) {
5960 std::vector<int> clauses;
5961 std::vector<int> target;
5962 for (size_t i = 0; i < underlines.size(); ++i) {
5963 clauses.push_back(underlines[i].startOffset);
5964 clauses.push_back(underlines[i].endOffset);
5965 if (underlines[i].thick) {
5966 target.clear();
5967 target.push_back(underlines[i].startOffset);
5968 target.push_back(underlines[i].endOffset);
5971 std::set<WebPluginDelegateProxy*>::iterator it;
5972 for (it = plugin_delegates_.begin();
5973 it != plugin_delegates_.end(); ++it) {
5974 (*it)->ImeCompositionUpdated(text, clauses, target, selection_end,
5975 focused_plugin_id_);
5977 return;
5979 #endif
5980 RenderWidget::OnImeSetComposition(text,
5981 underlines,
5982 selection_start,
5983 selection_end);
5987 void RenderViewImpl::OnImeConfirmComposition(
5988 const string16& text, const ui::Range& replacement_range) {
5989 if (pepper_helper_->IsPluginFocused()) {
5990 // When a PPAPI plugin has focus, we bypass WebKit.
5991 pepper_helper_->OnImeConfirmComposition(text);
5992 } else {
5993 #if defined(OS_WIN)
5994 // Same as OnImeSetComposition(), we send the text from IMEs directly to
5995 // plug-ins. When we send IME text directly to plug-ins, we should not send
5996 // it to WebKit to prevent WebKit from controlling IMEs.
5997 // TODO(thakis): Honor |replacement_range| for plugins?
5998 if (focused_plugin_id_ >= 0) {
5999 std::set<WebPluginDelegateProxy*>::iterator it;
6000 for (it = plugin_delegates_.begin();
6001 it != plugin_delegates_.end(); ++it) {
6002 (*it)->ImeCompositionCompleted(text, focused_plugin_id_);
6004 return;
6006 #endif
6007 if (replacement_range.IsValid() && webview()) {
6008 // Select the text in |replacement_range|, it will then be replaced by
6009 // text added by the call to RenderWidget::OnImeConfirmComposition().
6010 if (WebFrame* frame = webview()->focusedFrame()) {
6011 WebRange webrange = WebRange::fromDocumentRange(
6012 frame, replacement_range.start(), replacement_range.length());
6013 if (!webrange.isNull())
6014 frame->selectRange(webrange);
6017 RenderWidget::OnImeConfirmComposition(text, replacement_range);
6021 void RenderViewImpl::SetDeviceScaleFactor(float device_scale_factor) {
6022 RenderWidget::SetDeviceScaleFactor(device_scale_factor);
6023 if (webview())
6024 webview()->setDeviceScaleFactor(device_scale_factor);
6027 ui::TextInputType RenderViewImpl::GetTextInputType() {
6028 return pepper_helper_->IsPluginFocused() ?
6029 pepper_helper_->GetTextInputType() : RenderWidget::GetTextInputType();
6032 void RenderViewImpl::GetSelectionBounds(gfx::Rect* start, gfx::Rect* end) {
6033 if (pepper_helper_->IsPluginFocused()) {
6034 // TODO(kinaba) http://crbug.com/101101
6035 // Current Pepper IME API does not handle selection bounds. So we simply
6036 // use the caret position as an empty range for now. It will be updated
6037 // after Pepper API equips features related to surrounding text retrieval.
6038 gfx::Rect caret = pepper_helper_->GetCaretBounds();
6039 *start = caret;
6040 *end = caret;
6041 return;
6043 RenderWidget::GetSelectionBounds(start, end);
6046 void RenderViewImpl::GetCompositionCharacterBounds(
6047 std::vector<gfx::Rect>* bounds) {
6048 DCHECK(bounds);
6049 bounds->clear();
6051 if (!webview())
6052 return;
6053 size_t start_offset = 0;
6054 size_t character_count = 0;
6055 if (!webview()->compositionRange(&start_offset, &character_count))
6056 return;
6057 if (character_count == 0)
6058 return;
6060 WebKit::WebFrame* frame = webview()->focusedFrame();
6061 if (!frame)
6062 return;
6064 bounds->reserve(character_count);
6065 WebKit::WebRect webrect;
6066 for (size_t i = 0; i < character_count; ++i) {
6067 if (!frame->firstRectForCharacterRange(start_offset + i, 1, webrect)) {
6068 DLOG(ERROR) << "Could not retrieve character rectangle at " << i;
6069 bounds->clear();
6070 return;
6072 bounds->push_back(webrect);
6076 bool RenderViewImpl::CanComposeInline() {
6077 return pepper_helper_->IsPluginFocused() ?
6078 pepper_helper_->CanComposeInline() : true;
6081 #if defined(OS_WIN)
6082 void RenderViewImpl::PluginFocusChanged(bool focused, int plugin_id) {
6083 if (focused)
6084 focused_plugin_id_ = plugin_id;
6085 else
6086 focused_plugin_id_ = -1;
6088 #endif
6090 #if defined(OS_MACOSX)
6091 void RenderViewImpl::PluginFocusChanged(bool focused, int plugin_id) {
6092 Send(new ViewHostMsg_PluginFocusChanged(routing_id(), focused, plugin_id));
6095 void RenderViewImpl::StartPluginIme() {
6096 IPC::Message* msg = new ViewHostMsg_StartPluginIme(routing_id());
6097 // This message can be sent during event-handling, and needs to be delivered
6098 // within that context.
6099 msg->set_unblock(true);
6100 Send(msg);
6103 gfx::PluginWindowHandle RenderViewImpl::AllocateFakePluginWindowHandle(
6104 bool opaque, bool root) {
6105 gfx::PluginWindowHandle window = gfx::kNullPluginWindow;
6106 Send(new ViewHostMsg_AllocateFakePluginWindowHandle(
6107 routing_id(), opaque, root, &window));
6108 if (window) {
6109 fake_plugin_window_handles_.insert(window);
6111 return window;
6114 void RenderViewImpl::DestroyFakePluginWindowHandle(
6115 gfx::PluginWindowHandle window) {
6116 if (window && fake_plugin_window_handles_.find(window) !=
6117 fake_plugin_window_handles_.end()) {
6118 Send(new ViewHostMsg_DestroyFakePluginWindowHandle(routing_id(), window));
6119 fake_plugin_window_handles_.erase(window);
6123 void RenderViewImpl::AcceleratedSurfaceSetIOSurface(
6124 gfx::PluginWindowHandle window,
6125 int32 width,
6126 int32 height,
6127 uint64 io_surface_identifier) {
6128 Send(new ViewHostMsg_AcceleratedSurfaceSetIOSurface(
6129 routing_id(), window, width, height, io_surface_identifier));
6132 void RenderViewImpl::AcceleratedSurfaceSetTransportDIB(
6133 gfx::PluginWindowHandle window,
6134 int32 width,
6135 int32 height,
6136 TransportDIB::Handle transport_dib) {
6137 Send(new ViewHostMsg_AcceleratedSurfaceSetTransportDIB(
6138 routing_id(), window, width, height, transport_dib));
6141 TransportDIB::Handle RenderViewImpl::AcceleratedSurfaceAllocTransportDIB(
6142 size_t size) {
6143 TransportDIB::Handle dib_handle;
6144 // Assume this is a synchronous RPC.
6145 if (Send(new ViewHostMsg_AllocTransportDIB(size, true, &dib_handle)))
6146 return dib_handle;
6147 // Return an invalid handle if Send() fails.
6148 return TransportDIB::DefaultHandleValue();
6151 void RenderViewImpl::AcceleratedSurfaceFreeTransportDIB(
6152 TransportDIB::Id dib_id) {
6153 Send(new ViewHostMsg_FreeTransportDIB(dib_id));
6156 void RenderViewImpl::AcceleratedSurfaceBuffersSwapped(
6157 gfx::PluginWindowHandle window, uint64 surface_handle) {
6158 Send(new ViewHostMsg_AcceleratedSurfaceBuffersSwapped(
6159 routing_id(), window, surface_handle));
6161 #endif // defined(OS_MACOSX)
6163 bool RenderViewImpl::ScheduleFileChooser(
6164 const FileChooserParams& params,
6165 WebFileChooserCompletion* completion) {
6166 static const size_t kMaximumPendingFileChooseRequests = 4;
6167 if (file_chooser_completions_.size() > kMaximumPendingFileChooseRequests) {
6168 // This sanity check prevents too many file choose requests from getting
6169 // queued which could DoS the user. Getting these is most likely a
6170 // programming error (there are many ways to DoS the user so it's not
6171 // considered a "real" security check), either in JS requesting many file
6172 // choosers to pop up, or in a plugin.
6174 // TODO(brettw) we might possibly want to require a user gesture to open
6175 // a file picker, which will address this issue in a better way.
6176 return false;
6179 file_chooser_completions_.push_back(linked_ptr<PendingFileChooser>(
6180 new PendingFileChooser(params, completion)));
6181 if (file_chooser_completions_.size() == 1) {
6182 // Actually show the browse dialog when this is the first request.
6183 Send(new ViewHostMsg_RunFileChooser(routing_id_, params));
6185 return true;
6188 WebKit::WebGeolocationClient* RenderViewImpl::geolocationClient() {
6189 if (!geolocation_dispatcher_)
6190 geolocation_dispatcher_ = new GeolocationDispatcher(this);
6191 return geolocation_dispatcher_;
6194 WebKit::WebSpeechInputController* RenderViewImpl::speechInputController(
6195 WebKit::WebSpeechInputListener* listener) {
6196 #if defined(ENABLE_INPUT_SPEECH)
6197 if (!input_tag_speech_dispatcher_)
6198 input_tag_speech_dispatcher_ =
6199 new InputTagSpeechDispatcher(this, listener);
6200 #endif
6201 return input_tag_speech_dispatcher_;
6204 WebKit::WebSpeechRecognizer* RenderViewImpl::speechRecognizer() {
6205 #if defined(ENABLE_INPUT_SPEECH)
6206 if (!speech_recognition_dispatcher_)
6207 speech_recognition_dispatcher_ = new SpeechRecognitionDispatcher(this);
6208 #endif
6209 return speech_recognition_dispatcher_;
6212 WebKit::WebDeviceOrientationClient* RenderViewImpl::deviceOrientationClient() {
6213 if (!device_orientation_dispatcher_)
6214 device_orientation_dispatcher_ = new DeviceOrientationDispatcher(this);
6215 return device_orientation_dispatcher_;
6218 void RenderViewImpl::zoomLimitsChanged(double minimum_level,
6219 double maximum_level) {
6220 // For now, don't remember plugin zoom values. We don't want to mix them with
6221 // normal web content (i.e. a fixed layout plugin would usually want them
6222 // different).
6223 bool remember = !webview()->mainFrame()->document().isPluginDocument();
6225 int minimum_percent = static_cast<int>(
6226 WebView::zoomLevelToZoomFactor(minimum_level) * 100);
6227 int maximum_percent = static_cast<int>(
6228 WebView::zoomLevelToZoomFactor(maximum_level) * 100);
6230 Send(new ViewHostMsg_UpdateZoomLimits(
6231 routing_id_, minimum_percent, maximum_percent, remember));
6234 void RenderViewImpl::zoomLevelChanged() {
6235 bool remember = !webview()->mainFrame()->document().isPluginDocument();
6236 float zoom_level = webview()->zoomLevel();
6238 FOR_EACH_OBSERVER(RenderViewObserver, observers_, ZoomLevelChanged());
6240 // Tell the browser which url got zoomed so it can update the menu and the
6241 // saved values if necessary
6242 Send(new ViewHostMsg_DidZoomURL(
6243 routing_id_, zoom_level, remember,
6244 GURL(webview()->mainFrame()->document().url())));
6247 void RenderViewImpl::registerProtocolHandler(const WebString& scheme,
6248 const WebString& base_url,
6249 const WebString& url,
6250 const WebString& title) {
6251 bool user_gesture = (webview()->focusedFrame() &&
6252 webview()->focusedFrame()->isProcessingUserGesture());
6253 GURL base(base_url);
6254 GURL absolute_url = base.Resolve(UTF16ToUTF8(url));
6255 if (base.GetOrigin() != absolute_url.GetOrigin()) {
6256 return;
6258 Send(new ViewHostMsg_RegisterProtocolHandler(routing_id_,
6259 UTF16ToUTF8(scheme),
6260 absolute_url,
6261 title,
6262 user_gesture));
6265 WebKit::WebPageVisibilityState RenderViewImpl::visibilityState() const {
6266 WebKit::WebPageVisibilityState current_state = is_hidden() ?
6267 WebKit::WebPageVisibilityStateHidden :
6268 WebKit::WebPageVisibilityStateVisible;
6269 WebKit::WebPageVisibilityState override_state = current_state;
6270 if (GetContentClient()->renderer()->
6271 ShouldOverridePageVisibilityState(this,
6272 &override_state))
6273 return override_state;
6274 return current_state;
6277 WebKit::WebUserMediaClient* RenderViewImpl::userMediaClient() {
6278 EnsureMediaStreamImpl();
6279 return media_stream_impl_;
6282 void RenderViewImpl::draggableRegionsChanged() {
6283 FOR_EACH_OBSERVER(
6284 RenderViewObserver,
6285 observers_,
6286 DraggableRegionsChanged(webview()->mainFrame()));
6289 #if defined(OS_ANDROID)
6290 WebContentDetectionResult RenderViewImpl::detectContentAround(
6291 const WebHitTestResult& touch_hit) {
6292 DCHECK(!touch_hit.isNull());
6293 DCHECK(!touch_hit.node().isNull());
6294 DCHECK(touch_hit.node().isTextNode());
6296 // Process the position with all the registered content detectors until
6297 // a match is found. Priority is provided by their relative order.
6298 for (ContentDetectorList::const_iterator it = content_detectors_.begin();
6299 it != content_detectors_.end(); ++it) {
6300 ContentDetector::Result content = (*it)->FindTappedContent(touch_hit);
6301 if (content.valid) {
6302 return WebContentDetectionResult(content.content_boundaries,
6303 UTF8ToUTF16(content.text), content.intent_url);
6306 return WebContentDetectionResult();
6309 void RenderViewImpl::scheduleContentIntent(const WebURL& intent) {
6310 // Introduce a short delay so that the user can notice the content.
6311 MessageLoop::current()->PostDelayedTask(
6312 FROM_HERE,
6313 base::Bind(&RenderViewImpl::LaunchAndroidContentIntent, AsWeakPtr(),
6314 intent, expected_content_intent_id_),
6315 base::TimeDelta::FromMilliseconds(kContentIntentDelayMilliseconds));
6318 void RenderViewImpl::cancelScheduledContentIntents() {
6319 ++expected_content_intent_id_;
6322 void RenderViewImpl::LaunchAndroidContentIntent(const GURL& intent,
6323 size_t request_id) {
6324 if (request_id != expected_content_intent_id_)
6325 return;
6327 // Remove the content highlighting if any.
6328 scheduleComposite();
6330 if (!intent.is_empty())
6331 Send(new ViewHostMsg_StartContentIntent(routing_id_, intent));
6334 bool RenderViewImpl::openDateTimeChooser(
6335 const WebKit::WebDateTimeChooserParams& params,
6336 WebKit::WebDateTimeChooserCompletion* completion) {
6337 date_time_picker_client_.reset(
6338 new RendererDateTimePicker(this, params, completion));
6339 return date_time_picker_client_->Open();
6342 #endif // defined(OS_ANDROID)
6344 void RenderViewImpl::OnAsyncFileOpened(
6345 base::PlatformFileError error_code,
6346 IPC::PlatformFileForTransit file_for_transit,
6347 int message_id) {
6348 pepper_helper_->OnAsyncFileOpened(
6349 error_code,
6350 IPC::PlatformFileForTransitToPlatformFile(file_for_transit),
6351 message_id);
6354 void RenderViewImpl::OnPpapiBrokerChannelCreated(
6355 int request_id,
6356 const IPC::ChannelHandle& handle) {
6357 pepper_helper_->OnPpapiBrokerChannelCreated(request_id,
6358 handle);
6361 void RenderViewImpl::OnPpapiBrokerPermissionResult(
6362 int request_id,
6363 bool result) {
6364 pepper_helper_->OnPpapiBrokerPermissionResult(request_id, result);
6367 #if defined(OS_MACOSX)
6368 void RenderViewImpl::OnSelectPopupMenuItem(int selected_index) {
6369 if (external_popup_menu_ == NULL) {
6370 // Crash reports from the field indicate that we can be notified with a
6371 // NULL external popup menu (we probably get notified twice).
6372 // If you hit this please file a bug against jcivelli and include the page
6373 // and steps to repro.
6374 NOTREACHED();
6375 return;
6377 external_popup_menu_->DidSelectItem(selected_index);
6378 external_popup_menu_.reset();
6380 #endif
6382 #if defined(OS_ANDROID)
6383 void RenderViewImpl::OnSelectPopupMenuItems(
6384 bool canceled,
6385 const std::vector<int>& selected_indices) {
6386 // It is possible to receive more than one of these calls if the user presses
6387 // a select faster than it takes for the show-select-popup IPC message to make
6388 // it to the browser UI thread. Ignore the extra-messages.
6389 // TODO(jcivelli): http:/b/5793321 Implement a better fix, as detailed in bug.
6390 if (!external_popup_menu_.get())
6391 return;
6393 external_popup_menu_->DidSelectItems(canceled, selected_indices);
6394 external_popup_menu_.reset();
6396 #endif
6398 void RenderViewImpl::OnContextMenuClosed(
6399 const CustomContextMenuContext& custom_context) {
6400 if (custom_context.request_id) {
6401 // External request, should be in our map.
6402 ContextMenuClient* client =
6403 pending_context_menus_.Lookup(custom_context.request_id);
6404 if (client) {
6405 client->OnMenuClosed(custom_context.request_id);
6406 pending_context_menus_.Remove(custom_context.request_id);
6408 } else {
6409 // Internal request, forward to WebKit.
6410 context_menu_node_.reset();
6414 void RenderViewImpl::OnEnableViewSourceMode() {
6415 if (!webview())
6416 return;
6417 WebFrame* main_frame = webview()->mainFrame();
6418 if (!main_frame)
6419 return;
6420 main_frame->enableViewSourceMode(true);
6423 bool RenderViewImpl::WebWidgetHandlesCompositorScheduling() const {
6424 return !!RenderThreadImpl::current()->compositor_thread();
6427 void RenderViewImpl::OnJavaBridgeInit() {
6428 DCHECK(!java_bridge_dispatcher_);
6429 #if defined(ENABLE_JAVA_BRIDGE)
6430 java_bridge_dispatcher_ = new JavaBridgeDispatcher(this);
6431 #endif
6434 void RenderViewImpl::OnDisownOpener() {
6435 if (!webview())
6436 return;
6438 WebFrame* main_frame = webview()->mainFrame();
6439 if (main_frame && main_frame->opener())
6440 main_frame->setOpener(NULL);
6443 void RenderViewImpl::OnUpdatedFrameTree(
6444 int process_id,
6445 int route_id,
6446 const std::string& frame_tree) {
6447 // TODO(nasko): Remove once http://crbug.com/153701 is fixed.
6448 DCHECK(false);
6449 // We should only act on this message if we are swapped out. It's possible
6450 // for this to happen due to races.
6451 if (!is_swapped_out_)
6452 return;
6454 base::DictionaryValue* frames = NULL;
6455 scoped_ptr<base::Value> tree(base::JSONReader::Read(frame_tree));
6456 if (tree.get() && tree->IsType(base::Value::TYPE_DICTIONARY))
6457 tree->GetAsDictionary(&frames);
6459 updating_frame_tree_ = true;
6460 active_frame_id_map_.clear();
6462 target_process_id_ = process_id;
6463 target_routing_id_ = route_id;
6464 CreateFrameTree(webview()->mainFrame(), frames);
6466 updating_frame_tree_ = false;
6469 #if defined(OS_ANDROID)
6470 bool RenderViewImpl::didTapMultipleTargets(
6471 const WebKit::WebGestureEvent& event,
6472 const WebVector<WebRect>& target_rects) {
6473 gfx::Rect finger_rect(
6474 event.x - event.data.tap.width / 2, event.y - event.data.tap.height / 2,
6475 event.data.tap.width, event.data.tap.height);
6476 gfx::Rect zoom_rect;
6477 float scale = DisambiguationPopupHelper::ComputeZoomAreaAndScaleFactor(
6478 finger_rect, target_rects, GetSize(), &zoom_rect);
6479 if (!scale)
6480 return false;
6482 gfx::Size canvas_size = zoom_rect.size();
6483 canvas_size = ToCeiledSize(gfx::ScaleSize(canvas_size, scale));
6484 TransportDIB* transport_dib = NULL;
6486 scoped_ptr<skia::PlatformCanvas> canvas(
6487 RenderProcess::current()->GetDrawingCanvas(&transport_dib,
6488 gfx::Rect(canvas_size)));
6489 if (!canvas.get())
6490 return false;
6492 canvas->scale(scale, scale);
6494 canvas->translate(-zoom_rect.x(), -zoom_rect.y());
6495 webwidget_->paint(webkit_glue::ToWebCanvas(canvas.get()), zoom_rect,
6496 WebWidget::ForceSoftwareRenderingAndIgnoreGPUResidentContent);
6498 Send(new ViewHostMsg_ShowDisambiguationPopup(routing_id_,
6499 zoom_rect,
6500 canvas_size,
6501 transport_dib->id()));
6503 return true;
6505 #endif
6507 void RenderViewImpl::OnReleaseDisambiguationPopupDIB(
6508 TransportDIB::Handle dib_handle) {
6509 TransportDIB* dib = TransportDIB::CreateWithHandle(dib_handle);
6510 RenderProcess::current()->ReleaseTransportDIB(dib);
6513 } // namespace content