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