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