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. 4 5 #include "content/renderer/render_view_impl.h" 6 7 #include <algorithm> 8 #include <cmath> 9 10 #include "base/auto_reset.h" 11 #include "base/bind.h" 12 #include "base/bind_helpers.h" 13 #include "base/command_line.h" 14 #include "base/compiler_specific.h" 15 #include "base/debug/alias.h" 16 #include "base/debug/trace_event.h" 17 #include "base/files/file_path.h" 18 #include "base/json/json_writer.h" 19 #include "base/lazy_instance.h" 20 #include "base/memory/scoped_ptr.h" 21 #include "base/message_loop/message_loop_proxy.h" 22 #include "base/metrics/histogram.h" 23 #include "base/path_service.h" 24 #include "base/process/kill.h" 25 #include "base/strings/string_number_conversions.h" 26 #include "base/strings/string_piece.h" 27 #include "base/strings/string_split.h" 28 #include "base/strings/string_util.h" 29 #include "base/strings/sys_string_conversions.h" 30 #include "base/strings/utf_string_conversions.h" 31 #include "base/time/time.h" 32 #include "content/child/appcache/appcache_dispatcher.h" 33 #include "content/child/appcache/web_application_cache_host_impl.h" 34 #include "content/child/child_thread.h" 35 #include "content/child/fileapi/file_system_dispatcher.h" 36 #include "content/child/fileapi/webfilesystem_callback_adapters.h" 37 #include "content/child/npapi/webplugin_delegate_impl.h" 38 #include "content/child/quota_dispatcher.h" 39 #include "content/child/request_extra_data.h" 40 #include "content/child/webmessageportchannel_impl.h" 41 #include "content/common/clipboard_messages.h" 42 #include "content/common/database_messages.h" 43 #include "content/common/dom_storage/dom_storage_types.h" 44 #include "content/common/drag_messages.h" 45 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h" 46 #include "content/common/input_messages.h" 47 #include "content/common/java_bridge_messages.h" 48 #include "content/common/pepper_messages.h" 49 #include "content/common/socket_stream_handle_data.h" 50 #include "content/common/ssl_status_serialization.h" 51 #include "content/common/view_messages.h" 52 #include "content/public/common/bindings_policy.h" 53 #include "content/public/common/content_client.h" 54 #include "content/public/common/content_constants.h" 55 #include "content/public/common/content_switches.h" 56 #include "content/public/common/context_menu_params.h" 57 #include "content/public/common/drop_data.h" 58 #include "content/public/common/favicon_url.h" 59 #include "content/public/common/file_chooser_params.h" 60 #include "content/public/common/page_zoom.h" 61 #include "content/public/common/ssl_status.h" 62 #include "content/public/common/three_d_api_types.h" 63 #include "content/public/common/url_constants.h" 64 #include "content/public/common/url_utils.h" 65 #include "content/public/renderer/content_renderer_client.h" 66 #include "content/public/renderer/context_menu_client.h" 67 #include "content/public/renderer/document_state.h" 68 #include "content/public/renderer/history_item_serialization.h" 69 #include "content/public/renderer/navigation_state.h" 70 #include "content/public/renderer/password_form_conversion_utils.h" 71 #include "content/public/renderer/render_view_observer.h" 72 #include "content/public/renderer/render_view_visitor.h" 73 #include "content/renderer/accessibility/renderer_accessibility.h" 74 #include "content/renderer/accessibility/renderer_accessibility_complete.h" 75 #include "content/renderer/accessibility/renderer_accessibility_focus_only.h" 76 #include "content/renderer/browser_plugin/browser_plugin.h" 77 #include "content/renderer/browser_plugin/browser_plugin_manager.h" 78 #include "content/renderer/browser_plugin/browser_plugin_manager_impl.h" 79 #include "content/renderer/context_menu_params_builder.h" 80 #include "content/renderer/device_orientation_dispatcher.h" 81 #include "content/renderer/devtools/devtools_agent.h" 82 #include "content/renderer/disambiguation_popup_helper.h" 83 #include "content/renderer/dom_automation_controller.h" 84 #include "content/renderer/dom_storage/webstoragenamespace_impl.h" 85 #include "content/renderer/drop_data_builder.h" 86 #include "content/renderer/external_popup_menu.h" 87 #include "content/renderer/fetchers/alt_error_page_resource_fetcher.h" 88 #include "content/renderer/geolocation_dispatcher.h" 89 #include "content/renderer/gpu/input_handler_manager.h" 90 #include "content/renderer/gpu/render_widget_compositor.h" 91 #include "content/renderer/idle_user_detector.h" 92 #include "content/renderer/image_loading_helper.h" 93 #include "content/renderer/ime_event_guard.h" 94 #include "content/renderer/input_tag_speech_dispatcher.h" 95 #include "content/renderer/internal_document_state_data.h" 96 #include "content/renderer/java/java_bridge_dispatcher.h" 97 #include "content/renderer/load_progress_tracker.h" 98 #include "content/renderer/media/audio_device_factory.h" 99 #include "content/renderer/media/audio_renderer_mixer_manager.h" 100 #include "content/renderer/media/media_stream_dependency_factory.h" 101 #include "content/renderer/media/media_stream_dispatcher.h" 102 #include "content/renderer/media/media_stream_impl.h" 103 #include "content/renderer/media/midi_dispatcher.h" 104 #include "content/renderer/media/render_media_log.h" 105 #include "content/renderer/media/rtc_peer_connection_handler.h" 106 #include "content/renderer/media/video_capture_impl_manager.h" 107 #include "content/renderer/media/webmediaplayer_impl.h" 108 #include "content/renderer/media/webmediaplayer_ms.h" 109 #include "content/renderer/media/webmediaplayer_params.h" 110 #include "content/renderer/mhtml_generator.h" 111 #include "content/renderer/notification_provider.h" 112 #include "content/renderer/render_frame_impl.h" 113 #include "content/renderer/render_process.h" 114 #include "content/renderer/render_thread_impl.h" 115 #include "content/renderer/render_view_impl_params.h" 116 #include "content/renderer/render_view_mouse_lock_dispatcher.h" 117 #include "content/renderer/render_widget_fullscreen_pepper.h" 118 #include "content/renderer/renderer_date_time_picker.h" 119 #include "content/renderer/renderer_webapplicationcachehost_impl.h" 120 #include "content/renderer/renderer_webcolorchooser_impl.h" 121 #include "content/renderer/savable_resources.h" 122 #include "content/renderer/speech_recognition_dispatcher.h" 123 #include "content/renderer/stats_collection_controller.h" 124 #include "content/renderer/stats_collection_observer.h" 125 #include "content/renderer/text_input_client_observer.h" 126 #include "content/renderer/v8_value_converter_impl.h" 127 #include "content/renderer/web_ui_extension.h" 128 #include "content/renderer/web_ui_extension_data.h" 129 #include "content/renderer/websharedworker_proxy.h" 130 #include "media/audio/audio_output_device.h" 131 #include "media/base/audio_renderer_mixer_input.h" 132 #include "media/base/filter_collection.h" 133 #include "media/base/media_switches.h" 134 #include "media/filters/audio_renderer_impl.h" 135 #include "media/filters/gpu_video_decoder_factories.h" 136 #include "net/base/data_url.h" 137 #include "net/base/escape.h" 138 #include "net/base/net_errors.h" 139 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 140 #include "net/http/http_util.h" 141 #include "third_party/WebKit/public/platform/WebCString.h" 142 #include "third_party/WebKit/public/platform/WebDragData.h" 143 #include "third_party/WebKit/public/platform/WebFileSystemType.h" 144 #include "third_party/WebKit/public/platform/WebHTTPBody.h" 145 #include "third_party/WebKit/public/platform/WebImage.h" 146 #include "third_party/WebKit/public/platform/WebMessagePortChannel.h" 147 #include "third_party/WebKit/public/platform/WebPoint.h" 148 #include "third_party/WebKit/public/platform/WebRect.h" 149 #include "third_party/WebKit/public/platform/WebSize.h" 150 #include "third_party/WebKit/public/platform/WebSocketStreamHandle.h" 151 #include "third_party/WebKit/public/platform/WebString.h" 152 #include "third_party/WebKit/public/platform/WebURL.h" 153 #include "third_party/WebKit/public/platform/WebURLError.h" 154 #include "third_party/WebKit/public/platform/WebURLRequest.h" 155 #include "third_party/WebKit/public/platform/WebURLResponse.h" 156 #include "third_party/WebKit/public/platform/WebVector.h" 157 #include "third_party/WebKit/public/web/WebAccessibilityObject.h" 158 #include "third_party/WebKit/public/web/WebColorName.h" 159 #include "third_party/WebKit/public/web/WebDOMEvent.h" 160 #include "third_party/WebKit/public/web/WebDOMMessageEvent.h" 161 #include "third_party/WebKit/public/web/WebDataSource.h" 162 #include "third_party/WebKit/public/web/WebDateTimeChooserCompletion.h" 163 #include "third_party/WebKit/public/web/WebDateTimeChooserParams.h" 164 #include "third_party/WebKit/public/web/WebDevToolsAgent.h" 165 #include "third_party/WebKit/public/web/WebDocument.h" 166 #include "third_party/WebKit/public/web/WebElement.h" 167 #include "third_party/WebKit/public/web/WebFileChooserParams.h" 168 #include "third_party/WebKit/public/web/WebFileSystemCallbacks.h" 169 #include "third_party/WebKit/public/web/WebFindOptions.h" 170 #include "third_party/WebKit/public/web/WebFormControlElement.h" 171 #include "third_party/WebKit/public/web/WebFormElement.h" 172 #include "third_party/WebKit/public/web/WebFrame.h" 173 #include "third_party/WebKit/public/web/WebGlyphCache.h" 174 #include "third_party/WebKit/public/web/WebHelperPlugin.h" 175 #include "third_party/WebKit/public/web/WebHistoryItem.h" 176 #include "third_party/WebKit/public/web/WebInputElement.h" 177 #include "third_party/WebKit/public/web/WebInputEvent.h" 178 #include "third_party/WebKit/public/web/WebMediaPlayerAction.h" 179 #include "third_party/WebKit/public/web/WebNavigationPolicy.h" 180 #include "third_party/WebKit/public/web/WebNodeList.h" 181 #include "third_party/WebKit/public/web/WebPageSerializer.h" 182 #include "third_party/WebKit/public/web/WebPlugin.h" 183 #include "third_party/WebKit/public/web/WebPluginAction.h" 184 #include "third_party/WebKit/public/web/WebPluginContainer.h" 185 #include "third_party/WebKit/public/web/WebPluginDocument.h" 186 #include "third_party/WebKit/public/web/WebPluginParams.h" 187 #include "third_party/WebKit/public/web/WebRange.h" 188 #include "third_party/WebKit/public/web/WebScriptSource.h" 189 #include "third_party/WebKit/public/web/WebSearchableFormData.h" 190 #include "third_party/WebKit/public/web/WebSecurityOrigin.h" 191 #include "third_party/WebKit/public/web/WebSecurityPolicy.h" 192 #include "third_party/WebKit/public/web/WebSerializedScriptValue.h" 193 #include "third_party/WebKit/public/web/WebSettings.h" 194 #include "third_party/WebKit/public/web/WebStorageQuotaCallbacks.h" 195 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" 196 #include "third_party/WebKit/public/web/WebUserMediaClient.h" 197 #include "third_party/WebKit/public/web/WebView.h" 198 #include "third_party/WebKit/public/web/WebWindowFeatures.h" 199 #include "third_party/WebKit/public/web/default/WebRenderTheme.h" 200 #include "ui/base/ui_base_switches_util.h" 201 #include "ui/gfx/native_widget_types.h" 202 #include "ui/gfx/point.h" 203 #include "ui/gfx/rect.h" 204 #include "ui/gfx/rect_conversions.h" 205 #include "ui/gfx/size_conversions.h" 206 #include "ui/shell_dialogs/selected_file_info.h" 207 #include "v8/include/v8.h" 208 #include "webkit/child/weburlresponse_extradata_impl.h" 209 #include "webkit/renderer/webpreferences_renderer.h" 210 211 #if defined(OS_ANDROID) 212 #include <cpu-features.h> 213 214 #include "content/common/android/device_telephony_info.h" 215 #include "content/common/gpu/client/context_provider_command_buffer.h" 216 #include "content/renderer/android/address_detector.h" 217 #include "content/renderer/android/content_detector.h" 218 #include "content/renderer/android/email_detector.h" 219 #include "content/renderer/android/phone_number_detector.h" 220 #include "content/renderer/android/synchronous_compositor_factory.h" 221 #include "content/renderer/media/android/renderer_media_player_manager.h" 222 #include "content/renderer/media/android/stream_texture_factory_android_impl.h" 223 #include "content/renderer/media/android/webmediaplayer_android.h" 224 #include "content/renderer/media/android/webmediaplayer_proxy_android.h" 225 #include "skia/ext/platform_canvas.h" 226 #include "third_party/WebKit/public/platform/WebFloatPoint.h" 227 #include "third_party/WebKit/public/platform/WebFloatRect.h" 228 #include "third_party/WebKit/public/web/WebHitTestResult.h" 229 #include "ui/gfx/rect_f.h" 230 231 #if defined(GOOGLE_TV) 232 #include "content/renderer/media/rtc_video_decoder_bridge_tv.h" 233 #include "content/renderer/media/rtc_video_decoder_factory_tv.h" 234 #endif 235 236 #elif defined(OS_WIN) 237 // TODO(port): these files are currently Windows only because they concern: 238 // * theming 239 #include "ui/native_theme/native_theme_win.h" 240 #elif defined(USE_X11) 241 #include "ui/native_theme/native_theme.h" 242 #elif defined(OS_MACOSX) 243 #include "skia/ext/skia_utils_mac.h" 244 #endif 245 246 #if defined(ENABLE_PLUGINS) 247 #include "content/renderer/npapi/webplugin_delegate_proxy.h" 248 #include "content/renderer/npapi/webplugin_impl.h" 249 #include "content/renderer/pepper/pepper_browser_connection.h" 250 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" 251 #include "content/renderer/pepper/pepper_plugin_registry.h" 252 #include "content/renderer/pepper/pepper_webplugin_impl.h" 253 #include "content/renderer/pepper/plugin_module.h" 254 #endif 255 256 using WebKit::WebAccessibilityNotification; 257 using WebKit::WebAccessibilityObject; 258 using WebKit::WebApplicationCacheHost; 259 using WebKit::WebApplicationCacheHostClient; 260 using WebKit::WebCString; 261 using WebKit::WebColor; 262 using WebKit::WebColorName; 263 using WebKit::WebConsoleMessage; 264 using WebKit::WebContextMenuData; 265 using WebKit::WebCookieJar; 266 using WebKit::WebData; 267 using WebKit::WebDataSource; 268 using WebKit::WebDocument; 269 using WebKit::WebDOMEvent; 270 using WebKit::WebDOMMessageEvent; 271 using WebKit::WebDragData; 272 using WebKit::WebDragOperation; 273 using WebKit::WebDragOperationsMask; 274 using WebKit::WebEditingAction; 275 using WebKit::WebElement; 276 using WebKit::WebExternalPopupMenu; 277 using WebKit::WebExternalPopupMenuClient; 278 using WebKit::WebFileChooserCompletion; 279 using WebKit::WebFileSystem; 280 using WebKit::WebFileSystemCallbacks; 281 using WebKit::WebFindOptions; 282 using WebKit::WebFormControlElement; 283 using WebKit::WebFormElement; 284 using WebKit::WebFrame; 285 using WebKit::WebGestureEvent; 286 using WebKit::WebHistoryItem; 287 using WebKit::WebHTTPBody; 288 using WebKit::WebIconURL; 289 using WebKit::WebImage; 290 using WebKit::WebInputElement; 291 using WebKit::WebInputEvent; 292 using WebKit::WebMediaPlayer; 293 using WebKit::WebMediaPlayerAction; 294 using WebKit::WebMediaPlayerClient; 295 using WebKit::WebMouseEvent; 296 using WebKit::WebNavigationPolicy; 297 using WebKit::WebNavigationType; 298 using WebKit::WebNode; 299 using WebKit::WebPageSerializer; 300 using WebKit::WebPageSerializerClient; 301 using WebKit::WebPeerConnection00Handler; 302 using WebKit::WebPeerConnection00HandlerClient; 303 using WebKit::WebPeerConnectionHandler; 304 using WebKit::WebPeerConnectionHandlerClient; 305 using WebKit::WebPluginAction; 306 using WebKit::WebPluginContainer; 307 using WebKit::WebPluginDocument; 308 using WebKit::WebPluginParams; 309 using WebKit::WebPoint; 310 using WebKit::WebPopupMenuInfo; 311 using WebKit::WebRange; 312 using WebKit::WebRect; 313 using WebKit::WebReferrerPolicy; 314 using WebKit::WebScriptSource; 315 using WebKit::WebSearchableFormData; 316 using WebKit::WebSecurityOrigin; 317 using WebKit::WebSecurityPolicy; 318 using WebKit::WebSerializedScriptValue; 319 using WebKit::WebSettings; 320 using WebKit::WebSharedWorker; 321 using WebKit::WebSize; 322 using WebKit::WebSocketStreamHandle; 323 using WebKit::WebStorageNamespace; 324 using WebKit::WebStorageQuotaCallbacks; 325 using WebKit::WebStorageQuotaError; 326 using WebKit::WebStorageQuotaType; 327 using WebKit::WebString; 328 using WebKit::WebTextAffinity; 329 using WebKit::WebTextDirection; 330 using WebKit::WebTouchEvent; 331 using WebKit::WebURL; 332 using WebKit::WebURLError; 333 using WebKit::WebURLRequest; 334 using WebKit::WebURLResponse; 335 using WebKit::WebUserGestureIndicator; 336 using WebKit::WebVector; 337 using WebKit::WebView; 338 using WebKit::WebWidget; 339 using WebKit::WebWindowFeatures; 340 using base::Time; 341 using base::TimeDelta; 342 using webkit_glue::WebURLResponseExtraDataImpl; 343 344 #if defined(OS_ANDROID) 345 using WebKit::WebContentDetectionResult; 346 using WebKit::WebFloatPoint; 347 using WebKit::WebFloatRect; 348 using WebKit::WebHitTestResult; 349 #endif 350 351 namespace content { 352 353 //----------------------------------------------------------------------------- 354 355 typedef std::map<WebKit::WebView*, RenderViewImpl*> ViewMap; 356 static base::LazyInstance<ViewMap> g_view_map = LAZY_INSTANCE_INITIALIZER; 357 typedef std::map<int32, RenderViewImpl*> RoutingIDViewMap; 358 static base::LazyInstance<RoutingIDViewMap> g_routing_id_view_map = 359 LAZY_INSTANCE_INITIALIZER; 360 361 // Time, in seconds, we delay before sending content state changes (such as form 362 // state and scroll position) to the browser. We delay sending changes to avoid 363 // spamming the browser. 364 // To avoid having tab/session restore require sending a message to get the 365 // current content state during tab closing we use a shorter timeout for the 366 // foreground renderer. This means there is a small window of time from which 367 // content state is modified and not sent to session restore, but this is 368 // better than having to wake up all renderers during shutdown. 369 static const int kDelaySecondsForContentStateSyncHidden = 5; 370 static const int kDelaySecondsForContentStateSync = 1; 371 372 static const size_t kExtraCharsBeforeAndAfterSelection = 100; 373 374 // The maximum number of popups that can be spawned from one page. 375 static const int kMaximumNumberOfUnacknowledgedPopups = 25; 376 377 static const float kScalingIncrement = 0.1f; 378 379 static const float kScalingIncrementForGesture = 0.01f; 380 381 #if defined(OS_ANDROID) 382 // Delay between tapping in content and launching the associated android intent. 383 // Used to allow users see what has been recognized as content. 384 static const size_t kContentIntentDelayMilliseconds = 700; 385 #endif 386 387 static RenderViewImpl* (*g_create_render_view_impl)(RenderViewImplParams*) = 388 NULL; 389 390 static void GetRedirectChain(WebDataSource* ds, std::vector<GURL>* result) { 391 // Replace any occurrences of swappedout:// with about:blank. 392 const WebURL& blank_url = GURL(kAboutBlankURL); 393 WebVector<WebURL> urls; 394 ds->redirectChain(urls); 395 result->reserve(urls.size()); 396 for (size_t i = 0; i < urls.size(); ++i) { 397 if (urls[i] != GURL(kSwappedOutURL)) 398 result->push_back(urls[i]); 399 else 400 result->push_back(blank_url); 401 } 402 } 403 404 // If |data_source| is non-null and has an InternalDocumentStateData associated 405 // with it, the AltErrorPageResourceFetcher is reset. 406 static void StopAltErrorPageFetcher(WebDataSource* data_source) { 407 if (data_source) { 408 InternalDocumentStateData* internal_data = 409 InternalDocumentStateData::FromDataSource(data_source); 410 if (internal_data) 411 internal_data->set_alt_error_page_fetcher(NULL); 412 } 413 } 414 415 static bool IsReload(const ViewMsg_Navigate_Params& params) { 416 return 417 params.navigation_type == ViewMsg_Navigate_Type::RELOAD || 418 params.navigation_type == ViewMsg_Navigate_Type::RELOAD_IGNORING_CACHE || 419 params.navigation_type == 420 ViewMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL; 421 } 422 423 // static 424 WebReferrerPolicy RenderViewImpl::GetReferrerPolicyFromRequest( 425 WebFrame* frame, 426 const WebURLRequest& request) { 427 return request.extraData() ? 428 static_cast<RequestExtraData*>(request.extraData())->referrer_policy() : 429 frame->document().referrerPolicy(); 430 } 431 432 // static 433 Referrer RenderViewImpl::GetReferrerFromRequest( 434 WebFrame* frame, 435 const WebURLRequest& request) { 436 return Referrer(GURL(request.httpHeaderField(WebString::fromUTF8("Referer"))), 437 GetReferrerPolicyFromRequest(frame, request)); 438 } 439 440 // static 441 WebURLResponseExtraDataImpl* RenderViewImpl::GetExtraDataFromResponse( 442 const WebURLResponse& response) { 443 return static_cast<WebURLResponseExtraDataImpl*>( 444 response.extraData()); 445 } 446 447 NOINLINE static void CrashIntentionally() { 448 // NOTE(shess): Crash directly rather than using NOTREACHED() so 449 // that the signature is easier to triage in crash reports. 450 volatile int* zero = NULL; 451 *zero = 0; 452 } 453 454 #if defined(ADDRESS_SANITIZER) 455 NOINLINE static void MaybeTriggerAsanError(const GURL& url) { 456 // NOTE(rogerm): We intentionally perform an invalid heap access here in 457 // order to trigger an Address Sanitizer (ASAN) error report. 458 static const char kCrashDomain[] = "crash"; 459 static const char kHeapOverflow[] = "/heap-overflow"; 460 static const char kHeapUnderflow[] = "/heap-underflow"; 461 static const char kUseAfterFree[] = "/use-after-free"; 462 static const int kArraySize = 5; 463 464 if (!url.DomainIs(kCrashDomain, sizeof(kCrashDomain) - 1)) 465 return; 466 467 if (!url.has_path()) 468 return; 469 470 scoped_ptr<int[]> array(new int[kArraySize]); 471 std::string crash_type(url.path()); 472 int dummy = 0; 473 if (crash_type == kHeapOverflow) { 474 dummy = array[kArraySize]; 475 } else if (crash_type == kHeapUnderflow ) { 476 dummy = array[-1]; 477 } else if (crash_type == kUseAfterFree) { 478 int* dangling = array.get(); 479 array.reset(); 480 dummy = dangling[kArraySize / 2]; 481 } 482 483 // Make sure the assignments to the dummy value aren't optimized away. 484 base::debug::Alias(&dummy); 485 } 486 #endif // ADDRESS_SANITIZER 487 488 static void MaybeHandleDebugURL(const GURL& url) { 489 if (!url.SchemeIs(chrome::kChromeUIScheme)) 490 return; 491 if (url == GURL(kChromeUICrashURL)) { 492 CrashIntentionally(); 493 } else if (url == GURL(kChromeUIKillURL)) { 494 base::KillProcess(base::GetCurrentProcessHandle(), 1, false); 495 } else if (url == GURL(kChromeUIHangURL)) { 496 for (;;) { 497 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); 498 } 499 } else if (url == GURL(kChromeUIShorthangURL)) { 500 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(20)); 501 } 502 503 #if defined(ADDRESS_SANITIZER) 504 MaybeTriggerAsanError(url); 505 #endif // ADDRESS_SANITIZER 506 } 507 508 // Returns false unless this is a top-level navigation. 509 static bool IsTopLevelNavigation(WebFrame* frame) { 510 return frame->parent() == NULL; 511 } 512 513 // Returns false unless this is a top-level navigation that crosses origins. 514 static bool IsNonLocalTopLevelNavigation(const GURL& url, 515 WebFrame* frame, 516 WebNavigationType type, 517 bool is_form_post) { 518 if (!IsTopLevelNavigation(frame)) 519 return false; 520 521 // Navigations initiated within Webkit are not sent out to the external host 522 // in the following cases. 523 // 1. The url scheme is not http/https 524 // 2. The origin of the url and the opener is the same in which case the 525 // opener relationship is maintained. 526 // 3. Reloads/form submits/back forward navigations 527 if (!url.SchemeIs(chrome::kHttpScheme) && !url.SchemeIs(chrome::kHttpsScheme)) 528 return false; 529 530 if (type != WebKit::WebNavigationTypeReload && 531 type != WebKit::WebNavigationTypeBackForward && !is_form_post) { 532 // The opener relationship between the new window and the parent allows the 533 // new window to script the parent and vice versa. This is not allowed if 534 // the origins of the two domains are different. This can be treated as a 535 // top level navigation and routed back to the host. 536 WebKit::WebFrame* opener = frame->opener(); 537 if (!opener) 538 return true; 539 540 if (url.GetOrigin() != GURL(opener->document().url()).GetOrigin()) 541 return true; 542 } 543 return false; 544 } 545 546 static void NotifyTimezoneChange(WebKit::WebFrame* frame) { 547 v8::HandleScope handle_scope; 548 v8::Context::Scope context_scope(frame->mainWorldScriptContext()); 549 v8::Date::DateTimeConfigurationChangeNotification(); 550 WebKit::WebFrame* child = frame->firstChild(); 551 for (; child; child = child->nextSibling()) 552 NotifyTimezoneChange(child); 553 } 554 555 static WindowOpenDisposition NavigationPolicyToDisposition( 556 WebNavigationPolicy policy) { 557 switch (policy) { 558 case WebKit::WebNavigationPolicyIgnore: 559 return IGNORE_ACTION; 560 case WebKit::WebNavigationPolicyDownload: 561 return SAVE_TO_DISK; 562 case WebKit::WebNavigationPolicyCurrentTab: 563 return CURRENT_TAB; 564 case WebKit::WebNavigationPolicyNewBackgroundTab: 565 return NEW_BACKGROUND_TAB; 566 case WebKit::WebNavigationPolicyNewForegroundTab: 567 return NEW_FOREGROUND_TAB; 568 case WebKit::WebNavigationPolicyNewWindow: 569 return NEW_WINDOW; 570 case WebKit::WebNavigationPolicyNewPopup: 571 return NEW_POPUP; 572 default: 573 NOTREACHED() << "Unexpected WebNavigationPolicy"; 574 return IGNORE_ACTION; 575 } 576 } 577 578 // Returns true if the device scale is high enough that losing subpixel 579 // antialiasing won't have a noticeable effect on text quality. 580 static bool DeviceScaleEnsuresTextQuality(float device_scale_factor) { 581 #if defined(OS_ANDROID) 582 // On Android, we never have subpixel antialiasing. 583 return true; 584 #else 585 return device_scale_factor > 1.5f; 586 #endif 587 588 } 589 590 static bool ShouldUseFixedPositionCompositing(float device_scale_factor) { 591 // Compositing for fixed-position elements is dependent on 592 // device_scale_factor if no flag is set. http://crbug.com/172738 593 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 594 595 if (command_line.HasSwitch(switches::kDisableCompositingForFixedPosition)) 596 return false; 597 598 if (command_line.HasSwitch(switches::kEnableCompositingForFixedPosition)) 599 return true; 600 601 return DeviceScaleEnsuresTextQuality(device_scale_factor); 602 } 603 604 static bool ShouldUseAcceleratedCompositingForOverflowScroll( 605 float device_scale_factor) { 606 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 607 608 if (command_line.HasSwitch(switches::kEnableAcceleratedOverflowScroll)) 609 return true; 610 611 return DeviceScaleEnsuresTextQuality(device_scale_factor); 612 } 613 614 static bool ShouldUseTransitionCompositing(float device_scale_factor) { 615 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 616 617 if (command_line.HasSwitch(switches::kDisableCompositingForTransition)) 618 return false; 619 620 if (command_line.HasSwitch(switches::kEnableCompositingForTransition)) 621 return true; 622 623 // TODO(ajuma): Re-enable this by default for high-DPI once the problem 624 // of excessive layer promotion caused by overlap has been addressed. 625 // http://crbug.com/178119. 626 return false; 627 } 628 629 static bool ShouldUseAcceleratedFixedRootBackground(float device_scale_factor) { 630 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 631 632 if (command_line.HasSwitch(switches::kDisableAcceleratedFixedRootBackground)) 633 return false; 634 635 if (command_line.HasSwitch(switches::kEnableAcceleratedFixedRootBackground)) 636 return true; 637 638 return DeviceScaleEnsuresTextQuality(device_scale_factor); 639 } 640 641 static FaviconURL::IconType ToFaviconType(WebKit::WebIconURL::Type type) { 642 switch (type) { 643 case WebKit::WebIconURL::TypeFavicon: 644 return FaviconURL::FAVICON; 645 case WebKit::WebIconURL::TypeTouch: 646 return FaviconURL::TOUCH_ICON; 647 case WebKit::WebIconURL::TypeTouchPrecomposed: 648 return FaviconURL::TOUCH_PRECOMPOSED_ICON; 649 case WebKit::WebIconURL::TypeInvalid: 650 return FaviconURL::INVALID_ICON; 651 } 652 return FaviconURL::INVALID_ICON; 653 } 654 655 /////////////////////////////////////////////////////////////////////////////// 656 657 struct RenderViewImpl::PendingFileChooser { 658 PendingFileChooser(const FileChooserParams& p, WebFileChooserCompletion* c) 659 : params(p), 660 completion(c) { 661 } 662 FileChooserParams params; 663 WebFileChooserCompletion* completion; // MAY BE NULL to skip callback. 664 }; 665 666 namespace { 667 668 class WebWidgetLockTarget : public MouseLockDispatcher::LockTarget { 669 public: 670 explicit WebWidgetLockTarget(WebKit::WebWidget* webwidget) 671 : webwidget_(webwidget) {} 672 673 virtual void OnLockMouseACK(bool succeeded) OVERRIDE { 674 if (succeeded) 675 webwidget_->didAcquirePointerLock(); 676 else 677 webwidget_->didNotAcquirePointerLock(); 678 } 679 680 virtual void OnMouseLockLost() OVERRIDE { 681 webwidget_->didLosePointerLock(); 682 } 683 684 virtual bool HandleMouseLockedInputEvent( 685 const WebKit::WebMouseEvent &event) OVERRIDE { 686 // The WebWidget handles mouse lock in WebKit's handleInputEvent(). 687 return false; 688 } 689 690 private: 691 WebKit::WebWidget* webwidget_; 692 }; 693 694 int64 ExtractPostId(const WebHistoryItem& item) { 695 if (item.isNull()) 696 return -1; 697 698 if (item.httpBody().isNull()) 699 return -1; 700 701 return item.httpBody().identifier(); 702 } 703 704 bool TouchEnabled() { 705 // Based on the definition of chrome::kEnableTouchIcon. 706 #if defined(OS_ANDROID) 707 return true; 708 #else 709 return false; 710 #endif 711 } 712 713 WebDragData DropDataToWebDragData(const DropData& drop_data) { 714 std::vector<WebDragData::Item> item_list; 715 716 // These fields are currently unused when dragging into WebKit. 717 DCHECK(drop_data.download_metadata.empty()); 718 DCHECK(drop_data.file_contents.empty()); 719 DCHECK(drop_data.file_description_filename.empty()); 720 721 if (!drop_data.text.is_null()) { 722 WebDragData::Item item; 723 item.storageType = WebDragData::Item::StorageTypeString; 724 item.stringType = WebString::fromUTF8(ui::Clipboard::kMimeTypeText); 725 item.stringData = drop_data.text.string(); 726 item_list.push_back(item); 727 } 728 729 // TODO(dcheng): Do we need to distinguish between null and empty URLs? Is it 730 // meaningful to write an empty URL to the clipboard? 731 if (!drop_data.url.is_empty()) { 732 WebDragData::Item item; 733 item.storageType = WebDragData::Item::StorageTypeString; 734 item.stringType = WebString::fromUTF8(ui::Clipboard::kMimeTypeURIList); 735 item.stringData = WebString::fromUTF8(drop_data.url.spec()); 736 item.title = drop_data.url_title; 737 item_list.push_back(item); 738 } 739 740 if (!drop_data.html.is_null()) { 741 WebDragData::Item item; 742 item.storageType = WebDragData::Item::StorageTypeString; 743 item.stringType = WebString::fromUTF8(ui::Clipboard::kMimeTypeHTML); 744 item.stringData = drop_data.html.string(); 745 item.baseURL = drop_data.html_base_url; 746 item_list.push_back(item); 747 } 748 749 for (std::vector<DropData::FileInfo>::const_iterator it = 750 drop_data.filenames.begin(); 751 it != drop_data.filenames.end(); 752 ++it) { 753 WebDragData::Item item; 754 item.storageType = WebDragData::Item::StorageTypeFilename; 755 item.filenameData = it->path; 756 item.displayNameData = it->display_name; 757 item_list.push_back(item); 758 } 759 760 for (std::map<base::string16, base::string16>::const_iterator it = 761 drop_data.custom_data.begin(); 762 it != drop_data.custom_data.end(); 763 ++it) { 764 WebDragData::Item item; 765 item.storageType = WebDragData::Item::StorageTypeString; 766 item.stringType = it->first; 767 item.stringData = it->second; 768 item_list.push_back(item); 769 } 770 771 WebDragData result; 772 result.initialize(); 773 result.setItems(item_list); 774 result.setFilesystemId(drop_data.filesystem_id); 775 return result; 776 } 777 778 } // namespace 779 780 RenderViewImpl::RenderViewImpl(RenderViewImplParams* params) 781 : RenderWidget(WebKit::WebPopupTypeNone, 782 params->screen_info, 783 params->swapped_out), 784 webkit_preferences_(params->webkit_prefs), 785 send_content_state_immediately_(false), 786 enabled_bindings_(0), 787 send_preferred_size_changes_(false), 788 is_loading_(false), 789 navigation_gesture_(NavigationGestureUnknown), 790 opened_by_user_gesture_(true), 791 opener_suppressed_(false), 792 page_id_(-1), 793 last_page_id_sent_to_browser_(-1), 794 next_page_id_(params->next_page_id), 795 history_list_offset_(-1), 796 history_list_length_(0), 797 target_url_status_(TARGET_NONE), 798 selection_text_offset_(0), 799 selection_range_(ui::Range::InvalidRange()), 800 #if defined(OS_ANDROID) 801 top_controls_constraints_(cc::BOTH), 802 #endif 803 cached_is_main_frame_pinned_to_left_(false), 804 cached_is_main_frame_pinned_to_right_(false), 805 cached_has_main_frame_horizontal_scrollbar_(false), 806 cached_has_main_frame_vertical_scrollbar_(false), 807 cookie_jar_(this), 808 notification_provider_(NULL), 809 geolocation_dispatcher_(NULL), 810 input_tag_speech_dispatcher_(NULL), 811 speech_recognition_dispatcher_(NULL), 812 device_orientation_dispatcher_(NULL), 813 media_stream_dispatcher_(NULL), 814 browser_plugin_manager_(NULL), 815 media_stream_client_(NULL), 816 web_user_media_client_(NULL), 817 midi_dispatcher_(NULL), 818 devtools_agent_(NULL), 819 accessibility_mode_(AccessibilityModeOff), 820 renderer_accessibility_(NULL), 821 java_bridge_dispatcher_(NULL), 822 mouse_lock_dispatcher_(NULL), 823 #if defined(OS_ANDROID) 824 body_background_color_(SK_ColorWHITE), 825 expected_content_intent_id_(0), 826 media_player_proxy_(NULL), 827 #endif 828 #if defined(OS_WIN) 829 focused_plugin_id_(-1), 830 #endif 831 #if defined(ENABLE_PLUGINS) 832 focused_pepper_plugin_(NULL), 833 pepper_last_mouse_event_target_(NULL), 834 #endif 835 enumeration_completion_id_(0), 836 #if defined(OS_ANDROID) 837 load_progress_tracker_(new LoadProgressTracker(this)), 838 #endif 839 session_storage_namespace_id_(params->session_storage_namespace_id), 840 decrement_shared_popup_at_destruction_(false), 841 handling_select_range_(false), 842 next_snapshot_id_(0), 843 allow_partial_swap_(params->allow_partial_swap), 844 context_menu_source_type_(ui::MENU_SOURCE_MOUSE) { 845 } 846 847 void RenderViewImpl::Initialize(RenderViewImplParams* params) { 848 RenderFrameImpl* main_frame = RenderFrameImpl::Create( 849 this, params->main_frame_routing_id); 850 main_render_frame_.reset(main_frame); 851 routing_id_ = params->routing_id; 852 surface_id_ = params->surface_id; 853 if (params->opener_id != MSG_ROUTING_NONE && params->is_renderer_created) 854 opener_id_ = params->opener_id; 855 856 // Ensure we start with a valid next_page_id_ from the browser. 857 DCHECK_GE(next_page_id_, 0); 858 859 #if defined(ENABLE_NOTIFICATIONS) 860 notification_provider_ = new NotificationProvider(this); 861 #else 862 notification_provider_ = NULL; 863 #endif 864 865 webwidget_ = WebView::create(this); 866 webwidget_mouse_lock_target_.reset(new WebWidgetLockTarget(webwidget_)); 867 868 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 869 870 if (command_line.HasSwitch(switches::kStatsCollectionController)) 871 stats_collection_observer_.reset(new StatsCollectionObserver(this)); 872 873 #if defined(OS_ANDROID) 874 content::DeviceTelephonyInfo device_info; 875 876 const std::string region_code = 877 command_line.HasSwitch(switches::kNetworkCountryIso) 878 ? command_line.GetSwitchValueASCII(switches::kNetworkCountryIso) 879 : device_info.GetNetworkCountryIso(); 880 content_detectors_.push_back(linked_ptr<ContentDetector>( 881 new AddressDetector())); 882 content_detectors_.push_back(linked_ptr<ContentDetector>( 883 new PhoneNumberDetector(region_code))); 884 content_detectors_.push_back(linked_ptr<ContentDetector>( 885 new EmailDetector())); 886 #endif 887 888 if (params->counter) { 889 shared_popup_counter_ = params->counter; 890 // Only count this if it isn't swapped out upon creation. 891 if (!params->swapped_out) 892 shared_popup_counter_->data++; 893 decrement_shared_popup_at_destruction_ = true; 894 } else { 895 shared_popup_counter_ = new SharedRenderViewCounter(0); 896 decrement_shared_popup_at_destruction_ = false; 897 } 898 899 RenderThread::Get()->AddRoute(routing_id_, this); 900 // Take a reference on behalf of the RenderThread. This will be balanced 901 // when we receive ViewMsg_ClosePage. 902 AddRef(); 903 904 // If this is a popup, we must wait for the CreatingNew_ACK message before 905 // completing initialization. Otherwise, we can finish it now. 906 if (opener_id_ == MSG_ROUTING_NONE) { 907 did_show_ = true; 908 CompleteInit(); 909 } 910 911 g_view_map.Get().insert(std::make_pair(webview(), this)); 912 g_routing_id_view_map.Get().insert(std::make_pair(routing_id_, this)); 913 webview()->setDeviceScaleFactor(device_scale_factor_); 914 webview()->settings()->setAcceleratedCompositingForFixedPositionEnabled( 915 ShouldUseFixedPositionCompositing(device_scale_factor_)); 916 webview()->settings()->setAcceleratedCompositingForOverflowScrollEnabled( 917 ShouldUseAcceleratedCompositingForOverflowScroll(device_scale_factor_)); 918 webview()->settings()->setAcceleratedCompositingForTransitionEnabled( 919 ShouldUseTransitionCompositing(device_scale_factor_)); 920 webview()->settings()->setAcceleratedCompositingForFixedRootBackgroundEnabled( 921 ShouldUseAcceleratedFixedRootBackground(device_scale_factor_)); 922 923 webkit_glue::ApplyWebPreferences(webkit_preferences_, webview()); 924 webview()->initializeMainFrame(main_render_frame_.get()); 925 926 if (switches::IsTouchDragDropEnabled()) 927 webview()->settings()->setTouchDragDropEnabled(true); 928 929 if (switches::IsTouchEditingEnabled()) 930 webview()->settings()->setTouchEditingEnabled(true); 931 932 if (!params->frame_name.empty()) 933 webview()->mainFrame()->setName(params->frame_name); 934 935 OnSetRendererPrefs(params->renderer_prefs); 936 937 #if defined(ENABLE_WEBRTC) 938 if (!media_stream_dispatcher_) 939 media_stream_dispatcher_ = new MediaStreamDispatcher(this); 940 #endif 941 942 new MHTMLGenerator(this); 943 #if defined(OS_MACOSX) 944 new TextInputClientObserver(this); 945 #endif // defined(OS_MACOSX) 946 947 #if defined(OS_ANDROID) 948 media_player_manager_.reset(new RendererMediaPlayerManager()); 949 #endif 950 951 // The next group of objects all implement RenderViewObserver, so are deleted 952 // along with the RenderView automatically. 953 devtools_agent_ = new DevToolsAgent(this); 954 if (RenderWidgetCompositor* rwc = compositor()) { 955 webview()->devToolsAgent()->setLayerTreeId(rwc->GetLayerTreeId()); 956 } 957 mouse_lock_dispatcher_ = new RenderViewMouseLockDispatcher(this); 958 new ImageLoadingHelper(this); 959 960 // Create renderer_accessibility_ if needed. 961 OnSetAccessibilityMode(params->accessibility_mode); 962 963 new IdleUserDetector(this); 964 965 if (command_line.HasSwitch(switches::kDomAutomationController)) 966 enabled_bindings_ |= BINDINGS_POLICY_DOM_AUTOMATION; 967 if (command_line.HasSwitch(switches::kStatsCollectionController)) 968 enabled_bindings_ |= BINDINGS_POLICY_STATS_COLLECTION; 969 970 ProcessViewLayoutFlags(command_line); 971 972 #if defined(ENABLE_PLUGINS) 973 new PepperBrowserConnection(this); 974 #endif 975 976 GetContentClient()->renderer()->RenderViewCreated(this); 977 978 // If we have an opener_id but we weren't created by a renderer, then 979 // it's the browser asking us to set our opener to another RenderView. 980 if (params->opener_id != MSG_ROUTING_NONE && !params->is_renderer_created) { 981 RenderViewImpl* opener_view = FromRoutingID(params->opener_id); 982 if (opener_view) 983 webview()->mainFrame()->setOpener(opener_view->webview()->mainFrame()); 984 } 985 986 // If we are initially swapped out, navigate to kSwappedOutURL. 987 // This ensures we are in a unique origin that others cannot script. 988 if (is_swapped_out_) 989 NavigateToSwappedOutURL(webview()->mainFrame()); 990 } 991 992 RenderViewImpl::~RenderViewImpl() { 993 history_page_ids_.clear(); 994 995 if (decrement_shared_popup_at_destruction_) 996 shared_popup_counter_->data--; 997 998 base::debug::TraceLog::GetInstance()->RemoveProcessLabel(routing_id_); 999 1000 // If file chooser is still waiting for answer, dispatch empty answer. 1001 while (!file_chooser_completions_.empty()) { 1002 if (file_chooser_completions_.front()->completion) { 1003 file_chooser_completions_.front()->completion->didChooseFile( 1004 WebVector<WebString>()); 1005 } 1006 file_chooser_completions_.pop_front(); 1007 } 1008 1009 #if defined(OS_ANDROID) 1010 // The date/time picker client is both a scoped_ptr member of this class and 1011 // a RenderViewObserver. Reset it to prevent double deletion. 1012 date_time_picker_client_.reset(); 1013 #endif 1014 1015 #ifndef NDEBUG 1016 // Make sure we are no longer referenced by the ViewMap or RoutingIDViewMap. 1017 ViewMap* views = g_view_map.Pointer(); 1018 for (ViewMap::iterator it = views->begin(); it != views->end(); ++it) 1019 DCHECK_NE(this, it->second) << "Failed to call Close?"; 1020 RoutingIDViewMap* routing_id_views = g_routing_id_view_map.Pointer(); 1021 for (RoutingIDViewMap::iterator it = routing_id_views->begin(); 1022 it != routing_id_views->end(); ++it) 1023 DCHECK_NE(this, it->second) << "Failed to call Close?"; 1024 #endif 1025 1026 FOR_EACH_OBSERVER(RenderViewObserver, observers_, RenderViewGone()); 1027 FOR_EACH_OBSERVER(RenderViewObserver, observers_, OnDestruct()); 1028 } 1029 1030 /*static*/ 1031 RenderViewImpl* RenderViewImpl::FromWebView(WebView* webview) { 1032 ViewMap* views = g_view_map.Pointer(); 1033 ViewMap::iterator it = views->find(webview); 1034 return it == views->end() ? NULL : it->second; 1035 } 1036 1037 /*static*/ 1038 RenderView* RenderView::FromWebView(WebKit::WebView* webview) { 1039 return RenderViewImpl::FromWebView(webview); 1040 } 1041 1042 /*static*/ 1043 RenderViewImpl* RenderViewImpl::FromRoutingID(int32 routing_id) { 1044 RoutingIDViewMap* views = g_routing_id_view_map.Pointer(); 1045 RoutingIDViewMap::iterator it = views->find(routing_id); 1046 return it == views->end() ? NULL : it->second; 1047 } 1048 1049 /*static*/ 1050 RenderView* RenderView::FromRoutingID(int routing_id) { 1051 return RenderViewImpl::FromRoutingID(routing_id); 1052 } 1053 1054 /*static*/ 1055 void RenderView::ForEach(RenderViewVisitor* visitor) { 1056 ViewMap* views = g_view_map.Pointer(); 1057 for (ViewMap::iterator it = views->begin(); it != views->end(); ++it) { 1058 if (!visitor->Visit(it->second)) 1059 return; 1060 } 1061 } 1062 1063 /*static*/ 1064 RenderViewImpl* RenderViewImpl::Create( 1065 int32 opener_id, 1066 const RendererPreferences& renderer_prefs, 1067 const WebPreferences& webkit_prefs, 1068 SharedRenderViewCounter* counter, 1069 int32 routing_id, 1070 int32 main_frame_routing_id, 1071 int32 surface_id, 1072 int64 session_storage_namespace_id, 1073 const string16& frame_name, 1074 bool is_renderer_created, 1075 bool swapped_out, 1076 int32 next_page_id, 1077 const WebKit::WebScreenInfo& screen_info, 1078 AccessibilityMode accessibility_mode, 1079 bool allow_partial_swap) { 1080 DCHECK(routing_id != MSG_ROUTING_NONE); 1081 RenderViewImplParams params( 1082 opener_id, 1083 renderer_prefs, 1084 webkit_prefs, 1085 counter, 1086 routing_id, 1087 main_frame_routing_id, 1088 surface_id, 1089 session_storage_namespace_id, 1090 frame_name, 1091 is_renderer_created, 1092 swapped_out, 1093 next_page_id, 1094 screen_info, 1095 accessibility_mode, 1096 allow_partial_swap); 1097 RenderViewImpl* render_view = NULL; 1098 if (g_create_render_view_impl) 1099 render_view = g_create_render_view_impl(¶ms); 1100 else 1101 render_view = new RenderViewImpl(¶ms); 1102 render_view->Initialize(¶ms); 1103 return render_view; 1104 } 1105 1106 // static 1107 void RenderViewImpl::InstallCreateHook( 1108 RenderViewImpl* (*create_render_view_impl)(RenderViewImplParams*)) { 1109 CHECK(!g_create_render_view_impl); 1110 g_create_render_view_impl = create_render_view_impl; 1111 } 1112 1113 void RenderViewImpl::AddObserver(RenderViewObserver* observer) { 1114 observers_.AddObserver(observer); 1115 } 1116 1117 void RenderViewImpl::RemoveObserver(RenderViewObserver* observer) { 1118 observer->RenderViewGone(); 1119 observers_.RemoveObserver(observer); 1120 } 1121 1122 WebKit::WebView* RenderViewImpl::webview() const { 1123 return static_cast<WebKit::WebView*>(webwidget()); 1124 } 1125 1126 #if defined(ENABLE_PLUGINS) 1127 void RenderViewImpl::PepperInstanceCreated(PepperPluginInstanceImpl* instance) { 1128 active_pepper_instances_.insert(instance); 1129 } 1130 1131 void RenderViewImpl::PepperInstanceDeleted(PepperPluginInstanceImpl* instance) { 1132 active_pepper_instances_.erase(instance); 1133 1134 if (pepper_last_mouse_event_target_ == instance) 1135 pepper_last_mouse_event_target_ = NULL; 1136 if (focused_pepper_plugin_ == instance) 1137 PepperFocusChanged(instance, false); 1138 } 1139 1140 void RenderViewImpl::PepperDidChangeCursor( 1141 PepperPluginInstanceImpl* instance, 1142 const WebKit::WebCursorInfo& cursor) { 1143 // Update the cursor appearance immediately if the requesting plugin is the 1144 // one which receives the last mouse event. Otherwise, the new cursor won't be 1145 // picked up until the plugin gets the next input event. That is bad if, e.g., 1146 // the plugin would like to set an invisible cursor when there isn't any user 1147 // input for a while. 1148 if (instance == pepper_last_mouse_event_target_) 1149 didChangeCursor(cursor); 1150 } 1151 1152 void RenderViewImpl::PepperDidReceiveMouseEvent( 1153 PepperPluginInstanceImpl* instance) { 1154 pepper_last_mouse_event_target_ = instance; 1155 } 1156 1157 void RenderViewImpl::PepperFocusChanged(PepperPluginInstanceImpl* instance, 1158 bool focused) { 1159 if (focused) 1160 focused_pepper_plugin_ = instance; 1161 else if (focused_pepper_plugin_ == instance) 1162 focused_pepper_plugin_ = NULL; 1163 1164 UpdateTextInputType(); 1165 UpdateSelectionBounds(); 1166 } 1167 1168 void RenderViewImpl::PepperTextInputTypeChanged( 1169 PepperPluginInstanceImpl* instance) { 1170 if (instance != focused_pepper_plugin_) 1171 return; 1172 1173 UpdateTextInputType(); 1174 if (renderer_accessibility_) 1175 renderer_accessibility_->FocusedNodeChanged(WebNode()); 1176 } 1177 1178 void RenderViewImpl::PepperCaretPositionChanged( 1179 PepperPluginInstanceImpl* instance) { 1180 if (instance != focused_pepper_plugin_) 1181 return; 1182 UpdateSelectionBounds(); 1183 } 1184 1185 void RenderViewImpl::PepperCancelComposition( 1186 PepperPluginInstanceImpl* instance) { 1187 if (instance != focused_pepper_plugin_) 1188 return; 1189 Send(new ViewHostMsg_ImeCancelComposition(routing_id()));; 1190 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA) 1191 UpdateCompositionInfo(true); 1192 #endif 1193 } 1194 1195 void RenderViewImpl::PepperSelectionChanged( 1196 PepperPluginInstanceImpl* instance) { 1197 if (instance != focused_pepper_plugin_) 1198 return; 1199 SyncSelectionIfRequired(); 1200 } 1201 1202 RenderWidgetFullscreenPepper* RenderViewImpl::CreatePepperFullscreenContainer( 1203 PepperPluginInstanceImpl* plugin) { 1204 GURL active_url; 1205 if (webview() && webview()->mainFrame()) 1206 active_url = GURL(webview()->mainFrame()->document().url()); 1207 RenderWidgetFullscreenPepper* widget = RenderWidgetFullscreenPepper::Create( 1208 routing_id_, plugin, active_url, screen_info_); 1209 widget->show(WebKit::WebNavigationPolicyIgnore); 1210 return widget; 1211 } 1212 1213 void RenderViewImpl::PepperPluginCreated(RendererPpapiHost* host) { 1214 FOR_EACH_OBSERVER(RenderViewObserver, observers_, 1215 DidCreatePepperPlugin(host)); 1216 } 1217 1218 bool RenderViewImpl::GetPepperCaretBounds(gfx::Rect* rect) { 1219 if (!focused_pepper_plugin_) 1220 return false; 1221 *rect = focused_pepper_plugin_->GetCaretBounds(); 1222 return true; 1223 } 1224 1225 bool RenderViewImpl::IsPepperAcceptingCompositionEvents() const { 1226 if (!focused_pepper_plugin_) 1227 return false; 1228 return focused_pepper_plugin_->IsPluginAcceptingCompositionEvents(); 1229 } 1230 1231 void RenderViewImpl::PluginCrashed(const base::FilePath& plugin_path, 1232 base::ProcessId plugin_pid) { 1233 Send(new ViewHostMsg_CrashedPlugin(routing_id_, plugin_path, plugin_pid)); 1234 } 1235 1236 void RenderViewImpl::RegisterPluginDelegate(WebPluginDelegateProxy* delegate) { 1237 plugin_delegates_.insert(delegate); 1238 // If the renderer is visible, set initial visibility and focus state. 1239 if (!is_hidden()) { 1240 #if defined(OS_MACOSX) 1241 delegate->SetContainerVisibility(true); 1242 if (webview() && webview()->isActive()) 1243 delegate->SetWindowFocus(true); 1244 #endif 1245 } 1246 // Plugins start assuming the content has focus (so that they work in 1247 // environments where RenderView isn't hosting them), so we always have to 1248 // set the initial state. See webplugin_delegate_impl.h for details. 1249 delegate->SetContentAreaFocus(has_focus()); 1250 } 1251 1252 void RenderViewImpl::UnregisterPluginDelegate( 1253 WebPluginDelegateProxy* delegate) { 1254 plugin_delegates_.erase(delegate); 1255 } 1256 1257 bool RenderViewImpl::GetPluginInfo(const GURL& url, 1258 const GURL& page_url, 1259 const std::string& mime_type, 1260 WebPluginInfo* plugin_info, 1261 std::string* actual_mime_type) { 1262 bool found = false; 1263 Send(new ViewHostMsg_GetPluginInfo( 1264 routing_id_, url, page_url, mime_type, &found, plugin_info, 1265 actual_mime_type)); 1266 return found; 1267 } 1268 1269 void RenderViewImpl::SimulateImeSetComposition( 1270 const string16& text, 1271 const std::vector<WebKit::WebCompositionUnderline>& underlines, 1272 int selection_start, 1273 int selection_end) { 1274 OnImeSetComposition(text, underlines, selection_start, selection_end); 1275 } 1276 1277 void RenderViewImpl::SimulateImeConfirmComposition( 1278 const string16& text, 1279 const ui::Range& replacement_range) { 1280 OnImeConfirmComposition(text, replacement_range, false); 1281 } 1282 1283 #if defined(OS_WIN) 1284 void RenderViewImpl::PluginFocusChanged(bool focused, int plugin_id) { 1285 if (focused) 1286 focused_plugin_id_ = plugin_id; 1287 else 1288 focused_plugin_id_ = -1; 1289 } 1290 #endif 1291 1292 #if defined(OS_MACOSX) 1293 void RenderViewImpl::PluginFocusChanged(bool focused, int plugin_id) { 1294 Send(new ViewHostMsg_PluginFocusChanged(routing_id(), focused, plugin_id)); 1295 } 1296 1297 void RenderViewImpl::StartPluginIme() { 1298 IPC::Message* msg = new ViewHostMsg_StartPluginIme(routing_id()); 1299 // This message can be sent during event-handling, and needs to be delivered 1300 // within that context. 1301 msg->set_unblock(true); 1302 Send(msg); 1303 } 1304 #endif // defined(OS_MACOSX) 1305 1306 #endif // ENABLE_PLUGINS 1307 1308 void RenderViewImpl::TransferActiveWheelFlingAnimation( 1309 const WebKit::WebActiveWheelFlingParameters& params) { 1310 if (webview()) 1311 webview()->transferActiveWheelFlingAnimation(params); 1312 } 1313 1314 bool RenderViewImpl::HasIMETextFocus() { 1315 return GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE; 1316 } 1317 1318 bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) { 1319 WebFrame* main_frame = webview() ? webview()->mainFrame() : NULL; 1320 if (main_frame) 1321 GetContentClient()->SetActiveURL(main_frame->document().url()); 1322 1323 ObserverListBase<RenderViewObserver>::Iterator it(observers_); 1324 RenderViewObserver* observer; 1325 while ((observer = it.GetNext()) != NULL) 1326 if (observer->OnMessageReceived(message)) 1327 return true; 1328 1329 bool handled = true; 1330 bool msg_is_ok = true; 1331 IPC_BEGIN_MESSAGE_MAP_EX(RenderViewImpl, message, msg_is_ok) 1332 IPC_MESSAGE_HANDLER(InputMsg_Copy, OnCopy) 1333 IPC_MESSAGE_HANDLER(InputMsg_Cut, OnCut) 1334 IPC_MESSAGE_HANDLER(InputMsg_Delete, OnDelete) 1335 IPC_MESSAGE_HANDLER(InputMsg_ExecuteEditCommand, OnExecuteEditCommand) 1336 IPC_MESSAGE_HANDLER(InputMsg_MoveCaret, OnMoveCaret) 1337 IPC_MESSAGE_HANDLER(InputMsg_Paste, OnPaste) 1338 IPC_MESSAGE_HANDLER(InputMsg_PasteAndMatchStyle, OnPasteAndMatchStyle) 1339 IPC_MESSAGE_HANDLER(InputMsg_Redo, OnRedo) 1340 IPC_MESSAGE_HANDLER(InputMsg_Replace, OnReplace) 1341 IPC_MESSAGE_HANDLER(InputMsg_ReplaceMisspelling, OnReplaceMisspelling) 1342 IPC_MESSAGE_HANDLER(InputMsg_ScrollFocusedEditableNodeIntoRect, 1343 OnScrollFocusedEditableNodeIntoRect) 1344 IPC_MESSAGE_HANDLER(InputMsg_SelectAll, OnSelectAll) 1345 IPC_MESSAGE_HANDLER(InputMsg_SelectRange, OnSelectRange) 1346 IPC_MESSAGE_HANDLER(InputMsg_SetEditCommandsForNextKeyEvent, 1347 OnSetEditCommandsForNextKeyEvent) 1348 IPC_MESSAGE_HANDLER(InputMsg_Undo, OnUndo) 1349 IPC_MESSAGE_HANDLER(InputMsg_Unselect, OnUnselect) 1350 IPC_MESSAGE_HANDLER(ViewMsg_Navigate, OnNavigate) 1351 IPC_MESSAGE_HANDLER(ViewMsg_Stop, OnStop) 1352 IPC_MESSAGE_HANDLER(ViewMsg_ReloadFrame, OnReloadFrame) 1353 IPC_MESSAGE_HANDLER(ViewMsg_SetName, OnSetName) 1354 IPC_MESSAGE_HANDLER(ViewMsg_SetEditableSelectionOffsets, 1355 OnSetEditableSelectionOffsets) 1356 IPC_MESSAGE_HANDLER(ViewMsg_SetCompositionFromExistingText, 1357 OnSetCompositionFromExistingText) 1358 IPC_MESSAGE_HANDLER(ViewMsg_ExtendSelectionAndDelete, 1359 OnExtendSelectionAndDelete) 1360 IPC_MESSAGE_HANDLER(ViewMsg_CopyImageAt, OnCopyImageAt) 1361 IPC_MESSAGE_HANDLER(ViewMsg_Find, OnFind) 1362 IPC_MESSAGE_HANDLER(ViewMsg_StopFinding, OnStopFinding) 1363 IPC_MESSAGE_HANDLER(ViewMsg_Zoom, OnZoom) 1364 IPC_MESSAGE_HANDLER(ViewMsg_SetZoomLevel, OnSetZoomLevel) 1365 IPC_MESSAGE_HANDLER(ViewMsg_ZoomFactor, OnZoomFactor) 1366 IPC_MESSAGE_HANDLER(ViewMsg_SetZoomLevelForLoadingURL, 1367 OnSetZoomLevelForLoadingURL) 1368 IPC_MESSAGE_HANDLER(ViewMsg_SetPageEncoding, OnSetPageEncoding) 1369 IPC_MESSAGE_HANDLER(ViewMsg_ResetPageEncodingToDefault, 1370 OnResetPageEncodingToDefault) 1371 IPC_MESSAGE_HANDLER(ViewMsg_ScriptEvalRequest, OnScriptEvalRequest) 1372 IPC_MESSAGE_HANDLER(ViewMsg_PostMessageEvent, OnPostMessageEvent) 1373 IPC_MESSAGE_HANDLER(ViewMsg_CSSInsertRequest, OnCSSInsertRequest) 1374 IPC_MESSAGE_HANDLER(DragMsg_TargetDragEnter, OnDragTargetDragEnter) 1375 IPC_MESSAGE_HANDLER(DragMsg_TargetDragOver, OnDragTargetDragOver) 1376 IPC_MESSAGE_HANDLER(DragMsg_TargetDragLeave, OnDragTargetDragLeave) 1377 IPC_MESSAGE_HANDLER(DragMsg_TargetDrop, OnDragTargetDrop) 1378 IPC_MESSAGE_HANDLER(DragMsg_SourceEndedOrMoved, OnDragSourceEndedOrMoved) 1379 IPC_MESSAGE_HANDLER(DragMsg_SourceSystemDragEnded, 1380 OnDragSourceSystemDragEnded) 1381 IPC_MESSAGE_HANDLER(ViewMsg_AllowBindings, OnAllowBindings) 1382 IPC_MESSAGE_HANDLER(ViewMsg_SetInitialFocus, OnSetInitialFocus) 1383 IPC_MESSAGE_HANDLER(ViewMsg_UpdateTargetURL_ACK, OnUpdateTargetURLAck) 1384 IPC_MESSAGE_HANDLER(ViewMsg_UpdateWebPreferences, OnUpdateWebPreferences) 1385 IPC_MESSAGE_HANDLER(ViewMsg_TimezoneChange, OnUpdateTimezone) 1386 IPC_MESSAGE_HANDLER(ViewMsg_SetAltErrorPageURL, OnSetAltErrorPageURL) 1387 IPC_MESSAGE_HANDLER(ViewMsg_EnumerateDirectoryResponse, 1388 OnEnumerateDirectoryResponse) 1389 IPC_MESSAGE_HANDLER(ViewMsg_RunFileChooserResponse, OnFileChooserResponse) 1390 IPC_MESSAGE_HANDLER(ViewMsg_ShouldClose, OnShouldClose) 1391 IPC_MESSAGE_HANDLER(ViewMsg_SwapOut, OnSwapOut) 1392 IPC_MESSAGE_HANDLER(ViewMsg_ClosePage, OnClosePage) 1393 IPC_MESSAGE_HANDLER(ViewMsg_ThemeChanged, OnThemeChanged) 1394 IPC_MESSAGE_HANDLER(ViewMsg_DisassociateFromPopupCount, 1395 OnDisassociateFromPopupCount) 1396 IPC_MESSAGE_HANDLER(ViewMsg_MoveOrResizeStarted, OnMoveOrResizeStarted) 1397 IPC_MESSAGE_HANDLER(ViewMsg_ClearFocusedNode, OnClearFocusedNode) 1398 IPC_MESSAGE_HANDLER(ViewMsg_SetBackground, OnSetBackground) 1399 IPC_MESSAGE_HANDLER(ViewMsg_EnablePreferredSizeChangedMode, 1400 OnEnablePreferredSizeChangedMode) 1401 IPC_MESSAGE_HANDLER(ViewMsg_EnableAutoResize, OnEnableAutoResize) 1402 IPC_MESSAGE_HANDLER(ViewMsg_DisableAutoResize, OnDisableAutoResize) 1403 IPC_MESSAGE_HANDLER(ViewMsg_DisableScrollbarsForSmallWindows, 1404 OnDisableScrollbarsForSmallWindows) 1405 IPC_MESSAGE_HANDLER(ViewMsg_SetRendererPrefs, OnSetRendererPrefs) 1406 IPC_MESSAGE_HANDLER(ViewMsg_MediaPlayerActionAt, OnMediaPlayerActionAt) 1407 IPC_MESSAGE_HANDLER(ViewMsg_OrientationChangeEvent, 1408 OnOrientationChangeEvent) 1409 IPC_MESSAGE_HANDLER(ViewMsg_PluginActionAt, OnPluginActionAt) 1410 IPC_MESSAGE_HANDLER(ViewMsg_SetActive, OnSetActive) 1411 IPC_MESSAGE_HANDLER(ViewMsg_CustomContextMenuAction, 1412 OnCustomContextMenuAction) 1413 IPC_MESSAGE_HANDLER(ViewMsg_GetAllSavableResourceLinksForCurrentPage, 1414 OnGetAllSavableResourceLinksForCurrentPage) 1415 IPC_MESSAGE_HANDLER( 1416 ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks, 1417 OnGetSerializedHtmlDataForCurrentPageWithLocalLinks) 1418 IPC_MESSAGE_HANDLER(ViewMsg_ContextMenuClosed, OnContextMenuClosed) 1419 IPC_MESSAGE_HANDLER(ViewMsg_ShowContextMenu, OnShowContextMenu) 1420 // TODO(viettrungluu): Move to a separate message filter. 1421 IPC_MESSAGE_HANDLER(ViewMsg_SetHistoryLengthAndPrune, 1422 OnSetHistoryLengthAndPrune) 1423 IPC_MESSAGE_HANDLER(ViewMsg_EnableViewSourceMode, OnEnableViewSourceMode) 1424 #if defined(OS_ANDROID) 1425 IPC_MESSAGE_HANDLER(JavaBridgeMsg_Init, OnJavaBridgeInit) 1426 #endif 1427 IPC_MESSAGE_HANDLER(ViewMsg_SetAccessibilityMode, OnSetAccessibilityMode) 1428 IPC_MESSAGE_HANDLER(ViewMsg_DisownOpener, OnDisownOpener) 1429 #if defined(OS_ANDROID) 1430 IPC_MESSAGE_HANDLER(InputMsg_ActivateNearestFindResult, 1431 OnActivateNearestFindResult) 1432 IPC_MESSAGE_HANDLER(ViewMsg_FindMatchRects, OnFindMatchRects) 1433 IPC_MESSAGE_HANDLER(ViewMsg_SelectPopupMenuItems, OnSelectPopupMenuItems) 1434 IPC_MESSAGE_HANDLER(ViewMsg_UndoScrollFocusedEditableNodeIntoView, 1435 OnUndoScrollFocusedEditableNodeIntoRect) 1436 IPC_MESSAGE_HANDLER(ViewMsg_UpdateTopControlsState, 1437 OnUpdateTopControlsState) 1438 IPC_MESSAGE_HANDLER(ViewMsg_PauseVideo, OnPauseVideo) 1439 #elif defined(OS_MACOSX) 1440 IPC_MESSAGE_HANDLER(InputMsg_CopyToFindPboard, OnCopyToFindPboard) 1441 IPC_MESSAGE_HANDLER(ViewMsg_PluginImeCompositionCompleted, 1442 OnPluginImeCompositionCompleted) 1443 IPC_MESSAGE_HANDLER(ViewMsg_SelectPopupMenuItem, OnSelectPopupMenuItem) 1444 IPC_MESSAGE_HANDLER(ViewMsg_SetInLiveResize, OnSetInLiveResize) 1445 IPC_MESSAGE_HANDLER(ViewMsg_SetWindowVisibility, OnSetWindowVisibility) 1446 IPC_MESSAGE_HANDLER(ViewMsg_WindowFrameChanged, OnWindowFrameChanged) 1447 #endif 1448 IPC_MESSAGE_HANDLER(ViewMsg_ReleaseDisambiguationPopupDIB, 1449 OnReleaseDisambiguationPopupDIB) 1450 IPC_MESSAGE_HANDLER(ViewMsg_WindowSnapshotCompleted, 1451 OnWindowSnapshotCompleted) 1452 1453 // Have the super handle all other messages. 1454 IPC_MESSAGE_UNHANDLED(handled = RenderWidget::OnMessageReceived(message)) 1455 IPC_END_MESSAGE_MAP() 1456 1457 if (!msg_is_ok) { 1458 // The message had a handler, but its deserialization failed. 1459 // Kill the renderer to avoid potential spoofing attacks. 1460 CHECK(false) << "Unable to deserialize message in RenderViewImpl."; 1461 } 1462 1463 return handled; 1464 } 1465 1466 void RenderViewImpl::OnNavigate(const ViewMsg_Navigate_Params& params) { 1467 MaybeHandleDebugURL(params.url); 1468 if (!webview()) 1469 return; 1470 1471 FOR_EACH_OBSERVER(RenderViewObserver, observers_, Navigate(params.url)); 1472 1473 bool is_reload = IsReload(params); 1474 1475 // If this is a stale back/forward (due to a recent navigation the browser 1476 // didn't know about), ignore it. 1477 if (IsBackForwardToStaleEntry(params, is_reload)) 1478 return; 1479 1480 // Swap this renderer back in if necessary. 1481 if (is_swapped_out_) { 1482 // We marked the view as hidden when swapping the view out, so be sure to 1483 // reset the visibility state before navigating to the new URL. 1484 webview()->setVisibilityState(visibilityState(), false); 1485 1486 // If this is an attempt to reload while we are swapped out, we should not 1487 // reload swappedout://, but the previous page, which is stored in 1488 // params.state. Setting is_reload to false will treat this like a back 1489 // navigation to accomplish that. 1490 is_reload = false; 1491 1492 // We refresh timezone when a view is swapped in since timezone 1493 // can get out of sync when the system timezone is updated while 1494 // the view is swapped out. 1495 NotifyTimezoneChange(webview()->mainFrame()); 1496 1497 SetSwappedOut(false); 1498 } 1499 1500 if (params.should_clear_history_list) { 1501 CHECK_EQ(params.pending_history_list_offset, -1); 1502 CHECK_EQ(params.current_history_list_offset, -1); 1503 CHECK_EQ(params.current_history_list_length, 0); 1504 } 1505 history_list_offset_ = params.current_history_list_offset; 1506 history_list_length_ = params.current_history_list_length; 1507 if (history_list_length_ >= 0) 1508 history_page_ids_.resize(history_list_length_, -1); 1509 if (params.pending_history_list_offset >= 0 && 1510 params.pending_history_list_offset < history_list_length_) 1511 history_page_ids_[params.pending_history_list_offset] = params.page_id; 1512 1513 GetContentClient()->SetActiveURL(params.url); 1514 1515 WebFrame* frame = webview()->mainFrame(); 1516 if (!params.frame_to_navigate.empty()) { 1517 frame = webview()->findFrameByName( 1518 WebString::fromUTF8(params.frame_to_navigate)); 1519 CHECK(frame) << "Invalid frame name passed: " << params.frame_to_navigate; 1520 } 1521 1522 if (is_reload && frame->currentHistoryItem().isNull()) { 1523 // We cannot reload if we do not have any history state. This happens, for 1524 // example, when recovering from a crash. Our workaround here is a bit of 1525 // a hack since it means that reload after a crashed tab does not cause an 1526 // end-to-end cache validation. 1527 is_reload = false; 1528 } 1529 1530 pending_navigation_params_.reset(new ViewMsg_Navigate_Params(params)); 1531 1532 // If we are reloading, then WebKit will use the history state of the current 1533 // page, so we should just ignore any given history state. Otherwise, if we 1534 // have history state, then we need to navigate to it, which corresponds to a 1535 // back/forward navigation event. 1536 if (is_reload) { 1537 bool reload_original_url = 1538 (params.navigation_type == 1539 ViewMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL); 1540 bool ignore_cache = (params.navigation_type == 1541 ViewMsg_Navigate_Type::RELOAD_IGNORING_CACHE); 1542 1543 if (reload_original_url) 1544 frame->reloadWithOverrideURL(params.url, true); 1545 else 1546 frame->reload(ignore_cache); 1547 } else if (params.page_state.IsValid()) { 1548 // We must know the page ID of the page we are navigating back to. 1549 DCHECK_NE(params.page_id, -1); 1550 WebHistoryItem item = PageStateToHistoryItem(params.page_state); 1551 if (!item.isNull()) { 1552 // Ensure we didn't save the swapped out URL in UpdateState, since the 1553 // browser should never be telling us to navigate to swappedout://. 1554 CHECK(item.urlString() != WebString::fromUTF8(kSwappedOutURL)); 1555 frame->loadHistoryItem(item); 1556 } 1557 } else if (!params.base_url_for_data_url.is_empty()) { 1558 // A loadData request with a specified base URL. 1559 std::string mime_type, charset, data; 1560 if (net::DataURL::Parse(params.url, &mime_type, &charset, &data)) { 1561 frame->loadData( 1562 WebData(data.c_str(), data.length()), 1563 WebString::fromUTF8(mime_type), 1564 WebString::fromUTF8(charset), 1565 params.base_url_for_data_url, 1566 params.history_url_for_data_url, 1567 false); 1568 } else { 1569 CHECK(false) << 1570 "Invalid URL passed: " << params.url.possibly_invalid_spec(); 1571 } 1572 } else { 1573 // Navigate to the given URL. 1574 WebURLRequest request(params.url); 1575 1576 // A session history navigation should have been accompanied by state. 1577 CHECK_EQ(params.page_id, -1); 1578 1579 if (frame->isViewSourceModeEnabled()) 1580 request.setCachePolicy(WebURLRequest::ReturnCacheDataElseLoad); 1581 1582 if (params.referrer.url.is_valid()) { 1583 WebString referrer = WebSecurityPolicy::generateReferrerHeader( 1584 params.referrer.policy, 1585 params.url, 1586 WebString::fromUTF8(params.referrer.url.spec())); 1587 if (!referrer.isEmpty()) 1588 request.setHTTPHeaderField(WebString::fromUTF8("Referer"), referrer); 1589 } 1590 1591 if (!params.extra_headers.empty()) { 1592 for (net::HttpUtil::HeadersIterator i(params.extra_headers.begin(), 1593 params.extra_headers.end(), "\n"); 1594 i.GetNext(); ) { 1595 request.addHTTPHeaderField(WebString::fromUTF8(i.name()), 1596 WebString::fromUTF8(i.values())); 1597 } 1598 } 1599 1600 if (params.is_post) { 1601 request.setHTTPMethod(WebString::fromUTF8("POST")); 1602 1603 // Set post data. 1604 WebHTTPBody http_body; 1605 http_body.initialize(); 1606 http_body.appendData(WebData( 1607 reinterpret_cast<const char*>( 1608 ¶ms.browser_initiated_post_data.front()), 1609 params.browser_initiated_post_data.size())); 1610 request.setHTTPBody(http_body); 1611 } 1612 1613 frame->loadRequest(request); 1614 1615 // If this is a cross-process navigation, the browser process will send 1616 // along the proper navigation start value. 1617 if (!params.browser_navigation_start.is_null() && 1618 frame->provisionalDataSource()) { 1619 // browser_navigation_start is likely before this process existed, so we 1620 // can't use InterProcessTimeTicksConverter. Instead, the best we can do 1621 // is just ensure we don't report a bogus value in the future. 1622 base::TimeTicks navigation_start = std::min( 1623 base::TimeTicks::Now(), params.browser_navigation_start); 1624 double navigation_start_seconds = 1625 (navigation_start - base::TimeTicks()).InSecondsF(); 1626 frame->provisionalDataSource()->setNavigationStartTime( 1627 navigation_start_seconds); 1628 } 1629 } 1630 1631 // In case LoadRequest failed before DidCreateDataSource was called. 1632 pending_navigation_params_.reset(); 1633 } 1634 1635 bool RenderViewImpl::IsBackForwardToStaleEntry( 1636 const ViewMsg_Navigate_Params& params, 1637 bool is_reload) { 1638 // Make sure this isn't a back/forward to an entry we have already cropped 1639 // or replaced from our history, before the browser knew about it. If so, 1640 // a new navigation has committed in the mean time, and we can ignore this. 1641 bool is_back_forward = !is_reload && params.page_state.IsValid(); 1642 1643 // Note: if the history_list_length_ is 0 for a back/forward, we must be 1644 // restoring from a previous session. We'll update our state in OnNavigate. 1645 if (!is_back_forward || history_list_length_ <= 0) 1646 return false; 1647 1648 DCHECK_EQ(static_cast<int>(history_page_ids_.size()), history_list_length_); 1649 1650 // Check for whether the forward history has been cropped due to a recent 1651 // navigation the browser didn't know about. 1652 if (params.pending_history_list_offset >= history_list_length_) 1653 return true; 1654 1655 // Check for whether this entry has been replaced with a new one. 1656 int expected_page_id = 1657 history_page_ids_[params.pending_history_list_offset]; 1658 if (expected_page_id > 0 && params.page_id != expected_page_id) { 1659 if (params.page_id < expected_page_id) 1660 return true; 1661 1662 // Otherwise we've removed an earlier entry and should have shifted all 1663 // entries left. For now, it's ok to lazily update the list. 1664 // TODO(creis): Notify all live renderers when we remove entries from 1665 // the front of the list, so that we don't hit this case. 1666 history_page_ids_[params.pending_history_list_offset] = params.page_id; 1667 } 1668 1669 return false; 1670 } 1671 1672 // Stop loading the current page 1673 void RenderViewImpl::OnStop() { 1674 if (webview()) { 1675 WebFrame* main_frame = webview()->mainFrame(); 1676 // Stop the alt error page fetcher. If we let it continue it may complete 1677 // and cause RenderViewHostManager to swap to this RenderView, even though 1678 // it may no longer be active. 1679 StopAltErrorPageFetcher(main_frame->provisionalDataSource()); 1680 StopAltErrorPageFetcher(main_frame->dataSource()); 1681 main_frame->stopLoading(); 1682 } 1683 } 1684 1685 // Reload current focused frame. 1686 // E.g. called by right-clicking on the frame and picking "reload this frame". 1687 void RenderViewImpl::OnReloadFrame() { 1688 if (webview() && webview()->focusedFrame()) { 1689 // We always obey the cache (ignore_cache=false) here. 1690 // TODO(evanm): perhaps we could allow shift-clicking the menu item to do 1691 // a cache-ignoring reload of the frame. 1692 webview()->focusedFrame()->reload(false); 1693 } 1694 } 1695 1696 void RenderViewImpl::OnCopyImageAt(int x, int y) { 1697 webview()->copyImageAt(WebPoint(x, y)); 1698 } 1699 1700 void RenderViewImpl::OnUpdateTargetURLAck() { 1701 // Check if there is a targeturl waiting to be sent. 1702 if (target_url_status_ == TARGET_PENDING) { 1703 Send(new ViewHostMsg_UpdateTargetURL(routing_id_, page_id_, 1704 pending_target_url_)); 1705 } 1706 1707 target_url_status_ = TARGET_NONE; 1708 } 1709 1710 void RenderViewImpl::OnCopy() { 1711 if (!webview()) 1712 return; 1713 1714 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1715 WebNode current_node = context_menu_node_.isNull() ? 1716 GetFocusedNode() : context_menu_node_; 1717 webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Copy"), 1718 current_node); 1719 } 1720 1721 void RenderViewImpl::OnCut() { 1722 if (!webview()) 1723 return; 1724 1725 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1726 webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Cut"), 1727 GetFocusedNode()); 1728 } 1729 1730 void RenderViewImpl::OnDelete() { 1731 if (!webview()) 1732 return; 1733 1734 webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Delete"), 1735 GetFocusedNode()); 1736 } 1737 1738 void RenderViewImpl::OnExecuteEditCommand(const std::string& name, 1739 const std::string& value) { 1740 if (!webview() || !webview()->focusedFrame()) 1741 return; 1742 1743 webview()->focusedFrame()->executeCommand( 1744 WebString::fromUTF8(name), WebString::fromUTF8(value)); 1745 } 1746 1747 void RenderViewImpl::OnMoveCaret(const gfx::Point& point) { 1748 if (!webview()) 1749 return; 1750 1751 Send(new ViewHostMsg_MoveCaret_ACK(routing_id_)); 1752 1753 webview()->focusedFrame()->moveCaretSelectionTowardsWindowPoint(point); 1754 } 1755 1756 void RenderViewImpl::OnPaste() { 1757 if (!webview()) 1758 return; 1759 1760 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1761 webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Paste"), 1762 GetFocusedNode()); 1763 } 1764 1765 void RenderViewImpl::OnPasteAndMatchStyle() { 1766 if (!webview()) 1767 return; 1768 1769 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1770 webview()->focusedFrame()->executeCommand( 1771 WebString::fromUTF8("PasteAndMatchStyle"), GetFocusedNode()); 1772 } 1773 1774 void RenderViewImpl::OnRedo() { 1775 if (!webview()) 1776 return; 1777 1778 webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Redo"), 1779 GetFocusedNode()); 1780 } 1781 1782 void RenderViewImpl::OnReplace(const string16& text) { 1783 if (!webview()) 1784 return; 1785 1786 WebFrame* frame = webview()->focusedFrame(); 1787 if (!frame->hasSelection()) 1788 frame->selectWordAroundCaret(); 1789 1790 frame->replaceSelection(text); 1791 } 1792 1793 void RenderViewImpl::OnReplaceMisspelling(const string16& text) { 1794 if (!webview()) 1795 return; 1796 1797 WebFrame* frame = webview()->focusedFrame(); 1798 if (!frame->hasSelection()) 1799 return; 1800 1801 frame->replaceMisspelledRange(text); 1802 } 1803 1804 void RenderViewImpl::OnScrollFocusedEditableNodeIntoRect( 1805 const gfx::Rect& rect) { 1806 WebKit::WebNode node = GetFocusedNode(); 1807 if (!node.isNull()) { 1808 if (IsEditableNode(node)) { 1809 webview()->saveScrollAndScaleState(); 1810 webview()->scrollFocusedNodeIntoRect(rect); 1811 } 1812 } 1813 } 1814 1815 void RenderViewImpl::OnSelectAll() { 1816 if (!webview()) 1817 return; 1818 1819 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1820 webview()->focusedFrame()->executeCommand( 1821 WebString::fromUTF8("SelectAll"), GetFocusedNode()); 1822 } 1823 1824 void RenderViewImpl::OnSelectRange(const gfx::Point& start, 1825 const gfx::Point& end) { 1826 if (!webview()) 1827 return; 1828 1829 Send(new ViewHostMsg_SelectRange_ACK(routing_id_)); 1830 1831 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1832 webview()->focusedFrame()->selectRange(start, end); 1833 } 1834 1835 void RenderViewImpl::OnSetEditCommandsForNextKeyEvent( 1836 const EditCommands& edit_commands) { 1837 edit_commands_ = edit_commands; 1838 } 1839 1840 void RenderViewImpl::OnUndo() { 1841 if (!webview()) 1842 return; 1843 1844 webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Undo"), 1845 GetFocusedNode()); 1846 } 1847 1848 void RenderViewImpl::OnUnselect() { 1849 if (!webview()) 1850 return; 1851 1852 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1853 webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Unselect"), 1854 GetFocusedNode()); 1855 } 1856 1857 #if defined(OS_MACOSX) 1858 void RenderViewImpl::OnCopyToFindPboard() { 1859 if (!webview()) 1860 return; 1861 1862 // Since the find pasteboard supports only plain text, this can be simpler 1863 // than the |OnCopy()| case. 1864 WebFrame* frame = webview()->focusedFrame(); 1865 if (frame->hasSelection()) { 1866 string16 selection = frame->selectionAsText(); 1867 RenderThread::Get()->Send( 1868 new ClipboardHostMsg_FindPboardWriteStringAsync(selection)); 1869 } 1870 } 1871 #endif 1872 1873 void RenderViewImpl::OnSetName(const std::string& name) { 1874 if (!webview()) 1875 return; 1876 1877 webview()->mainFrame()->setName(WebString::fromUTF8(name)); 1878 } 1879 1880 void RenderViewImpl::OnSetEditableSelectionOffsets(int start, int end) { 1881 base::AutoReset<bool> handling_select_range(&handling_select_range_, true); 1882 if (!ShouldHandleImeEvent()) 1883 return; 1884 ImeEventGuard guard(this); 1885 webview()->setEditableSelectionOffsets(start, end); 1886 } 1887 1888 void RenderViewImpl::OnSetCompositionFromExistingText( 1889 int start, int end, 1890 const std::vector<WebKit::WebCompositionUnderline>& underlines) { 1891 if (!ShouldHandleImeEvent()) 1892 return; 1893 ImeEventGuard guard(this); 1894 webview()->setCompositionFromExistingText(start, end, underlines); 1895 } 1896 1897 void RenderViewImpl::OnExtendSelectionAndDelete(int before, int after) { 1898 if (!ShouldHandleImeEvent()) 1899 return; 1900 ImeEventGuard guard(this); 1901 webview()->extendSelectionAndDelete(before, after); 1902 } 1903 1904 void RenderViewImpl::OnSetHistoryLengthAndPrune(int history_length, 1905 int32 minimum_page_id) { 1906 DCHECK_GE(history_length, 0); 1907 DCHECK(history_list_offset_ == history_list_length_ - 1); 1908 DCHECK_GE(minimum_page_id, -1); 1909 1910 // Generate the new list. 1911 std::vector<int32> new_history_page_ids(history_length, -1); 1912 for (size_t i = 0; i < history_page_ids_.size(); ++i) { 1913 if (minimum_page_id >= 0 && history_page_ids_[i] < minimum_page_id) 1914 continue; 1915 new_history_page_ids.push_back(history_page_ids_[i]); 1916 } 1917 new_history_page_ids.swap(history_page_ids_); 1918 1919 // Update indexes. 1920 history_list_length_ = history_page_ids_.size(); 1921 history_list_offset_ = history_list_length_ - 1; 1922 } 1923 1924 1925 void RenderViewImpl::OnSetInitialFocus(bool reverse) { 1926 if (!webview()) 1927 return; 1928 webview()->setInitialFocus(reverse); 1929 } 1930 1931 #if defined(OS_MACOSX) 1932 void RenderViewImpl::OnSetInLiveResize(bool in_live_resize) { 1933 if (!webview()) 1934 return; 1935 if (in_live_resize) 1936 webview()->willStartLiveResize(); 1937 else 1938 webview()->willEndLiveResize(); 1939 } 1940 #endif 1941 1942 #if defined(OS_ANDROID) 1943 void RenderViewImpl::OnUndoScrollFocusedEditableNodeIntoRect() { 1944 const WebNode node = GetFocusedNode(); 1945 if (!node.isNull() && IsEditableNode(node)) 1946 webview()->restoreScrollAndScaleState(); 1947 } 1948 1949 void RenderViewImpl::OnPauseVideo() { 1950 // Inform RendererMediaPlayerManager to release all video player resources. 1951 // If something is in progress the resource will not be freed, it will 1952 // only be freed once the tab is destroyed or if the user navigates away 1953 // via WebMediaPlayerAndroid::Destroy. 1954 media_player_manager_->ReleaseVideoResources(); 1955 } 1956 #endif 1957 1958 /////////////////////////////////////////////////////////////////////////////// 1959 1960 // Tell the embedding application that the URL of the active page has changed 1961 void RenderViewImpl::UpdateURL(WebFrame* frame) { 1962 WebDataSource* ds = frame->dataSource(); 1963 DCHECK(ds); 1964 1965 const WebURLRequest& request = ds->request(); 1966 const WebURLRequest& original_request = ds->originalRequest(); 1967 const WebURLResponse& response = ds->response(); 1968 1969 DocumentState* document_state = DocumentState::FromDataSource(ds); 1970 NavigationState* navigation_state = document_state->navigation_state(); 1971 InternalDocumentStateData* internal_data = 1972 InternalDocumentStateData::FromDocumentState(document_state); 1973 1974 ViewHostMsg_FrameNavigate_Params params; 1975 params.http_status_code = response.httpStatusCode(); 1976 params.is_post = false; 1977 params.post_id = -1; 1978 params.page_id = page_id_; 1979 params.frame_id = frame->identifier(); 1980 params.socket_address.set_host(response.remoteIPAddress().utf8()); 1981 params.socket_address.set_port(response.remotePort()); 1982 WebURLResponseExtraDataImpl* extra_data = GetExtraDataFromResponse(response); 1983 if (extra_data) { 1984 params.was_fetched_via_proxy = extra_data->was_fetched_via_proxy(); 1985 } 1986 params.was_within_same_page = navigation_state->was_within_same_page(); 1987 params.security_info = response.securityInfo(); 1988 1989 // Set the URL to be displayed in the browser UI to the user. 1990 params.url = GetLoadingUrl(frame); 1991 DCHECK(!is_swapped_out_ || params.url == GURL(kSwappedOutURL)); 1992 1993 if (frame->document().baseURL() != params.url) 1994 params.base_url = frame->document().baseURL(); 1995 1996 GetRedirectChain(ds, ¶ms.redirects); 1997 params.should_update_history = !ds->hasUnreachableURL() && 1998 !response.isMultipartPayload() && (response.httpStatusCode() != 404); 1999 2000 params.searchable_form_url = internal_data->searchable_form_url(); 2001 params.searchable_form_encoding = internal_data->searchable_form_encoding(); 2002 2003 const PasswordForm* password_form_data = document_state->password_form_data(); 2004 if (password_form_data) 2005 params.password_form = *password_form_data; 2006 2007 params.gesture = navigation_gesture_; 2008 navigation_gesture_ = NavigationGestureUnknown; 2009 2010 // Make navigation state a part of the FrameNavigate message so that commited 2011 // entry had it at all times. 2012 WebHistoryItem item = frame->currentHistoryItem(); 2013 if (item.isNull()) { 2014 item.initialize(); 2015 item.setURLString(request.url().spec().utf16()); 2016 } 2017 params.page_state = HistoryItemToPageState(item); 2018 2019 if (!frame->parent()) { 2020 // Top-level navigation. 2021 2022 // Reset the zoom limits in case a plugin had changed them previously. This 2023 // will also call us back which will cause us to send a message to 2024 // update WebContentsImpl. 2025 webview()->zoomLimitsChanged(ZoomFactorToZoomLevel(kMinimumZoomFactor), 2026 ZoomFactorToZoomLevel(kMaximumZoomFactor)); 2027 2028 // Set zoom level, but don't do it for full-page plugin since they don't use 2029 // the same zoom settings. 2030 HostZoomLevels::iterator host_zoom = 2031 host_zoom_levels_.find(GURL(request.url())); 2032 if (webview()->mainFrame()->document().isPluginDocument()) { 2033 // Reset the zoom levels for plugins. 2034 webview()->setZoomLevel(false, 0); 2035 } else { 2036 if (host_zoom != host_zoom_levels_.end()) 2037 webview()->setZoomLevel(false, host_zoom->second); 2038 } 2039 2040 if (host_zoom != host_zoom_levels_.end()) { 2041 // This zoom level was merely recorded transiently for this load. We can 2042 // erase it now. If at some point we reload this page, the browser will 2043 // send us a new, up-to-date zoom level. 2044 host_zoom_levels_.erase(host_zoom); 2045 } 2046 2047 // Update contents MIME type for main frame. 2048 params.contents_mime_type = ds->response().mimeType().utf8(); 2049 2050 params.transition = navigation_state->transition_type(); 2051 if (!PageTransitionIsMainFrame(params.transition)) { 2052 // If the main frame does a load, it should not be reported as a subframe 2053 // navigation. This can occur in the following case: 2054 // 1. You're on a site with frames. 2055 // 2. You do a subframe navigation. This is stored with transition type 2056 // MANUAL_SUBFRAME. 2057 // 3. You navigate to some non-frame site, say, google.com. 2058 // 4. You navigate back to the page from step 2. Since it was initially 2059 // MANUAL_SUBFRAME, it will be that same transition type here. 2060 // We don't want that, because any navigation that changes the toplevel 2061 // frame should be tracked as a toplevel navigation (this allows us to 2062 // update the URL bar, etc). 2063 params.transition = PAGE_TRANSITION_LINK; 2064 } 2065 2066 // If the page contained a client redirect (meta refresh, document.loc...), 2067 // set the referrer and transition appropriately. 2068 if (ds->isClientRedirect()) { 2069 params.referrer = Referrer(params.redirects[0], 2070 GetReferrerPolicyFromRequest(frame, ds->request())); 2071 params.transition = static_cast<PageTransition>( 2072 params.transition | PAGE_TRANSITION_CLIENT_REDIRECT); 2073 } else { 2074 // Bug 654101: the referrer will be empty on https->http transitions. It 2075 // would be nice if we could get the real referrer from somewhere. 2076 params.referrer = GetReferrerFromRequest(frame, original_request); 2077 } 2078 2079 string16 method = request.httpMethod(); 2080 if (EqualsASCII(method, "POST")) { 2081 params.is_post = true; 2082 params.post_id = ExtractPostId(item); 2083 } 2084 2085 // Send the user agent override back. 2086 params.is_overriding_user_agent = internal_data->is_overriding_user_agent(); 2087 2088 // Track the URL of the original request. 2089 params.original_request_url = original_request.url(); 2090 2091 params.history_list_was_cleared = 2092 navigation_state->history_list_was_cleared(); 2093 2094 // Save some histogram data so we can compute the average memory used per 2095 // page load of the glyphs. 2096 UMA_HISTOGRAM_COUNTS_10000("Memory.GlyphPagesPerLoad", 2097 WebKit::WebGlyphCache::pageCount()); 2098 2099 // This message needs to be sent before any of allowScripts(), 2100 // allowImages(), allowPlugins() is called for the new page, so that when 2101 // these functions send a ViewHostMsg_ContentBlocked message, it arrives 2102 // after the ViewHostMsg_FrameNavigate message. 2103 Send(new ViewHostMsg_FrameNavigate(routing_id_, params)); 2104 } else { 2105 // Subframe navigation: the type depends on whether this navigation 2106 // generated a new session history entry. When they do generate a session 2107 // history entry, it means the user initiated the navigation and we should 2108 // mark it as such. This test checks if this is the first time UpdateURL 2109 // has been called since WillNavigateToURL was called to initiate the load. 2110 if (page_id_ > last_page_id_sent_to_browser_) 2111 params.transition = PAGE_TRANSITION_MANUAL_SUBFRAME; 2112 else 2113 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME; 2114 2115 DCHECK(!navigation_state->history_list_was_cleared()); 2116 params.history_list_was_cleared = false; 2117 2118 Send(new ViewHostMsg_FrameNavigate(routing_id_, params)); 2119 } 2120 2121 last_page_id_sent_to_browser_ = 2122 std::max(last_page_id_sent_to_browser_, page_id_); 2123 2124 // If we end up reusing this WebRequest (for example, due to a #ref click), 2125 // we don't want the transition type to persist. Just clear it. 2126 navigation_state->set_transition_type(PAGE_TRANSITION_LINK); 2127 } 2128 2129 // Tell the embedding application that the title of the active page has changed 2130 void RenderViewImpl::UpdateTitle(WebFrame* frame, 2131 const string16& title, 2132 WebTextDirection title_direction) { 2133 // Ignore all but top level navigations. 2134 if (frame->parent()) 2135 return; 2136 2137 base::debug::TraceLog::GetInstance()->UpdateProcessLabel( 2138 routing_id_, UTF16ToUTF8(title)); 2139 2140 string16 shortened_title = title.substr(0, kMaxTitleChars); 2141 Send(new ViewHostMsg_UpdateTitle(routing_id_, page_id_, shortened_title, 2142 title_direction)); 2143 } 2144 2145 void RenderViewImpl::UpdateEncoding(WebFrame* frame, 2146 const std::string& encoding_name) { 2147 // Only update main frame's encoding_name. 2148 if (webview()->mainFrame() == frame && 2149 last_encoding_name_ != encoding_name) { 2150 // Save the encoding name for later comparing. 2151 last_encoding_name_ = encoding_name; 2152 2153 Send(new ViewHostMsg_UpdateEncoding(routing_id_, last_encoding_name_)); 2154 } 2155 } 2156 2157 // Sends the last committed session history state to the browser so it will be 2158 // saved before we navigate to a new page. This must be called *before* the 2159 // page ID has been updated so we know what it was. 2160 void RenderViewImpl::UpdateSessionHistory(WebFrame* frame) { 2161 // If we have a valid page ID at this point, then it corresponds to the page 2162 // we are navigating away from. Otherwise, this is the first navigation, so 2163 // there is no past session history to record. 2164 if (page_id_ == -1) 2165 return; 2166 2167 const WebHistoryItem& item = 2168 webview()->mainFrame()->previousHistoryItem(); 2169 SendUpdateState(item); 2170 } 2171 2172 void RenderViewImpl::SendUpdateState(const WebHistoryItem& item) { 2173 if (item.isNull()) 2174 return; 2175 2176 // Don't send state updates for kSwappedOutURL. 2177 if (item.urlString() == WebString::fromUTF8(kSwappedOutURL)) 2178 return; 2179 2180 Send(new ViewHostMsg_UpdateState( 2181 routing_id_, page_id_, HistoryItemToPageState(item))); 2182 } 2183 2184 void RenderViewImpl::OpenURL(WebFrame* frame, 2185 const GURL& url, 2186 const Referrer& referrer, 2187 WebNavigationPolicy policy) { 2188 ViewHostMsg_OpenURL_Params params; 2189 params.url = url; 2190 params.referrer = referrer; 2191 params.disposition = NavigationPolicyToDisposition(policy); 2192 params.frame_id = frame->identifier(); 2193 WebDataSource* ds = frame->provisionalDataSource(); 2194 if (ds) { 2195 params.should_replace_current_entry = ds->replacesCurrentHistoryItem(); 2196 } else { 2197 params.should_replace_current_entry = false; 2198 } 2199 params.user_gesture = WebUserGestureIndicator::isProcessingUserGesture(); 2200 if (GetContentClient()->renderer()->AllowPopup()) 2201 params.user_gesture = true; 2202 2203 if (policy == WebKit::WebNavigationPolicyNewBackgroundTab || 2204 policy == WebKit::WebNavigationPolicyNewForegroundTab || 2205 policy == WebKit::WebNavigationPolicyNewWindow || 2206 policy == WebKit::WebNavigationPolicyNewPopup) { 2207 WebUserGestureIndicator::consumeUserGesture(); 2208 } 2209 2210 Send(new ViewHostMsg_OpenURL(routing_id_, params)); 2211 } 2212 2213 // WebViewDelegate ------------------------------------------------------------ 2214 2215 void RenderViewImpl::LoadNavigationErrorPage( 2216 WebFrame* frame, 2217 const WebURLRequest& failed_request, 2218 const WebURLError& error, 2219 const std::string& html, 2220 bool replace) { 2221 std::string alt_html; 2222 const std::string* error_html; 2223 2224 if (!html.empty()) { 2225 error_html = &html; 2226 } else { 2227 GetContentClient()->renderer()->GetNavigationErrorStrings( 2228 frame, failed_request, error, &alt_html, NULL); 2229 error_html = &alt_html; 2230 } 2231 2232 frame->loadHTMLString(*error_html, 2233 GURL(kUnreachableWebDataURL), 2234 error.unreachableURL, 2235 replace); 2236 } 2237 2238 bool RenderViewImpl::RunJavaScriptMessage(JavaScriptMessageType type, 2239 const string16& message, 2240 const string16& default_value, 2241 const GURL& frame_url, 2242 string16* result) { 2243 bool success = false; 2244 string16 result_temp; 2245 if (!result) 2246 result = &result_temp; 2247 2248 SendAndRunNestedMessageLoop(new ViewHostMsg_RunJavaScriptMessage( 2249 routing_id_, message, default_value, frame_url, type, &success, result)); 2250 return success; 2251 } 2252 2253 bool RenderViewImpl::SendAndRunNestedMessageLoop(IPC::SyncMessage* message) { 2254 // Before WebKit asks us to show an alert (etc.), it takes care of doing the 2255 // equivalent of WebView::willEnterModalLoop. In the case of showModalDialog 2256 // it is particularly important that we do not call willEnterModalLoop as 2257 // that would defer resource loads for the dialog itself. 2258 if (RenderThreadImpl::current()) // Will be NULL during unit tests. 2259 RenderThreadImpl::current()->DoNotNotifyWebKitOfModalLoop(); 2260 2261 message->EnableMessagePumping(); // Runs a nested message loop. 2262 return Send(message); 2263 } 2264 2265 void RenderViewImpl::GetWindowSnapshot(const WindowSnapshotCallback& callback) { 2266 int id = next_snapshot_id_++; 2267 pending_snapshots_.insert(std::make_pair(id, callback)); 2268 Send(new ViewHostMsg_GetWindowSnapshot(routing_id_, id)); 2269 } 2270 2271 void RenderViewImpl::OnWindowSnapshotCompleted(const int snapshot_id, 2272 const gfx::Size& size, const std::vector<unsigned char>& png) { 2273 PendingSnapshotMap::iterator it = pending_snapshots_.find(snapshot_id); 2274 DCHECK(it != pending_snapshots_.end()); 2275 it->second.Run(size, png); 2276 pending_snapshots_.erase(it); 2277 } 2278 2279 // WebKit::WebViewClient ------------------------------------------------------ 2280 2281 WebView* RenderViewImpl::createView( 2282 WebFrame* creator, 2283 const WebURLRequest& request, 2284 const WebWindowFeatures& features, 2285 const WebString& frame_name, 2286 WebNavigationPolicy policy) { 2287 // Check to make sure we aren't overloading on popups. 2288 if (shared_popup_counter_->data > kMaximumNumberOfUnacknowledgedPopups) 2289 return NULL; 2290 2291 ViewHostMsg_CreateWindow_Params params; 2292 params.opener_id = routing_id_; 2293 params.user_gesture = WebUserGestureIndicator::isProcessingUserGesture(); 2294 if (GetContentClient()->renderer()->AllowPopup()) 2295 params.user_gesture = true; 2296 params.window_container_type = WindowFeaturesToContainerType(features); 2297 params.session_storage_namespace_id = session_storage_namespace_id_; 2298 if (frame_name != "_blank") 2299 params.frame_name = frame_name; 2300 params.opener_frame_id = creator->identifier(); 2301 params.opener_url = creator->document().url(); 2302 params.opener_top_level_frame_url = creator->top()->document().url(); 2303 GURL security_url(creator->document().securityOrigin().toString().utf8()); 2304 if (!security_url.is_valid()) 2305 security_url = GURL(); 2306 params.opener_security_origin = security_url; 2307 params.opener_suppressed = creator->willSuppressOpenerInNewFrame(); 2308 params.disposition = NavigationPolicyToDisposition(policy); 2309 if (!request.isNull()) { 2310 params.target_url = request.url(); 2311 params.referrer = GetReferrerFromRequest(creator, request); 2312 } 2313 params.features = features; 2314 2315 int32 routing_id = MSG_ROUTING_NONE; 2316 int32 main_frame_routing_id = MSG_ROUTING_NONE; 2317 int32 surface_id = 0; 2318 int64 cloned_session_storage_namespace_id; 2319 2320 RenderThread::Get()->Send( 2321 new ViewHostMsg_CreateWindow(params, 2322 &routing_id, 2323 &main_frame_routing_id, 2324 &surface_id, 2325 &cloned_session_storage_namespace_id)); 2326 if (routing_id == MSG_ROUTING_NONE) 2327 return NULL; 2328 2329 WebUserGestureIndicator::consumeUserGesture(); 2330 2331 WebPreferences transferred_preferences = webkit_preferences_; 2332 2333 // Unless accelerated compositing has been explicitly disabled from the 2334 // command line (e.g. via the blacklist or about:flags) re-enable it for 2335 // new views that get spawned by this view. This gets around the issue that 2336 // background extension pages disable accelerated compositing via web prefs 2337 // but can themselves spawn a visible render view which should be allowed 2338 // use gpu acceleration. 2339 if (!webkit_preferences_.accelerated_compositing_enabled) { 2340 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 2341 if (!command_line.HasSwitch(switches::kDisableAcceleratedCompositing)) 2342 transferred_preferences.accelerated_compositing_enabled = true; 2343 } 2344 2345 RenderViewImpl* view = RenderViewImpl::Create( 2346 routing_id_, 2347 renderer_preferences_, 2348 transferred_preferences, 2349 shared_popup_counter_.get(), 2350 routing_id, 2351 main_frame_routing_id, 2352 surface_id, 2353 cloned_session_storage_namespace_id, 2354 string16(), // WebCore will take care of setting the correct name. 2355 true, 2356 false, 2357 1, 2358 screen_info_, 2359 accessibility_mode_, 2360 allow_partial_swap_); 2361 view->opened_by_user_gesture_ = params.user_gesture; 2362 2363 // Record whether the creator frame is trying to suppress the opener field. 2364 view->opener_suppressed_ = params.opener_suppressed; 2365 2366 // Copy over the alternate error page URL so we can have alt error pages in 2367 // the new render view (we don't need the browser to send the URL back down). 2368 view->alternate_error_page_url_ = alternate_error_page_url_; 2369 2370 return view->webview(); 2371 } 2372 2373 WebWidget* RenderViewImpl::createPopupMenu(WebKit::WebPopupType popup_type) { 2374 RenderWidget* widget = 2375 RenderWidget::Create(routing_id_, popup_type, screen_info_); 2376 return widget->webwidget(); 2377 } 2378 2379 WebExternalPopupMenu* RenderViewImpl::createExternalPopupMenu( 2380 const WebPopupMenuInfo& popup_menu_info, 2381 WebExternalPopupMenuClient* popup_menu_client) { 2382 // An IPC message is sent to the browser to build and display the actual 2383 // popup. The user could have time to click a different select by the time 2384 // the popup is shown. In that case external_popup_menu_ is non NULL. 2385 // By returning NULL in that case, we instruct WebKit to cancel that new 2386 // popup. So from the user perspective, only the first one will show, and 2387 // will have to close the first one before another one can be shown. 2388 if (external_popup_menu_) 2389 return NULL; 2390 external_popup_menu_.reset( 2391 new ExternalPopupMenu(this, popup_menu_info, popup_menu_client)); 2392 return external_popup_menu_.get(); 2393 } 2394 2395 WebStorageNamespace* RenderViewImpl::createSessionStorageNamespace() { 2396 CHECK(session_storage_namespace_id_ != kInvalidSessionStorageNamespaceId); 2397 return new WebStorageNamespaceImpl(session_storage_namespace_id_); 2398 } 2399 2400 void RenderViewImpl::didAddMessageToConsole( 2401 const WebConsoleMessage& message, const WebString& source_name, 2402 unsigned source_line) { 2403 logging::LogSeverity log_severity = logging::LOG_VERBOSE; 2404 switch (message.level) { 2405 case WebConsoleMessage::LevelDebug: 2406 log_severity = logging::LOG_VERBOSE; 2407 break; 2408 case WebConsoleMessage::LevelLog: 2409 log_severity = logging::LOG_INFO; 2410 break; 2411 case WebConsoleMessage::LevelWarning: 2412 log_severity = logging::LOG_WARNING; 2413 break; 2414 case WebConsoleMessage::LevelError: 2415 log_severity = logging::LOG_ERROR; 2416 break; 2417 default: 2418 NOTREACHED(); 2419 } 2420 2421 Send(new ViewHostMsg_AddMessageToConsole(routing_id_, 2422 static_cast<int32>(log_severity), 2423 message.text, 2424 static_cast<int32>(source_line), 2425 source_name)); 2426 } 2427 2428 void RenderViewImpl::printPage(WebFrame* frame) { 2429 FOR_EACH_OBSERVER(RenderViewObserver, observers_, 2430 PrintPage(frame, handling_input_event_)); 2431 } 2432 2433 WebKit::WebNotificationPresenter* RenderViewImpl::notificationPresenter() { 2434 return notification_provider_; 2435 } 2436 2437 bool RenderViewImpl::enumerateChosenDirectory( 2438 const WebString& path, 2439 WebFileChooserCompletion* chooser_completion) { 2440 int id = enumeration_completion_id_++; 2441 enumeration_completions_[id] = chooser_completion; 2442 return Send(new ViewHostMsg_EnumerateDirectory( 2443 routing_id_, 2444 id, 2445 base::FilePath::FromUTF16Unsafe(path))); 2446 } 2447 2448 void RenderViewImpl::initializeHelperPluginWebFrame( 2449 WebKit::WebHelperPlugin* plugin) { 2450 plugin->initializeFrame(main_render_frame_.get()); 2451 } 2452 2453 void RenderViewImpl::didStartLoading() { 2454 if (is_loading_) { 2455 DVLOG(1) << "didStartLoading called while loading"; 2456 return; 2457 } 2458 2459 is_loading_ = true; 2460 2461 Send(new ViewHostMsg_DidStartLoading(routing_id_)); 2462 2463 FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidStartLoading()); 2464 } 2465 2466 void RenderViewImpl::didStopLoading() { 2467 if (!is_loading_) { 2468 DVLOG(1) << "DidStopLoading called while not loading"; 2469 return; 2470 } 2471 2472 is_loading_ = false; 2473 2474 // NOTE: For now we're doing the safest thing, and sending out notification 2475 // when done loading. This currently isn't an issue as the favicon is only 2476 // displayed when done loading. Ideally we would send notification when 2477 // finished parsing the head, but webkit doesn't support that yet. 2478 // The feed discovery code would also benefit from access to the head. 2479 Send(new ViewHostMsg_DidStopLoading(routing_id_)); 2480 2481 if (load_progress_tracker_ != NULL) 2482 load_progress_tracker_->DidStopLoading(); 2483 2484 DidStopLoadingIcons(); 2485 2486 FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidStopLoading()); 2487 } 2488 2489 void RenderViewImpl::didChangeLoadProgress(WebFrame* frame, 2490 double load_progress) { 2491 if (load_progress_tracker_ != NULL) 2492 load_progress_tracker_->DidChangeLoadProgress(frame, load_progress); 2493 } 2494 2495 void RenderViewImpl::didCancelCompositionOnSelectionChange() { 2496 Send(new ViewHostMsg_ImeCancelComposition(routing_id())); 2497 } 2498 2499 void RenderViewImpl::didChangeSelection(bool is_empty_selection) { 2500 if (!handling_input_event_ && !handling_select_range_) 2501 return; 2502 2503 if (is_empty_selection) 2504 selection_text_.clear(); 2505 2506 SyncSelectionIfRequired(); 2507 UpdateTextInputType(); 2508 #if defined(OS_ANDROID) 2509 UpdateTextInputState(false, true); 2510 #endif 2511 } 2512 2513 void RenderViewImpl::didExecuteCommand(const WebString& command_name) { 2514 const std::string& name = UTF16ToUTF8(command_name); 2515 if (StartsWithASCII(name, "Move", true) || 2516 StartsWithASCII(name, "Insert", true) || 2517 StartsWithASCII(name, "Delete", true)) 2518 return; 2519 RenderThreadImpl::current()->RecordUserMetrics(name); 2520 } 2521 2522 bool RenderViewImpl::handleCurrentKeyboardEvent() { 2523 if (edit_commands_.empty()) 2524 return false; 2525 2526 WebFrame* frame = webview()->focusedFrame(); 2527 if (!frame) 2528 return false; 2529 2530 EditCommands::iterator it = edit_commands_.begin(); 2531 EditCommands::iterator end = edit_commands_.end(); 2532 2533 bool did_execute_command = false; 2534 for (; it != end; ++it) { 2535 // In gtk and cocoa, it's possible to bind multiple edit commands to one 2536 // key (but it's the exception). Once one edit command is not executed, it 2537 // seems safest to not execute the rest. 2538 if (!frame->executeCommand(WebString::fromUTF8(it->name), 2539 WebString::fromUTF8(it->value), 2540 GetFocusedNode())) 2541 break; 2542 did_execute_command = true; 2543 } 2544 2545 return did_execute_command; 2546 } 2547 2548 WebKit::WebColorChooser* RenderViewImpl::createColorChooser( 2549 WebKit::WebColorChooserClient* client, 2550 const WebKit::WebColor& initial_color) { 2551 RendererWebColorChooserImpl* color_chooser = 2552 new RendererWebColorChooserImpl(this, client); 2553 color_chooser->Open(static_cast<SkColor>(initial_color)); 2554 return color_chooser; 2555 } 2556 2557 bool RenderViewImpl::runFileChooser( 2558 const WebKit::WebFileChooserParams& params, 2559 WebFileChooserCompletion* chooser_completion) { 2560 // Do not open the file dialog in a hidden RenderView. 2561 if (is_hidden()) 2562 return false; 2563 FileChooserParams ipc_params; 2564 if (params.directory) 2565 ipc_params.mode = FileChooserParams::UploadFolder; 2566 else if (params.multiSelect) 2567 ipc_params.mode = FileChooserParams::OpenMultiple; 2568 else if (params.saveAs) 2569 ipc_params.mode = FileChooserParams::Save; 2570 else 2571 ipc_params.mode = FileChooserParams::Open; 2572 ipc_params.title = params.title; 2573 ipc_params.default_file_name = 2574 base::FilePath::FromUTF16Unsafe(params.initialValue); 2575 ipc_params.accept_types.reserve(params.acceptTypes.size()); 2576 for (size_t i = 0; i < params.acceptTypes.size(); ++i) 2577 ipc_params.accept_types.push_back(params.acceptTypes[i]); 2578 #if defined(OS_ANDROID) 2579 ipc_params.capture = params.useMediaCapture; 2580 #endif 2581 2582 return ScheduleFileChooser(ipc_params, chooser_completion); 2583 } 2584 2585 void RenderViewImpl::runModalAlertDialog(WebFrame* frame, 2586 const WebString& message) { 2587 RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_ALERT, 2588 message, 2589 string16(), 2590 frame->document().url(), 2591 NULL); 2592 } 2593 2594 bool RenderViewImpl::runModalConfirmDialog(WebFrame* frame, 2595 const WebString& message) { 2596 return RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_CONFIRM, 2597 message, 2598 string16(), 2599 frame->document().url(), 2600 NULL); 2601 } 2602 2603 bool RenderViewImpl::runModalPromptDialog(WebFrame* frame, 2604 const WebString& message, 2605 const WebString& default_value, 2606 WebString* actual_value) { 2607 string16 result; 2608 bool ok = RunJavaScriptMessage(JAVASCRIPT_MESSAGE_TYPE_PROMPT, 2609 message, 2610 default_value, 2611 frame->document().url(), 2612 &result); 2613 if (ok) 2614 actual_value->assign(result); 2615 return ok; 2616 } 2617 2618 bool RenderViewImpl::runModalBeforeUnloadDialog( 2619 WebFrame* frame, const WebString& message) { 2620 bool is_reload = false; 2621 WebDataSource* ds = frame->provisionalDataSource(); 2622 if (ds) 2623 is_reload = (ds->navigationType() == WebKit::WebNavigationTypeReload); 2624 return runModalBeforeUnloadDialog(frame, is_reload, message); 2625 } 2626 2627 bool RenderViewImpl::runModalBeforeUnloadDialog( 2628 WebFrame* frame, bool is_reload, const WebString& message) { 2629 // If we are swapping out, we have already run the beforeunload handler. 2630 // TODO(creis): Fix OnSwapOut to clear the frame without running beforeunload 2631 // at all, to avoid running it twice. 2632 if (is_swapped_out_) 2633 return true; 2634 2635 bool success = false; 2636 // This is an ignored return value, but is included so we can accept the same 2637 // response as RunJavaScriptMessage. 2638 string16 ignored_result; 2639 SendAndRunNestedMessageLoop(new ViewHostMsg_RunBeforeUnloadConfirm( 2640 routing_id_, frame->document().url(), message, is_reload, 2641 &success, &ignored_result)); 2642 return success; 2643 } 2644 2645 void RenderViewImpl::showContextMenu( 2646 WebFrame* frame, const WebContextMenuData& data) { 2647 ContextMenuParams params = ContextMenuParamsBuilder::Build(data); 2648 params.source_type = context_menu_source_type_; 2649 if (context_menu_source_type_ == ui::MENU_SOURCE_TOUCH_EDIT_MENU) { 2650 params.x = touch_editing_context_menu_location_.x(); 2651 params.y = touch_editing_context_menu_location_.y(); 2652 } 2653 2654 // Plugins, e.g. PDF, don't currently update the render view when their 2655 // selected text changes, but the context menu params do contain the updated 2656 // selection. If that's the case, update the render view's state just prior 2657 // to showing the context menu. 2658 // TODO(asvitkine): http://crbug.com/152432 2659 if (ShouldUpdateSelectionTextFromContextMenuParams(selection_text_, 2660 selection_text_offset_, 2661 selection_range_, 2662 params)) { 2663 selection_text_ = params.selection_text; 2664 // TODO(asvitkine): Text offset and range is not available in this case. 2665 selection_text_offset_ = 0; 2666 selection_range_ = ui::Range(0, selection_text_.length()); 2667 Send(new ViewHostMsg_SelectionChanged(routing_id_, 2668 selection_text_, 2669 selection_text_offset_, 2670 selection_range_)); 2671 } 2672 2673 // frame is NULL if invoked by BlockedPlugin. 2674 if (frame) 2675 params.frame_id = frame->identifier(); 2676 2677 // Serializing a GURL longer than kMaxURLChars will fail, so don't do 2678 // it. We replace it with an empty GURL so the appropriate items are disabled 2679 // in the context menu. 2680 // TODO(jcivelli): http://crbug.com/45160 This prevents us from saving large 2681 // data encoded images. We should have a way to save them. 2682 if (params.src_url.spec().size() > kMaxURLChars) 2683 params.src_url = GURL(); 2684 context_menu_node_ = data.node; 2685 2686 #if defined(OS_ANDROID) 2687 gfx::Rect start_rect; 2688 gfx::Rect end_rect; 2689 GetSelectionBounds(&start_rect, &end_rect); 2690 params.selection_start = gfx::Point(start_rect.x(), start_rect.bottom()); 2691 params.selection_end = gfx::Point(end_rect.right(), end_rect.bottom()); 2692 #endif 2693 2694 Send(new ViewHostMsg_ContextMenu(routing_id_, params)); 2695 2696 FOR_EACH_OBSERVER( 2697 RenderViewObserver, observers_, DidRequestShowContextMenu(frame, data)); 2698 } 2699 2700 void RenderViewImpl::setStatusText(const WebString& text) { 2701 } 2702 2703 void RenderViewImpl::UpdateTargetURL(const GURL& url, 2704 const GURL& fallback_url) { 2705 GURL latest_url = url.is_empty() ? fallback_url : url; 2706 if (latest_url == target_url_) 2707 return; 2708 2709 // Tell the browser to display a destination link. 2710 if (target_url_status_ == TARGET_INFLIGHT || 2711 target_url_status_ == TARGET_PENDING) { 2712 // If we have a request in-flight, save the URL to be sent when we 2713 // receive an ACK to the in-flight request. We can happily overwrite 2714 // any existing pending sends. 2715 pending_target_url_ = latest_url; 2716 target_url_status_ = TARGET_PENDING; 2717 } else { 2718 // URLs larger than |kMaxURLChars| cannot be sent through IPC - 2719 // see |ParamTraits<GURL>|. 2720 if (latest_url.possibly_invalid_spec().size() > kMaxURLChars) 2721 latest_url = GURL(); 2722 Send(new ViewHostMsg_UpdateTargetURL(routing_id_, page_id_, latest_url)); 2723 target_url_ = latest_url; 2724 target_url_status_ = TARGET_INFLIGHT; 2725 } 2726 } 2727 2728 gfx::RectF RenderViewImpl::ClientRectToPhysicalWindowRect( 2729 const gfx::RectF& rect) const { 2730 gfx::RectF window_rect = rect; 2731 window_rect.Scale(device_scale_factor_ * webview()->pageScaleFactor()); 2732 return window_rect; 2733 } 2734 2735 void RenderViewImpl::StartNavStateSyncTimerIfNecessary() { 2736 // No need to update state if no page has committed yet. 2737 if (page_id_ == -1) 2738 return; 2739 2740 int delay; 2741 if (send_content_state_immediately_) 2742 delay = 0; 2743 else if (is_hidden()) 2744 delay = kDelaySecondsForContentStateSyncHidden; 2745 else 2746 delay = kDelaySecondsForContentStateSync; 2747 2748 if (nav_state_sync_timer_.IsRunning()) { 2749 // The timer is already running. If the delay of the timer maches the amount 2750 // we want to delay by, then return. Otherwise stop the timer so that it 2751 // gets started with the right delay. 2752 if (nav_state_sync_timer_.GetCurrentDelay().InSeconds() == delay) 2753 return; 2754 nav_state_sync_timer_.Stop(); 2755 } 2756 2757 nav_state_sync_timer_.Start(FROM_HERE, TimeDelta::FromSeconds(delay), this, 2758 &RenderViewImpl::SyncNavigationState); 2759 } 2760 2761 void RenderViewImpl::setMouseOverURL(const WebURL& url) { 2762 mouse_over_url_ = GURL(url); 2763 UpdateTargetURL(mouse_over_url_, focus_url_); 2764 } 2765 2766 void RenderViewImpl::setKeyboardFocusURL(const WebURL& url) { 2767 focus_url_ = GURL(url); 2768 UpdateTargetURL(focus_url_, mouse_over_url_); 2769 } 2770 2771 void RenderViewImpl::startDragging(WebFrame* frame, 2772 const WebDragData& data, 2773 WebDragOperationsMask mask, 2774 const WebImage& image, 2775 const WebPoint& webImageOffset) { 2776 DropData drop_data(DropDataBuilder::Build(data)); 2777 drop_data.referrer_policy = frame->document().referrerPolicy(); 2778 gfx::Vector2d imageOffset(webImageOffset.x, webImageOffset.y); 2779 Send(new DragHostMsg_StartDragging(routing_id_, 2780 drop_data, 2781 mask, 2782 image.getSkBitmap(), 2783 imageOffset, 2784 possible_drag_event_info_)); 2785 } 2786 2787 bool RenderViewImpl::acceptsLoadDrops() { 2788 return renderer_preferences_.can_accept_load_drops; 2789 } 2790 2791 void RenderViewImpl::focusNext() { 2792 Send(new ViewHostMsg_TakeFocus(routing_id_, false)); 2793 } 2794 2795 void RenderViewImpl::focusPrevious() { 2796 Send(new ViewHostMsg_TakeFocus(routing_id_, true)); 2797 } 2798 2799 void RenderViewImpl::focusedNodeChanged(const WebNode& node) { 2800 Send(new ViewHostMsg_FocusedNodeChanged(routing_id_, IsEditableNode(node))); 2801 2802 FOR_EACH_OBSERVER(RenderViewObserver, observers_, FocusedNodeChanged(node)); 2803 } 2804 2805 void RenderViewImpl::numberOfWheelEventHandlersChanged(unsigned num_handlers) { 2806 Send(new ViewHostMsg_DidChangeNumWheelEvents(routing_id_, num_handlers)); 2807 } 2808 2809 void RenderViewImpl::didUpdateLayout() { 2810 FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidUpdateLayout()); 2811 2812 // We don't always want to set up a timer, only if we've been put in that 2813 // mode by getting a |ViewMsg_EnablePreferredSizeChangedMode| 2814 // message. 2815 if (!send_preferred_size_changes_ || !webview()) 2816 return; 2817 2818 if (check_preferred_size_timer_.IsRunning()) 2819 return; 2820 check_preferred_size_timer_.Start(FROM_HERE, 2821 TimeDelta::FromMilliseconds(0), this, 2822 &RenderViewImpl::CheckPreferredSize); 2823 } 2824 2825 void RenderViewImpl::navigateBackForwardSoon(int offset) { 2826 Send(new ViewHostMsg_GoToEntryAtOffset(routing_id_, offset)); 2827 } 2828 2829 int RenderViewImpl::historyBackListCount() { 2830 return history_list_offset_ < 0 ? 0 : history_list_offset_; 2831 } 2832 2833 int RenderViewImpl::historyForwardListCount() { 2834 return history_list_length_ - historyBackListCount() - 1; 2835 } 2836 2837 void RenderViewImpl::postAccessibilityNotification( 2838 const WebAccessibilityObject& obj, 2839 WebAccessibilityNotification notification) { 2840 if (renderer_accessibility_) { 2841 renderer_accessibility_->HandleWebAccessibilityNotification( 2842 obj, notification); 2843 } 2844 } 2845 2846 void RenderViewImpl::didUpdateInspectorSetting(const WebString& key, 2847 const WebString& value) { 2848 Send(new ViewHostMsg_UpdateInspectorSetting(routing_id_, 2849 key.utf8(), 2850 value.utf8())); 2851 } 2852 2853 // WebKit::WebWidgetClient ---------------------------------------------------- 2854 2855 void RenderViewImpl::didFocus() { 2856 // TODO(jcivelli): when https://bugs.webkit.org/show_bug.cgi?id=33389 is fixed 2857 // we won't have to test for user gesture anymore and we can 2858 // move that code back to render_widget.cc 2859 if (WebUserGestureIndicator::isProcessingUserGesture() && 2860 !RenderThreadImpl::current()->layout_test_mode()) { 2861 Send(new ViewHostMsg_Focus(routing_id_)); 2862 } 2863 } 2864 2865 void RenderViewImpl::didBlur() { 2866 // TODO(jcivelli): see TODO above in didFocus(). 2867 if (WebUserGestureIndicator::isProcessingUserGesture() && 2868 !RenderThreadImpl::current()->layout_test_mode()) { 2869 Send(new ViewHostMsg_Blur(routing_id_)); 2870 } 2871 } 2872 2873 // We are supposed to get a single call to Show for a newly created RenderView 2874 // that was created via RenderViewImpl::CreateWebView. So, we wait until this 2875 // point to dispatch the ShowView message. 2876 // 2877 // This method provides us with the information about how to display the newly 2878 // created RenderView (i.e., as a blocked popup or as a new tab). 2879 // 2880 void RenderViewImpl::show(WebNavigationPolicy policy) { 2881 if (did_show_) { 2882 // When supports_multiple_windows is disabled, popups are reusing 2883 // the same view. In some scenarios, this makes WebKit to call show() twice. 2884 if (webkit_preferences_.supports_multiple_windows) 2885 NOTREACHED() << "received extraneous Show call"; 2886 return; 2887 } 2888 did_show_ = true; 2889 2890 DCHECK(opener_id_ != MSG_ROUTING_NONE); 2891 2892 // Force new windows to a popup if they were not opened with a user gesture. 2893 if (!opened_by_user_gesture_) { 2894 // We exempt background tabs for compat with older versions of Chrome. 2895 // TODO(darin): This seems bogus. These should have a user gesture, so 2896 // we probably don't need this check. 2897 if (policy != WebKit::WebNavigationPolicyNewBackgroundTab) 2898 policy = WebKit::WebNavigationPolicyNewPopup; 2899 } 2900 2901 // NOTE: initial_pos_ may still have its default values at this point, but 2902 // that's okay. It'll be ignored if disposition is not NEW_POPUP, or the 2903 // browser process will impose a default position otherwise. 2904 Send(new ViewHostMsg_ShowView(opener_id_, routing_id_, 2905 NavigationPolicyToDisposition(policy), initial_pos_, 2906 opened_by_user_gesture_)); 2907 SetPendingWindowRect(initial_pos_); 2908 } 2909 2910 void RenderViewImpl::runModal() { 2911 DCHECK(did_show_) << "should already have shown the view"; 2912 2913 // We must keep WebKit's shared timer running in this case in order to allow 2914 // showModalDialog to function properly. 2915 // 2916 // TODO(darin): WebKit should really be smarter about suppressing events and 2917 // timers so that we do not need to manage the shared timer in such a heavy 2918 // handed manner. 2919 // 2920 if (RenderThreadImpl::current()) // Will be NULL during unit tests. 2921 RenderThreadImpl::current()->DoNotSuspendWebKitSharedTimer(); 2922 2923 SendAndRunNestedMessageLoop(new ViewHostMsg_RunModal( 2924 routing_id_, opener_id_)); 2925 } 2926 2927 bool RenderViewImpl::enterFullScreen() { 2928 Send(new ViewHostMsg_ToggleFullscreen(routing_id_, true)); 2929 return true; 2930 } 2931 2932 void RenderViewImpl::exitFullScreen() { 2933 Send(new ViewHostMsg_ToggleFullscreen(routing_id_, false)); 2934 } 2935 2936 bool RenderViewImpl::requestPointerLock() { 2937 return mouse_lock_dispatcher_->LockMouse(webwidget_mouse_lock_target_.get()); 2938 } 2939 2940 void RenderViewImpl::requestPointerUnlock() { 2941 mouse_lock_dispatcher_->UnlockMouse(webwidget_mouse_lock_target_.get()); 2942 } 2943 2944 bool RenderViewImpl::isPointerLocked() { 2945 return mouse_lock_dispatcher_->IsMouseLockedTo( 2946 webwidget_mouse_lock_target_.get()); 2947 } 2948 2949 void RenderViewImpl::didActivateCompositor(int input_handler_identifier) { 2950 #if !defined(OS_MACOSX) // many events are unhandled - http://crbug.com/138003 2951 InputHandlerManager* input_handler_manager = 2952 RenderThreadImpl::current()->input_handler_manager(); 2953 if (input_handler_manager) { 2954 input_handler_manager->AddInputHandler( 2955 routing_id_, 2956 compositor_->GetInputHandler(), 2957 AsWeakPtr()); 2958 } 2959 #endif 2960 2961 RenderWidget::didActivateCompositor(input_handler_identifier); 2962 } 2963 2964 void RenderViewImpl::didHandleGestureEvent( 2965 const WebGestureEvent& event, 2966 bool event_cancelled) { 2967 RenderWidget::didHandleGestureEvent(event, event_cancelled); 2968 FOR_EACH_OBSERVER(RenderViewObserver, observers_, 2969 DidHandleGestureEvent(event)); 2970 } 2971 2972 void RenderViewImpl::initializeLayerTreeView() { 2973 RenderWidget::initializeLayerTreeView(); 2974 RenderWidgetCompositor* rwc = compositor(); 2975 if (!rwc || !webview() || !webview()->devToolsAgent()) 2976 return; 2977 webview()->devToolsAgent()->setLayerTreeId(rwc->GetLayerTreeId()); 2978 } 2979 2980 // WebKit::WebFrameClient ----------------------------------------------------- 2981 2982 WebKit::WebPlugin* RenderViewImpl::createPlugin(WebFrame* frame, 2983 const WebPluginParams& params) { 2984 NOTREACHED(); 2985 return NULL; 2986 } 2987 2988 WebSharedWorker* RenderViewImpl::createSharedWorker( 2989 WebFrame* frame, const WebURL& url, const WebString& name, 2990 unsigned long long document_id) { 2991 NOTREACHED(); 2992 return NULL; 2993 } 2994 2995 WebMediaPlayer* RenderViewImpl::createMediaPlayer( 2996 WebFrame* frame, const WebKit::WebURL& url, WebMediaPlayerClient* client) { 2997 FOR_EACH_OBSERVER( 2998 RenderViewObserver, observers_, WillCreateMediaPlayer(frame, client)); 2999 3000 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 3001 #if defined(ENABLE_WEBRTC) 3002 EnsureMediaStreamClient(); 3003 #if !defined(GOOGLE_TV) 3004 if (media_stream_client_ && media_stream_client_->IsMediaStream(url)) { 3005 #if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL) 3006 bool found_neon = 3007 (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; 3008 UMA_HISTOGRAM_BOOLEAN("Platform.WebRtcNEONFound", found_neon); 3009 #endif // defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL) 3010 return new WebMediaPlayerMS( 3011 frame, client, AsWeakPtr(), media_stream_client_, new RenderMediaLog()); 3012 } 3013 #endif // !defined(GOOGLE_TV) 3014 #endif // defined(ENABLE_WEBRTC) 3015 3016 #if defined(OS_ANDROID) 3017 GpuChannelHost* gpu_channel_host = 3018 RenderThreadImpl::current()->EstablishGpuChannelSync( 3019 CAUSE_FOR_GPU_LAUNCH_VIDEODECODEACCELERATOR_INITIALIZE); 3020 if (!gpu_channel_host) { 3021 LOG(ERROR) << "Failed to establish GPU channel for media player"; 3022 return NULL; 3023 } 3024 3025 scoped_refptr<cc::ContextProvider> context_provider = 3026 RenderThreadImpl::current()->OffscreenContextProviderForMainThread(); 3027 scoped_ptr<StreamTextureFactory> stream_texture_factory; 3028 if (UsingSynchronousRendererCompositor()) { 3029 SynchronousCompositorFactory* factory = 3030 SynchronousCompositorFactory::GetInstance(); 3031 stream_texture_factory = factory->CreateStreamTextureFactory(routing_id_); 3032 } else { 3033 if (!context_provider.get()) { 3034 LOG(ERROR) << "Failed to get context3d for media player"; 3035 return NULL; 3036 } 3037 3038 stream_texture_factory.reset(new StreamTextureFactoryImpl( 3039 context_provider->Context3d(), gpu_channel_host, routing_id_)); 3040 } 3041 3042 if (!media_player_proxy_) { 3043 media_player_proxy_ = new WebMediaPlayerProxyAndroid( 3044 this, media_player_manager_.get()); 3045 } 3046 3047 scoped_ptr<WebMediaPlayerAndroid> web_media_player_android( 3048 new WebMediaPlayerAndroid( 3049 frame, 3050 client, 3051 AsWeakPtr(), 3052 media_player_manager_.get(), 3053 media_player_proxy_, 3054 stream_texture_factory.release(), 3055 RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy(), 3056 new RenderMediaLog())); 3057 #if defined(ENABLE_WEBRTC) && defined(GOOGLE_TV) 3058 if (media_stream_client_->IsMediaStream(url)) { 3059 RTCVideoDecoderFactoryTv* factory = RenderThreadImpl::current() 3060 ->GetMediaStreamDependencyFactory()->decoder_factory_tv(); 3061 // |media_stream_client| and |factory| outlives |web_media_player_android|. 3062 if (!factory->AcquireDemuxer() || 3063 !web_media_player_android->InjectMediaStream( 3064 media_stream_client_, 3065 factory, 3066 base::Bind( 3067 base::IgnoreResult(&RTCVideoDecoderFactoryTv::ReleaseDemuxer), 3068 base::Unretained(factory)))) { 3069 LOG(ERROR) << "Failed to inject media stream."; 3070 return NULL; 3071 } 3072 } 3073 #endif // defined(ENABLE_WEBRTC) && defined(GOOGLE_TV) 3074 return web_media_player_android.release(); 3075 #endif // defined(OS_ANDROID) 3076 3077 scoped_refptr<media::AudioRendererSink> sink; 3078 if (!cmd_line->HasSwitch(switches::kDisableAudio)) { 3079 sink = RenderThreadImpl::current()->GetAudioRendererMixerManager()-> 3080 CreateInput(routing_id_); 3081 DVLOG(1) << "Using AudioRendererMixerManager-provided sink: " << sink.get(); 3082 } 3083 3084 scoped_refptr<media::GpuVideoDecoderFactories> gpu_factories = 3085 RenderThreadImpl::current()->GetGpuFactories( 3086 RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy()); 3087 3088 WebMediaPlayerParams params( 3089 RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy(), 3090 base::Bind(&ContentRendererClient::DeferMediaLoad, 3091 base::Unretained(GetContentClient()->renderer()), 3092 static_cast<RenderView*>(this)), 3093 sink, 3094 gpu_factories, 3095 new RenderMediaLog()); 3096 return new WebMediaPlayerImpl(frame, client, AsWeakPtr(), params); 3097 } 3098 3099 WebApplicationCacheHost* RenderViewImpl::createApplicationCacheHost( 3100 WebFrame* frame, WebApplicationCacheHostClient* client) { 3101 NOTREACHED(); 3102 return NULL; 3103 } 3104 3105 WebCookieJar* RenderViewImpl::cookieJar(WebFrame* frame) { 3106 return &cookie_jar_; 3107 } 3108 3109 void RenderViewImpl::didAccessInitialDocument(WebFrame* frame) { 3110 // Notify the browser process that it is no longer safe to show the pending 3111 // URL of the main frame, since a URL spoof is now possible. 3112 if (!frame->parent() && page_id_ == -1) 3113 Send(new ViewHostMsg_DidAccessInitialDocument(routing_id_)); 3114 } 3115 3116 void RenderViewImpl::didCreateFrame(WebFrame* parent, WebFrame* child) { 3117 NOTREACHED(); 3118 } 3119 3120 void RenderViewImpl::didDisownOpener(WebKit::WebFrame* frame) { 3121 // We only need to notify the browser if the active, top-level frame clears 3122 // its opener. We can ignore cases where a swapped out frame clears its 3123 // opener after hearing about it from the browser, and the browser does not 3124 // (yet) care about subframe openers. 3125 if (is_swapped_out_ || frame->parent()) 3126 return; 3127 3128 // Notify WebContents and all its swapped out RenderViews. 3129 Send(new ViewHostMsg_DidDisownOpener(routing_id_)); 3130 } 3131 3132 void RenderViewImpl::frameDetached(WebFrame* frame) { 3133 FOR_EACH_OBSERVER(RenderViewObserver, observers_, FrameDetached(frame)); 3134 } 3135 3136 void RenderViewImpl::willClose(WebFrame* frame) { 3137 FOR_EACH_OBSERVER(RenderViewObserver, observers_, FrameWillClose(frame)); 3138 } 3139 3140 void RenderViewImpl::didChangeName(WebFrame* frame, 3141 const WebString& name) { 3142 NOTREACHED(); 3143 } 3144 3145 void RenderViewImpl::loadURLExternally( 3146 WebFrame* frame, const WebURLRequest& request, 3147 WebNavigationPolicy policy) { 3148 NOTREACHED(); 3149 } 3150 3151 void RenderViewImpl::Repaint(const gfx::Size& size) { 3152 OnRepaint(size); 3153 } 3154 3155 void RenderViewImpl::SetEditCommandForNextKeyEvent(const std::string& name, 3156 const std::string& value) { 3157 EditCommands edit_commands; 3158 edit_commands.push_back(EditCommand(name, value)); 3159 OnSetEditCommandsForNextKeyEvent(edit_commands); 3160 } 3161 3162 void RenderViewImpl::ClearEditCommands() { 3163 edit_commands_.clear(); 3164 } 3165 3166 SSLStatus RenderViewImpl::GetSSLStatusOfFrame(WebKit::WebFrame* frame) const { 3167 std::string security_info; 3168 if (frame && frame->dataSource()) 3169 security_info = frame->dataSource()->response().securityInfo(); 3170 3171 SSLStatus ssl_status; 3172 DeserializeSecurityInfo(security_info, 3173 &ssl_status.cert_id, 3174 &ssl_status.cert_status, 3175 &ssl_status.security_bits, 3176 &ssl_status.connection_status); 3177 return ssl_status; 3178 } 3179 3180 void RenderViewImpl::loadURLExternally( 3181 WebFrame* frame, const WebURLRequest& request, 3182 WebNavigationPolicy policy, 3183 const WebString& suggested_name) { 3184 NOTREACHED(); 3185 } 3186 3187 WebNavigationPolicy RenderViewImpl::decidePolicyForNavigation( 3188 WebFrame* frame, WebDataSource::ExtraData* extraData, 3189 const WebURLRequest& request, WebNavigationType type, 3190 WebNavigationPolicy default_policy, bool is_redirect) { 3191 if (request.url() != GURL(kSwappedOutURL) && 3192 GetContentClient()->renderer()->HandleNavigation( 3193 this, 3194 static_cast<DocumentState*>(extraData), 3195 opener_id_, 3196 frame, 3197 request, type, 3198 default_policy, 3199 is_redirect)) { 3200 return WebKit::WebNavigationPolicyIgnore; 3201 } 3202 3203 Referrer referrer(GetReferrerFromRequest(frame, request)); 3204 3205 if (is_swapped_out_) { 3206 if (request.url() != GURL(kSwappedOutURL)) { 3207 // Targeted links may try to navigate a swapped out frame. Allow the 3208 // browser process to navigate the tab instead. Note that it is also 3209 // possible for non-targeted navigations (from this view) to arrive 3210 // here just after we are swapped out. It's ok to send them to the 3211 // browser, as long as they're for the top level frame. 3212 // TODO(creis): Ensure this supports targeted form submissions when 3213 // fixing http://crbug.com/101395. 3214 if (frame->parent() == NULL) { 3215 OpenURL(frame, request.url(), referrer, default_policy); 3216 return WebKit::WebNavigationPolicyIgnore; // Suppress the load here. 3217 } 3218 3219 // We should otherwise ignore in-process iframe navigations, if they 3220 // arrive just after we are swapped out. 3221 return WebKit::WebNavigationPolicyIgnore; 3222 } 3223 3224 // Allow kSwappedOutURL to complete. 3225 return default_policy; 3226 } 3227 3228 // Webkit is asking whether to navigate to a new URL. 3229 // This is fine normally, except if we're showing UI from one security 3230 // context and they're trying to navigate to a different context. 3231 const GURL& url = request.url(); 3232 3233 // A content initiated navigation may have originated from a link-click, 3234 // script, drag-n-drop operation, etc. 3235 bool is_content_initiated = static_cast<DocumentState*>(extraData)-> 3236 navigation_state()->is_content_initiated(); 3237 3238 // Experimental: 3239 // If --enable-strict-site-isolation or --site-per-process is enabled, send 3240 // all top-level navigations to the browser to let it swap processes when 3241 // crossing site boundaries. This is currently expected to break some script 3242 // calls and navigations, such as form submissions. 3243 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 3244 bool force_swap_due_to_flag = 3245 command_line.HasSwitch(switches::kEnableStrictSiteIsolation) || 3246 command_line.HasSwitch(switches::kSitePerProcess); 3247 if (force_swap_due_to_flag && 3248 !frame->parent() && (is_content_initiated || is_redirect)) { 3249 WebString origin_str = frame->document().securityOrigin().toString(); 3250 GURL frame_url(origin_str.utf8().data()); 3251 // TODO(cevans): revisit whether this site check is still necessary once 3252 // crbug.com/101395 is fixed. 3253 bool same_domain_or_host = 3254 net::registry_controlled_domains::SameDomainOrHost( 3255 frame_url, 3256 url, 3257 net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); 3258 if (!same_domain_or_host || frame_url.scheme() != url.scheme()) { 3259 OpenURL(frame, url, referrer, default_policy); 3260 return WebKit::WebNavigationPolicyIgnore; 3261 } 3262 } 3263 3264 // If the browser is interested, then give it a chance to look at the request. 3265 if (is_content_initiated) { 3266 bool is_form_post = ((type == WebKit::WebNavigationTypeFormSubmitted) || 3267 (type == WebKit::WebNavigationTypeFormResubmitted)) && 3268 EqualsASCII(request.httpMethod(), "POST"); 3269 bool browser_handles_request = 3270 renderer_preferences_.browser_handles_non_local_top_level_requests && 3271 IsNonLocalTopLevelNavigation(url, frame, type, is_form_post); 3272 if (!browser_handles_request) { 3273 browser_handles_request = 3274 renderer_preferences_.browser_handles_all_top_level_requests && 3275 IsTopLevelNavigation(frame); 3276 } 3277 3278 if (browser_handles_request) { 3279 // Reset these counters as the RenderView could be reused for the next 3280 // navigation. 3281 page_id_ = -1; 3282 last_page_id_sent_to_browser_ = -1; 3283 OpenURL(frame, url, referrer, default_policy); 3284 return WebKit::WebNavigationPolicyIgnore; // Suppress the load here. 3285 } 3286 } 3287 3288 // Use the frame's original request's URL rather than the document's URL for 3289 // subsequent checks. For a popup, the document's URL may become the opener 3290 // window's URL if the opener has called document.write(). 3291 // See http://crbug.com/93517. 3292 GURL old_url(frame->dataSource()->request().url()); 3293 3294 // Detect when we're crossing a permission-based boundary (e.g. into or out of 3295 // an extension or app origin, leaving a WebUI page, etc). We only care about 3296 // top-level navigations (not iframes). But we sometimes navigate to 3297 // about:blank to clear a tab, and we want to still allow that. 3298 // 3299 // Note: this is known to break POST submissions when crossing process 3300 // boundaries until http://crbug.com/101395 is fixed. This is better for 3301 // security than loading a WebUI, extension or app page in the wrong process. 3302 // POST requests don't work because this mechanism does not preserve form 3303 // POST data. We will need to send the request's httpBody data up to the 3304 // browser process, and issue a special POST navigation in WebKit (via 3305 // FrameLoader::loadFrameRequest). See ResourceDispatcher and WebURLLoaderImpl 3306 // for examples of how to send the httpBody data. 3307 if (!frame->parent() && is_content_initiated && 3308 !url.SchemeIs(chrome::kAboutScheme)) { 3309 bool send_referrer = false; 3310 3311 // All navigations to or from WebUI URLs or within WebUI-enabled 3312 // RenderProcesses must be handled by the browser process so that the 3313 // correct bindings and data sources can be registered. 3314 // Similarly, navigations to view-source URLs or within ViewSource mode 3315 // must be handled by the browser process (except for reloads - those are 3316 // safe to leave within the renderer). 3317 // Lastly, access to file:// URLs from non-file:// URL pages must be 3318 // handled by the browser so that ordinary renderer processes don't get 3319 // blessed with file permissions. 3320 int cumulative_bindings = RenderProcess::current()->GetEnabledBindings(); 3321 bool is_initial_navigation = page_id_ == -1; 3322 bool should_fork = HasWebUIScheme(url) || HasWebUIScheme(old_url) || 3323 (cumulative_bindings & BINDINGS_POLICY_WEB_UI) || 3324 url.SchemeIs(kViewSourceScheme) || 3325 (frame->isViewSourceModeEnabled() && 3326 type != WebKit::WebNavigationTypeReload); 3327 3328 if (!should_fork && url.SchemeIs(chrome::kFileScheme)) { 3329 // Fork non-file to file opens. Check the opener URL if this is the 3330 // initial navigation in a newly opened window. 3331 GURL source_url(old_url); 3332 if (is_initial_navigation && source_url.is_empty() && frame->opener()) 3333 source_url = frame->opener()->top()->document().url(); 3334 DCHECK(!source_url.is_empty()); 3335 should_fork = !source_url.SchemeIs(chrome::kFileScheme); 3336 } 3337 3338 if (!should_fork) { 3339 // Give the embedder a chance. 3340 should_fork = GetContentClient()->renderer()->ShouldFork( 3341 frame, url, request.httpMethod().utf8(), is_initial_navigation, 3342 is_redirect, &send_referrer); 3343 } 3344 3345 if (should_fork) { 3346 OpenURL( 3347 frame, url, send_referrer ? referrer : Referrer(), default_policy); 3348 return WebKit::WebNavigationPolicyIgnore; // Suppress the load here. 3349 } 3350 } 3351 3352 // Detect when a page is "forking" a new tab that can be safely rendered in 3353 // its own process. This is done by sites like Gmail that try to open links 3354 // in new windows without script connections back to the original page. We 3355 // treat such cases as browser navigations (in which we will create a new 3356 // renderer for a cross-site navigation), rather than WebKit navigations. 3357 // 3358 // We use the following heuristic to decide whether to fork a new page in its 3359 // own process: 3360 // The parent page must open a new tab to about:blank, set the new tab's 3361 // window.opener to null, and then redirect the tab to a cross-site URL using 3362 // JavaScript. 3363 // 3364 // TODO(creis): Deprecate this logic once we can rely on rel=noreferrer 3365 // (see below). 3366 bool is_fork = 3367 // Must start from a tab showing about:blank, which is later redirected. 3368 old_url == GURL(kAboutBlankURL) && 3369 // Must be the first real navigation of the tab. 3370 historyBackListCount() < 1 && 3371 historyForwardListCount() < 1 && 3372 // The parent page must have set the child's window.opener to null before 3373 // redirecting to the desired URL. 3374 frame->opener() == NULL && 3375 // Must be a top-level frame. 3376 frame->parent() == NULL && 3377 // Must not have issued the request from this page. 3378 is_content_initiated && 3379 // Must be targeted at the current tab. 3380 default_policy == WebKit::WebNavigationPolicyCurrentTab && 3381 // Must be a JavaScript navigation, which appears as "other". 3382 type == WebKit::WebNavigationTypeOther; 3383 3384 if (is_fork) { 3385 // Open the URL via the browser, not via WebKit. 3386 OpenURL(frame, url, Referrer(), default_policy); 3387 return WebKit::WebNavigationPolicyIgnore; 3388 } 3389 3390 return default_policy; 3391 } 3392 3393 bool RenderViewImpl::shouldAbortNavigationAfterUrlResolve(const WebURL& base, 3394 const WebString& fragment, 3395 const WebURL& result) { 3396 return GetContentClient()->renderer()->ShouldAbortNavigationAfterUrlResolve( 3397 this, base, fragment, result); 3398 } 3399 3400 WebNavigationPolicy RenderViewImpl::decidePolicyForNavigation( 3401 WebFrame* frame, const WebURLRequest& request, WebNavigationType type, 3402 WebNavigationPolicy default_policy, bool is_redirect) { 3403 return decidePolicyForNavigation(frame, 3404 frame->provisionalDataSource()->extraData(), 3405 request, type, default_policy, is_redirect); 3406 } 3407 3408 void RenderViewImpl::willSendSubmitEvent(WebKit::WebFrame* frame, 3409 const WebKit::WebFormElement& form) { 3410 NOTREACHED(); 3411 } 3412 3413 void RenderViewImpl::willSubmitForm(WebFrame* frame, 3414 const WebFormElement& form) { 3415 FOR_EACH_OBSERVER( 3416 RenderViewObserver, observers_, WillSubmitForm(frame, form)); 3417 } 3418 3419 void RenderViewImpl::didCreateDataSource(WebFrame* frame, WebDataSource* ds) { 3420 bool content_initiated = !pending_navigation_params_.get(); 3421 3422 DocumentState* document_state = DocumentState::FromDataSource(ds); 3423 if (!document_state) { 3424 document_state = new DocumentState; 3425 ds->setExtraData(document_state); 3426 if (!content_initiated) 3427 PopulateDocumentStateFromPending(document_state); 3428 } 3429 3430 // Carry over the user agent override flag, if it exists. 3431 if (content_initiated && webview() && webview()->mainFrame() && 3432 webview()->mainFrame()->dataSource()) { 3433 DocumentState* old_document_state = 3434 DocumentState::FromDataSource(webview()->mainFrame()->dataSource()); 3435 if (old_document_state) { 3436 InternalDocumentStateData* internal_data = 3437 InternalDocumentStateData::FromDocumentState(document_state); 3438 InternalDocumentStateData* old_internal_data = 3439 InternalDocumentStateData::FromDocumentState(old_document_state); 3440 internal_data->set_is_overriding_user_agent( 3441 old_internal_data->is_overriding_user_agent()); 3442 } 3443 } 3444 3445 // The rest of RenderView assumes that a WebDataSource will always have a 3446 // non-null NavigationState. 3447 if (content_initiated) { 3448 document_state->set_navigation_state( 3449 NavigationState::CreateContentInitiated()); 3450 } else { 3451 document_state->set_navigation_state(CreateNavigationStateFromPending()); 3452 pending_navigation_params_.reset(); 3453 } 3454 3455 // DocumentState::referred_by_prefetcher_ is true if we are 3456 // navigating from a page that used prefetching using a link on that 3457 // page. We are early enough in the request process here that we 3458 // can still see the DocumentState of the previous page and set 3459 // this value appropriately. 3460 // TODO(gavinp): catch the important case of navigation in a new 3461 // renderer process. 3462 if (webview()) { 3463 if (WebFrame* old_frame = webview()->mainFrame()) { 3464 const WebURLRequest& original_request = ds->originalRequest(); 3465 const GURL referrer( 3466 original_request.httpHeaderField(WebString::fromUTF8("Referer"))); 3467 if (!referrer.is_empty() && 3468 DocumentState::FromDataSource( 3469 old_frame->dataSource())->was_prefetcher()) { 3470 for (; old_frame; old_frame = old_frame->traverseNext(false)) { 3471 WebDataSource* old_frame_ds = old_frame->dataSource(); 3472 if (old_frame_ds && referrer == GURL(old_frame_ds->request().url())) { 3473 document_state->set_was_referred_by_prefetcher(true); 3474 break; 3475 } 3476 } 3477 } 3478 } 3479 } 3480 3481 if (content_initiated) { 3482 const WebURLRequest& request = ds->request(); 3483 switch (request.cachePolicy()) { 3484 case WebURLRequest::UseProtocolCachePolicy: // normal load. 3485 document_state->set_load_type(DocumentState::LINK_LOAD_NORMAL); 3486 break; 3487 case WebURLRequest::ReloadIgnoringCacheData: // reload. 3488 document_state->set_load_type(DocumentState::LINK_LOAD_RELOAD); 3489 break; 3490 case WebURLRequest::ReturnCacheDataElseLoad: // allow stale data. 3491 document_state->set_load_type( 3492 DocumentState::LINK_LOAD_CACHE_STALE_OK); 3493 break; 3494 case WebURLRequest::ReturnCacheDataDontLoad: // Don't re-post. 3495 document_state->set_load_type(DocumentState::LINK_LOAD_CACHE_ONLY); 3496 break; 3497 } 3498 } 3499 3500 FOR_EACH_OBSERVER( 3501 RenderViewObserver, observers_, DidCreateDataSource(frame, ds)); 3502 } 3503 3504 void RenderViewImpl::PopulateDocumentStateFromPending( 3505 DocumentState* document_state) { 3506 const ViewMsg_Navigate_Params& params = *pending_navigation_params_.get(); 3507 document_state->set_request_time(params.request_time); 3508 3509 InternalDocumentStateData* internal_data = 3510 InternalDocumentStateData::FromDocumentState(document_state); 3511 3512 if (!params.url.SchemeIs(chrome::kJavaScriptScheme) && 3513 params.navigation_type == ViewMsg_Navigate_Type::RESTORE) { 3514 // We're doing a load of a page that was restored from the last session. By 3515 // default this prefers the cache over loading (LOAD_PREFERRING_CACHE) which 3516 // can result in stale data for pages that are set to expire. We explicitly 3517 // override that by setting the policy here so that as necessary we load 3518 // from the network. 3519 internal_data->set_cache_policy_override( 3520 WebURLRequest::UseProtocolCachePolicy); 3521 } 3522 3523 if (IsReload(params)) 3524 document_state->set_load_type(DocumentState::RELOAD); 3525 else if (params.page_state.IsValid()) 3526 document_state->set_load_type(DocumentState::HISTORY_LOAD); 3527 else 3528 document_state->set_load_type(DocumentState::NORMAL_LOAD); 3529 3530 internal_data->set_referrer_policy(params.referrer.policy); 3531 internal_data->set_is_overriding_user_agent(params.is_overriding_user_agent); 3532 internal_data->set_must_reset_scroll_and_scale_state( 3533 params.navigation_type == 3534 ViewMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL); 3535 document_state->set_can_load_local_resources(params.can_load_local_resources); 3536 } 3537 3538 NavigationState* RenderViewImpl::CreateNavigationStateFromPending() { 3539 const ViewMsg_Navigate_Params& params = *pending_navigation_params_.get(); 3540 NavigationState* navigation_state = NULL; 3541 3542 // A navigation resulting from loading a javascript URL should not be treated 3543 // as a browser initiated event. Instead, we want it to look as if the page 3544 // initiated any load resulting from JS execution. 3545 if (!params.url.SchemeIs(chrome::kJavaScriptScheme)) { 3546 navigation_state = NavigationState::CreateBrowserInitiated( 3547 params.page_id, 3548 params.pending_history_list_offset, 3549 params.should_clear_history_list, 3550 params.transition); 3551 navigation_state->set_transferred_request_child_id( 3552 params.transferred_request_child_id); 3553 navigation_state->set_transferred_request_request_id( 3554 params.transferred_request_request_id); 3555 navigation_state->set_allow_download(params.allow_download); 3556 navigation_state->set_extra_headers(params.extra_headers); 3557 } else { 3558 navigation_state = NavigationState::CreateContentInitiated(); 3559 } 3560 return navigation_state; 3561 } 3562 3563 void RenderViewImpl::ProcessViewLayoutFlags(const CommandLine& command_line) { 3564 bool enable_viewport = 3565 command_line.HasSwitch(switches::kEnableViewport); 3566 bool enable_fixed_layout = 3567 command_line.HasSwitch(switches::kEnableFixedLayout); 3568 3569 webview()->enableFixedLayoutMode(enable_fixed_layout || enable_viewport); 3570 3571 // If viewport tag is enabled, then the WebKit side will take care 3572 // of setting the fixed layout size and page scale limits. 3573 if (enable_viewport) 3574 return; 3575 3576 // When navigating to a new page, reset the page scale factor to be 1.0. 3577 webview()->setInitialPageScaleOverride(1.f); 3578 3579 if (enable_fixed_layout) { 3580 std::string str = 3581 command_line.GetSwitchValueASCII(switches::kEnableFixedLayout); 3582 std::vector<std::string> tokens; 3583 base::SplitString(str, ',', &tokens); 3584 if (tokens.size() == 2) { 3585 int width, height; 3586 if (base::StringToInt(tokens[0], &width) && 3587 base::StringToInt(tokens[1], &height)) 3588 webview()->setFixedLayoutSize(WebSize(width, height)); 3589 } 3590 } 3591 float maxPageScaleFactor = 3592 command_line.HasSwitch(switches::kEnablePinch) ? 4.f : 1.f ; 3593 webview()->setPageScaleFactorLimits(1, maxPageScaleFactor); 3594 } 3595 3596 void RenderViewImpl::didStartProvisionalLoad(WebFrame* frame) { 3597 WebDataSource* ds = frame->provisionalDataSource(); 3598 3599 // In fast/loader/stop-provisional-loads.html, we abort the load before this 3600 // callback is invoked. 3601 if (!ds) 3602 return; 3603 3604 DocumentState* document_state = DocumentState::FromDataSource(ds); 3605 3606 // We should only navigate to swappedout:// when is_swapped_out_ is true. 3607 CHECK((ds->request().url() != GURL(kSwappedOutURL)) || 3608 is_swapped_out_) << "Heard swappedout:// when not swapped out."; 3609 3610 // Update the request time if WebKit has better knowledge of it. 3611 if (document_state->request_time().is_null()) { 3612 double event_time = ds->triggeringEventTime(); 3613 if (event_time != 0.0) 3614 document_state->set_request_time(Time::FromDoubleT(event_time)); 3615 } 3616 3617 // Start time is only set after request time. 3618 document_state->set_start_load_time(Time::Now()); 3619 3620 bool is_top_most = !frame->parent(); 3621 if (is_top_most) { 3622 navigation_gesture_ = WebUserGestureIndicator::isProcessingUserGesture() ? 3623 NavigationGestureUser : NavigationGestureAuto; 3624 3625 // If the navigation is not triggered by a user gesture, e.g. by some ajax 3626 // callback, then inherit the submitted password form from the previous 3627 // state. This fixes the no password save issue for ajax login, tracked in 3628 // [http://crbug/43219]. Note that there are still some sites that this 3629 // fails for because they use some element other than a submit button to 3630 // trigger submission. 3631 if (navigation_gesture_ == NavigationGestureAuto) { 3632 DocumentState* old_document_state = DocumentState::FromDataSource( 3633 frame->dataSource()); 3634 const content::PasswordForm* old_password_form = 3635 old_document_state->password_form_data(); 3636 if (old_password_form) { 3637 document_state->set_password_form_data( 3638 make_scoped_ptr(new content::PasswordForm(*old_password_form))); 3639 } 3640 } 3641 } else if (frame->parent()->isLoading()) { 3642 // Take note of AUTO_SUBFRAME loads here, so that we can know how to 3643 // load an error page. See didFailProvisionalLoad. 3644 document_state->navigation_state()->set_transition_type( 3645 PAGE_TRANSITION_AUTO_SUBFRAME); 3646 } 3647 3648 FOR_EACH_OBSERVER( 3649 RenderViewObserver, observers_, DidStartProvisionalLoad(frame)); 3650 3651 Send(new ViewHostMsg_DidStartProvisionalLoadForFrame( 3652 routing_id_, frame->identifier(), 3653 frame->parent() ? frame->parent()->identifier() : -1, 3654 is_top_most, ds->request().url())); 3655 } 3656 3657 void RenderViewImpl::didReceiveServerRedirectForProvisionalLoad( 3658 WebFrame* frame) { 3659 if (frame->parent()) 3660 return; 3661 // Received a redirect on the main frame. 3662 WebDataSource* data_source = frame->provisionalDataSource(); 3663 if (!data_source) { 3664 // Should only be invoked when we have a data source. 3665 NOTREACHED(); 3666 return; 3667 } 3668 std::vector<GURL> redirects; 3669 GetRedirectChain(data_source, &redirects); 3670 if (redirects.size() >= 2) { 3671 Send(new ViewHostMsg_DidRedirectProvisionalLoad(routing_id_, page_id_, 3672 redirects[redirects.size() - 2], redirects.back())); 3673 } 3674 } 3675 3676 void RenderViewImpl::didFailProvisionalLoad(WebFrame* frame, 3677 const WebURLError& error) { 3678 // Notify the browser that we failed a provisional load with an error. 3679 // 3680 // Note: It is important this notification occur before DidStopLoading so the 3681 // SSL manager can react to the provisional load failure before being 3682 // notified the load stopped. 3683 // 3684 WebDataSource* ds = frame->provisionalDataSource(); 3685 DCHECK(ds); 3686 3687 const WebURLRequest& failed_request = ds->request(); 3688 3689 FOR_EACH_OBSERVER( 3690 RenderViewObserver, observers_, DidFailProvisionalLoad(frame, error)); 3691 3692 bool show_repost_interstitial = 3693 (error.reason == net::ERR_CACHE_MISS && 3694 EqualsASCII(failed_request.httpMethod(), "POST")); 3695 3696 ViewHostMsg_DidFailProvisionalLoadWithError_Params params; 3697 params.frame_id = frame->identifier(); 3698 params.is_main_frame = !frame->parent(); 3699 params.error_code = error.reason; 3700 GetContentClient()->renderer()->GetNavigationErrorStrings( 3701 frame, 3702 failed_request, 3703 error, 3704 NULL, 3705 ¶ms.error_description); 3706 params.url = error.unreachableURL; 3707 params.showing_repost_interstitial = show_repost_interstitial; 3708 Send(new ViewHostMsg_DidFailProvisionalLoadWithError( 3709 routing_id_, params)); 3710 3711 // Don't display an error page if this is simply a cancelled load. Aside 3712 // from being dumb, WebCore doesn't expect it and it will cause a crash. 3713 if (error.reason == net::ERR_ABORTED) 3714 return; 3715 3716 if (RenderThreadImpl::current()->layout_test_mode()) 3717 return; 3718 3719 // Make sure we never show errors in view source mode. 3720 frame->enableViewSourceMode(false); 3721 3722 DocumentState* document_state = DocumentState::FromDataSource(ds); 3723 NavigationState* navigation_state = document_state->navigation_state(); 3724 3725 // If this is a failed back/forward/reload navigation, then we need to do a 3726 // 'replace' load. This is necessary to avoid messing up session history. 3727 // Otherwise, we do a normal load, which simulates a 'go' navigation as far 3728 // as session history is concerned. 3729 // 3730 // AUTO_SUBFRAME loads should always be treated as loads that do not advance 3731 // the page id. 3732 // 3733 bool replace = 3734 navigation_state->pending_page_id() != -1 || 3735 PageTransitionCoreTypeIs(navigation_state->transition_type(), 3736 PAGE_TRANSITION_AUTO_SUBFRAME); 3737 3738 // If we failed on a browser initiated request, then make sure that our error 3739 // page load is regarded as the same browser initiated request. 3740 if (!navigation_state->is_content_initiated()) { 3741 pending_navigation_params_.reset(new ViewMsg_Navigate_Params); 3742 pending_navigation_params_->page_id = 3743 navigation_state->pending_page_id(); 3744 pending_navigation_params_->pending_history_list_offset = 3745 navigation_state->pending_history_list_offset(); 3746 pending_navigation_params_->should_clear_history_list = 3747 navigation_state->history_list_was_cleared(); 3748 pending_navigation_params_->transition = 3749 navigation_state->transition_type(); 3750 pending_navigation_params_->request_time = 3751 document_state->request_time(); 3752 } 3753 3754 // Provide the user with a more helpful error page? 3755 if (MaybeLoadAlternateErrorPage(frame, error, replace)) 3756 return; 3757 3758 // Fallback to a local error page. 3759 LoadNavigationErrorPage(frame, failed_request, error, std::string(), replace); 3760 } 3761 3762 void RenderViewImpl::didCommitProvisionalLoad(WebFrame* frame, 3763 bool is_new_navigation) { 3764 DocumentState* document_state = 3765 DocumentState::FromDataSource(frame->dataSource()); 3766 NavigationState* navigation_state = document_state->navigation_state(); 3767 InternalDocumentStateData* internal_data = 3768 InternalDocumentStateData::FromDocumentState(document_state); 3769 3770 if (document_state->commit_load_time().is_null()) 3771 document_state->set_commit_load_time(Time::Now()); 3772 3773 if (internal_data->must_reset_scroll_and_scale_state()) { 3774 webview()->resetScrollAndScaleState(); 3775 internal_data->set_must_reset_scroll_and_scale_state(false); 3776 } 3777 internal_data->set_use_error_page(false); 3778 3779 if (is_new_navigation) { 3780 // When we perform a new navigation, we need to update the last committed 3781 // session history entry with state for the page we are leaving. 3782 UpdateSessionHistory(frame); 3783 3784 // We bump our Page ID to correspond with the new session history entry. 3785 page_id_ = next_page_id_++; 3786 3787 // Don't update history_page_ids_ (etc) for kSwappedOutURL, since 3788 // we don't want to forget the entry that was there, and since we will 3789 // never come back to kSwappedOutURL. Note that we have to call 3790 // UpdateSessionHistory and update page_id_ even in this case, so that 3791 // the current entry gets a state update and so that we don't send a 3792 // state update to the wrong entry when we swap back in. 3793 if (GetLoadingUrl(frame) != GURL(kSwappedOutURL)) { 3794 // Advance our offset in session history, applying the length limit. 3795 // There is now no forward history. 3796 history_list_offset_++; 3797 if (history_list_offset_ >= kMaxSessionHistoryEntries) 3798 history_list_offset_ = kMaxSessionHistoryEntries - 1; 3799 history_list_length_ = history_list_offset_ + 1; 3800 history_page_ids_.resize(history_list_length_, -1); 3801 history_page_ids_[history_list_offset_] = page_id_; 3802 } 3803 } else { 3804 // Inspect the navigation_state on this frame to see if the navigation 3805 // corresponds to a session history navigation... Note: |frame| may or 3806 // may not be the toplevel frame, but for the case of capturing session 3807 // history, the first committed frame suffices. We keep track of whether 3808 // we've seen this commit before so that only capture session history once 3809 // per navigation. 3810 // 3811 // Note that we need to check if the page ID changed. In the case of a 3812 // reload, the page ID doesn't change, and UpdateSessionHistory gets the 3813 // previous URL and the current page ID, which would be wrong. 3814 if (navigation_state->pending_page_id() != -1 && 3815 navigation_state->pending_page_id() != page_id_ && 3816 !navigation_state->request_committed()) { 3817 // This is a successful session history navigation! 3818 UpdateSessionHistory(frame); 3819 page_id_ = navigation_state->pending_page_id(); 3820 3821 history_list_offset_ = navigation_state->pending_history_list_offset(); 3822 3823 // If the history list is valid, our list of page IDs should be correct. 3824 DCHECK(history_list_length_ <= 0 || 3825 history_list_offset_ < 0 || 3826 history_list_offset_ >= history_list_length_ || 3827 history_page_ids_[history_list_offset_] == page_id_); 3828 } 3829 } 3830 3831 FOR_EACH_OBSERVER(RenderViewObserver, observers_, 3832 DidCommitProvisionalLoad(frame, is_new_navigation)); 3833 3834 // Remember that we've already processed this request, so we don't update 3835 // the session history again. We do this regardless of whether this is 3836 // a session history navigation, because if we attempted a session history 3837 // navigation without valid HistoryItem state, WebCore will think it is a 3838 // new navigation. 3839 navigation_state->set_request_committed(true); 3840 3841 UpdateURL(frame); 3842 3843 // Check whether we have new encoding name. 3844 UpdateEncoding(frame, frame->view()->pageEncoding().utf8()); 3845 3846 if (!frame->parent()) { // Only for top frames. 3847 RenderThreadImpl* render_thread_impl = RenderThreadImpl::current(); 3848 if (render_thread_impl) { // Can be NULL in tests. 3849 render_thread_impl->histogram_customizer()-> 3850 RenderViewNavigatedToHost(GURL(GetLoadingUrl(frame)).host(), 3851 g_view_map.Get().size()); 3852 } 3853 } 3854 } 3855 3856 void RenderViewImpl::didClearWindowObject(WebFrame* frame) { 3857 FOR_EACH_OBSERVER(RenderViewObserver, observers_, 3858 DidClearWindowObject(frame)); 3859 3860 if (enabled_bindings_ & BINDINGS_POLICY_DOM_AUTOMATION) { 3861 if (!dom_automation_controller_) 3862 dom_automation_controller_.reset(new DomAutomationController()); 3863 dom_automation_controller_->set_message_sender( 3864 static_cast<RenderView*>(this)); 3865 dom_automation_controller_->set_routing_id(routing_id()); 3866 dom_automation_controller_->BindToJavascript(frame, 3867 "domAutomationController"); 3868 } 3869 3870 if (enabled_bindings_ & BINDINGS_POLICY_STATS_COLLECTION) { 3871 if (!stats_collection_controller_.get()) 3872 stats_collection_controller_.reset(new StatsCollectionController()); 3873 stats_collection_controller_->set_message_sender( 3874 static_cast<RenderView*>(this)); 3875 stats_collection_controller_->BindToJavascript(frame, 3876 "statsCollectionController"); 3877 } 3878 } 3879 3880 void RenderViewImpl::didCreateDocumentElement(WebFrame* frame) { 3881 FOR_EACH_OBSERVER(RenderViewObserver, observers_, 3882 DidCreateDocumentElement(frame)); 3883 } 3884 3885 void RenderViewImpl::didReceiveTitle(WebFrame* frame, const WebString& title, 3886 WebTextDirection direction) { 3887 UpdateTitle(frame, title, direction); 3888 3889 // Also check whether we have new encoding name. 3890 UpdateEncoding(frame, frame->view()->pageEncoding().utf8()); 3891 } 3892 3893 void RenderViewImpl::didChangeIcon(WebFrame* frame, 3894 WebIconURL::Type icon_type) { 3895 if (frame->parent()) 3896 return; 3897 3898 if (!TouchEnabled() && icon_type != WebIconURL::TypeFavicon) 3899 return; 3900 3901 WebVector<WebIconURL> icon_urls = frame->iconURLs(icon_type); 3902 std::vector<FaviconURL> urls; 3903 for (size_t i = 0; i < icon_urls.size(); i++) { 3904 urls.push_back(FaviconURL(icon_urls[i].iconURL(), 3905 ToFaviconType(icon_urls[i].iconType()))); 3906 } 3907 SendUpdateFaviconURL(urls); 3908 } 3909 3910 void RenderViewImpl::didFinishDocumentLoad(WebFrame* frame) { 3911 WebDataSource* ds = frame->dataSource(); 3912 DocumentState* document_state = DocumentState::FromDataSource(ds); 3913 document_state->set_finish_document_load_time(Time::Now()); 3914 3915 Send(new ViewHostMsg_DocumentLoadedInFrame(routing_id_, frame->identifier())); 3916 3917 FOR_EACH_OBSERVER(RenderViewObserver, observers_, 3918 DidFinishDocumentLoad(frame)); 3919 3920 // Check whether we have new encoding name. 3921 UpdateEncoding(frame, frame->view()->pageEncoding().utf8()); 3922 } 3923 3924 void RenderViewImpl::didHandleOnloadEvents(WebFrame* frame) { 3925 if (webview()->mainFrame() == frame) { 3926 Send(new ViewHostMsg_DocumentOnLoadCompletedInMainFrame(routing_id_, 3927 page_id_)); 3928 } 3929 } 3930 3931 void RenderViewImpl::didFailLoad(WebFrame* frame, const WebURLError& error) { 3932 WebDataSource* ds = frame->dataSource(); 3933 DCHECK(ds); 3934 3935 3936 FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidFailLoad(frame, error)); 3937 3938 const WebURLRequest& failed_request = ds->request(); 3939 string16 error_description; 3940 GetContentClient()->renderer()->GetNavigationErrorStrings( 3941 frame, 3942 failed_request, 3943 error, 3944 NULL, 3945 &error_description); 3946 Send(new ViewHostMsg_DidFailLoadWithError(routing_id_, 3947 frame->identifier(), 3948 failed_request.url(), 3949 !frame->parent(), 3950 error.reason, 3951 error_description)); 3952 } 3953 3954 void RenderViewImpl::didFinishLoad(WebFrame* frame) { 3955 WebDataSource* ds = frame->dataSource(); 3956 DocumentState* document_state = DocumentState::FromDataSource(ds); 3957 if (document_state->finish_load_time().is_null()) { 3958 if (!frame->parent()) { 3959 TRACE_EVENT_INSTANT0("WebCore", "LoadFinished", 3960 TRACE_EVENT_SCOPE_PROCESS); 3961 } 3962 document_state->set_finish_load_time(Time::Now()); 3963 } 3964 3965 FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidFinishLoad(frame)); 3966 3967 Send(new ViewHostMsg_DidFinishLoad(routing_id_, 3968 frame->identifier(), 3969 ds->request().url(), 3970 !frame->parent())); 3971 } 3972 3973 void RenderViewImpl::didNavigateWithinPage( 3974 WebFrame* frame, bool is_new_navigation) { 3975 // If this was a reference fragment navigation that we initiated, then we 3976 // could end up having a non-null pending navigation params. We just need to 3977 // update the ExtraData on the datasource so that others who read the 3978 // ExtraData will get the new NavigationState. Similarly, if we did not 3979 // initiate this navigation, then we need to take care to reset any pre- 3980 // existing navigation state to a content-initiated navigation state. 3981 // DidCreateDataSource conveniently takes care of this for us. 3982 didCreateDataSource(frame, frame->dataSource()); 3983 3984 DocumentState* document_state = 3985 DocumentState::FromDataSource(frame->dataSource()); 3986 NavigationState* new_state = document_state->navigation_state(); 3987 new_state->set_was_within_same_page(true); 3988 3989 didCommitProvisionalLoad(frame, is_new_navigation); 3990 3991 WebDataSource* datasource = frame->view()->mainFrame()->dataSource(); 3992 UpdateTitle(frame, datasource->pageTitle(), datasource->pageTitleDirection()); 3993 } 3994 3995 void RenderViewImpl::didUpdateCurrentHistoryItem(WebFrame* frame) { 3996 StartNavStateSyncTimerIfNecessary(); 3997 } 3998 3999 void RenderViewImpl::willSendRequest(WebFrame* frame, 4000 unsigned identifier, 4001 WebURLRequest& request, 4002 const WebURLResponse& redirect_response) { 4003 NOTREACHED(); 4004 } 4005 4006 void RenderViewImpl::didReceiveResponse( 4007 WebFrame* frame, unsigned identifier, const WebURLResponse& response) { 4008 NOTREACHED(); 4009 } 4010 4011 void RenderViewImpl::didFinishResourceLoad( 4012 WebFrame* frame, unsigned identifier) { 4013 InternalDocumentStateData* internal_data = 4014 InternalDocumentStateData::FromDataSource(frame->dataSource()); 4015 if (!internal_data->use_error_page()) 4016 return; 4017 4018 // Do not show error page when DevTools is attached. 4019 if (devtools_agent_->IsAttached()) 4020 return; 4021 4022 // Display error page, if appropriate. 4023 int http_status_code = internal_data->http_status_code(); 4024 if (http_status_code == 404) { 4025 // On 404s, try a remote search page as a fallback. 4026 const GURL& document_url = frame->document().url(); 4027 4028 const GURL& error_page_url = 4029 GetAlternateErrorPageURL(document_url, HTTP_404); 4030 if (error_page_url.is_valid()) { 4031 WebURLError original_error; 4032 original_error.domain = "http"; 4033 original_error.reason = 404; 4034 original_error.unreachableURL = document_url; 4035 4036 internal_data->set_alt_error_page_fetcher( 4037 new AltErrorPageResourceFetcher( 4038 error_page_url, frame, frame->dataSource()->request(), 4039 original_error, 4040 base::Bind(&RenderViewImpl::AltErrorPageFinished, 4041 base::Unretained(this)))); 4042 return; 4043 } 4044 } 4045 4046 std::string error_domain; 4047 if (GetContentClient()->renderer()->HasErrorPage( 4048 http_status_code, &error_domain)) { 4049 WebURLError error; 4050 error.unreachableURL = frame->document().url(); 4051 error.domain = WebString::fromUTF8(error_domain); 4052 error.reason = http_status_code; 4053 4054 LoadNavigationErrorPage( 4055 frame, frame->dataSource()->request(), error, std::string(), true); 4056 } 4057 } 4058 4059 void RenderViewImpl::didLoadResourceFromMemoryCache( 4060 WebFrame* frame, const WebURLRequest& request, 4061 const WebURLResponse& response) { 4062 NOTREACHED(); 4063 } 4064 4065 void RenderViewImpl::didDisplayInsecureContent(WebFrame* frame) { 4066 NOTREACHED(); 4067 } 4068 4069 void RenderViewImpl::didRunInsecureContent( 4070 WebFrame* frame, const WebSecurityOrigin& origin, const WebURL& target) { 4071 NOTREACHED(); 4072 } 4073 4074 void RenderViewImpl::didExhaustMemoryAvailableForScript(WebFrame* frame) { 4075 NOTREACHED(); 4076 } 4077 4078 void RenderViewImpl::didCreateScriptContext(WebFrame* frame, 4079 v8::Handle<v8::Context> context, 4080 int extension_group, 4081 int world_id) { 4082 NOTREACHED(); 4083 } 4084 4085 void RenderViewImpl::willReleaseScriptContext(WebFrame* frame, 4086 v8::Handle<v8::Context> context, 4087 int world_id) { 4088 NOTREACHED(); 4089 } 4090 4091 void RenderViewImpl::CheckPreferredSize() { 4092 // We don't always want to send the change messages over IPC, only if we've 4093 // been put in that mode by getting a |ViewMsg_EnablePreferredSizeChangedMode| 4094 // message. 4095 if (!send_preferred_size_changes_ || !webview()) 4096 return; 4097 4098 gfx::Size size = webview()->contentsPreferredMinimumSize(); 4099 4100 // In the presence of zoom, these sizes are still reported as if unzoomed, 4101 // so we need to adjust. 4102 double zoom_factor = ZoomLevelToZoomFactor(webview()->zoomLevel()); 4103 size.set_width(static_cast<int>(size.width() * zoom_factor)); 4104 size.set_height(static_cast<int>(size.height() * zoom_factor)); 4105 4106 if (size == preferred_size_) 4107 return; 4108 4109 preferred_size_ = size; 4110 Send(new ViewHostMsg_DidContentsPreferredSizeChange(routing_id_, 4111 preferred_size_)); 4112 } 4113 4114 BrowserPluginManager* RenderViewImpl::GetBrowserPluginManager() { 4115 if (!browser_plugin_manager_.get()) 4116 browser_plugin_manager_ = BrowserPluginManager::Create(this); 4117 return browser_plugin_manager_.get(); 4118 } 4119 4120 void RenderViewImpl::EnsureMediaStreamClient() { 4121 if (!RenderThreadImpl::current()) // Will be NULL during unit tests. 4122 return; 4123 4124 #if defined(OS_ANDROID) 4125 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableWebRTC)) 4126 return; 4127 #endif 4128 4129 #if defined(ENABLE_WEBRTC) 4130 if (!media_stream_dispatcher_) 4131 media_stream_dispatcher_ = new MediaStreamDispatcher(this); 4132 4133 if (!media_stream_client_) { 4134 MediaStreamImpl* media_stream_impl = new MediaStreamImpl( 4135 this, 4136 media_stream_dispatcher_, 4137 RenderThreadImpl::current()->GetMediaStreamDependencyFactory()); 4138 media_stream_client_ = media_stream_impl; 4139 web_user_media_client_ = media_stream_impl; 4140 } 4141 #endif 4142 } 4143 4144 void RenderViewImpl::didChangeContentsSize(WebFrame* frame, 4145 const WebSize& size) { 4146 if (webview()->mainFrame() != frame) 4147 return; 4148 WebView* frameView = frame->view(); 4149 if (!frameView) 4150 return; 4151 4152 bool has_horizontal_scrollbar = frame->hasHorizontalScrollbar(); 4153 bool has_vertical_scrollbar = frame->hasVerticalScrollbar(); 4154 4155 if (has_horizontal_scrollbar != cached_has_main_frame_horizontal_scrollbar_ || 4156 has_vertical_scrollbar != cached_has_main_frame_vertical_scrollbar_) { 4157 Send(new ViewHostMsg_DidChangeScrollbarsForMainFrame( 4158 routing_id_, has_horizontal_scrollbar, has_vertical_scrollbar)); 4159 4160 cached_has_main_frame_horizontal_scrollbar_ = has_horizontal_scrollbar; 4161 cached_has_main_frame_vertical_scrollbar_ = has_vertical_scrollbar; 4162 } 4163 } 4164 4165 void RenderViewImpl::UpdateScrollState(WebFrame* frame) { 4166 WebSize offset = frame->scrollOffset(); 4167 WebSize minimum_offset = frame->minimumScrollOffset(); 4168 WebSize maximum_offset = frame->maximumScrollOffset(); 4169 4170 bool is_pinned_to_left = offset.width <= minimum_offset.width; 4171 bool is_pinned_to_right = offset.width >= maximum_offset.width; 4172 4173 if (is_pinned_to_left != cached_is_main_frame_pinned_to_left_ || 4174 is_pinned_to_right != cached_is_main_frame_pinned_to_right_) { 4175 Send(new ViewHostMsg_DidChangeScrollOffsetPinningForMainFrame( 4176 routing_id_, is_pinned_to_left, is_pinned_to_right)); 4177 4178 cached_is_main_frame_pinned_to_left_ = is_pinned_to_left; 4179 cached_is_main_frame_pinned_to_right_ = is_pinned_to_right; 4180 } 4181 4182 Send(new ViewHostMsg_DidChangeScrollOffset(routing_id_)); 4183 } 4184 4185 void RenderViewImpl::didChangeScrollOffset(WebFrame* frame) { 4186 StartNavStateSyncTimerIfNecessary(); 4187 4188 if (webview()->mainFrame() == frame) 4189 UpdateScrollState(frame); 4190 4191 FOR_EACH_OBSERVER( 4192 RenderViewObserver, observers_, DidChangeScrollOffset(frame)); 4193 } 4194 4195 void RenderViewImpl::willInsertBody(WebKit::WebFrame* frame) { 4196 NOTREACHED(); 4197 } 4198 4199 void RenderViewImpl::didFirstVisuallyNonEmptyLayout(WebFrame* frame) { 4200 if (frame != webview()->mainFrame()) 4201 return; 4202 4203 InternalDocumentStateData* data = 4204 InternalDocumentStateData::FromDataSource(frame->dataSource()); 4205 data->set_did_first_visually_non_empty_layout(true); 4206 4207 #if defined(OS_ANDROID) 4208 // Update body background color if necessary. 4209 SkColor bg_color = webwidget_->backgroundColor(); 4210 4211 // If not initialized, default to white. Note that 0 is different from black 4212 // as black still has alpha 0xFF. 4213 if (!bg_color) 4214 bg_color = SK_ColorWHITE; 4215 4216 if (bg_color != body_background_color_) { 4217 body_background_color_ = bg_color; 4218 Send(new ViewHostMsg_DidChangeBodyBackgroundColor( 4219 GetRoutingID(), bg_color)); 4220 } 4221 #endif 4222 } 4223 4224 void RenderViewImpl::SendFindReply(int request_id, 4225 int match_count, 4226 int ordinal, 4227 const WebRect& selection_rect, 4228 bool final_status_update) { 4229 Send(new ViewHostMsg_Find_Reply(routing_id_, 4230 request_id, 4231 match_count, 4232 selection_rect, 4233 ordinal, 4234 final_status_update)); 4235 } 4236 4237 // static 4238 bool RenderViewImpl::ShouldUpdateSelectionTextFromContextMenuParams( 4239 const string16& selection_text, 4240 size_t selection_text_offset, 4241 const ui::Range& selection_range, 4242 const ContextMenuParams& params) { 4243 string16 trimmed_selection_text; 4244 if (!selection_text.empty() && !selection_range.is_empty()) { 4245 const int start = selection_range.GetMin() - selection_text_offset; 4246 const size_t length = selection_range.length(); 4247 if (start >= 0 && start + length <= selection_text.length()) { 4248 TrimWhitespace(selection_text.substr(start, length), TRIM_ALL, 4249 &trimmed_selection_text); 4250 } 4251 } 4252 string16 trimmed_params_text; 4253 TrimWhitespace(params.selection_text, TRIM_ALL, &trimmed_params_text); 4254 return trimmed_params_text != trimmed_selection_text; 4255 } 4256 4257 void RenderViewImpl::reportFindInPageMatchCount(int request_id, 4258 int count, 4259 bool final_update) { 4260 // TODO(jam): switch PepperPluginInstanceImpl to take a RenderFrame 4261 main_render_frame_->reportFindInPageMatchCount( 4262 request_id, count, final_update); 4263 } 4264 4265 void RenderViewImpl::reportFindInPageSelection(int request_id, 4266 int active_match_ordinal, 4267 const WebRect& selection_rect) { 4268 // TODO(jam): switch PepperPluginInstanceImpl to take a RenderFrame 4269 main_render_frame_->reportFindInPageSelection( 4270 request_id, active_match_ordinal, selection_rect); 4271 } 4272 4273 void RenderViewImpl::openFileSystem( 4274 WebFrame* frame, 4275 WebKit::WebFileSystemType type, 4276 long long size, 4277 bool create, 4278 WebFileSystemCallbacks* callbacks) { 4279 NOTREACHED(); 4280 } 4281 4282 void RenderViewImpl::deleteFileSystem( 4283 WebFrame* frame, 4284 WebKit::WebFileSystemType type , 4285 WebFileSystemCallbacks* callbacks) { 4286 NOTREACHED(); 4287 } 4288 4289 void RenderViewImpl::requestStorageQuota( 4290 WebFrame* frame, 4291 WebStorageQuotaType type, 4292 unsigned long long requested_size, 4293 WebStorageQuotaCallbacks* callbacks) { 4294 NOTREACHED(); 4295 } 4296 4297 bool RenderViewImpl::willCheckAndDispatchMessageEvent( 4298 WebKit::WebFrame* sourceFrame, 4299 WebKit::WebFrame* targetFrame, 4300 WebKit::WebSecurityOrigin target_origin, 4301 WebKit::WebDOMMessageEvent event) { 4302 if (!is_swapped_out_) 4303 return false; 4304 4305 ViewMsg_PostMessage_Params params; 4306 params.data = event.data().toString(); 4307 params.source_origin = event.origin(); 4308 if (!target_origin.isNull()) 4309 params.target_origin = target_origin.toString(); 4310 4311 // Include the routing ID for the source frame, which the browser process 4312 // will translate into the routing ID for the equivalent frame in the target 4313 // process. 4314 params.source_routing_id = MSG_ROUTING_NONE; 4315 RenderViewImpl* source_view = FromWebView(sourceFrame->view()); 4316 if (source_view) 4317 params.source_routing_id = source_view->routing_id(); 4318 4319 Send(new ViewHostMsg_RouteMessageEvent(routing_id_, params)); 4320 return true; 4321 } 4322 4323 void RenderViewImpl::willOpenSocketStream( 4324 WebSocketStreamHandle* handle) { 4325 NOTREACHED(); 4326 } 4327 4328 void RenderViewImpl::willStartUsingPeerConnectionHandler( 4329 WebKit::WebFrame* frame, WebKit::WebRTCPeerConnectionHandler* handler) { 4330 NOTREACHED(); 4331 } 4332 4333 WebKit::WebString RenderViewImpl::acceptLanguages() { 4334 return WebString::fromUTF8(renderer_preferences_.accept_languages); 4335 } 4336 4337 WebKit::WebString RenderViewImpl::userAgentOverride( 4338 WebKit::WebFrame* frame, 4339 const WebKit::WebURL& url) { 4340 NOTREACHED(); 4341 return WebKit::WebString(); 4342 } 4343 4344 WebString RenderViewImpl::doNotTrackValue(WebFrame* frame) { 4345 NOTREACHED(); 4346 return WebKit::WebString(); 4347 } 4348 4349 bool RenderViewImpl::allowWebGL(WebFrame* frame, bool default_value) { 4350 NOTREACHED(); 4351 return false; 4352 } 4353 4354 void RenderViewImpl::didLoseWebGLContext( 4355 WebKit::WebFrame* frame, 4356 int arb_robustness_status_code) { 4357 NOTREACHED(); 4358 } 4359 4360 // WebKit::WebPageSerializerClient implementation ------------------------------ 4361 4362 void RenderViewImpl::didSerializeDataForFrame( 4363 const WebURL& frame_url, 4364 const WebCString& data, 4365 WebPageSerializerClient::PageSerializationStatus status) { 4366 Send(new ViewHostMsg_SendSerializedHtmlData( 4367 routing_id(), 4368 frame_url, 4369 data.data(), 4370 static_cast<int32>(status))); 4371 } 4372 4373 // RenderView implementation --------------------------------------------------- 4374 4375 bool RenderViewImpl::Send(IPC::Message* message) { 4376 return RenderWidget::Send(message); 4377 } 4378 4379 int RenderViewImpl::GetRoutingID() const { 4380 return routing_id_; 4381 } 4382 4383 int RenderViewImpl::GetPageId() const { 4384 return page_id_; 4385 } 4386 4387 gfx::Size RenderViewImpl::GetSize() const { 4388 return size(); 4389 } 4390 4391 WebPreferences& RenderViewImpl::GetWebkitPreferences() { 4392 return webkit_preferences_; 4393 } 4394 4395 void RenderViewImpl::SetWebkitPreferences(const WebPreferences& preferences) { 4396 OnUpdateWebPreferences(preferences); 4397 } 4398 4399 WebKit::WebView* RenderViewImpl::GetWebView() { 4400 return webview(); 4401 } 4402 4403 WebKit::WebNode RenderViewImpl::GetFocusedNode() const { 4404 if (!webview()) 4405 return WebNode(); 4406 WebFrame* focused_frame = webview()->focusedFrame(); 4407 if (focused_frame) { 4408 WebDocument doc = focused_frame->document(); 4409 if (!doc.isNull()) 4410 return doc.focusedNode(); 4411 } 4412 4413 return WebNode(); 4414 } 4415 4416 WebKit::WebNode RenderViewImpl::GetContextMenuNode() const { 4417 return context_menu_node_; 4418 } 4419 4420 bool RenderViewImpl::IsEditableNode(const WebNode& node) const { 4421 if (node.isNull()) 4422 return false; 4423 4424 if (node.isContentEditable()) 4425 return true; 4426 4427 if (node.isElementNode()) { 4428 const WebElement& element = node.toConst<WebElement>(); 4429 if (element.isTextFormControlElement()) 4430 return true; 4431 4432 // Also return true if it has an ARIA role of 'textbox'. 4433 for (unsigned i = 0; i < element.attributeCount(); ++i) { 4434 if (LowerCaseEqualsASCII(element.attributeLocalName(i), "role")) { 4435 if (LowerCaseEqualsASCII(element.attributeValue(i), "textbox")) 4436 return true; 4437 break; 4438 } 4439 } 4440 } 4441 4442 return false; 4443 } 4444 4445 WebKit::WebPlugin* RenderViewImpl::CreatePlugin( 4446 WebKit::WebFrame* frame, 4447 const WebPluginInfo& info, 4448 const WebKit::WebPluginParams& params) { 4449 #if defined(ENABLE_PLUGINS) 4450 bool pepper_plugin_was_registered = false; 4451 scoped_refptr<PluginModule> pepper_module(PluginModule::Create( 4452 this, info, &pepper_plugin_was_registered)); 4453 if (pepper_plugin_was_registered) { 4454 if (pepper_module.get()) 4455 return new PepperWebPluginImpl(pepper_module.get(), params, AsWeakPtr()); 4456 } 4457 4458 return new WebPluginImpl(frame, params, info.path, AsWeakPtr()); 4459 #else 4460 return NULL; 4461 #endif 4462 } 4463 4464 void RenderViewImpl::EvaluateScript(const string16& frame_xpath, 4465 const string16& jscript, 4466 int id, 4467 bool notify_result) { 4468 v8::HandleScope handle_scope; 4469 v8::Handle<v8::Value> result; 4470 WebFrame* web_frame = GetChildFrame(frame_xpath); 4471 if (web_frame) 4472 result = web_frame->executeScriptAndReturnValue(WebScriptSource(jscript)); 4473 if (notify_result) { 4474 base::ListValue list; 4475 if (!result.IsEmpty() && web_frame) { 4476 v8::Local<v8::Context> context = web_frame->mainWorldScriptContext(); 4477 v8::Context::Scope context_scope(context); 4478 V8ValueConverterImpl converter; 4479 converter.SetDateAllowed(true); 4480 converter.SetRegExpAllowed(true); 4481 base::Value* result_value = converter.FromV8Value(result, context); 4482 list.Set(0, result_value ? result_value : base::Value::CreateNullValue()); 4483 } else { 4484 list.Set(0, base::Value::CreateNullValue()); 4485 } 4486 Send(new ViewHostMsg_ScriptEvalResponse(routing_id_, id, list)); 4487 } 4488 } 4489 4490 bool RenderViewImpl::ShouldDisplayScrollbars(int width, int height) const { 4491 return (!send_preferred_size_changes_ || 4492 (disable_scrollbars_size_limit_.width() <= width || 4493 disable_scrollbars_size_limit_.height() <= height)); 4494 } 4495 4496 int RenderViewImpl::GetEnabledBindings() const { 4497 return enabled_bindings_; 4498 } 4499 4500 bool RenderViewImpl::GetContentStateImmediately() const { 4501 return send_content_state_immediately_; 4502 } 4503 4504 float RenderViewImpl::GetFilteredTimePerFrame() const { 4505 return filtered_time_per_frame(); 4506 } 4507 4508 int RenderViewImpl::ShowContextMenu(ContextMenuClient* client, 4509 const ContextMenuParams& params) { 4510 DCHECK(client); // A null client means "internal" when we issue callbacks. 4511 ContextMenuParams our_params(params); 4512 our_params.custom_context.request_id = pending_context_menus_.Add(client); 4513 Send(new ViewHostMsg_ContextMenu(routing_id_, our_params)); 4514 return our_params.custom_context.request_id; 4515 } 4516 4517 void RenderViewImpl::CancelContextMenu(int request_id) { 4518 DCHECK(pending_context_menus_.Lookup(request_id)); 4519 pending_context_menus_.Remove(request_id); 4520 } 4521 4522 WebKit::WebPageVisibilityState RenderViewImpl::GetVisibilityState() const { 4523 return visibilityState(); 4524 } 4525 4526 void RenderViewImpl::RunModalAlertDialog(WebKit::WebFrame* frame, 4527 const WebKit::WebString& message) { 4528 return runModalAlertDialog(frame, message); 4529 } 4530 4531 void RenderViewImpl::LoadURLExternally( 4532 WebKit::WebFrame* frame, 4533 const WebKit::WebURLRequest& request, 4534 WebKit::WebNavigationPolicy policy) { 4535 main_render_frame_->loadURLExternally(frame, request, policy); 4536 } 4537 4538 void RenderViewImpl::DidStartLoading() { 4539 didStartLoading(); 4540 } 4541 4542 void RenderViewImpl::DidStopLoading() { 4543 didStopLoading(); 4544 } 4545 4546 void RenderViewImpl::DidPlay(WebKit::WebMediaPlayer* player) { 4547 Send(new ViewHostMsg_MediaNotification(routing_id_, 4548 reinterpret_cast<int64>(player), 4549 player->hasVideo(), 4550 player->hasAudio(), 4551 true)); 4552 } 4553 4554 void RenderViewImpl::DidPause(WebKit::WebMediaPlayer* player) { 4555 Send(new ViewHostMsg_MediaNotification(routing_id_, 4556 reinterpret_cast<int64>(player), 4557 player->hasVideo(), 4558 player->hasAudio(), 4559 false)); 4560 } 4561 4562 void RenderViewImpl::PlayerGone(WebKit::WebMediaPlayer* player) { 4563 DidPause(player); 4564 } 4565 4566 void RenderViewImpl::SyncNavigationState() { 4567 if (!webview()) 4568 return; 4569 4570 const WebHistoryItem& item = webview()->mainFrame()->currentHistoryItem(); 4571 SendUpdateState(item); 4572 } 4573 4574 void RenderViewImpl::SyncSelectionIfRequired() { 4575 WebFrame* frame = webview()->focusedFrame(); 4576 if (!frame) 4577 return; 4578 4579 string16 text; 4580 size_t offset; 4581 ui::Range range; 4582 #if defined(ENABLE_PLUGINS) 4583 if (focused_pepper_plugin_) { 4584 focused_pepper_plugin_->GetSurroundingText(&text, &range); 4585 offset = 0; // Pepper API does not support offset reporting. 4586 // TODO(kinaba): cut as needed. 4587 } else 4588 #endif 4589 { 4590 size_t location, length; 4591 if (!webview()->caretOrSelectionRange(&location, &length)) 4592 return; 4593 4594 range = ui::Range(location, location + length); 4595 4596 if (webview()->textInputInfo().type != WebKit::WebTextInputTypeNone) { 4597 // If current focused element is editable, we will send 100 more chars 4598 // before and after selection. It is for input method surrounding text 4599 // feature. 4600 if (location > kExtraCharsBeforeAndAfterSelection) 4601 offset = location - kExtraCharsBeforeAndAfterSelection; 4602 else 4603 offset = 0; 4604 length = location + length - offset + kExtraCharsBeforeAndAfterSelection; 4605 WebRange webrange = WebRange::fromDocumentRange(frame, offset, length); 4606 if (!webrange.isNull()) 4607 text = WebRange::fromDocumentRange(frame, offset, length).toPlainText(); 4608 } else { 4609 offset = location; 4610 text = frame->selectionAsText(); 4611 // http://crbug.com/101435 4612 // In some case, frame->selectionAsText() returned text's length is not 4613 // equal to the length returned from webview()->caretOrSelectionRange(). 4614 // So we have to set the range according to text.length(). 4615 range.set_end(range.start() + text.length()); 4616 } 4617 } 4618 4619 // Sometimes we get repeated didChangeSelection calls from webkit when 4620 // the selection hasn't actually changed. We don't want to report these 4621 // because it will cause us to continually claim the X clipboard. 4622 if (selection_text_offset_ != offset || 4623 selection_range_ != range || 4624 selection_text_ != text) { 4625 selection_text_ = text; 4626 selection_text_offset_ = offset; 4627 selection_range_ = range; 4628 Send(new ViewHostMsg_SelectionChanged(routing_id_, text, offset, range)); 4629 } 4630 UpdateSelectionBounds(); 4631 } 4632 4633 GURL RenderViewImpl::GetAlternateErrorPageURL(const GURL& failed_url, 4634 ErrorPageType error_type) { 4635 if (failed_url.SchemeIsSecure()) { 4636 // If the URL that failed was secure, then the embedding web page was not 4637 // expecting a network attacker to be able to manipulate its contents. As 4638 // we fetch alternate error pages over HTTP, we would be allowing a network 4639 // attacker to manipulate the contents of the response if we tried to use 4640 // the link doctor here. 4641 return GURL(); 4642 } 4643 4644 // Grab the base URL from the browser process. 4645 if (!alternate_error_page_url_.is_valid()) 4646 return GURL(); 4647 4648 // Strip query params from the failed URL. 4649 GURL::Replacements remove_params; 4650 remove_params.ClearUsername(); 4651 remove_params.ClearPassword(); 4652 remove_params.ClearQuery(); 4653 remove_params.ClearRef(); 4654 const GURL url_to_send = failed_url.ReplaceComponents(remove_params); 4655 std::string spec_to_send = url_to_send.spec(); 4656 // Notify link doctor of the url truncation by sending of "?" at the end. 4657 if (failed_url.has_query()) 4658 spec_to_send.append("?"); 4659 4660 // Construct the query params to send to link doctor. 4661 std::string params(alternate_error_page_url_.query()); 4662 params.append("&url="); 4663 params.append(net::EscapeQueryParamValue(spec_to_send, true)); 4664 params.append("&sourceid=chrome"); 4665 params.append("&error="); 4666 switch (error_type) { 4667 case DNS_ERROR: 4668 params.append("dnserror"); 4669 break; 4670 4671 case HTTP_404: 4672 params.append("http404"); 4673 break; 4674 4675 case CONNECTION_ERROR: 4676 params.append("connectionfailure"); 4677 break; 4678 4679 default: 4680 NOTREACHED() << "unknown ErrorPageType"; 4681 } 4682 4683 // OK, build the final url to return. 4684 GURL::Replacements link_doctor_params; 4685 link_doctor_params.SetQueryStr(params); 4686 GURL url = alternate_error_page_url_.ReplaceComponents(link_doctor_params); 4687 return url; 4688 } 4689 4690 GURL RenderViewImpl::GetLoadingUrl(WebKit::WebFrame* frame) const { 4691 WebDataSource* ds = frame->dataSource(); 4692 if (ds->hasUnreachableURL()) 4693 return ds->unreachableURL(); 4694 4695 const WebURLRequest& request = ds->request(); 4696 return request.url(); 4697 } 4698 4699 WebKit::WebPlugin* RenderViewImpl::GetWebPluginFromPluginDocument() { 4700 return webview()->mainFrame()->document().to<WebPluginDocument>().plugin(); 4701 } 4702 4703 void RenderViewImpl::OnFind(int request_id, 4704 const string16& search_text, 4705 const WebFindOptions& options) { 4706 WebFrame* main_frame = webview()->mainFrame(); 4707 4708 // Check if the plugin still exists in the document. 4709 if (main_frame->document().isPluginDocument() && 4710 GetWebPluginFromPluginDocument()) { 4711 if (options.findNext) { 4712 // Just navigate back/forward. 4713 GetWebPluginFromPluginDocument()->selectFindResult(options.forward); 4714 } else { 4715 if (!GetWebPluginFromPluginDocument()->startFind( 4716 search_text, options.matchCase, request_id)) { 4717 // Send "no results". 4718 SendFindReply(request_id, 0, 0, gfx::Rect(), true); 4719 } 4720 } 4721 return; 4722 } 4723 4724 WebFrame* frame_after_main = main_frame->traverseNext(true); 4725 WebFrame* focused_frame = webview()->focusedFrame(); 4726 WebFrame* search_frame = focused_frame; // start searching focused frame. 4727 4728 bool multi_frame = (frame_after_main != main_frame); 4729 4730 // If we have multiple frames, we don't want to wrap the search within the 4731 // frame, so we check here if we only have main_frame in the chain. 4732 bool wrap_within_frame = !multi_frame; 4733 4734 WebRect selection_rect; 4735 bool result = false; 4736 4737 // If something is selected when we start searching it means we cannot just 4738 // increment the current match ordinal; we need to re-generate it. 4739 WebRange current_selection = focused_frame->selectionRange(); 4740 4741 do { 4742 result = search_frame->find( 4743 request_id, search_text, options, wrap_within_frame, &selection_rect); 4744 4745 if (!result) { 4746 // don't leave text selected as you move to the next frame. 4747 search_frame->executeCommand(WebString::fromUTF8("Unselect"), 4748 GetFocusedNode()); 4749 4750 // Find the next frame, but skip the invisible ones. 4751 do { 4752 // What is the next frame to search? (we might be going backwards). Note 4753 // that we specify wrap=true so that search_frame never becomes NULL. 4754 search_frame = options.forward ? 4755 search_frame->traverseNext(true) : 4756 search_frame->traversePrevious(true); 4757 } while (!search_frame->hasVisibleContent() && 4758 search_frame != focused_frame); 4759 4760 // Make sure selection doesn't affect the search operation in new frame. 4761 search_frame->executeCommand(WebString::fromUTF8("Unselect"), 4762 GetFocusedNode()); 4763 4764 // If we have multiple frames and we have wrapped back around to the 4765 // focused frame, we need to search it once more allowing wrap within 4766 // the frame, otherwise it will report 'no match' if the focused frame has 4767 // reported matches, but no frames after the focused_frame contain a 4768 // match for the search word(s). 4769 if (multi_frame && search_frame == focused_frame) { 4770 result = search_frame->find( 4771 request_id, search_text, options, true, // Force wrapping. 4772 &selection_rect); 4773 } 4774 } 4775 4776 webview()->setFocusedFrame(search_frame); 4777 } while (!result && search_frame != focused_frame); 4778 4779 if (options.findNext && current_selection.isNull()) { 4780 // Force the main_frame to report the actual count. 4781 main_frame->increaseMatchCount(0, request_id); 4782 } else { 4783 // If nothing is found, set result to "0 of 0", otherwise, set it to 4784 // "-1 of 1" to indicate that we found at least one item, but we don't know 4785 // yet what is active. 4786 int ordinal = result ? -1 : 0; // -1 here means, we might know more later. 4787 int match_count = result ? 1 : 0; // 1 here means possibly more coming. 4788 4789 // If we find no matches then this will be our last status update. 4790 // Otherwise the scoping effort will send more results. 4791 bool final_status_update = !result; 4792 4793 SendFindReply(request_id, match_count, ordinal, selection_rect, 4794 final_status_update); 4795 4796 // Scoping effort begins, starting with the mainframe. 4797 search_frame = main_frame; 4798 4799 main_frame->resetMatchCount(); 4800 4801 do { 4802 // Cancel all old scoping requests before starting a new one. 4803 search_frame->cancelPendingScopingEffort(); 4804 4805 // We don't start another scoping effort unless at least one match has 4806 // been found. 4807 if (result) { 4808 // Start new scoping request. If the scoping function determines that it 4809 // needs to scope, it will defer until later. 4810 search_frame->scopeStringMatches(request_id, 4811 search_text, 4812 options, 4813 true); // reset the tickmarks 4814 } 4815 4816 // Iterate to the next frame. The frame will not necessarily scope, for 4817 // example if it is not visible. 4818 search_frame = search_frame->traverseNext(true); 4819 } while (search_frame != main_frame); 4820 } 4821 } 4822 4823 void RenderViewImpl::OnStopFinding(StopFindAction action) { 4824 WebView* view = webview(); 4825 if (!view) 4826 return; 4827 4828 WebDocument doc = view->mainFrame()->document(); 4829 if (doc.isPluginDocument() && GetWebPluginFromPluginDocument()) { 4830 GetWebPluginFromPluginDocument()->stopFind(); 4831 return; 4832 } 4833 4834 bool clear_selection = action == STOP_FIND_ACTION_CLEAR_SELECTION; 4835 if (clear_selection) { 4836 view->focusedFrame()->executeCommand(WebString::fromUTF8("Unselect"), 4837 GetFocusedNode()); 4838 } 4839 4840 WebFrame* frame = view->mainFrame(); 4841 while (frame) { 4842 frame->stopFinding(clear_selection); 4843 frame = frame->traverseNext(false); 4844 } 4845 4846 if (action == STOP_FIND_ACTION_ACTIVATE_SELECTION) { 4847 WebFrame* focused_frame = view->focusedFrame(); 4848 if (focused_frame) { 4849 WebDocument doc = focused_frame->document(); 4850 if (!doc.isNull()) { 4851 WebNode node = doc.focusedNode(); 4852 if (!node.isNull()) 4853 node.simulateClick(); 4854 } 4855 } 4856 } 4857 } 4858 4859 #if defined(OS_ANDROID) 4860 void RenderViewImpl::OnActivateNearestFindResult(int request_id, 4861 float x, float y) { 4862 if (!webview()) 4863 return; 4864 4865 WebFrame* main_frame = webview()->mainFrame(); 4866 WebRect selection_rect; 4867 int ordinal = main_frame->selectNearestFindMatch(WebFloatPoint(x, y), 4868 &selection_rect); 4869 if (ordinal == -1) { 4870 // Something went wrong, so send a no-op reply (force the main_frame to 4871 // report the current match count) in case the host is waiting for a 4872 // response due to rate-limiting). 4873 main_frame->increaseMatchCount(0, request_id); 4874 return; 4875 } 4876 4877 SendFindReply(request_id, 4878 -1 /* number_of_matches */, 4879 ordinal, 4880 selection_rect, 4881 true /* final_update */); 4882 } 4883 4884 void RenderViewImpl::OnFindMatchRects(int current_version) { 4885 if (!webview()) 4886 return; 4887 4888 WebFrame* main_frame = webview()->mainFrame(); 4889 std::vector<gfx::RectF> match_rects; 4890 4891 int rects_version = main_frame->findMatchMarkersVersion(); 4892 if (current_version != rects_version) { 4893 WebVector<WebFloatRect> web_match_rects; 4894 main_frame->findMatchRects(web_match_rects); 4895 match_rects.reserve(web_match_rects.size()); 4896 for (size_t i = 0; i < web_match_rects.size(); ++i) 4897 match_rects.push_back(gfx::RectF(web_match_rects[i])); 4898 } 4899 4900 gfx::RectF active_rect = main_frame->activeFindMatchRect(); 4901 Send(new ViewHostMsg_FindMatchRects_Reply(routing_id_, 4902 rects_version, 4903 match_rects, 4904 active_rect)); 4905 } 4906 #endif 4907 4908 void RenderViewImpl::OnZoom(PageZoom zoom) { 4909 if (!webview()) // Not sure if this can happen, but no harm in being safe. 4910 return; 4911 4912 webview()->hidePopups(); 4913 4914 double old_zoom_level = webview()->zoomLevel(); 4915 double zoom_level; 4916 if (zoom == PAGE_ZOOM_RESET) { 4917 zoom_level = 0; 4918 } else if (static_cast<int>(old_zoom_level) == old_zoom_level) { 4919 // Previous zoom level is a whole number, so just increment/decrement. 4920 zoom_level = old_zoom_level + zoom; 4921 } else { 4922 // Either the user hit the zoom factor limit and thus the zoom level is now 4923 // not a whole number, or a plugin changed it to a custom value. We want 4924 // to go to the next whole number so that the user can always get back to 4925 // 100% with the keyboard/menu. 4926 if ((old_zoom_level > 1 && zoom > 0) || 4927 (old_zoom_level < 1 && zoom < 0)) { 4928 zoom_level = static_cast<int>(old_zoom_level + zoom); 4929 } else { 4930 // We're going towards 100%, so first go to the next whole number. 4931 zoom_level = static_cast<int>(old_zoom_level); 4932 } 4933 } 4934 webview()->setZoomLevel(false, zoom_level); 4935 zoomLevelChanged(); 4936 } 4937 4938 void RenderViewImpl::OnZoomFactor(PageZoom zoom, int zoom_center_x, 4939 int zoom_center_y) { 4940 ZoomFactorHelper(zoom, zoom_center_x, zoom_center_y, 4941 kScalingIncrementForGesture); 4942 } 4943 4944 void RenderViewImpl::ZoomFactorHelper(PageZoom zoom, 4945 int zoom_center_x, 4946 int zoom_center_y, 4947 float scaling_increment) { 4948 if (!webview()) // Not sure if this can happen, but no harm in being safe. 4949 return; 4950 4951 double old_page_scale_factor = webview()->pageScaleFactor(); 4952 double page_scale_factor; 4953 if (zoom == PAGE_ZOOM_RESET) { 4954 page_scale_factor = 1.0; 4955 } else { 4956 page_scale_factor = old_page_scale_factor + 4957 (zoom > 0 ? scaling_increment : -scaling_increment); 4958 } 4959 if (page_scale_factor > 0) { 4960 webview()->setPageScaleFactor(page_scale_factor, 4961 WebPoint(zoom_center_x, zoom_center_y)); 4962 } 4963 } 4964 4965 void RenderViewImpl::OnSetZoomLevel(double zoom_level) { 4966 webview()->hidePopups(); 4967 webview()->setZoomLevel(false, zoom_level); 4968 zoomLevelChanged(); 4969 } 4970 4971 void RenderViewImpl::OnSetZoomLevelForLoadingURL(const GURL& url, 4972 double zoom_level) { 4973 #if !defined(OS_ANDROID) 4974 // On Android, page zoom isn't used, and in case of WebView, text zoom is used 4975 // for legacy WebView text scaling emulation. Thus, the code that resets 4976 // the zoom level from this map will be effectively resetting text zoom level. 4977 host_zoom_levels_[url] = zoom_level; 4978 #endif 4979 } 4980 4981 void RenderViewImpl::OnSetPageEncoding(const std::string& encoding_name) { 4982 webview()->setPageEncoding(WebString::fromUTF8(encoding_name)); 4983 } 4984 4985 void RenderViewImpl::OnResetPageEncodingToDefault() { 4986 WebString no_encoding; 4987 webview()->setPageEncoding(no_encoding); 4988 } 4989 4990 WebFrame* RenderViewImpl::GetChildFrame(const string16& xpath) const { 4991 if (xpath.empty()) 4992 return webview()->mainFrame(); 4993 4994 // xpath string can represent a frame deep down the tree (across multiple 4995 // frame DOMs). 4996 // Example, /html/body/table/tbody/tr/td/iframe\n/frameset/frame[0] 4997 // should break into 2 xpaths 4998 // /html/body/table/tbody/tr/td/iframe & /frameset/frame[0] 4999 std::vector<string16> xpaths; 5000 base::SplitString(xpath, '\n', &xpaths); 5001 5002 WebFrame* frame = webview()->mainFrame(); 5003 for (std::vector<string16>::const_iterator i = xpaths.begin(); 5004 frame && i != xpaths.end(); ++i) { 5005 frame = frame->findChildByExpression(*i); 5006 } 5007 5008 return frame; 5009 } 5010 5011 void RenderViewImpl::OnScriptEvalRequest(const string16& frame_xpath, 5012 const string16& jscript, 5013 int id, 5014 bool notify_result) { 5015 TRACE_EVENT_INSTANT0("test_tracing", "OnScriptEvalRequest", 5016 TRACE_EVENT_SCOPE_THREAD); 5017 EvaluateScript(frame_xpath, jscript, id, notify_result); 5018 } 5019 5020 void RenderViewImpl::OnPostMessageEvent( 5021 const ViewMsg_PostMessage_Params& params) { 5022 // TODO(nasko): Support sending to subframes. 5023 WebFrame* frame = webview()->mainFrame(); 5024 5025 // Find the source frame if it exists. 5026 WebFrame* source_frame = NULL; 5027 if (params.source_routing_id != MSG_ROUTING_NONE) { 5028 RenderViewImpl* source_view = FromRoutingID(params.source_routing_id); 5029 if (source_view) 5030 source_frame = source_view->webview()->mainFrame(); 5031 } 5032 5033 // Create an event with the message. The final parameter to initMessageEvent 5034 // is the last event ID, which is not used with postMessage. 5035 WebDOMEvent event = frame->document().createEvent("MessageEvent"); 5036 WebDOMMessageEvent msg_event = event.to<WebDOMMessageEvent>(); 5037 msg_event.initMessageEvent("message", 5038 // |canBubble| and |cancellable| are always false 5039 false, false, 5040 WebSerializedScriptValue::fromString(params.data), 5041 params.source_origin, source_frame, ""); 5042 5043 // We must pass in the target_origin to do the security check on this side, 5044 // since it may have changed since the original postMessage call was made. 5045 WebSecurityOrigin target_origin; 5046 if (!params.target_origin.empty()) { 5047 target_origin = 5048 WebSecurityOrigin::createFromString(WebString(params.target_origin)); 5049 } 5050 frame->dispatchMessageEventWithOriginCheck(target_origin, msg_event); 5051 } 5052 5053 void RenderViewImpl::OnCSSInsertRequest(const string16& frame_xpath, 5054 const std::string& css) { 5055 WebFrame* frame = GetChildFrame(frame_xpath); 5056 if (!frame) 5057 return; 5058 5059 frame->document().insertUserStyleSheet( 5060 WebString::fromUTF8(css), 5061 WebDocument::UserStyleAuthorLevel); 5062 } 5063 5064 void RenderViewImpl::OnAllowBindings(int enabled_bindings_flags) { 5065 if ((enabled_bindings_flags & BINDINGS_POLICY_WEB_UI) && 5066 !(enabled_bindings_ & BINDINGS_POLICY_WEB_UI)) { 5067 RenderThread::Get()->RegisterExtension(WebUIExtension::Get()); 5068 new WebUIExtensionData(this); 5069 } 5070 5071 enabled_bindings_ |= enabled_bindings_flags; 5072 5073 // Keep track of the total bindings accumulated in this process. 5074 RenderProcess::current()->AddBindings(enabled_bindings_flags); 5075 } 5076 5077 void RenderViewImpl::OnDragTargetDragEnter(const DropData& drop_data, 5078 const gfx::Point& client_point, 5079 const gfx::Point& screen_point, 5080 WebDragOperationsMask ops, 5081 int key_modifiers) { 5082 WebDragOperation operation = webview()->dragTargetDragEnter( 5083 DropDataToWebDragData(drop_data), 5084 client_point, 5085 screen_point, 5086 ops, 5087 key_modifiers); 5088 5089 Send(new DragHostMsg_UpdateDragCursor(routing_id_, operation)); 5090 } 5091 5092 void RenderViewImpl::OnDragTargetDragOver(const gfx::Point& client_point, 5093 const gfx::Point& screen_point, 5094 WebDragOperationsMask ops, 5095 int key_modifiers) { 5096 WebDragOperation operation = webview()->dragTargetDragOver( 5097 client_point, 5098 screen_point, 5099 ops, 5100 key_modifiers); 5101 5102 Send(new DragHostMsg_UpdateDragCursor(routing_id_, operation)); 5103 } 5104 5105 void RenderViewImpl::OnDragTargetDragLeave() { 5106 webview()->dragTargetDragLeave(); 5107 } 5108 5109 void RenderViewImpl::OnDragTargetDrop(const gfx::Point& client_point, 5110 const gfx::Point& screen_point, 5111 int key_modifiers) { 5112 webview()->dragTargetDrop(client_point, screen_point, key_modifiers); 5113 5114 Send(new DragHostMsg_TargetDrop_ACK(routing_id_)); 5115 } 5116 5117 void RenderViewImpl::OnDragSourceEndedOrMoved(const gfx::Point& client_point, 5118 const gfx::Point& screen_point, 5119 bool ended, 5120 WebDragOperation op) { 5121 if (ended) { 5122 webview()->dragSourceEndedAt(client_point, screen_point, op); 5123 } else { 5124 webview()->dragSourceMovedTo(client_point, screen_point, op); 5125 } 5126 } 5127 5128 void RenderViewImpl::OnDragSourceSystemDragEnded() { 5129 webview()->dragSourceSystemDragEnded(); 5130 } 5131 5132 void RenderViewImpl::OnUpdateWebPreferences(const WebPreferences& prefs) { 5133 webkit_preferences_ = prefs; 5134 webkit_glue::ApplyWebPreferences(webkit_preferences_, webview()); 5135 } 5136 5137 void RenderViewImpl::OnUpdateTimezone() { 5138 if (webview()) 5139 NotifyTimezoneChange(webview()->mainFrame()); 5140 } 5141 5142 void RenderViewImpl::OnSetAltErrorPageURL(const GURL& url) { 5143 alternate_error_page_url_ = url; 5144 } 5145 5146 void RenderViewImpl::OnCustomContextMenuAction( 5147 const CustomContextMenuContext& custom_context, 5148 unsigned action) { 5149 if (custom_context.request_id) { 5150 // External context menu request, look in our map. 5151 ContextMenuClient* client = 5152 pending_context_menus_.Lookup(custom_context.request_id); 5153 if (client) 5154 client->OnMenuAction(custom_context.request_id, action); 5155 } else { 5156 // Internal request, forward to WebKit. 5157 webview()->performCustomContextMenuAction(action); 5158 } 5159 } 5160 5161 void RenderViewImpl::OnEnumerateDirectoryResponse( 5162 int id, 5163 const std::vector<base::FilePath>& paths) { 5164 if (!enumeration_completions_[id]) 5165 return; 5166 5167 WebVector<WebString> ws_file_names(paths.size()); 5168 for (size_t i = 0; i < paths.size(); ++i) 5169 ws_file_names[i] = paths[i].AsUTF16Unsafe(); 5170 5171 enumeration_completions_[id]->didChooseFile(ws_file_names); 5172 enumeration_completions_.erase(id); 5173 } 5174 5175 void RenderViewImpl::OnFileChooserResponse( 5176 const std::vector<ui::SelectedFileInfo>& files) { 5177 // This could happen if we navigated to a different page before the user 5178 // closed the chooser. 5179 if (file_chooser_completions_.empty()) 5180 return; 5181 5182 // Convert Chrome's SelectedFileInfo list to WebKit's. 5183 WebVector<WebFileChooserCompletion::SelectedFileInfo> selected_files( 5184 files.size()); 5185 for (size_t i = 0; i < files.size(); ++i) { 5186 WebFileChooserCompletion::SelectedFileInfo selected_file; 5187 selected_file.path = files[i].local_path.AsUTF16Unsafe(); 5188 selected_file.displayName = 5189 base::FilePath(files[i].display_name).AsUTF16Unsafe(); 5190 selected_files[i] = selected_file; 5191 } 5192 5193 if (file_chooser_completions_.front()->completion) 5194 file_chooser_completions_.front()->completion->didChooseFile( 5195 selected_files); 5196 file_chooser_completions_.pop_front(); 5197 5198 // If there are more pending file chooser requests, schedule one now. 5199 if (!file_chooser_completions_.empty()) { 5200 Send(new ViewHostMsg_RunFileChooser(routing_id_, 5201 file_chooser_completions_.front()->params)); 5202 } 5203 } 5204 5205 void RenderViewImpl::OnEnableAutoResize(const gfx::Size& min_size, 5206 const gfx::Size& max_size) { 5207 DCHECK(disable_scrollbars_size_limit_.IsEmpty()); 5208 if (!webview()) 5209 return; 5210 auto_resize_mode_ = true; 5211 webview()->enableAutoResizeMode(min_size, max_size); 5212 } 5213 5214 void RenderViewImpl::OnDisableAutoResize(const gfx::Size& new_size) { 5215 DCHECK(disable_scrollbars_size_limit_.IsEmpty()); 5216 if (!webview()) 5217 return; 5218 auto_resize_mode_ = false; 5219 webview()->disableAutoResizeMode(); 5220 5221 if (!new_size.IsEmpty()) { 5222 Resize(new_size, 5223 physical_backing_size_, 5224 overdraw_bottom_height_, 5225 resizer_rect_, 5226 is_fullscreen_, 5227 NO_RESIZE_ACK); 5228 } 5229 } 5230 5231 void RenderViewImpl::OnEnablePreferredSizeChangedMode() { 5232 if (send_preferred_size_changes_) 5233 return; 5234 send_preferred_size_changes_ = true; 5235 5236 // Start off with an initial preferred size notification (in case 5237 // |didUpdateLayout| was already called). 5238 didUpdateLayout(); 5239 } 5240 5241 void RenderViewImpl::OnDisableScrollbarsForSmallWindows( 5242 const gfx::Size& disable_scrollbar_size_limit) { 5243 disable_scrollbars_size_limit_ = disable_scrollbar_size_limit; 5244 } 5245 5246 void RenderViewImpl::OnSetRendererPrefs( 5247 const RendererPreferences& renderer_prefs) { 5248 double old_zoom_level = renderer_preferences_.default_zoom_level; 5249 renderer_preferences_ = renderer_prefs; 5250 UpdateFontRenderingFromRendererPrefs(); 5251 5252 #if defined(USE_DEFAULT_RENDER_THEME) || defined(TOOLKIT_GTK) 5253 if (renderer_prefs.use_custom_colors) { 5254 WebColorName name = WebKit::WebColorWebkitFocusRingColor; 5255 WebKit::setNamedColors(&name, &renderer_prefs.focus_ring_color, 1); 5256 WebKit::setCaretBlinkInterval(renderer_prefs.caret_blink_interval); 5257 #if defined(TOOLKIT_GTK) 5258 ui::NativeTheme::instance()->SetScrollbarColors( 5259 renderer_prefs.thumb_inactive_color, 5260 renderer_prefs.thumb_active_color, 5261 renderer_prefs.track_color); 5262 #endif // defined(TOOLKIT_GTK) 5263 5264 if (webview()) { 5265 #if defined(TOOLKIT_GTK) 5266 webview()->setScrollbarColors( 5267 renderer_prefs.thumb_inactive_color, 5268 renderer_prefs.thumb_active_color, 5269 renderer_prefs.track_color); 5270 #endif // defined(TOOLKIT_GTK) 5271 webview()->setSelectionColors( 5272 renderer_prefs.active_selection_bg_color, 5273 renderer_prefs.active_selection_fg_color, 5274 renderer_prefs.inactive_selection_bg_color, 5275 renderer_prefs.inactive_selection_fg_color); 5276 webview()->themeChanged(); 5277 } 5278 } 5279 #endif // defined(USE_DEFAULT_RENDER_THEME) || defined(TOOLKIT_GTK) 5280 5281 if (RenderThreadImpl::current()) // Will be NULL during unit tests. 5282 RenderThreadImpl::current()->SetFlingCurveParameters( 5283 renderer_prefs.touchpad_fling_profile, 5284 renderer_prefs.touchscreen_fling_profile); 5285 5286 // If the zoom level for this page matches the old zoom default, and this 5287 // is not a plugin, update the zoom level to match the new default. 5288 if (webview() && !webview()->mainFrame()->document().isPluginDocument() && 5289 !ZoomValuesEqual(old_zoom_level, 5290 renderer_preferences_.default_zoom_level) && 5291 ZoomValuesEqual(webview()->zoomLevel(), old_zoom_level)) { 5292 webview()->setZoomLevel(false, renderer_preferences_.default_zoom_level); 5293 zoomLevelChanged(); 5294 } 5295 } 5296 5297 void RenderViewImpl::OnMediaPlayerActionAt(const gfx::Point& location, 5298 const WebMediaPlayerAction& action) { 5299 if (webview()) 5300 webview()->performMediaPlayerAction(action, location); 5301 } 5302 5303 void RenderViewImpl::OnOrientationChangeEvent(int orientation) { 5304 webview()->mainFrame()->sendOrientationChangeEvent(orientation); 5305 } 5306 5307 void RenderViewImpl::OnPluginActionAt(const gfx::Point& location, 5308 const WebPluginAction& action) { 5309 if (webview()) 5310 webview()->performPluginAction(action, location); 5311 } 5312 5313 void RenderViewImpl::OnGetAllSavableResourceLinksForCurrentPage( 5314 const GURL& page_url) { 5315 // Prepare list to storage all savable resource links. 5316 std::vector<GURL> resources_list; 5317 std::vector<GURL> referrer_urls_list; 5318 std::vector<WebKit::WebReferrerPolicy> referrer_policies_list; 5319 std::vector<GURL> frames_list; 5320 SavableResourcesResult result(&resources_list, 5321 &referrer_urls_list, 5322 &referrer_policies_list, 5323 &frames_list); 5324 5325 // webkit/ doesn't know about Referrer. 5326 if (!GetAllSavableResourceLinksForCurrentPage( 5327 webview(), 5328 page_url, 5329 &result, 5330 const_cast<const char**>(GetSavableSchemes()))) { 5331 // If something is wrong when collecting all savable resource links, 5332 // send empty list to embedder(browser) to tell it failed. 5333 referrer_urls_list.clear(); 5334 referrer_policies_list.clear(); 5335 resources_list.clear(); 5336 frames_list.clear(); 5337 } 5338 5339 std::vector<Referrer> referrers_list; 5340 CHECK_EQ(referrer_urls_list.size(), referrer_policies_list.size()); 5341 for (unsigned i = 0; i < referrer_urls_list.size(); ++i) { 5342 referrers_list.push_back( 5343 Referrer(referrer_urls_list[i], referrer_policies_list[i])); 5344 } 5345 5346 // Send result of all savable resource links to embedder. 5347 Send(new ViewHostMsg_SendCurrentPageAllSavableResourceLinks(routing_id(), 5348 resources_list, 5349 referrers_list, 5350 frames_list)); 5351 } 5352 5353 void RenderViewImpl::OnGetSerializedHtmlDataForCurrentPageWithLocalLinks( 5354 const std::vector<GURL>& links, 5355 const std::vector<base::FilePath>& local_paths, 5356 const base::FilePath& local_directory_name) { 5357 5358 // Convert std::vector of GURLs to WebVector<WebURL> 5359 WebVector<WebURL> weburl_links(links); 5360 5361 // Convert std::vector of base::FilePath to WebVector<WebString> 5362 WebVector<WebString> webstring_paths(local_paths.size()); 5363 for (size_t i = 0; i < local_paths.size(); i++) 5364 webstring_paths[i] = local_paths[i].AsUTF16Unsafe(); 5365 5366 WebPageSerializer::serialize(webview()->mainFrame(), true, this, weburl_links, 5367 webstring_paths, 5368 local_directory_name.AsUTF16Unsafe()); 5369 } 5370 5371 void RenderViewImpl::OnShouldClose() { 5372 base::TimeTicks before_unload_start_time = base::TimeTicks::Now(); 5373 bool should_close = webview()->dispatchBeforeUnloadEvent(); 5374 base::TimeTicks before_unload_end_time = base::TimeTicks::Now(); 5375 Send(new ViewHostMsg_ShouldClose_ACK(routing_id_, should_close, 5376 before_unload_start_time, 5377 before_unload_end_time)); 5378 } 5379 5380 void RenderViewImpl::OnSwapOut() { 5381 // Only run unload if we're not swapped out yet, but send the ack either way. 5382 if (!is_swapped_out_) { 5383 // Swap this RenderView out so the tab can navigate to a page rendered by a 5384 // different process. This involves running the unload handler and clearing 5385 // the page. Once WasSwappedOut is called, we also allow this process to 5386 // exit if there are no other active RenderViews in it. 5387 5388 // Send an UpdateState message before we get swapped out. 5389 SyncNavigationState(); 5390 5391 // Synchronously run the unload handler before sending the ACK. 5392 webview()->dispatchUnloadEvent(); 5393 5394 // Swap out and stop sending any IPC messages that are not ACKs. 5395 SetSwappedOut(true); 5396 5397 // Now that we're swapped out and filtering IPC messages, stop loading to 5398 // ensure that no other in-progress navigation continues. We do this here 5399 // to avoid sending a DidStopLoading message to the browser process. 5400 OnStop(); 5401 5402 // Replace the page with a blank dummy URL. The unload handler will not be 5403 // run a second time, thanks to a check in FrameLoader::stopLoading. 5404 // TODO(creis): Need to add a better way to do this that avoids running the 5405 // beforeunload handler. For now, we just run it a second time silently. 5406 NavigateToSwappedOutURL(webview()->mainFrame()); 5407 5408 // Let WebKit know that this view is hidden so it can drop resources and 5409 // stop compositing. 5410 webview()->setVisibilityState(WebKit::WebPageVisibilityStateHidden, false); 5411 } 5412 5413 Send(new ViewHostMsg_SwapOut_ACK(routing_id_)); 5414 } 5415 5416 void RenderViewImpl::NavigateToSwappedOutURL(WebKit::WebFrame* frame) { 5417 // We use loadRequest instead of loadHTMLString because the former commits 5418 // synchronously. Otherwise a new navigation can interrupt the navigation 5419 // to kSwappedOutURL. If that happens to be to the page we had been 5420 // showing, then WebKit will never send a commit and we'll be left spinning. 5421 CHECK(is_swapped_out_); 5422 GURL swappedOutURL(kSwappedOutURL); 5423 WebURLRequest request(swappedOutURL); 5424 frame->loadRequest(request); 5425 } 5426 5427 void RenderViewImpl::OnClosePage() { 5428 FOR_EACH_OBSERVER(RenderViewObserver, observers_, ClosePage()); 5429 // TODO(creis): We'd rather use webview()->Close() here, but that currently 5430 // sets the WebView's delegate_ to NULL, preventing any JavaScript dialogs 5431 // in the onunload handler from appearing. For now, we're bypassing that and 5432 // calling the FrameLoader's CloseURL method directly. This should be 5433 // revisited to avoid having two ways to close a page. Having a single way 5434 // to close that can run onunload is also useful for fixing 5435 // http://b/issue?id=753080. 5436 webview()->dispatchUnloadEvent(); 5437 5438 Send(new ViewHostMsg_ClosePage_ACK(routing_id_)); 5439 } 5440 5441 void RenderViewImpl::OnThemeChanged() { 5442 #if defined(USE_AURA) 5443 // Aura doesn't care if we switch themes. 5444 #elif defined(OS_WIN) 5445 ui::NativeThemeWin::instance()->CloseHandles(); 5446 if (webview()) 5447 webview()->themeChanged(); 5448 #else // defined(OS_WIN) 5449 // TODO(port): we don't support theming on non-Windows platforms yet 5450 NOTIMPLEMENTED(); 5451 #endif 5452 } 5453 5454 void RenderViewImpl::OnDisassociateFromPopupCount() { 5455 if (decrement_shared_popup_at_destruction_) 5456 shared_popup_counter_->data--; 5457 shared_popup_counter_ = new SharedRenderViewCounter(0); 5458 decrement_shared_popup_at_destruction_ = false; 5459 } 5460 5461 bool RenderViewImpl::MaybeLoadAlternateErrorPage(WebFrame* frame, 5462 const WebURLError& error, 5463 bool replace) { 5464 // We only show alternate error pages in the main frame. They are 5465 // intended to assist the user when navigating, so there is not much 5466 // value in showing them for failed subframes. Ideally, we would be 5467 // able to use the TYPED transition type for this, but that flag is 5468 // not preserved across page reloads. 5469 if (frame->parent()) 5470 return false; 5471 5472 // Use the alternate error page service if this is a DNS failure or 5473 // connection failure. 5474 int ec = error.reason; 5475 if (ec != net::ERR_NAME_NOT_RESOLVED && 5476 ec != net::ERR_CONNECTION_FAILED && 5477 ec != net::ERR_CONNECTION_REFUSED && 5478 ec != net::ERR_ADDRESS_UNREACHABLE && 5479 ec != net::ERR_CONNECTION_TIMED_OUT) { 5480 return false; 5481 } 5482 5483 const GURL& error_page_url = GetAlternateErrorPageURL(error.unreachableURL, 5484 ec == net::ERR_NAME_NOT_RESOLVED ? DNS_ERROR : CONNECTION_ERROR); 5485 if (!error_page_url.is_valid()) 5486 return false; 5487 5488 WebDataSource* ds = frame->provisionalDataSource(); 5489 const WebURLRequest& failed_request = ds->request(); 5490 5491 // Load an empty page first so there is an immediate response to the error, 5492 // and then kick off a request for the alternate error page. 5493 frame->loadHTMLString(std::string(), 5494 GURL(kUnreachableWebDataURL), 5495 error.unreachableURL, 5496 replace); 5497 5498 // Now, create a fetcher for the error page and associate it with the data 5499 // source we just created via the LoadHTMLString call. That way if another 5500 // navigation occurs, the fetcher will get destroyed. 5501 InternalDocumentStateData* internal_data = 5502 InternalDocumentStateData::FromDataSource(frame->provisionalDataSource()); 5503 internal_data->set_alt_error_page_fetcher( 5504 new AltErrorPageResourceFetcher( 5505 error_page_url, frame, failed_request, error, 5506 base::Bind(&RenderViewImpl::AltErrorPageFinished, 5507 base::Unretained(this)))); 5508 return true; 5509 } 5510 5511 void RenderViewImpl::AltErrorPageFinished(WebFrame* frame, 5512 const WebURLRequest& original_request, 5513 const WebURLError& original_error, 5514 const std::string& html) { 5515 // Here, we replace the blank page we loaded previously. 5516 // If we failed to download the alternate error page, LoadNavigationErrorPage 5517 // will simply display a default error page. 5518 LoadNavigationErrorPage(frame, original_request, original_error, html, true); 5519 } 5520 5521 void RenderViewImpl::OnMoveOrResizeStarted() { 5522 if (webview()) 5523 webview()->hidePopups(); 5524 } 5525 5526 void RenderViewImpl::OnResize(const ViewMsg_Resize_Params& params) { 5527 if (webview()) { 5528 webview()->hidePopups(); 5529 if (send_preferred_size_changes_) { 5530 webview()->mainFrame()->setCanHaveScrollbars( 5531 ShouldDisplayScrollbars(params.new_size.width(), 5532 params.new_size.height())); 5533 } 5534 UpdateScrollState(webview()->mainFrame()); 5535 } 5536 5537 RenderWidget::OnResize(params); 5538 } 5539 5540 void RenderViewImpl::WillInitiatePaint() { 5541 #if defined(ENABLE_PLUGINS) 5542 // Notify all of our instances that we started painting. This is used for 5543 // internal bookkeeping only, so we know that the set can not change under 5544 // us. 5545 for (PepperPluginSet::iterator i = active_pepper_instances_.begin(); 5546 i != active_pepper_instances_.end(); ++i) 5547 (*i)->ViewWillInitiatePaint(); 5548 #endif 5549 } 5550 5551 void RenderViewImpl::DidInitiatePaint() { 5552 #if defined(ENABLE_PLUGINS) 5553 // Notify all instances that we painted. The same caveats apply as for 5554 // ViewFlushedPaint regarding instances closing themselves, so we take 5555 // similar precautions. 5556 PepperPluginSet plugins = active_pepper_instances_; 5557 for (PepperPluginSet::iterator i = plugins.begin(); i != plugins.end(); ++i) { 5558 if (active_pepper_instances_.find(*i) != active_pepper_instances_.end()) 5559 (*i)->ViewInitiatedPaint(); 5560 } 5561 #endif 5562 } 5563 5564 void RenderViewImpl::DidFlushPaint() { 5565 #if defined(ENABLE_PLUGINS) 5566 // Notify all instances that we flushed. This will call into the plugin, and 5567 // we it may ask to close itself as a result. This will, in turn, modify our 5568 // set, possibly invalidating the iterator. So we iterate on a copy that 5569 // won't change out from under us. 5570 PepperPluginSet plugins = active_pepper_instances_; 5571 for (PepperPluginSet::iterator i = plugins.begin(); i != plugins.end(); ++i) { 5572 // The copy above makes sure our iterator is never invalid if some plugins 5573 // are destroyed. But some plugin may decide to close all of its views in 5574 // response to a paint in one of them, so we need to make sure each one is 5575 // still "current" before using it. 5576 // 5577 // It's possible that a plugin was destroyed, but another one was created 5578 // with the same address. In this case, we'll call ViewFlushedPaint on that 5579 // new plugin. But that's OK for this particular case since we're just 5580 // notifying all of our instances that the view flushed, and the new one is 5581 // one of our instances. 5582 // 5583 // What about the case where a new one is created in a callback at a new 5584 // address and we don't issue the callback? We're still OK since this 5585 // callback is used for flush callbacks and we could not have possibly 5586 // started a new paint (ViewWillInitiatePaint) for the new plugin while 5587 // processing a previous paint for an existing one. 5588 if (active_pepper_instances_.find(*i) != active_pepper_instances_.end()) 5589 (*i)->ViewFlushedPaint(); 5590 } 5591 #endif 5592 5593 // If the RenderWidget is closing down then early-exit, otherwise we'll crash. 5594 // See crbug.com/112921. 5595 if (!webview()) 5596 return; 5597 5598 WebFrame* main_frame = webview()->mainFrame(); 5599 5600 // If we have a provisional frame we are between the start and commit stages 5601 // of loading and we don't want to save stats. 5602 if (!main_frame->provisionalDataSource()) { 5603 WebDataSource* ds = main_frame->dataSource(); 5604 DocumentState* document_state = DocumentState::FromDataSource(ds); 5605 InternalDocumentStateData* data = 5606 InternalDocumentStateData::FromDocumentState(document_state); 5607 if (data->did_first_visually_non_empty_layout() && 5608 !data->did_first_visually_non_empty_paint()) { 5609 data->set_did_first_visually_non_empty_paint(true); 5610 Send(new ViewHostMsg_DidFirstVisuallyNonEmptyPaint(routing_id_, 5611 page_id_)); 5612 } 5613 5614 // TODO(jar): The following code should all be inside a method, probably in 5615 // NavigatorState. 5616 Time now = Time::Now(); 5617 if (document_state->first_paint_time().is_null()) { 5618 document_state->set_first_paint_time(now); 5619 } 5620 if (document_state->first_paint_after_load_time().is_null() && 5621 !document_state->finish_load_time().is_null()) { 5622 document_state->set_first_paint_after_load_time(now); 5623 } 5624 } 5625 } 5626 5627 PepperPluginInstanceImpl* RenderViewImpl::GetBitmapForOptimizedPluginPaint( 5628 const gfx::Rect& paint_bounds, 5629 TransportDIB** dib, 5630 gfx::Rect* location, 5631 gfx::Rect* clip, 5632 float* scale_factor) { 5633 #if defined(ENABLE_PLUGINS) 5634 for (PepperPluginSet::iterator i = active_pepper_instances_.begin(); 5635 i != active_pepper_instances_.end(); ++i) { 5636 PepperPluginInstanceImpl* instance = *i; 5637 // In Flash fullscreen , the plugin contents should be painted onto the 5638 // fullscreen widget instead of the web page. 5639 if (!instance->FlashIsFullscreenOrPending() && 5640 instance->GetBitmapForOptimizedPluginPaint(paint_bounds, dib, location, 5641 clip, scale_factor)) 5642 return *i; 5643 } 5644 #endif 5645 return NULL; 5646 } 5647 5648 gfx::Vector2d RenderViewImpl::GetScrollOffset() { 5649 WebSize scroll_offset = webview()->mainFrame()->scrollOffset(); 5650 return gfx::Vector2d(scroll_offset.width, scroll_offset.height); 5651 } 5652 5653 void RenderViewImpl::OnClearFocusedNode() { 5654 if (webview()) 5655 webview()->clearFocusedNode(); 5656 } 5657 5658 void RenderViewImpl::OnSetBackground(const SkBitmap& background) { 5659 if (webview()) 5660 webview()->setIsTransparent(!background.empty()); 5661 if (compositor_) 5662 compositor_->setHasTransparentBackground(!background.empty()); 5663 5664 SetBackground(background); 5665 } 5666 5667 void RenderViewImpl::OnSetAccessibilityMode(AccessibilityMode new_mode) { 5668 if (accessibility_mode_ == new_mode) 5669 return; 5670 accessibility_mode_ = new_mode; 5671 if (renderer_accessibility_) { 5672 delete renderer_accessibility_; 5673 renderer_accessibility_ = NULL; 5674 } 5675 if (accessibility_mode_ == AccessibilityModeComplete) 5676 renderer_accessibility_ = new RendererAccessibilityComplete(this); 5677 #if !defined(OS_ANDROID) 5678 else if (accessibility_mode_ == AccessibilityModeEditableTextOnly) 5679 renderer_accessibility_ = new RendererAccessibilityFocusOnly(this); 5680 #endif 5681 } 5682 5683 void RenderViewImpl::OnSetActive(bool active) { 5684 if (webview()) 5685 webview()->setIsActive(active); 5686 5687 #if defined(ENABLE_PLUGINS) && 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); 5692 } 5693 #endif 5694 } 5695 5696 #if defined(OS_MACOSX) 5697 void RenderViewImpl::OnSetWindowVisibility(bool visible) { 5698 #if defined(ENABLE_PLUGINS) 5699 // Inform plugins that their container has changed visibility. 5700 std::set<WebPluginDelegateProxy*>::iterator plugin_it; 5701 for (plugin_it = plugin_delegates_.begin(); 5702 plugin_it != plugin_delegates_.end(); ++plugin_it) { 5703 (*plugin_it)->SetContainerVisibility(visible); 5704 } 5705 #endif 5706 } 5707 5708 void RenderViewImpl::OnWindowFrameChanged(const gfx::Rect& window_frame, 5709 const gfx::Rect& view_frame) { 5710 #if defined(ENABLE_PLUGINS) 5711 // Inform plugins that their window's frame has changed. 5712 std::set<WebPluginDelegateProxy*>::iterator plugin_it; 5713 for (plugin_it = plugin_delegates_.begin(); 5714 plugin_it != plugin_delegates_.end(); ++plugin_it) { 5715 (*plugin_it)->WindowFrameChanged(window_frame, view_frame); 5716 } 5717 #endif 5718 } 5719 5720 void RenderViewImpl::OnPluginImeCompositionCompleted(const string16& text, 5721 int plugin_id) { 5722 // WebPluginDelegateProxy is responsible for figuring out if this event 5723 // applies to it or not, so inform all the delegates. 5724 std::set<WebPluginDelegateProxy*>::iterator plugin_it; 5725 for (plugin_it = plugin_delegates_.begin(); 5726 plugin_it != plugin_delegates_.end(); ++plugin_it) { 5727 (*plugin_it)->ImeCompositionCompleted(text, plugin_id); 5728 } 5729 } 5730 #endif // OS_MACOSX 5731 5732 void RenderViewImpl::Close() { 5733 // We need to grab a pointer to the doomed WebView before we destroy it. 5734 WebView* doomed = webview(); 5735 RenderWidget::Close(); 5736 g_view_map.Get().erase(doomed); 5737 g_routing_id_view_map.Get().erase(routing_id_); 5738 } 5739 5740 void RenderViewImpl::DidHandleKeyEvent() { 5741 ClearEditCommands(); 5742 } 5743 5744 bool RenderViewImpl::WillHandleMouseEvent(const WebKit::WebMouseEvent& event) { 5745 context_menu_source_type_ = ui::MENU_SOURCE_MOUSE; 5746 possible_drag_event_info_.event_source = 5747 ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE; 5748 possible_drag_event_info_.event_location = 5749 gfx::Point(event.globalX, event.globalY); 5750 5751 #if defined(ENABLE_PLUGINS) 5752 // This method is called for every mouse event that the render view receives. 5753 // And then the mouse event is forwarded to WebKit, which dispatches it to the 5754 // event target. Potentially a Pepper plugin will receive the event. 5755 // In order to tell whether a plugin gets the last mouse event and which it 5756 // is, we set |pepper_last_mouse_event_target_| to NULL here. If a plugin gets 5757 // the event, it will notify us via DidReceiveMouseEvent() and set itself as 5758 // |pepper_last_mouse_event_target_|. 5759 pepper_last_mouse_event_target_ = NULL; 5760 #endif 5761 5762 // If the mouse is locked, only the current owner of the mouse lock can 5763 // process mouse events. 5764 return mouse_lock_dispatcher_->WillHandleMouseEvent(event); 5765 } 5766 5767 bool RenderViewImpl::WillHandleKeyEvent(const WebKit::WebKeyboardEvent& event) { 5768 context_menu_source_type_ = ui::MENU_SOURCE_KEYBOARD; 5769 return false; 5770 } 5771 5772 bool RenderViewImpl::WillHandleGestureEvent( 5773 const WebKit::WebGestureEvent& event) { 5774 context_menu_source_type_ = ui::MENU_SOURCE_TOUCH; 5775 possible_drag_event_info_.event_source = 5776 ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH; 5777 possible_drag_event_info_.event_location = 5778 gfx::Point(event.globalX, event.globalY); 5779 return false; 5780 } 5781 5782 void RenderViewImpl::DidHandleMouseEvent(const WebMouseEvent& event) { 5783 FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidHandleMouseEvent(event)); 5784 } 5785 5786 void RenderViewImpl::DidHandleTouchEvent(const WebTouchEvent& event) { 5787 FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidHandleTouchEvent(event)); 5788 } 5789 5790 bool RenderViewImpl::HasTouchEventHandlersAt(const gfx::Point& point) const { 5791 if (!webview()) 5792 return false; 5793 return webview()->hasTouchEventHandlersAt(point); 5794 } 5795 5796 void RenderViewImpl::OnWasHidden() { 5797 RenderWidget::OnWasHidden(); 5798 5799 #if defined(OS_ANDROID) && defined(ENABLE_WEBRTC) 5800 RenderThreadImpl::current()->video_capture_impl_manager()-> 5801 SuspendDevices(true); 5802 #endif 5803 5804 if (webview()) 5805 webview()->setVisibilityState(visibilityState(), false); 5806 5807 #if defined(ENABLE_PLUGINS) 5808 // Inform PPAPI plugins that their page is no longer visible. 5809 for (PepperPluginSet::iterator i = active_pepper_instances_.begin(); 5810 i != active_pepper_instances_.end(); ++i) 5811 (*i)->PageVisibilityChanged(false); 5812 5813 #if defined(OS_MACOSX) 5814 // Inform NPAPI plugins that their container is no longer visible. 5815 std::set<WebPluginDelegateProxy*>::iterator plugin_it; 5816 for (plugin_it = plugin_delegates_.begin(); 5817 plugin_it != plugin_delegates_.end(); ++plugin_it) { 5818 (*plugin_it)->SetContainerVisibility(false); 5819 } 5820 #endif // OS_MACOSX 5821 #endif // ENABLE_PLUGINS 5822 } 5823 5824 void RenderViewImpl::OnWasShown(bool needs_repainting) { 5825 RenderWidget::OnWasShown(needs_repainting); 5826 5827 #if defined(OS_ANDROID) && defined(ENABLE_WEBRTC) 5828 RenderThreadImpl::current()->video_capture_impl_manager()-> 5829 SuspendDevices(false); 5830 #endif 5831 5832 if (webview()) 5833 webview()->setVisibilityState(visibilityState(), false); 5834 5835 #if defined(ENABLE_PLUGINS) 5836 // Inform PPAPI plugins that their page is visible. 5837 for (PepperPluginSet::iterator i = active_pepper_instances_.begin(); 5838 i != active_pepper_instances_.end(); ++i) 5839 (*i)->PageVisibilityChanged(true); 5840 5841 #if defined(OS_MACOSX) 5842 // Inform NPAPI plugins that their container is now visible. 5843 std::set<WebPluginDelegateProxy*>::iterator plugin_it; 5844 for (plugin_it = plugin_delegates_.begin(); 5845 plugin_it != plugin_delegates_.end(); ++plugin_it) { 5846 (*plugin_it)->SetContainerVisibility(true); 5847 } 5848 #endif // OS_MACOSX 5849 #endif // ENABLE_PLUGINS 5850 } 5851 5852 GURL RenderViewImpl::GetURLForGraphicsContext3D() { 5853 DCHECK(webview()); 5854 if (webview()->mainFrame()) 5855 return GURL(webview()->mainFrame()->document().url()); 5856 else 5857 return GURL("chrome://gpu/RenderViewImpl::CreateGraphicsContext3D"); 5858 } 5859 5860 bool RenderViewImpl::ForceCompositingModeEnabled() { 5861 return webkit_preferences_.force_compositing_mode; 5862 } 5863 5864 void RenderViewImpl::OnSetFocus(bool enable) { 5865 RenderWidget::OnSetFocus(enable); 5866 5867 #if defined(ENABLE_PLUGINS) 5868 if (webview() && webview()->isActive()) { 5869 // Notify all NPAPI plugins. 5870 std::set<WebPluginDelegateProxy*>::iterator plugin_it; 5871 for (plugin_it = plugin_delegates_.begin(); 5872 plugin_it != plugin_delegates_.end(); ++plugin_it) { 5873 #if defined(OS_MACOSX) 5874 // RenderWidget's call to setFocus can cause the underlying webview's 5875 // activation state to change just like a call to setIsActive. 5876 if (enable) 5877 (*plugin_it)->SetWindowFocus(true); 5878 #endif 5879 (*plugin_it)->SetContentAreaFocus(enable); 5880 } 5881 } 5882 // Notify all Pepper plugins. 5883 for (PepperPluginSet::iterator i = active_pepper_instances_.begin(); 5884 i != active_pepper_instances_.end(); ++i) 5885 (*i)->SetContentAreaFocus(enable); 5886 #endif 5887 // Notify all BrowserPlugins of the RenderView's focus state. 5888 if (browser_plugin_manager_.get()) 5889 browser_plugin_manager_->UpdateFocusState(); 5890 } 5891 5892 void RenderViewImpl::OnImeSetComposition( 5893 const string16& text, 5894 const std::vector<WebKit::WebCompositionUnderline>& underlines, 5895 int selection_start, 5896 int selection_end) { 5897 #if defined(ENABLE_PLUGINS) 5898 if (focused_pepper_plugin_) { 5899 // When a PPAPI plugin has focus, we bypass WebKit. 5900 if (!IsPepperAcceptingCompositionEvents()) { 5901 pepper_composition_text_ = text; 5902 } else { 5903 // TODO(kinaba) currently all composition events are sent directly to 5904 // plugins. Use DOM event mechanism after WebKit is made aware about 5905 // plugins that support composition. 5906 // The code below mimics the behavior of WebCore::Editor::setComposition. 5907 5908 // Empty -> nonempty: composition started. 5909 if (pepper_composition_text_.empty() && !text.empty()) 5910 focused_pepper_plugin_->HandleCompositionStart(string16()); 5911 // Nonempty -> empty: composition canceled. 5912 if (!pepper_composition_text_.empty() && text.empty()) 5913 focused_pepper_plugin_->HandleCompositionEnd(string16()); 5914 pepper_composition_text_ = text; 5915 // Nonempty: composition is ongoing. 5916 if (!pepper_composition_text_.empty()) { 5917 focused_pepper_plugin_->HandleCompositionUpdate( 5918 pepper_composition_text_, underlines, selection_start, 5919 selection_end); 5920 } 5921 } 5922 return; 5923 } 5924 5925 #if defined(OS_WIN) 5926 // When a plug-in has focus, we create platform-specific IME data used by 5927 // our IME emulator and send it directly to the focused plug-in, i.e. we 5928 // bypass WebKit. (WebPluginDelegate dispatches this IME data only when its 5929 // instance ID is the same one as the specified ID.) 5930 if (focused_plugin_id_ >= 0) { 5931 std::vector<int> clauses; 5932 std::vector<int> target; 5933 for (size_t i = 0; i < underlines.size(); ++i) { 5934 clauses.push_back(underlines[i].startOffset); 5935 clauses.push_back(underlines[i].endOffset); 5936 if (underlines[i].thick) { 5937 target.clear(); 5938 target.push_back(underlines[i].startOffset); 5939 target.push_back(underlines[i].endOffset); 5940 } 5941 } 5942 std::set<WebPluginDelegateProxy*>::iterator it; 5943 for (it = plugin_delegates_.begin(); it != plugin_delegates_.end(); ++it) { 5944 (*it)->ImeCompositionUpdated(text, clauses, target, selection_end, 5945 focused_plugin_id_); 5946 } 5947 return; 5948 } 5949 #endif // OS_WIN 5950 #endif // ENABLE_PLUGINS 5951 RenderWidget::OnImeSetComposition(text, 5952 underlines, 5953 selection_start, 5954 selection_end); 5955 } 5956 5957 void RenderViewImpl::OnImeConfirmComposition(const string16& text, 5958 const ui::Range& replacement_range, 5959 bool keep_selection) { 5960 #if defined(ENABLE_PLUGINS) 5961 if (focused_pepper_plugin_) { 5962 // When a PPAPI plugin has focus, we bypass WebKit. 5963 // Here, text.empty() has a special meaning. It means to commit the last 5964 // update of composition text (see 5965 // RenderWidgetHost::ImeConfirmComposition()). 5966 const string16& last_text = text.empty() ? pepper_composition_text_ : text; 5967 5968 // last_text is empty only when both text and pepper_composition_text_ is. 5969 // Ignore it. 5970 if (last_text.empty()) 5971 return; 5972 5973 if (!IsPepperAcceptingCompositionEvents()) { 5974 for (size_t i = 0; i < text.size(); ++i) { 5975 WebKit::WebKeyboardEvent char_event; 5976 char_event.type = WebKit::WebInputEvent::Char; 5977 char_event.timeStampSeconds = base::Time::Now().ToDoubleT(); 5978 char_event.modifiers = 0; 5979 char_event.windowsKeyCode = last_text[i]; 5980 char_event.nativeKeyCode = last_text[i]; 5981 char_event.text[0] = last_text[i]; 5982 char_event.unmodifiedText[0] = last_text[i]; 5983 if (webwidget()) 5984 webwidget()->handleInputEvent(char_event); 5985 } 5986 } else { 5987 // Mimics the order of events sent by WebKit. 5988 // See WebCore::Editor::setComposition() for the corresponding code. 5989 focused_pepper_plugin_->HandleCompositionEnd(last_text); 5990 focused_pepper_plugin_->HandleTextInput(last_text); 5991 } 5992 pepper_composition_text_.clear(); 5993 return; 5994 } 5995 #if defined(OS_WIN) 5996 // Same as OnImeSetComposition(), we send the text from IMEs directly to 5997 // plug-ins. When we send IME text directly to plug-ins, we should not send 5998 // it to WebKit to prevent WebKit from controlling IMEs. 5999 // TODO(thakis): Honor |replacement_range| for plugins? 6000 if (focused_plugin_id_ >= 0) { 6001 std::set<WebPluginDelegateProxy*>::iterator it; 6002 for (it = plugin_delegates_.begin(); 6003 it != plugin_delegates_.end(); ++it) { 6004 (*it)->ImeCompositionCompleted(text, focused_plugin_id_); 6005 } 6006 return; 6007 } 6008 #endif // OS_WIN 6009 #endif // ENABLE_PLUGINS 6010 if (replacement_range.IsValid() && webview()) { 6011 // Select the text in |replacement_range|, it will then be replaced by 6012 // text added by the call to RenderWidget::OnImeConfirmComposition(). 6013 if (WebFrame* frame = webview()->focusedFrame()) { 6014 WebRange webrange = WebRange::fromDocumentRange( 6015 frame, replacement_range.start(), replacement_range.length()); 6016 if (!webrange.isNull()) 6017 frame->selectRange(webrange); 6018 } 6019 } 6020 RenderWidget::OnImeConfirmComposition(text, 6021 replacement_range, 6022 keep_selection); 6023 } 6024 6025 void RenderViewImpl::SetDeviceScaleFactor(float device_scale_factor) { 6026 RenderWidget::SetDeviceScaleFactor(device_scale_factor); 6027 if (webview()) { 6028 webview()->setDeviceScaleFactor(device_scale_factor); 6029 webview()->settings()->setAcceleratedCompositingForFixedPositionEnabled( 6030 ShouldUseFixedPositionCompositing(device_scale_factor_)); 6031 webview()->settings()->setAcceleratedCompositingForOverflowScrollEnabled( 6032 ShouldUseAcceleratedCompositingForOverflowScroll(device_scale_factor_)); 6033 webview()->settings()->setAcceleratedCompositingForTransitionEnabled( 6034 ShouldUseTransitionCompositing(device_scale_factor_)); 6035 webview()->settings()-> 6036 setAcceleratedCompositingForFixedRootBackgroundEnabled( 6037 ShouldUseAcceleratedFixedRootBackground(device_scale_factor_)); 6038 } 6039 if (auto_resize_mode_) 6040 AutoResizeCompositor(); 6041 6042 if (browser_plugin_manager_.get()) 6043 browser_plugin_manager_->UpdateDeviceScaleFactor(device_scale_factor_); 6044 } 6045 6046 ui::TextInputType RenderViewImpl::GetTextInputType() { 6047 #if defined(ENABLE_PLUGINS) 6048 if (focused_pepper_plugin_) 6049 return focused_pepper_plugin_->text_input_type(); 6050 #endif 6051 return RenderWidget::GetTextInputType(); 6052 } 6053 6054 void RenderViewImpl::GetSelectionBounds(gfx::Rect* start, gfx::Rect* end) { 6055 #if defined(ENABLE_PLUGINS) 6056 if (focused_pepper_plugin_) { 6057 // TODO(kinaba) http://crbug.com/101101 6058 // Current Pepper IME API does not handle selection bounds. So we simply 6059 // use the caret position as an empty range for now. It will be updated 6060 // after Pepper API equips features related to surrounding text retrieval. 6061 gfx::Rect caret = focused_pepper_plugin_->GetCaretBounds(); 6062 *start = caret; 6063 *end = caret; 6064 return; 6065 } 6066 #endif 6067 RenderWidget::GetSelectionBounds(start, end); 6068 } 6069 6070 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA) 6071 void RenderViewImpl::GetCompositionCharacterBounds( 6072 std::vector<gfx::Rect>* bounds) { 6073 DCHECK(bounds); 6074 bounds->clear(); 6075 6076 #if defined(ENABLE_PLUGINS) 6077 if (focused_pepper_plugin_) { 6078 return; 6079 } 6080 #endif 6081 6082 if (!webview()) 6083 return; 6084 size_t start_offset = 0; 6085 size_t character_count = 0; 6086 if (!webview()->compositionRange(&start_offset, &character_count)) 6087 return; 6088 if (character_count == 0) 6089 return; 6090 6091 WebKit::WebFrame* frame = webview()->focusedFrame(); 6092 if (!frame) 6093 return; 6094 6095 bounds->reserve(character_count); 6096 WebKit::WebRect webrect; 6097 for (size_t i = 0; i < character_count; ++i) { 6098 if (!frame->firstRectForCharacterRange(start_offset + i, 1, webrect)) { 6099 DLOG(ERROR) << "Could not retrieve character rectangle at " << i; 6100 bounds->clear(); 6101 return; 6102 } 6103 bounds->push_back(webrect); 6104 } 6105 } 6106 6107 void RenderViewImpl::GetCompositionRange(ui::Range* range) { 6108 #if defined(ENABLE_PLUGINS) 6109 if (focused_pepper_plugin_) { 6110 return; 6111 } 6112 #endif 6113 RenderWidget::GetCompositionRange(range); 6114 } 6115 #endif 6116 6117 bool RenderViewImpl::CanComposeInline() { 6118 #if defined(ENABLE_PLUGINS) 6119 if (focused_pepper_plugin_) 6120 return IsPepperAcceptingCompositionEvents(); 6121 #endif 6122 return true; 6123 } 6124 6125 void RenderViewImpl::InstrumentWillBeginFrame() { 6126 if (!webview()) 6127 return; 6128 if (!webview()->devToolsAgent()) 6129 return; 6130 webview()->devToolsAgent()->didBeginFrame(); 6131 } 6132 6133 void RenderViewImpl::InstrumentDidBeginFrame() { 6134 if (!webview()) 6135 return; 6136 if (!webview()->devToolsAgent()) 6137 return; 6138 // TODO(jamesr/caseq): Decide if this needs to be renamed. 6139 webview()->devToolsAgent()->didComposite(); 6140 } 6141 6142 void RenderViewImpl::InstrumentDidCancelFrame() { 6143 if (!webview()) 6144 return; 6145 if (!webview()->devToolsAgent()) 6146 return; 6147 webview()->devToolsAgent()->didCancelFrame(); 6148 } 6149 6150 void RenderViewImpl::InstrumentWillComposite() { 6151 if (!webview()) 6152 return; 6153 if (!webview()->devToolsAgent()) 6154 return; 6155 webview()->devToolsAgent()->willComposite(); 6156 } 6157 6158 bool RenderViewImpl::AllowPartialSwap() const { 6159 return allow_partial_swap_; 6160 } 6161 6162 bool RenderViewImpl::ScheduleFileChooser( 6163 const FileChooserParams& params, 6164 WebFileChooserCompletion* completion) { 6165 static const size_t kMaximumPendingFileChooseRequests = 4; 6166 if (file_chooser_completions_.size() > kMaximumPendingFileChooseRequests) { 6167 // This sanity check prevents too many file choose requests from getting 6168 // queued which could DoS the user. Getting these is most likely a 6169 // programming error (there are many ways to DoS the user so it's not 6170 // considered a "real" security check), either in JS requesting many file 6171 // choosers to pop up, or in a plugin. 6172 // 6173 // TODO(brettw) we might possibly want to require a user gesture to open 6174 // a file picker, which will address this issue in a better way. 6175 return false; 6176 } 6177 6178 file_chooser_completions_.push_back(linked_ptr<PendingFileChooser>( 6179 new PendingFileChooser(params, completion))); 6180 if (file_chooser_completions_.size() == 1) { 6181 // Actually show the browse dialog when this is the first request. 6182 Send(new ViewHostMsg_RunFileChooser(routing_id_, params)); 6183 } 6184 return true; 6185 } 6186 6187 WebKit::WebGeolocationClient* RenderViewImpl::geolocationClient() { 6188 if (!geolocation_dispatcher_) 6189 geolocation_dispatcher_ = new GeolocationDispatcher(this); 6190 return geolocation_dispatcher_; 6191 } 6192 6193 WebKit::WebSpeechInputController* RenderViewImpl::speechInputController( 6194 WebKit::WebSpeechInputListener* listener) { 6195 #if defined(ENABLE_INPUT_SPEECH) 6196 if (!input_tag_speech_dispatcher_) 6197 input_tag_speech_dispatcher_ = 6198 new InputTagSpeechDispatcher(this, listener); 6199 #endif 6200 return input_tag_speech_dispatcher_; 6201 } 6202 6203 WebKit::WebSpeechRecognizer* RenderViewImpl::speechRecognizer() { 6204 if (!speech_recognition_dispatcher_) 6205 speech_recognition_dispatcher_ = new SpeechRecognitionDispatcher(this); 6206 return speech_recognition_dispatcher_; 6207 } 6208 6209 WebKit::WebDeviceOrientationClient* RenderViewImpl::deviceOrientationClient() { 6210 if (!device_orientation_dispatcher_) 6211 device_orientation_dispatcher_ = new DeviceOrientationDispatcher(this); 6212 return device_orientation_dispatcher_; 6213 } 6214 6215 void RenderViewImpl::zoomLimitsChanged(double minimum_level, 6216 double maximum_level) { 6217 // For now, don't remember plugin zoom values. We don't want to mix them with 6218 // normal web content (i.e. a fixed layout plugin would usually want them 6219 // different). 6220 bool remember = !webview()->mainFrame()->document().isPluginDocument(); 6221 6222 int minimum_percent = static_cast<int>( 6223 ZoomLevelToZoomFactor(minimum_level) * 100); 6224 int maximum_percent = static_cast<int>( 6225 ZoomLevelToZoomFactor(maximum_level) * 100); 6226 6227 Send(new ViewHostMsg_UpdateZoomLimits( 6228 routing_id_, minimum_percent, maximum_percent, remember)); 6229 } 6230 6231 void RenderViewImpl::zoomLevelChanged() { 6232 bool remember = !webview()->mainFrame()->document().isPluginDocument(); 6233 float zoom_level = webview()->zoomLevel(); 6234 6235 FOR_EACH_OBSERVER(RenderViewObserver, observers_, ZoomLevelChanged()); 6236 6237 // Tell the browser which url got zoomed so it can update the menu and the 6238 // saved values if necessary 6239 Send(new ViewHostMsg_DidZoomURL( 6240 routing_id_, zoom_level, remember, 6241 GURL(webview()->mainFrame()->document().url()))); 6242 } 6243 6244 double RenderViewImpl::zoomLevelToZoomFactor(double zoom_level) const { 6245 return ZoomLevelToZoomFactor(zoom_level); 6246 } 6247 6248 double RenderViewImpl::zoomFactorToZoomLevel(double factor) const { 6249 return ZoomFactorToZoomLevel(factor); 6250 } 6251 6252 void RenderViewImpl::registerProtocolHandler(const WebString& scheme, 6253 const WebString& base_url, 6254 const WebString& url, 6255 const WebString& title) { 6256 bool user_gesture = WebUserGestureIndicator::isProcessingUserGesture(); 6257 GURL base(base_url); 6258 GURL absolute_url = base.Resolve(UTF16ToUTF8(url)); 6259 if (base.GetOrigin() != absolute_url.GetOrigin()) { 6260 return; 6261 } 6262 Send(new ViewHostMsg_RegisterProtocolHandler(routing_id_, 6263 UTF16ToUTF8(scheme), 6264 absolute_url, 6265 title, 6266 user_gesture)); 6267 } 6268 6269 WebKit::WebPageVisibilityState RenderViewImpl::visibilityState() const { 6270 WebKit::WebPageVisibilityState current_state = is_hidden() ? 6271 WebKit::WebPageVisibilityStateHidden : 6272 WebKit::WebPageVisibilityStateVisible; 6273 WebKit::WebPageVisibilityState override_state = current_state; 6274 if (GetContentClient()->renderer()-> 6275 ShouldOverridePageVisibilityState(this, 6276 &override_state)) 6277 return override_state; 6278 return current_state; 6279 } 6280 6281 WebKit::WebUserMediaClient* RenderViewImpl::userMediaClient() { 6282 EnsureMediaStreamClient(); 6283 return web_user_media_client_; 6284 } 6285 6286 WebKit::WebMIDIClient* RenderViewImpl::webMIDIClient() { 6287 if (!midi_dispatcher_) 6288 midi_dispatcher_ = new MIDIDispatcher(this); 6289 return midi_dispatcher_; 6290 } 6291 6292 void RenderViewImpl::draggableRegionsChanged() { 6293 FOR_EACH_OBSERVER( 6294 RenderViewObserver, 6295 observers_, 6296 DraggableRegionsChanged(webview()->mainFrame())); 6297 } 6298 6299 #if defined(OS_ANDROID) 6300 WebContentDetectionResult RenderViewImpl::detectContentAround( 6301 const WebHitTestResult& touch_hit) { 6302 DCHECK(!touch_hit.isNull()); 6303 DCHECK(!touch_hit.node().isNull()); 6304 DCHECK(touch_hit.node().isTextNode()); 6305 6306 // Process the position with all the registered content detectors until 6307 // a match is found. Priority is provided by their relative order. 6308 for (ContentDetectorList::const_iterator it = content_detectors_.begin(); 6309 it != content_detectors_.end(); ++it) { 6310 ContentDetector::Result content = (*it)->FindTappedContent(touch_hit); 6311 if (content.valid) { 6312 return WebContentDetectionResult(content.content_boundaries, 6313 UTF8ToUTF16(content.text), content.intent_url); 6314 } 6315 } 6316 return WebContentDetectionResult(); 6317 } 6318 6319 void RenderViewImpl::scheduleContentIntent(const WebURL& intent) { 6320 // Introduce a short delay so that the user can notice the content. 6321 base::MessageLoop::current()->PostDelayedTask( 6322 FROM_HERE, 6323 base::Bind(&RenderViewImpl::LaunchAndroidContentIntent, 6324 AsWeakPtr(), 6325 intent, 6326 expected_content_intent_id_), 6327 base::TimeDelta::FromMilliseconds(kContentIntentDelayMilliseconds)); 6328 } 6329 6330 void RenderViewImpl::cancelScheduledContentIntents() { 6331 ++expected_content_intent_id_; 6332 } 6333 6334 void RenderViewImpl::LaunchAndroidContentIntent(const GURL& intent, 6335 size_t request_id) { 6336 if (request_id != expected_content_intent_id_) 6337 return; 6338 6339 // Remove the content highlighting if any. 6340 scheduleComposite(); 6341 6342 if (!intent.is_empty()) 6343 Send(new ViewHostMsg_StartContentIntent(routing_id_, intent)); 6344 } 6345 6346 bool RenderViewImpl::openDateTimeChooser( 6347 const WebKit::WebDateTimeChooserParams& params, 6348 WebKit::WebDateTimeChooserCompletion* completion) { 6349 date_time_picker_client_.reset( 6350 new RendererDateTimePicker(this, params, completion)); 6351 return date_time_picker_client_->Open(); 6352 } 6353 6354 #endif // defined(OS_ANDROID) 6355 6356 #if defined(OS_MACOSX) 6357 void RenderViewImpl::OnSelectPopupMenuItem(int selected_index) { 6358 if (external_popup_menu_ == NULL) { 6359 // Crash reports from the field indicate that we can be notified with a 6360 // NULL external popup menu (we probably get notified twice). 6361 // If you hit this please file a bug against jcivelli and include the page 6362 // and steps to repro. 6363 NOTREACHED(); 6364 return; 6365 } 6366 external_popup_menu_->DidSelectItem(selected_index); 6367 external_popup_menu_.reset(); 6368 } 6369 #endif 6370 6371 #if defined(OS_ANDROID) 6372 void RenderViewImpl::OnSelectPopupMenuItems( 6373 bool canceled, 6374 const std::vector<int>& selected_indices) { 6375 // It is possible to receive more than one of these calls if the user presses 6376 // a select faster than it takes for the show-select-popup IPC message to make 6377 // it to the browser UI thread. Ignore the extra-messages. 6378 // TODO(jcivelli): http:/b/5793321 Implement a better fix, as detailed in bug. 6379 if (!external_popup_menu_) 6380 return; 6381 6382 external_popup_menu_->DidSelectItems(canceled, selected_indices); 6383 external_popup_menu_.reset(); 6384 } 6385 #endif 6386 6387 void RenderViewImpl::OnContextMenuClosed( 6388 const CustomContextMenuContext& custom_context) { 6389 if (custom_context.request_id) { 6390 // External request, should be in our map. 6391 ContextMenuClient* client = 6392 pending_context_menus_.Lookup(custom_context.request_id); 6393 if (client) { 6394 client->OnMenuClosed(custom_context.request_id); 6395 pending_context_menus_.Remove(custom_context.request_id); 6396 } 6397 } else { 6398 // Internal request, forward to WebKit. 6399 context_menu_node_.reset(); 6400 } 6401 } 6402 6403 void RenderViewImpl::OnShowContextMenu(const gfx::Point& location) { 6404 context_menu_source_type_ = ui::MENU_SOURCE_TOUCH_EDIT_MENU; 6405 touch_editing_context_menu_location_ = location; 6406 if (webview()) 6407 webview()->showContextMenu(); 6408 } 6409 6410 void RenderViewImpl::OnEnableViewSourceMode() { 6411 if (!webview()) 6412 return; 6413 WebFrame* main_frame = webview()->mainFrame(); 6414 if (!main_frame) 6415 return; 6416 main_frame->enableViewSourceMode(true); 6417 } 6418 6419 #if defined(OS_ANDROID) 6420 void RenderViewImpl::OnJavaBridgeInit() { 6421 DCHECK(!java_bridge_dispatcher_); 6422 java_bridge_dispatcher_ = new JavaBridgeDispatcher(this); 6423 } 6424 #endif 6425 6426 void RenderViewImpl::OnDisownOpener() { 6427 if (!webview()) 6428 return; 6429 6430 WebFrame* main_frame = webview()->mainFrame(); 6431 if (main_frame && main_frame->opener()) 6432 main_frame->setOpener(NULL); 6433 } 6434 6435 #if defined(OS_ANDROID) 6436 bool RenderViewImpl::didTapMultipleTargets( 6437 const WebKit::WebGestureEvent& event, 6438 const WebVector<WebRect>& target_rects) { 6439 // Never show a disambiguation popup when accessibility is enabled, 6440 // as this interferes with "touch exploration". 6441 if (accessibility_mode_ == AccessibilityModeComplete) 6442 return false; 6443 6444 gfx::Rect finger_rect( 6445 event.x - event.data.tap.width / 2, event.y - event.data.tap.height / 2, 6446 event.data.tap.width, event.data.tap.height); 6447 gfx::Rect zoom_rect; 6448 float new_total_scale = 6449 DisambiguationPopupHelper::ComputeZoomAreaAndScaleFactor( 6450 finger_rect, target_rects, GetSize(), 6451 gfx::Rect(webview()->mainFrame()->visibleContentRect()).size(), 6452 device_scale_factor_ * webview()->pageScaleFactor(), &zoom_rect); 6453 if (!new_total_scale) 6454 return false; 6455 6456 TapMultipleTargetsStrategy multitarget_strategy = 6457 renderer_preferences_.tap_multiple_targets_strategy; 6458 if (multitarget_strategy == TAP_MULTIPLE_TARGETS_STRATEGY_ZOOM) { 6459 return webview()->zoomToMultipleTargetsRect(zoom_rect); 6460 } else if (multitarget_strategy == TAP_MULTIPLE_TARGETS_STRATEGY_POPUP) { 6461 gfx::Size canvas_size = 6462 gfx::ToCeiledSize(gfx::ScaleSize(zoom_rect.size(), new_total_scale)); 6463 TransportDIB* transport_dib = NULL; 6464 { 6465 scoped_ptr<skia::PlatformCanvas> canvas( 6466 RenderProcess::current()->GetDrawingCanvas(&transport_dib, 6467 gfx::Rect(canvas_size))); 6468 if (!canvas) 6469 return false; 6470 6471 // TODO(trchen): Cleanup the device scale factor mess. 6472 // device scale will be applied in WebKit 6473 // --> zoom_rect doesn't include device scale, 6474 // but WebKit will still draw on zoom_rect * device_scale_factor_ 6475 canvas->scale(new_total_scale / device_scale_factor_, 6476 new_total_scale / device_scale_factor_); 6477 canvas->translate(-zoom_rect.x() * device_scale_factor_, 6478 -zoom_rect.y() * device_scale_factor_); 6479 6480 webwidget_->paint( 6481 canvas.get(), 6482 zoom_rect, 6483 WebWidget::ForceSoftwareRenderingAndIgnoreGPUResidentContent); 6484 } 6485 6486 gfx::Rect physical_window_zoom_rect = gfx::ToEnclosingRect( 6487 ClientRectToPhysicalWindowRect(gfx::RectF(zoom_rect))); 6488 Send(new ViewHostMsg_ShowDisambiguationPopup(routing_id_, 6489 physical_window_zoom_rect, 6490 canvas_size, 6491 transport_dib->id())); 6492 } else { 6493 return false; 6494 } 6495 6496 return true; 6497 } 6498 #endif 6499 6500 unsigned RenderViewImpl::GetLocalSessionHistoryLengthForTesting() const { 6501 return history_list_length_; 6502 } 6503 6504 void RenderViewImpl::SetFocusAndActivateForTesting(bool enable) { 6505 if (enable) { 6506 if (has_focus()) 6507 return; 6508 OnSetActive(true); 6509 OnSetFocus(true); 6510 } else { 6511 if (!has_focus()) 6512 return; 6513 OnSetFocus(false); 6514 OnSetActive(false); 6515 } 6516 } 6517 6518 void RenderViewImpl::SetDeviceScaleFactorForTesting(float factor) { 6519 ViewMsg_Resize_Params params; 6520 params.screen_info = screen_info_; 6521 params.screen_info.deviceScaleFactor = factor; 6522 params.new_size = size(); 6523 params.physical_backing_size = 6524 gfx::ToCeiledSize(gfx::ScaleSize(size(), factor)); 6525 params.overdraw_bottom_height = 0.f; 6526 params.resizer_rect = WebRect(); 6527 params.is_fullscreen = is_fullscreen(); 6528 OnResize(params); 6529 } 6530 6531 void RenderViewImpl::EnableAutoResizeForTesting(const gfx::Size& min_size, 6532 const gfx::Size& max_size) { 6533 OnEnableAutoResize(min_size, max_size); 6534 } 6535 6536 void RenderViewImpl::DisableAutoResizeForTesting(const gfx::Size& new_size) { 6537 OnDisableAutoResize(new_size); 6538 } 6539 6540 void RenderViewImpl::SetMediaStreamClientForTesting( 6541 MediaStreamClient* media_stream_client) { 6542 DCHECK(!media_stream_client_); 6543 DCHECK(!web_user_media_client_); 6544 media_stream_client_ = media_stream_client; 6545 } 6546 6547 void RenderViewImpl::OnReleaseDisambiguationPopupDIB( 6548 TransportDIB::Handle dib_handle) { 6549 TransportDIB* dib = TransportDIB::CreateWithHandle(dib_handle); 6550 RenderProcess::current()->ReleaseTransportDIB(dib); 6551 } 6552 6553 void RenderViewImpl::DidCommitCompositorFrame() { 6554 RenderWidget::DidCommitCompositorFrame(); 6555 FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidCommitCompositorFrame()); 6556 } 6557 6558 void RenderViewImpl::SendUpdateFaviconURL(const std::vector<FaviconURL>& urls) { 6559 if (!urls.empty()) 6560 Send(new ViewHostMsg_UpdateFaviconURL(routing_id_, page_id_, urls)); 6561 } 6562 6563 void RenderViewImpl::DidStopLoadingIcons() { 6564 int icon_types = WebIconURL::TypeFavicon; 6565 if (TouchEnabled()) 6566 icon_types |= WebIconURL::TypeTouchPrecomposed | WebIconURL::TypeTouch; 6567 6568 WebVector<WebIconURL> icon_urls = 6569 webview()->mainFrame()->iconURLs(icon_types); 6570 6571 std::vector<FaviconURL> urls; 6572 for (size_t i = 0; i < icon_urls.size(); i++) { 6573 WebURL url = icon_urls[i].iconURL(); 6574 if (!url.isEmpty()) 6575 urls.push_back(FaviconURL(url, 6576 ToFaviconType(icon_urls[i].iconType()))); 6577 } 6578 SendUpdateFaviconURL(urls); 6579 } 6580 6581 6582 } // namespace content 6583