| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/renderer/render_frame_impl.h" |
| |
| #include <map> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/auto_reset.h" |
| #include "base/bind_helpers.h" |
| #include "base/command_line.h" |
| #include "base/debug/alias.h" |
| #include "base/debug/asan_invalid_access.h" |
| #include "base/debug/crash_logging.h" |
| #include "base/debug/dump_without_crashing.h" |
| #include "base/files/file.h" |
| #include "base/i18n/char_iterator.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/shared_memory.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/metrics/field_trial.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/process/process.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/task_runner_util.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "base/trace_event/trace_event.h" |
| #include "build/build_config.h" |
| #include "cc/base/switches.h" |
| #include "content/child/appcache/appcache_dispatcher.h" |
| #include "content/child/feature_policy/feature_policy_platform.h" |
| #include "content/child/quota_dispatcher.h" |
| #include "content/child/request_extra_data.h" |
| #include "content/child/service_worker/service_worker_handle_reference.h" |
| #include "content/child/service_worker/service_worker_network_provider.h" |
| #include "content/child/service_worker/service_worker_provider_context.h" |
| #include "content/child/service_worker/web_service_worker_provider_impl.h" |
| #include "content/child/v8_value_converter_impl.h" |
| #include "content/child/web_url_loader_impl.h" |
| #include "content/child/web_url_request_util.h" |
| #include "content/child/webmessageportchannel_impl.h" |
| #include "content/child/weburlresponse_extradata_impl.h" |
| #include "content/common/accessibility_messages.h" |
| #include "content/common/associated_interface_provider_impl.h" |
| #include "content/common/associated_interfaces.mojom.h" |
| #include "content/common/clipboard_messages.h" |
| #include "content/common/content_constants_internal.h" |
| #include "content/common/content_security_policy/csp_context.h" |
| #include "content/common/content_security_policy_header.h" |
| #include "content/common/download/mhtml_save_status.h" |
| #include "content/common/edit_command.h" |
| #include "content/common/frame_messages.h" |
| #include "content/common/frame_owner_properties.h" |
| #include "content/common/frame_replication_state.h" |
| #include "content/common/input_messages.h" |
| #include "content/common/navigation_params.h" |
| #include "content/common/page_messages.h" |
| #include "content/common/savable_subframe.h" |
| #include "content/common/service_worker/service_worker_types.h" |
| #include "content/common/site_isolation_policy.h" |
| #include "content/common/swapped_out_messages.h" |
| #include "content/common/view_messages.h" |
| #include "content/public/common/appcache_info.h" |
| #include "content/public/common/associated_interface_provider.h" |
| #include "content/public/common/bindings_policy.h" |
| #include "content/public/common/browser_side_navigation_policy.h" |
| #include "content/public/common/content_constants.h" |
| #include "content/public/common/content_features.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/common/context_menu_params.h" |
| #include "content/public/common/file_chooser_file_info.h" |
| #include "content/public/common/file_chooser_params.h" |
| #include "content/public/common/isolated_world_ids.h" |
| #include "content/public/common/page_state.h" |
| #include "content/public/common/resource_response.h" |
| #include "content/public/common/service_manager_connection.h" |
| #include "content/public/common/url_constants.h" |
| #include "content/public/common/url_utils.h" |
| #include "content/public/renderer/browser_plugin_delegate.h" |
| #include "content/public/renderer/content_renderer_client.h" |
| #include "content/public/renderer/context_menu_client.h" |
| #include "content/public/renderer/document_state.h" |
| #include "content/public/renderer/navigation_state.h" |
| #include "content/public/renderer/render_frame_observer.h" |
| #include "content/public/renderer/renderer_ppapi_host.h" |
| #include "content/renderer/accessibility/render_accessibility_impl.h" |
| #include "content/renderer/browser_plugin/browser_plugin.h" |
| #include "content/renderer/browser_plugin/browser_plugin_manager.h" |
| #include "content/renderer/child_frame_compositing_helper.h" |
| #include "content/renderer/content_security_policy_util.h" |
| #include "content/renderer/context_menu_params_builder.h" |
| #include "content/renderer/devtools/devtools_agent.h" |
| #include "content/renderer/dom_automation_controller.h" |
| #include "content/renderer/effective_connection_type_helper.h" |
| #include "content/renderer/external_popup_menu.h" |
| #include "content/renderer/frame_owner_properties.h" |
| #include "content/renderer/gpu/gpu_benchmarking_extension.h" |
| #include "content/renderer/history_entry.h" |
| #include "content/renderer/history_serialization.h" |
| #include "content/renderer/image_downloader/image_downloader_impl.h" |
| #include "content/renderer/ime_event_guard.h" |
| #include "content/renderer/input/input_handler_manager.h" |
| #include "content/renderer/installedapp/related_apps_fetcher.h" |
| #include "content/renderer/internal_document_state_data.h" |
| #include "content/renderer/manifest/manifest_manager.h" |
| #include "content/renderer/media/audio_device_factory.h" |
| #include "content/renderer/media/media_devices_listener_impl.h" |
| #include "content/renderer/media/media_permission_dispatcher.h" |
| #include "content/renderer/media/media_stream_dispatcher.h" |
| #include "content/renderer/media/media_stream_renderer_factory_impl.h" |
| #include "content/renderer/media/render_media_log.h" |
| #include "content/renderer/media/renderer_webmediaplayer_delegate.h" |
| #include "content/renderer/media/user_media_client_impl.h" |
| #include "content/renderer/media/web_media_element_source_utils.h" |
| #include "content/renderer/media/webmediaplayer_ms.h" |
| #include "content/renderer/mojo/blink_interface_registry_impl.h" |
| #include "content/renderer/mojo/interface_provider_js_wrapper.h" |
| #include "content/renderer/mojo_bindings_controller.h" |
| #include "content/renderer/navigation_state_impl.h" |
| #include "content/renderer/pepper/pepper_audio_controller.h" |
| #include "content/renderer/pepper/plugin_instance_throttler_impl.h" |
| #include "content/renderer/presentation/presentation_dispatcher.h" |
| #include "content/renderer/push_messaging/push_messaging_client.h" |
| #include "content/renderer/render_frame_proxy.h" |
| #include "content/renderer/render_process.h" |
| #include "content/renderer/render_thread_impl.h" |
| #include "content/renderer/render_view_impl.h" |
| #include "content/renderer/render_widget_fullscreen_pepper.h" |
| #include "content/renderer/renderer_webapplicationcachehost_impl.h" |
| #include "content/renderer/renderer_webcolorchooser_impl.h" |
| #include "content/renderer/savable_resources.h" |
| #include "content/renderer/screen_orientation/screen_orientation_dispatcher.h" |
| #include "content/renderer/shared_worker/shared_worker_repository.h" |
| #include "content/renderer/shared_worker/websharedworker_proxy.h" |
| #include "content/renderer/skia_benchmarking_extension.h" |
| #include "content/renderer/stats_collection_controller.h" |
| #include "content/renderer/web_frame_utils.h" |
| #include "content/renderer/web_ui_extension.h" |
| #include "content/renderer/web_ui_extension_data.h" |
| #include "crypto/sha2.h" |
| #include "gin/modules/console.h" |
| #include "gin/modules/module_registry.h" |
| #include "media/audio/audio_output_device.h" |
| #include "media/base/audio_renderer_mixer_input.h" |
| #include "media/base/cdm_factory.h" |
| #include "media/base/decoder_factory.h" |
| #include "media/base/media.h" |
| #include "media/base/media_log.h" |
| #include "media/base/media_switches.h" |
| #include "media/blink/url_index.h" |
| #include "media/blink/webencryptedmediaclient_impl.h" |
| #include "media/blink/webmediaplayer_impl.h" |
| #include "media/media_features.h" |
| #include "media/renderers/gpu_video_accelerator_factories.h" |
| #include "mojo/edk/js/core.h" |
| #include "mojo/edk/js/support.h" |
| #include "net/base/data_url.h" |
| #include "net/base/load_flags.h" |
| #include "net/base/net_errors.h" |
| #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| #include "net/http/http_util.h" |
| #include "ppapi/features/features.h" |
| #include "services/service_manager/public/cpp/interface_provider.h" |
| #include "services/service_manager/public/cpp/interface_registry.h" |
| #include "services/ui/public/cpp/gpu/context_provider_command_buffer.h" |
| #include "storage/common/data_element.h" |
| #include "third_party/WebKit/public/platform/FilePathConversion.h" |
| #include "third_party/WebKit/public/platform/URLConversion.h" |
| #include "third_party/WebKit/public/platform/WebCachePolicy.h" |
| #include "third_party/WebKit/public/platform/WebData.h" |
| #include "third_party/WebKit/public/platform/WebKeyboardEvent.h" |
| #include "third_party/WebKit/public/platform/WebMediaPlayer.h" |
| #include "third_party/WebKit/public/platform/WebMediaPlayerSource.h" |
| #include "third_party/WebKit/public/platform/WebPoint.h" |
| #include "third_party/WebKit/public/platform/WebSecurityOrigin.h" |
| #include "third_party/WebKit/public/platform/WebStorageQuotaCallbacks.h" |
| #include "third_party/WebKit/public/platform/WebString.h" |
| #include "third_party/WebKit/public/platform/WebURL.h" |
| #include "third_party/WebKit/public/platform/WebURLError.h" |
| #include "third_party/WebKit/public/platform/WebURLResponse.h" |
| #include "third_party/WebKit/public/platform/WebVector.h" |
| #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerNetworkProvider.h" |
| #include "third_party/WebKit/public/platform/scheduler/renderer/renderer_scheduler.h" |
| #include "third_party/WebKit/public/web/WebColorSuggestion.h" |
| #include "third_party/WebKit/public/web/WebConsoleMessage.h" |
| #include "third_party/WebKit/public/web/WebDocument.h" |
| #include "third_party/WebKit/public/web/WebFindOptions.h" |
| #include "third_party/WebKit/public/web/WebFrameOwnerProperties.h" |
| #include "third_party/WebKit/public/web/WebFrameSerializer.h" |
| #include "third_party/WebKit/public/web/WebFrameSerializerCacheControlPolicy.h" |
| #include "third_party/WebKit/public/web/WebFrameWidget.h" |
| #include "third_party/WebKit/public/web/WebInputMethodController.h" |
| #include "third_party/WebKit/public/web/WebKit.h" |
| #include "third_party/WebKit/public/web/WebLocalFrame.h" |
| #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h" |
| #include "third_party/WebKit/public/web/WebNavigationPolicy.h" |
| #include "third_party/WebKit/public/web/WebPlugin.h" |
| #include "third_party/WebKit/public/web/WebPluginContainer.h" |
| #include "third_party/WebKit/public/web/WebPluginDocument.h" |
| #include "third_party/WebKit/public/web/WebPluginParams.h" |
| #include "third_party/WebKit/public/web/WebRange.h" |
| #include "third_party/WebKit/public/web/WebScopedUserGesture.h" |
| #include "third_party/WebKit/public/web/WebScriptSource.h" |
| #include "third_party/WebKit/public/web/WebSearchableFormData.h" |
| #include "third_party/WebKit/public/web/WebSecurityPolicy.h" |
| #include "third_party/WebKit/public/web/WebSerializedScriptValue.h" |
| #include "third_party/WebKit/public/web/WebSettings.h" |
| #include "third_party/WebKit/public/web/WebSurroundingText.h" |
| #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" |
| #include "third_party/WebKit/public/web/WebView.h" |
| #include "third_party/WebKit/public/web/WebWidget.h" |
| #include "ui/events/base_event_utils.h" |
| #include "url/origin.h" |
| #include "url/url_constants.h" |
| #include "url/url_util.h" |
| |
| #if BUILDFLAG(ENABLE_PLUGINS) |
| #include "content/renderer/pepper/pepper_browser_connection.h" |
| #include "content/renderer/pepper/pepper_plugin_instance_impl.h" |
| #include "content/renderer/pepper/pepper_plugin_registry.h" |
| #include "content/renderer/pepper/pepper_webplugin_impl.h" |
| #include "content/renderer/pepper/plugin_module.h" |
| #endif |
| |
| #if BUILDFLAG(ENABLE_WEBRTC) |
| #include "content/renderer/media/rtc_peer_connection_handler.h" |
| #endif |
| |
| #if defined(OS_ANDROID) |
| #include <cpu-features.h> |
| |
| #include "content/renderer/java/gin_java_bridge_dispatcher.h" |
| #include "content/renderer/media/android/media_player_renderer_client_factory.h" |
| #include "content/renderer/media/android/renderer_media_player_manager.h" |
| #include "content/renderer/media/android/renderer_surface_view_manager.h" |
| #include "content/renderer/media/android/stream_texture_factory.h" |
| #include "content/renderer/media/android/stream_texture_wrapper_impl.h" |
| #include "media/base/android/media_codec_util.h" |
| #include "third_party/WebKit/public/platform/WebFloatPoint.h" |
| #endif |
| |
| #if BUILDFLAG(ENABLE_PEPPER_CDMS) |
| #include "content/renderer/media/cdm/pepper_cdm_wrapper_impl.h" |
| #include "content/renderer/media/cdm/render_cdm_factory.h" |
| #endif |
| |
| #if defined(ENABLE_MOJO_MEDIA) |
| #include "content/renderer/media/media_interface_provider.h" |
| #endif |
| |
| #if defined(ENABLE_MOJO_CDM) |
| #include "media/mojo/clients/mojo_cdm_factory.h" // nogncheck |
| #endif |
| |
| #if defined(ENABLE_MOJO_RENDERER) |
| #include "media/mojo/clients/mojo_renderer_factory.h" // nogncheck |
| #endif |
| |
| #if !defined(ENABLE_MOJO_RENDERER) || \ |
| BUILDFLAG(ENABLE_RUNTIME_MEDIA_RENDERER_SELECTION) |
| #include "media/renderers/default_renderer_factory.h" // nogncheck |
| #endif |
| |
| #if defined(ENABLE_MOJO_AUDIO_DECODER) || defined(ENABLE_MOJO_VIDEO_DECODER) |
| #include "media/mojo/clients/mojo_decoder_factory.h" // nogncheck |
| #endif |
| |
| #if BUILDFLAG(ENABLE_MEDIA_REMOTING) |
| #include "content/renderer/image_downloader/single_image_downloader.h" // nogncheck |
| #include "media/remoting/adaptive_renderer_factory.h" // nogncheck |
| #include "media/remoting/remoting_cdm_controller.h" // nogncheck |
| #include "media/remoting/remoting_cdm_factory.h" // nogncheck |
| #include "media/remoting/renderer_controller.h" // nogncheck |
| #include "media/remoting/shared_session.h" // nogncheck |
| #include "media/remoting/sink_availability_observer.h" // nogncheck |
| #endif |
| |
| using base::Time; |
| using base::TimeDelta; |
| using blink::WebCachePolicy; |
| using blink::WebContentDecryptionModule; |
| using blink::WebContextMenuData; |
| using blink::WebCString; |
| using blink::WebData; |
| using blink::WebDataSource; |
| using blink::WebDocument; |
| using blink::WebDOMEvent; |
| using blink::WebDOMMessageEvent; |
| using blink::WebElement; |
| using blink::WebExternalPopupMenu; |
| using blink::WebExternalPopupMenuClient; |
| using blink::WebFindOptions; |
| using blink::WebFrame; |
| using blink::WebFrameLoadType; |
| using blink::WebFrameSerializer; |
| using blink::WebFrameSerializerClient; |
| using blink::WebHistoryItem; |
| using blink::WebHTTPBody; |
| using blink::WebLocalFrame; |
| using blink::WebMediaPlayer; |
| using blink::WebMediaPlayerClient; |
| using blink::WebMediaPlayerEncryptedMediaClient; |
| using blink::WebNavigationPolicy; |
| using blink::WebNavigationType; |
| using blink::WebNode; |
| using blink::WebPluginDocument; |
| using blink::WebPluginParams; |
| using blink::WebPoint; |
| using blink::WebPopupMenuInfo; |
| using blink::WebRange; |
| using blink::WebRect; |
| using blink::WebReferrerPolicy; |
| using blink::WebScriptSource; |
| using blink::WebSearchableFormData; |
| using blink::WebSecurityOrigin; |
| using blink::WebSecurityPolicy; |
| using blink::WebSerializedScriptValue; |
| using blink::WebServiceWorkerProvider; |
| using blink::WebSettings; |
| using blink::WebStorageQuotaCallbacks; |
| using blink::WebString; |
| using blink::WebThreadSafeData; |
| using blink::WebURL; |
| using blink::WebURLError; |
| using blink::WebURLRequest; |
| using blink::WebURLResponse; |
| using blink::WebUserGestureIndicator; |
| using blink::WebVector; |
| using blink::WebView; |
| |
| #if defined(OS_ANDROID) |
| using blink::WebFloatPoint; |
| using blink::WebFloatRect; |
| #endif |
| |
| #define STATIC_ASSERT_ENUM(a, b) \ |
| static_assert(static_cast<int>(a) == static_cast<int>(b), \ |
| "mismatching enums: " #a) |
| |
| namespace content { |
| |
| namespace { |
| |
| const int kExtraCharsBeforeAndAfterSelection = 100; |
| |
| typedef std::map<int, RenderFrameImpl*> RoutingIDFrameMap; |
| static base::LazyInstance<RoutingIDFrameMap>::DestructorAtExit |
| g_routing_id_frame_map = LAZY_INSTANCE_INITIALIZER; |
| |
| typedef std::map<blink::WebFrame*, RenderFrameImpl*> FrameMap; |
| base::LazyInstance<FrameMap>::DestructorAtExit g_frame_map = |
| LAZY_INSTANCE_INITIALIZER; |
| |
| int64_t ExtractPostId(const WebHistoryItem& item) { |
| if (item.isNull() || item.httpBody().isNull()) |
| return -1; |
| |
| return item.httpBody().identifier(); |
| } |
| |
| WebURLResponseExtraDataImpl* GetExtraDataFromResponse( |
| const WebURLResponse& response) { |
| return static_cast<WebURLResponseExtraDataImpl*>(response.getExtraData()); |
| } |
| |
| void GetRedirectChain(WebDataSource* ds, std::vector<GURL>* result) { |
| WebVector<WebURL> urls; |
| ds->redirectChain(urls); |
| result->reserve(urls.size()); |
| for (size_t i = 0; i < urls.size(); ++i) { |
| result->push_back(urls[i]); |
| } |
| } |
| |
| // Gets URL that should override the default getter for this data source |
| // (if any), storing it in |output|. Returns true if there is an override URL. |
| bool MaybeGetOverriddenURL(WebDataSource* ds, GURL* output) { |
| DocumentState* document_state = DocumentState::FromDataSource(ds); |
| |
| // If load was from a data URL, then the saved data URL, not the history |
| // URL, should be the URL of the data source. |
| if (document_state->was_load_data_with_base_url_request()) { |
| *output = document_state->data_url(); |
| return true; |
| } |
| |
| // WebDataSource has unreachable URL means that the frame is loaded through |
| // blink::WebFrame::loadData(), and the base URL will be in the redirect |
| // chain. However, we never visited the baseURL. So in this case, we should |
| // use the unreachable URL as the original URL. |
| if (ds->hasUnreachableURL()) { |
| *output = ds->unreachableURL(); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| // Returns the original request url. If there is no redirect, the original |
| // url is the same as ds->getRequest()->url(). If the WebDataSource belongs to a |
| // frame was loaded by loadData, the original url will be ds->unreachableURL() |
| GURL GetOriginalRequestURL(WebDataSource* ds) { |
| GURL overriden_url; |
| if (MaybeGetOverriddenURL(ds, &overriden_url)) |
| return overriden_url; |
| |
| std::vector<GURL> redirects; |
| GetRedirectChain(ds, &redirects); |
| if (!redirects.empty()) |
| return redirects.at(0); |
| |
| return ds->originalRequest().url(); |
| } |
| |
| bool IsBrowserInitiated(NavigationParams* pending) { |
| // A navigation resulting from loading a javascript URL should not be treated |
| // as a browser initiated event. Instead, we want it to look as if the page |
| // initiated any load resulting from JS execution. |
| return pending && |
| !pending->common_params.url.SchemeIs(url::kJavaScriptScheme); |
| } |
| |
| NOINLINE void ExhaustMemory() { |
| volatile void* ptr = nullptr; |
| do { |
| ptr = malloc(0x10000000); |
| base::debug::Alias(&ptr); |
| } while (ptr); |
| } |
| |
| NOINLINE void CrashIntentionally() { |
| // NOTE(shess): Crash directly rather than using NOTREACHED() so |
| // that the signature is easier to triage in crash reports. |
| // |
| // Linker's ICF feature may merge this function with other functions with the |
| // same definition and it may confuse the crash report processing system. |
| static int static_variable_to_make_this_function_unique = 0; |
| base::debug::Alias(&static_variable_to_make_this_function_unique); |
| |
| volatile int* zero = nullptr; |
| *zero = 0; |
| } |
| |
| NOINLINE void BadCastCrashIntentionally() { |
| class A { |
| virtual void f() {} |
| }; |
| |
| class B { |
| virtual void f() {} |
| }; |
| |
| A a; |
| (void)(B*)&a; |
| } |
| |
| #if defined(ADDRESS_SANITIZER) || defined(SYZYASAN) |
| NOINLINE void MaybeTriggerAsanError(const GURL& url) { |
| // NOTE(rogerm): We intentionally perform an invalid heap access here in |
| // order to trigger an Address Sanitizer (ASAN) error report. |
| const char kCrashDomain[] = "crash"; |
| const char kHeapOverflow[] = "/heap-overflow"; |
| const char kHeapUnderflow[] = "/heap-underflow"; |
| const char kUseAfterFree[] = "/use-after-free"; |
| #if defined(SYZYASAN) |
| const char kCorruptHeapBlock[] = "/corrupt-heap-block"; |
| const char kCorruptHeap[] = "/corrupt-heap"; |
| #endif |
| |
| if (!url.DomainIs(kCrashDomain)) |
| return; |
| |
| if (!url.has_path()) |
| return; |
| |
| std::string crash_type(url.path()); |
| if (crash_type == kHeapOverflow) { |
| LOG(ERROR) |
| << "Intentionally causing ASAN heap overflow" |
| << " because user navigated to " << url.spec(); |
| base::debug::AsanHeapOverflow(); |
| } else if (crash_type == kHeapUnderflow) { |
| LOG(ERROR) |
| << "Intentionally causing ASAN heap underflow" |
| << " because user navigated to " << url.spec(); |
| base::debug::AsanHeapUnderflow(); |
| } else if (crash_type == kUseAfterFree) { |
| LOG(ERROR) |
| << "Intentionally causing ASAN heap use-after-free" |
| << " because user navigated to " << url.spec(); |
| base::debug::AsanHeapUseAfterFree(); |
| #if defined(SYZYASAN) |
| } else if (crash_type == kCorruptHeapBlock) { |
| LOG(ERROR) |
| << "Intentionally causing ASAN corrupt heap block" |
| << " because user navigated to " << url.spec(); |
| base::debug::AsanCorruptHeapBlock(); |
| } else if (crash_type == kCorruptHeap) { |
| LOG(ERROR) |
| << "Intentionally causing ASAN corrupt heap" |
| << " because user navigated to " << url.spec(); |
| base::debug::AsanCorruptHeap(); |
| #endif |
| } |
| } |
| #endif // ADDRESS_SANITIZER || SYZYASAN |
| |
| void MaybeHandleDebugURL(const GURL& url) { |
| if (!url.SchemeIs(kChromeUIScheme)) |
| return; |
| if (url == kChromeUIBadCastCrashURL) { |
| LOG(ERROR) |
| << "Intentionally crashing (with bad cast)" |
| << " because user navigated to " << url.spec(); |
| BadCastCrashIntentionally(); |
| } else if (url == kChromeUICrashURL) { |
| LOG(ERROR) << "Intentionally crashing (with null pointer dereference)" |
| << " because user navigated to " << url.spec(); |
| CrashIntentionally(); |
| } else if (url == kChromeUIDumpURL) { |
| // This URL will only correctly create a crash dump file if content is |
| // hosted in a process that has correctly called |
| // base::debug::SetDumpWithoutCrashingFunction. Refer to the documentation |
| // of base::debug::DumpWithoutCrashing for more details. |
| base::debug::DumpWithoutCrashing(); |
| } else if (url == kChromeUIKillURL) { |
| LOG(ERROR) << "Intentionally issuing kill signal to current process" |
| << " because user navigated to " << url.spec(); |
| base::Process::Current().Terminate(1, false); |
| } else if (url == kChromeUIHangURL) { |
| LOG(ERROR) << "Intentionally hanging ourselves with sleep infinite loop" |
| << " because user navigated to " << url.spec(); |
| for (;;) { |
| base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); |
| } |
| } else if (url == kChromeUIShorthangURL) { |
| LOG(ERROR) << "Intentionally sleeping renderer for 20 seconds" |
| << " because user navigated to " << url.spec(); |
| base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(20)); |
| } else if (url == kChromeUIMemoryExhaustURL) { |
| LOG(ERROR) |
| << "Intentionally exhausting renderer memory because user navigated to " |
| << url.spec(); |
| ExhaustMemory(); |
| } else if (url == kChromeUICheckCrashURL) { |
| LOG(ERROR) |
| << "Intentionally causing CHECK because user navigated to " |
| << url.spec(); |
| CHECK(false); |
| } |
| |
| #if defined(ADDRESS_SANITIZER) || defined(SYZYASAN) |
| MaybeTriggerAsanError(url); |
| #endif // ADDRESS_SANITIZER || SYZYASAN |
| } |
| |
| // Returns false unless this is a top-level navigation. |
| bool IsTopLevelNavigation(WebFrame* frame) { |
| return frame->parent() == NULL; |
| } |
| |
| WebURLRequest CreateURLRequestForNavigation( |
| const CommonNavigationParams& common_params, |
| const RequestNavigationParams& request_params, |
| std::unique_ptr<StreamOverrideParameters> stream_override, |
| bool is_view_source_mode_enabled, |
| bool is_same_document_navigation) { |
| // PlzNavigate: use the original navigation url to construct the |
| // WebURLRequest. The WebURLloaderImpl will replay the redirects afterwards |
| // and will eventually commit the final url. |
| const GURL navigation_url = IsBrowserSideNavigationEnabled() && |
| !request_params.original_url.is_empty() |
| ? request_params.original_url |
| : common_params.url; |
| const std::string navigation_method = |
| IsBrowserSideNavigationEnabled() && |
| !request_params.original_method.empty() |
| ? request_params.original_method |
| : common_params.method; |
| WebURLRequest request(navigation_url); |
| request.setHTTPMethod(WebString::fromUTF8(navigation_method)); |
| |
| if (is_view_source_mode_enabled) |
| request.setCachePolicy(WebCachePolicy::ReturnCacheDataElseLoad); |
| |
| if (common_params.referrer.url.is_valid()) { |
| WebString web_referrer = WebSecurityPolicy::generateReferrerHeader( |
| common_params.referrer.policy, common_params.url, |
| WebString::fromUTF8(common_params.referrer.url.spec())); |
| if (!web_referrer.isEmpty()) { |
| request.setHTTPReferrer(web_referrer, common_params.referrer.policy); |
| request.addHTTPOriginIfNeeded( |
| WebSecurityOrigin(url::Origin(common_params.referrer.url))); |
| } |
| } |
| |
| request.setIsSameDocumentNavigation(is_same_document_navigation); |
| request.setPreviewsState( |
| static_cast<WebURLRequest::PreviewsState>(common_params.previews_state)); |
| |
| RequestExtraData* extra_data = new RequestExtraData(); |
| extra_data->set_stream_override(std::move(stream_override)); |
| extra_data->set_navigation_initiated_by_renderer( |
| request_params.nav_entry_id == 0); |
| request.setExtraData(extra_data); |
| |
| // Set the ui timestamp for this navigation. Currently the timestamp here is |
| // only non empty when the navigation was triggered by an Android intent. The |
| // timestamp is converted to a double version supported by blink. It will be |
| // passed back to the browser in the DidCommitProvisionalLoad and the |
| // DocumentLoadComplete IPCs. |
| base::TimeDelta ui_timestamp = common_params.ui_timestamp - base::TimeTicks(); |
| request.setUiStartTime(ui_timestamp.InSecondsF()); |
| request.setInputPerfMetricReportPolicy( |
| static_cast<WebURLRequest::InputToLoadPerfMetricReportPolicy>( |
| common_params.report_type)); |
| return request; |
| } |
| |
| // Sanitizes the navigation_start timestamp for browser-initiated navigations, |
| // where the browser possibly has a better notion of start time than the |
| // renderer. In the case of cross-process navigations, this carries over the |
| // time of finishing the onbeforeunload handler of the previous page. |
| // TimeTicks is sometimes not monotonic across processes, and because |
| // |browser_navigation_start| is likely before this process existed, |
| // InterProcessTimeTicksConverter won't help. The timestamp is sanitized by |
| // clamping it to renderer_navigation_start, initialized earlier in the call |
| // stack. |
| base::TimeTicks SanitizeNavigationTiming( |
| const base::TimeTicks& browser_navigation_start, |
| const base::TimeTicks& renderer_navigation_start) { |
| DCHECK(!browser_navigation_start.is_null()); |
| return std::min(browser_navigation_start, renderer_navigation_start); |
| } |
| |
| // PlzNavigate |
| CommonNavigationParams MakeCommonNavigationParams( |
| const blink::WebFrameClient::NavigationPolicyInfo& info, |
| int load_flags) { |
| Referrer referrer( |
| GURL(info.urlRequest.httpHeaderField( |
| WebString::fromUTF8("Referer")).latin1()), |
| info.urlRequest.getReferrerPolicy()); |
| |
| // Set the ui timestamp for this navigation. Currently the timestamp here is |
| // only non empty when the navigation was triggered by an Android intent, or |
| // by the user clicking on a link. The timestamp is converted from a double |
| // version supported by blink. It will be passed back to the renderer in the |
| // CommitNavigation IPC, and then back to the browser again in the |
| // DidCommitProvisionalLoad and the DocumentLoadComplete IPCs. |
| base::TimeTicks ui_timestamp = |
| base::TimeTicks() + |
| base::TimeDelta::FromSecondsD(info.urlRequest.uiStartTime()); |
| FrameMsg_UILoadMetricsReportType::Value report_type = |
| static_cast<FrameMsg_UILoadMetricsReportType::Value>( |
| info.urlRequest.inputPerfMetricReportPolicy()); |
| |
| // No history-navigation is expected to happen. |
| DCHECK(info.navigationType != blink::WebNavigationTypeBackForward); |
| |
| // Determine the navigation type. No same-document navigation is expected |
| // because it is loaded immediately by the FrameLoader. |
| FrameMsg_Navigate_Type::Value navigation_type = |
| FrameMsg_Navigate_Type::DIFFERENT_DOCUMENT; |
| if (info.navigationType == blink::WebNavigationTypeReload) { |
| if (load_flags & net::LOAD_BYPASS_CACHE) |
| navigation_type = FrameMsg_Navigate_Type::RELOAD_BYPASSING_CACHE; |
| else |
| navigation_type = FrameMsg_Navigate_Type::RELOAD; |
| } |
| |
| const RequestExtraData* extra_data = |
| static_cast<RequestExtraData*>(info.urlRequest.getExtraData()); |
| DCHECK(extra_data); |
| return CommonNavigationParams( |
| info.urlRequest.url(), referrer, extra_data->transition_type(), |
| navigation_type, true, info.replacesCurrentHistoryItem, ui_timestamp, |
| report_type, GURL(), GURL(), |
| static_cast<PreviewsState>(info.urlRequest.getPreviewsState()), |
| base::TimeTicks::Now(), info.urlRequest.httpMethod().latin1(), |
| GetRequestBodyForWebURLRequest(info.urlRequest)); |
| } |
| |
| media::Context3D GetSharedMainThreadContext3D( |
| scoped_refptr<ui::ContextProviderCommandBuffer> provider) { |
| if (!provider) |
| return media::Context3D(); |
| return media::Context3D(provider->ContextGL(), provider->GrContext()); |
| } |
| |
| WebFrameLoadType ReloadFrameLoadTypeFor( |
| FrameMsg_Navigate_Type::Value navigation_type) { |
| switch (navigation_type) { |
| case FrameMsg_Navigate_Type::RELOAD: |
| case FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL: |
| return WebFrameLoadType::ReloadMainResource; |
| |
| case FrameMsg_Navigate_Type::RELOAD_BYPASSING_CACHE: |
| return WebFrameLoadType::ReloadBypassingCache; |
| |
| default: |
| NOTREACHED(); |
| return WebFrameLoadType::Standard; |
| } |
| } |
| |
| RenderFrameImpl::CreateRenderFrameImplFunction g_create_render_frame_impl = |
| nullptr; |
| |
| WebString ConvertRelativePathToHtmlAttribute(const base::FilePath& path) { |
| DCHECK(!path.IsAbsolute()); |
| return WebString::fromUTF8( |
| std::string("./") + |
| path.NormalizePathSeparatorsTo(FILE_PATH_LITERAL('/')).AsUTF8Unsafe()); |
| } |
| |
| // Implementation of WebFrameSerializer::LinkRewritingDelegate that responds |
| // based on the payload of FrameMsg_GetSerializedHtmlWithLocalLinks. |
| class LinkRewritingDelegate : public WebFrameSerializer::LinkRewritingDelegate { |
| public: |
| LinkRewritingDelegate( |
| const std::map<GURL, base::FilePath>& url_to_local_path, |
| const std::map<int, base::FilePath>& frame_routing_id_to_local_path) |
| : url_to_local_path_(url_to_local_path), |
| frame_routing_id_to_local_path_(frame_routing_id_to_local_path) {} |
| |
| bool rewriteFrameSource(WebFrame* frame, WebString* rewritten_link) override { |
| int routing_id = GetRoutingIdForFrameOrProxy(frame); |
| auto it = frame_routing_id_to_local_path_.find(routing_id); |
| if (it == frame_routing_id_to_local_path_.end()) |
| return false; // This can happen because of https://crbug.com/541354. |
| |
| const base::FilePath& local_path = it->second; |
| *rewritten_link = ConvertRelativePathToHtmlAttribute(local_path); |
| return true; |
| } |
| |
| bool rewriteLink(const WebURL& url, WebString* rewritten_link) override { |
| auto it = url_to_local_path_.find(url); |
| if (it == url_to_local_path_.end()) |
| return false; |
| |
| const base::FilePath& local_path = it->second; |
| *rewritten_link = ConvertRelativePathToHtmlAttribute(local_path); |
| return true; |
| } |
| |
| private: |
| const std::map<GURL, base::FilePath>& url_to_local_path_; |
| const std::map<int, base::FilePath>& frame_routing_id_to_local_path_; |
| }; |
| |
| // Implementation of WebFrameSerializer::MHTMLPartsGenerationDelegate that |
| // 1. Bases shouldSkipResource and getContentID responses on contents of |
| // FrameMsg_SerializeAsMHTML_Params. |
| // 2. Stores digests of urls of serialized resources (i.e. urls reported via |
| // shouldSkipResource) into |serialized_resources_uri_digests| passed |
| // to the constructor. |
| class MHTMLPartsGenerationDelegate |
| : public WebFrameSerializer::MHTMLPartsGenerationDelegate { |
| public: |
| MHTMLPartsGenerationDelegate( |
| const FrameMsg_SerializeAsMHTML_Params& params, |
| std::set<std::string>* serialized_resources_uri_digests) |
| : params_(params), |
| serialized_resources_uri_digests_(serialized_resources_uri_digests) { |
| DCHECK(serialized_resources_uri_digests_); |
| } |
| |
| bool shouldSkipResource(const WebURL& url) override { |
| std::string digest = |
| crypto::SHA256HashString(params_.salt + GURL(url).spec()); |
| |
| // Skip if the |url| already covered by serialization of an *earlier* frame. |
| if (base::ContainsKey(params_.digests_of_uris_to_skip, digest)) |
| return true; |
| |
| // Let's record |url| as being serialized for the *current* frame. |
| auto pair = serialized_resources_uri_digests_->insert(digest); |
| bool insertion_took_place = pair.second; |
| DCHECK(insertion_took_place); // Blink should dedupe within a frame. |
| |
| return false; |
| } |
| |
| WebString getContentID(WebFrame* frame) override { |
| int routing_id = GetRoutingIdForFrameOrProxy(frame); |
| |
| auto it = params_.frame_routing_id_to_content_id.find(routing_id); |
| if (it == params_.frame_routing_id_to_content_id.end()) |
| return WebString(); |
| |
| const std::string& content_id = it->second; |
| return WebString::fromUTF8(content_id); |
| } |
| |
| blink::WebFrameSerializerCacheControlPolicy cacheControlPolicy() override { |
| return params_.mhtml_cache_control_policy; |
| } |
| |
| bool useBinaryEncoding() override { return params_.mhtml_binary_encoding; } |
| |
| bool removePopupOverlay() override { |
| return params_.mhtml_popup_overlay_removal; |
| } |
| |
| private: |
| const FrameMsg_SerializeAsMHTML_Params& params_; |
| std::set<std::string>* serialized_resources_uri_digests_; |
| |
| DISALLOW_COPY_AND_ASSIGN(MHTMLPartsGenerationDelegate); |
| }; |
| |
| bool IsHttpPost(const blink::WebURLRequest& request) { |
| return request.httpMethod().utf8() == "POST"; |
| } |
| |
| // Writes to file the serialized and encoded MHTML data from WebThreadSafeData |
| // instances. |
| MhtmlSaveStatus WriteMHTMLToDisk(std::vector<WebThreadSafeData> mhtml_contents, |
| base::File file) { |
| TRACE_EVENT0("page-serialization", "WriteMHTMLToDisk (RenderFrameImpl)"); |
| SCOPED_UMA_HISTOGRAM_TIMER( |
| "PageSerialization.MhtmlGeneration.WriteToDiskTime.SingleFrame"); |
| DCHECK(!RenderThread::Get()) << "Should not run in the main renderer thread"; |
| MhtmlSaveStatus save_status = MhtmlSaveStatus::SUCCESS; |
| for (const WebThreadSafeData& data : mhtml_contents) { |
| if (!data.isEmpty() && |
| file.WriteAtCurrentPos(data.data(), data.size()) < 0) { |
| save_status = MhtmlSaveStatus::FILE_WRITTING_ERROR; |
| break; |
| } |
| } |
| // Explicitly close |file| here to make sure to include any flush operations |
| // in the UMA metric. |
| file.Close(); |
| return save_status; |
| } |
| |
| #if defined(OS_ANDROID) |
| // Returns true if the MediaPlayerRenderer should be used for playback, false |
| // if the default renderer should be used instead. |
| // |
| // Note that HLS and MP4 detection are pre-redirect and path-based. It is |
| // possible to load such a URL and find different content. |
| bool UseMediaPlayerRenderer(const GURL& url) { |
| // Always use the default renderer for playing blob URLs. |
| if (url.SchemeIsBlob()) |
| return false; |
| |
| // The default renderer does not support HLS. |
| if (media::MediaCodecUtil::IsHLSURL(url)) |
| return true; |
| |
| // Don't use the default renderer if the container likely contains a codec we |
| // can't decode in software and platform decoders are not available. |
| if (!media::HasPlatformDecoderSupport()) { |
| // Assume that "mp4" means H264. Without platform decoder support we cannot |
| // play it with the default renderer so use MediaPlayerRenderer. |
| // http://crbug.com/642988. |
| if (base::ToLowerASCII(url.spec()).find("mp4") != std::string::npos) |
| return true; |
| } |
| |
| // Indicates if the Android MediaPlayer should be used instead of WMPI. |
| if (GetContentClient()->renderer()->ShouldUseMediaPlayerForURL(url)) |
| return true; |
| |
| // Otherwise, use the default renderer. |
| return false; |
| } |
| #endif // defined(OS_ANDROID) |
| |
| double ConvertToBlinkTime(const base::TimeTicks& time_ticks) { |
| return (time_ticks - base::TimeTicks()).InSecondsF(); |
| } |
| |
| } // namespace |
| |
| struct RenderFrameImpl::PendingFileChooser { |
| PendingFileChooser(const FileChooserParams& p, |
| blink::WebFileChooserCompletion* c) |
| : params(p), completion(c) {} |
| FileChooserParams params; |
| blink::WebFileChooserCompletion* completion; // MAY BE NULL to skip callback. |
| }; |
| |
| // static |
| RenderFrameImpl* RenderFrameImpl::Create(RenderViewImpl* render_view, |
| int32_t routing_id) { |
| DCHECK(routing_id != MSG_ROUTING_NONE); |
| CreateParams params(render_view, routing_id); |
| |
| if (g_create_render_frame_impl) |
| return g_create_render_frame_impl(params); |
| else |
| return new RenderFrameImpl(params); |
| } |
| |
| // static |
| RenderFrame* RenderFrame::FromRoutingID(int routing_id) { |
| return RenderFrameImpl::FromRoutingID(routing_id); |
| } |
| |
| // static |
| RenderFrameImpl* RenderFrameImpl::FromRoutingID(int routing_id) { |
| RoutingIDFrameMap::iterator iter = |
| g_routing_id_frame_map.Get().find(routing_id); |
| if (iter != g_routing_id_frame_map.Get().end()) |
| return iter->second; |
| return NULL; |
| } |
| |
| // static |
| RenderFrameImpl* RenderFrameImpl::CreateMainFrame( |
| RenderViewImpl* render_view, |
| int32_t routing_id, |
| int32_t widget_routing_id, |
| bool hidden, |
| const ScreenInfo& screen_info, |
| CompositorDependencies* compositor_deps, |
| blink::WebFrame* opener) { |
| // A main frame RenderFrame must have a RenderWidget. |
| DCHECK_NE(MSG_ROUTING_NONE, widget_routing_id); |
| |
| RenderFrameImpl* render_frame = |
| RenderFrameImpl::Create(render_view, routing_id); |
| render_frame->InitializeBlameContext(nullptr); |
| WebLocalFrame* web_frame = WebLocalFrame::create( |
| blink::WebTreeScopeType::Document, render_frame, |
| render_frame->blink_interface_provider_.get(), |
| render_frame->blink_interface_registry_.get(), opener); |
| render_frame->BindToWebFrame(web_frame); |
| render_view->webview()->setMainFrame(web_frame); |
| render_frame->render_widget_ = RenderWidget::CreateForFrame( |
| widget_routing_id, hidden, screen_info, compositor_deps, web_frame); |
| // TODO(avi): This DCHECK is to track cleanup for https://crbug.com/545684 |
| DCHECK_EQ(render_view->GetWidget(), render_frame->render_widget_) |
| << "Main frame is no longer reusing the RenderView as its widget! " |
| << "Does the RenderFrame need to register itself with the RenderWidget?"; |
| return render_frame; |
| } |
| |
| // static |
| void RenderFrameImpl::CreateFrame( |
| int routing_id, |
| int proxy_routing_id, |
| int opener_routing_id, |
| int parent_routing_id, |
| int previous_sibling_routing_id, |
| const FrameReplicationState& replicated_state, |
| CompositorDependencies* compositor_deps, |
| const mojom::CreateFrameWidgetParams& widget_params, |
| const FrameOwnerProperties& frame_owner_properties) { |
| blink::WebLocalFrame* web_frame; |
| RenderFrameImpl* render_frame; |
| if (proxy_routing_id == MSG_ROUTING_NONE) { |
| RenderFrameProxy* parent_proxy = |
| RenderFrameProxy::FromRoutingID(parent_routing_id); |
| // If the browser is sending a valid parent routing id, it should already |
| // be created and registered. |
| CHECK(parent_proxy); |
| blink::WebRemoteFrame* parent_web_frame = parent_proxy->web_frame(); |
| |
| blink::WebFrame* previous_sibling_web_frame = nullptr; |
| RenderFrameProxy* previous_sibling_proxy = |
| RenderFrameProxy::FromRoutingID(previous_sibling_routing_id); |
| if (previous_sibling_proxy) |
| previous_sibling_web_frame = previous_sibling_proxy->web_frame(); |
| |
| // Create the RenderFrame and WebLocalFrame, linking the two. |
| render_frame = |
| RenderFrameImpl::Create(parent_proxy->render_view(), routing_id); |
| render_frame->InitializeBlameContext(FromRoutingID(parent_routing_id)); |
| web_frame = parent_web_frame->createLocalChild( |
| replicated_state.scope, WebString::fromUTF8(replicated_state.name), |
| WebString::fromUTF8(replicated_state.unique_name), |
| replicated_state.sandbox_flags, render_frame, |
| render_frame->blink_interface_provider_.get(), |
| render_frame->blink_interface_registry_.get(), |
| previous_sibling_web_frame, |
| ConvertFrameOwnerPropertiesToWebFrameOwnerProperties( |
| frame_owner_properties), |
| ResolveOpener(opener_routing_id)); |
| |
| // The RenderFrame is created and inserted into the frame tree in the above |
| // call to createLocalChild. |
| render_frame->in_frame_tree_ = true; |
| } else { |
| RenderFrameProxy* proxy = |
| RenderFrameProxy::FromRoutingID(proxy_routing_id); |
| // The remote frame could've been detached while the remote-to-local |
| // navigation was being initiated in the browser process. Drop the |
| // navigation and don't create the frame in that case. See |
| // https://crbug.com/526304. |
| if (!proxy) |
| return; |
| |
| render_frame = RenderFrameImpl::Create(proxy->render_view(), routing_id); |
| render_frame->InitializeBlameContext(nullptr); |
| render_frame->proxy_routing_id_ = proxy_routing_id; |
| proxy->set_provisional_frame_routing_id(routing_id); |
| web_frame = blink::WebLocalFrame::createProvisional( |
| render_frame, render_frame->blink_interface_provider_.get(), |
| render_frame->blink_interface_registry_.get(), proxy->web_frame(), |
| replicated_state.sandbox_flags); |
| } |
| render_frame->BindToWebFrame(web_frame); |
| CHECK(parent_routing_id != MSG_ROUTING_NONE || !web_frame->parent()); |
| |
| if (widget_params.routing_id != MSG_ROUTING_NONE) { |
| CHECK(!web_frame->parent() || |
| SiteIsolationPolicy::AreCrossProcessFramesPossible()); |
| render_frame->render_widget_ = RenderWidget::CreateForFrame( |
| widget_params.routing_id, widget_params.hidden, |
| render_frame->render_view_->screen_info(), compositor_deps, web_frame); |
| // TODO(avi): The main frame re-uses the RenderViewImpl as its widget, so |
| // avoid double-registering the frame as an observer. |
| // https://crbug.com/545684 |
| if (web_frame->parent()) |
| render_frame->render_widget_->RegisterRenderFrame(render_frame); |
| } |
| |
| render_frame->Initialize(); |
| } |
| |
| // static |
| RenderFrame* RenderFrame::FromWebFrame(blink::WebFrame* web_frame) { |
| return RenderFrameImpl::FromWebFrame(web_frame); |
| } |
| |
| // static |
| RenderFrameImpl* RenderFrameImpl::FromWebFrame(blink::WebFrame* web_frame) { |
| FrameMap::iterator iter = g_frame_map.Get().find(web_frame); |
| if (iter != g_frame_map.Get().end()) |
| return iter->second; |
| return NULL; |
| } |
| |
| // static |
| void RenderFrameImpl::InstallCreateHook( |
| CreateRenderFrameImplFunction create_render_frame_impl) { |
| CHECK(!g_create_render_frame_impl); |
| g_create_render_frame_impl = create_render_frame_impl; |
| } |
| |
| // static |
| blink::WebFrame* RenderFrameImpl::ResolveOpener(int opener_frame_routing_id) { |
| if (opener_frame_routing_id == MSG_ROUTING_NONE) |
| return nullptr; |
| |
| // Opener routing ID could refer to either a RenderFrameProxy or a |
| // RenderFrame, so need to check both. |
| RenderFrameProxy* opener_proxy = |
| RenderFrameProxy::FromRoutingID(opener_frame_routing_id); |
| if (opener_proxy) |
| return opener_proxy->web_frame(); |
| |
| RenderFrameImpl* opener_frame = |
| RenderFrameImpl::FromRoutingID(opener_frame_routing_id); |
| if (opener_frame) |
| return opener_frame->GetWebFrame(); |
| |
| return nullptr; |
| } |
| |
| blink::WebURL RenderFrameImpl::overrideFlashEmbedWithHTML( |
| const blink::WebURL& url) { |
| return GetContentClient()->renderer()->OverrideFlashEmbedWithHTML(url); |
| } |
| |
| // RenderFrameImpl ---------------------------------------------------------- |
| RenderFrameImpl::RenderFrameImpl(const CreateParams& params) |
| : frame_(NULL), |
| is_main_frame_(true), |
| in_browser_initiated_detach_(false), |
| in_frame_tree_(false), |
| render_view_(params.render_view), |
| routing_id_(params.routing_id), |
| proxy_routing_id_(MSG_ROUTING_NONE), |
| #if BUILDFLAG(ENABLE_PLUGINS) |
| plugin_power_saver_helper_(nullptr), |
| plugin_find_handler_(nullptr), |
| #endif |
| cookie_jar_(this), |
| selection_text_offset_(0), |
| selection_range_(gfx::Range::InvalidRange()), |
| handling_select_range_(false), |
| web_user_media_client_(NULL), |
| #if defined(OS_ANDROID) |
| media_player_manager_(NULL), |
| #endif |
| media_surface_manager_(nullptr), |
| devtools_agent_(nullptr), |
| presentation_dispatcher_(NULL), |
| push_messaging_client_(NULL), |
| screen_orientation_dispatcher_(NULL), |
| manifest_manager_(NULL), |
| accessibility_mode_(AccessibilityModeOff), |
| render_accessibility_(NULL), |
| media_player_delegate_(NULL), |
| previews_state_(PREVIEWS_UNSPECIFIED), |
| effective_connection_type_( |
| blink::WebEffectiveConnectionType::TypeUnknown), |
| is_pasting_(false), |
| suppress_further_dialogs_(false), |
| blame_context_(nullptr), |
| #if BUILDFLAG(ENABLE_PLUGINS) |
| focused_pepper_plugin_(nullptr), |
| pepper_last_mouse_event_target_(nullptr), |
| #endif |
| engagement_binding_(this), |
| frame_binding_(this), |
| host_zoom_binding_(this), |
| frame_bindings_control_binding_(this), |
| has_accessed_initial_document_(false), |
| weak_factory_(this) { |
| // We don't have a service_manager::Connection at this point, so use empty |
| // identity/specs. |
| // TODO(beng): We should fix this, so we can apply policy about which |
| // interfaces get exposed. |
| interface_registry_ = base::MakeUnique<service_manager::InterfaceRegistry>( |
| mojom::kNavigation_FrameSpec); |
| service_manager::mojom::InterfaceProviderPtr remote_interfaces; |
| pending_remote_interface_provider_request_ = MakeRequest(&remote_interfaces); |
| remote_interfaces_.reset(new service_manager::InterfaceProvider); |
| remote_interfaces_->Bind(std::move(remote_interfaces)); |
| blink_interface_provider_.reset(new BlinkInterfaceProviderImpl( |
| remote_interfaces_->GetWeakPtr())); |
| blink_interface_registry_.reset( |
| new BlinkInterfaceRegistryImpl(interface_registry_->GetWeakPtr())); |
| |
| std::pair<RoutingIDFrameMap::iterator, bool> result = |
| g_routing_id_frame_map.Get().insert(std::make_pair(routing_id_, this)); |
| CHECK(result.second) << "Inserting a duplicate item."; |
| |
| RenderThread::Get()->AddRoute(routing_id_, this); |
| |
| render_view_->RegisterRenderFrame(this); |
| |
| // Everything below subclasses RenderFrameObserver and is automatically |
| // deleted when the RenderFrame gets deleted. |
| #if defined(OS_ANDROID) |
| new GinJavaBridgeDispatcher(this); |
| #endif |
| |
| #if BUILDFLAG(ENABLE_PLUGINS) |
| // Manages its own lifetime. |
| plugin_power_saver_helper_ = new PluginPowerSaverHelper(this); |
| #endif |
| |
| manifest_manager_ = new ManifestManager(this); |
| |
| #if BUILDFLAG(ENABLE_MEDIA_REMOTING) |
| // Create the SinkAvailabilityObserver to monitor the remoting sink |
| // availablity. |
| media::mojom::RemotingSourcePtr remoting_source; |
| media::mojom::RemotingSourceRequest remoting_source_request(&remoting_source); |
| media::mojom::RemoterPtr remoter; |
| GetRemoterFactory()->Create(std::move(remoting_source), |
| mojo::MakeRequest(&remoter)); |
| remoting_sink_observer_ = |
| base::MakeUnique<media::remoting::SinkAvailabilityObserver>( |
| std::move(remoting_source_request), std::move(remoter)); |
| #endif // BUILDFLAG(ENABLE_MEDIA_REMOTING) |
| } |
| |
| RenderFrameImpl::~RenderFrameImpl() { |
| // If file chooser is still waiting for answer, dispatch empty answer. |
| while (!file_chooser_completions_.empty()) { |
| if (file_chooser_completions_.front()->completion) { |
| file_chooser_completions_.front()->completion->didChooseFile( |
| WebVector<WebString>()); |
| } |
| file_chooser_completions_.pop_front(); |
| } |
| |
| for (auto& observer : observers_) |
| observer.RenderFrameGone(); |
| for (auto& observer : observers_) |
| observer.OnDestruct(); |
| |
| base::trace_event::TraceLog::GetInstance()->RemoveProcessLabel(routing_id_); |
| |
| // Unregister from InputHandlerManager. render_thread may be NULL in tests. |
| RenderThreadImpl* render_thread = RenderThreadImpl::current(); |
| InputHandlerManager* input_handler_manager = |
| render_thread ? render_thread->input_handler_manager() : nullptr; |
| if (input_handler_manager) |
| input_handler_manager->UnregisterRoutingID(GetRoutingID()); |
| |
| if (is_main_frame_) { |
| // Ensure the RenderView doesn't point to this object, once it is destroyed. |
| // TODO(nasko): Add a check that the |main_render_frame_| of |render_view_| |
| // is |this|, once the object is no longer leaked. |
| // See https://crbug.com/464764. |
| render_view_->main_render_frame_ = nullptr; |
| } |
| |
| render_view_->UnregisterRenderFrame(this); |
| g_routing_id_frame_map.Get().erase(routing_id_); |
| RenderThread::Get()->RemoveRoute(routing_id_); |
| } |
| |
| void RenderFrameImpl::BindToWebFrame(blink::WebLocalFrame* web_frame) { |
| DCHECK(!frame_); |
| |
| std::pair<FrameMap::iterator, bool> result = g_frame_map.Get().insert( |
| std::make_pair(web_frame, this)); |
| CHECK(result.second) << "Inserting a duplicate item."; |
| |
| frame_ = web_frame; |
| } |
| |
| void RenderFrameImpl::Initialize() { |
| is_main_frame_ = !frame_->parent(); |
| |
| RenderFrameImpl* parent_frame = RenderFrameImpl::FromWebFrame( |
| frame_->parent()); |
| if (parent_frame) { |
| previews_state_ = parent_frame->GetPreviewsState(); |
| effective_connection_type_ = parent_frame->getEffectiveConnectionType(); |
| } |
| |
| bool is_tracing_rail = false; |
| bool is_tracing_navigation = false; |
| TRACE_EVENT_CATEGORY_GROUP_ENABLED("navigation", &is_tracing_navigation); |
| TRACE_EVENT_CATEGORY_GROUP_ENABLED("rail", &is_tracing_rail); |
| if (is_tracing_rail || is_tracing_navigation) { |
| int parent_id = GetRoutingIdForFrameOrProxy(frame_->parent()); |
| TRACE_EVENT2("navigation,rail", "RenderFrameImpl::Initialize", |
| "id", routing_id_, |
| "parent", parent_id); |
| } |
| |
| #if BUILDFLAG(ENABLE_PLUGINS) |
| new PepperBrowserConnection(this); |
| #endif |
| shared_worker_repository_ = base::MakeUnique<SharedWorkerRepository>(this); |
| GetWebFrame()->setSharedWorkerRepositoryClient( |
| shared_worker_repository_.get()); |
| |
| if (IsLocalRoot()) { |
| // DevToolsAgent is a RenderFrameObserver, and will destruct itself |
| // when |this| is deleted. |
| devtools_agent_ = new DevToolsAgent(this); |
| } |
| |
| RegisterMojoInterfaces(); |
| |
| // We delay calling this until we have the WebFrame so that any observer or |
| // embedder can call GetWebFrame on any RenderFrame. |
| GetContentClient()->renderer()->RenderFrameCreated(this); |
| |
| RenderThreadImpl* render_thread = RenderThreadImpl::current(); |
| // render_thread may be NULL in tests. |
| InputHandlerManager* input_handler_manager = |
| render_thread ? render_thread->input_handler_manager() : nullptr; |
| if (input_handler_manager) { |
| DCHECK(render_view_->HasAddedInputHandler()); |
| input_handler_manager->RegisterRoutingID(GetRoutingID()); |
| } |
| |
| const base::CommandLine& command_line = |
| *base::CommandLine::ForCurrentProcess(); |
| if (command_line.HasSwitch(switches::kDomAutomationController)) |
| enabled_bindings_ |= BINDINGS_POLICY_DOM_AUTOMATION; |
| if (command_line.HasSwitch(switches::kStatsCollectionController)) |
| enabled_bindings_ |= BINDINGS_POLICY_STATS_COLLECTION; |
| } |
| |
| void RenderFrameImpl::InitializeBlameContext(RenderFrameImpl* parent_frame) { |
| DCHECK(!blame_context_); |
| blame_context_ = base::MakeUnique<FrameBlameContext>(this, parent_frame); |
| blame_context_->Initialize(); |
| } |
| |
| RenderWidget* RenderFrameImpl::GetRenderWidget() { |
| return GetLocalRoot()->render_widget_.get(); |
| } |
| |
| #if BUILDFLAG(ENABLE_PLUGINS) |
| void RenderFrameImpl::PepperPluginCreated(RendererPpapiHost* host) { |
| for (auto& observer : observers_) |
| observer.DidCreatePepperPlugin(host); |
| } |
| |
| void RenderFrameImpl::PepperDidChangeCursor( |
| PepperPluginInstanceImpl* instance, |
| const blink::WebCursorInfo& cursor) { |
| // Update the cursor appearance immediately if the requesting plugin is the |
| // one which receives the last mouse event. Otherwise, the new cursor won't be |
| // picked up until the plugin gets the next input event. That is bad if, e.g., |
| // the plugin would like to set an invisible cursor when there isn't any user |
| // input for a while. |
| if (instance == pepper_last_mouse_event_target_) |
| GetRenderWidget()->didChangeCursor(cursor); |
| } |
| |
| void RenderFrameImpl::PepperDidReceiveMouseEvent( |
| PepperPluginInstanceImpl* instance) { |
| set_pepper_last_mouse_event_target(instance); |
| } |
| |
| void RenderFrameImpl::PepperTextInputTypeChanged( |
| PepperPluginInstanceImpl* instance) { |
| if (instance != focused_pepper_plugin_) |
| return; |
| |
| GetRenderWidget()->UpdateTextInputState(); |
| |
| FocusedNodeChangedForAccessibility(WebNode()); |
| } |
| |
| void RenderFrameImpl::PepperCaretPositionChanged( |
| PepperPluginInstanceImpl* instance) { |
| if (instance != focused_pepper_plugin_) |
| return; |
| GetRenderWidget()->UpdateSelectionBounds(); |
| } |
| |
| void RenderFrameImpl::PepperCancelComposition( |
| PepperPluginInstanceImpl* instance) { |
| if (instance != focused_pepper_plugin_) |
| return; |
| Send(new InputHostMsg_ImeCancelComposition(render_view_->GetRoutingID())); |
| #if defined(OS_MACOSX) || defined(USE_AURA) |
| GetRenderWidget()->UpdateCompositionInfo( |
| false /* not an immediate request */); |
| #endif |
| } |
| |
| void RenderFrameImpl::PepperSelectionChanged( |
| PepperPluginInstanceImpl* instance) { |
| if (instance != focused_pepper_plugin_) |
| return; |
| SyncSelectionIfRequired(); |
| } |
| |
| RenderWidgetFullscreenPepper* RenderFrameImpl::CreatePepperFullscreenContainer( |
| PepperPluginInstanceImpl* plugin) { |
| GURL active_url; |
| if (render_view()->webview()) |
| active_url = render_view()->GetURLForGraphicsContext3D(); |
| |
| // Synchronous IPC to obtain a routing id for the fullscreen widget. |
| int32_t fullscreen_widget_routing_id = MSG_ROUTING_NONE; |
| if (!RenderThreadImpl::current_render_message_filter() |
| ->CreateFullscreenWidget(render_view()->routing_id(), |
| &fullscreen_widget_routing_id)) { |
| return nullptr; |
| } |
| RenderWidget::ShowCallback show_callback = |
| base::Bind(&RenderViewImpl::ShowCreatedFullscreenWidget, |
| render_view()->GetWeakPtr()); |
| |
| RenderWidgetFullscreenPepper* widget = RenderWidgetFullscreenPepper::Create( |
| fullscreen_widget_routing_id, show_callback, |
| GetRenderWidget()->compositor_deps(), plugin, active_url, |
| GetRenderWidget()->screen_info()); |
| // TODO(nick): The show() handshake seems like unnecessary complexity here, |
| // since there's no real delay between CreateFullscreenWidget and |
| // ShowCreatedFullscreenWidget. Would it be simpler to have the |
| // CreateFullscreenWidget mojo method implicitly show the window, and skip the |
| // subsequent step? |
| widget->show(blink::WebNavigationPolicyIgnore); |
| return widget; |
| } |
| |
| bool RenderFrameImpl::IsPepperAcceptingCompositionEvents() const { |
| if (!focused_pepper_plugin_) |
| return false; |
| return focused_pepper_plugin_->IsPluginAcceptingCompositionEvents(); |
| } |
| |
| void RenderFrameImpl::PluginCrashed(const base::FilePath& plugin_path, |
| base::ProcessId plugin_pid) { |
| // TODO(jam): dispatch this IPC in RenderFrameHost and switch to use |
| // routing_id_ as a result. |
| Send(new FrameHostMsg_PluginCrashed(routing_id_, plugin_path, plugin_pid)); |
| } |
| |
| void RenderFrameImpl::SimulateImeSetComposition( |
| const base::string16& text, |
| const std::vector<blink::WebCompositionUnderline>& underlines, |
| int selection_start, |
| int selection_end) { |
| render_view_->OnImeSetComposition( |
| text, underlines, gfx::Range::InvalidRange(), |
| selection_start, selection_end); |
| } |
| |
| void RenderFrameImpl::SimulateImeCommitText( |
| const base::string16& text, |
| const std::vector<blink::WebCompositionUnderline>& underlines, |
| const gfx::Range& replacement_range) { |
| render_view_->OnImeCommitText(text, underlines, replacement_range, 0); |
| } |
| |
| void RenderFrameImpl::SimulateImeFinishComposingText(bool keep_selection) { |
| render_view_->OnImeFinishComposingText(keep_selection); |
| } |
| |
| void RenderFrameImpl::OnImeSetComposition( |
| const base::string16& text, |
| const std::vector<blink::WebCompositionUnderline>& underlines, |
| int selection_start, |
| int selection_end) { |
| // When a PPAPI plugin has focus, we bypass WebKit. |
| if (!IsPepperAcceptingCompositionEvents()) { |
| pepper_composition_text_ = text; |
| } else { |
| // TODO(kinaba) currently all composition events are sent directly to |
| // plugins. Use DOM event mechanism after WebKit is made aware about |
| // plugins that support composition. |
| // The code below mimics the behavior of WebCore::Editor::setComposition. |
| |
| // Empty -> nonempty: composition started. |
| if (pepper_composition_text_.empty() && !text.empty()) { |
| focused_pepper_plugin_->HandleCompositionStart(base::string16()); |
| } |
| // Nonempty -> empty: composition canceled. |
| if (!pepper_composition_text_.empty() && text.empty()) { |
| focused_pepper_plugin_->HandleCompositionEnd(base::string16()); |
| } |
| pepper_composition_text_ = text; |
| // Nonempty: composition is ongoing. |
| if (!pepper_composition_text_.empty()) { |
| focused_pepper_plugin_->HandleCompositionUpdate( |
| pepper_composition_text_, underlines, selection_start, selection_end); |
| } |
| } |
| } |
| |
| void RenderFrameImpl::OnImeCommitText(const base::string16& text, |
| const gfx::Range& replacement_range, |
| int relative_cursor_pos) { |
| HandlePepperImeCommit(text); |
| } |
| |
| void RenderFrameImpl::OnImeFinishComposingText(bool keep_selection) { |
| const base::string16& text = pepper_composition_text_; |
| HandlePepperImeCommit(text); |
| } |
| #endif // BUILDFLAG(ENABLE_PLUGINS) |
| |
| MediaStreamDispatcher* RenderFrameImpl::GetMediaStreamDispatcher() { |
| if (!web_user_media_client_) |
| InitializeUserMediaClient(); |
| return web_user_media_client_ |
| ? web_user_media_client_->media_stream_dispatcher() |
| : nullptr; |
| } |
| |
| void RenderFrameImpl::ScriptedPrint(bool user_initiated) { |
| for (auto& observer : observers_) |
| observer.ScriptedPrint(user_initiated); |
| } |
| |
| bool RenderFrameImpl::Send(IPC::Message* message) { |
| return RenderThread::Get()->Send(message); |
| } |
| |
| #if defined(USE_EXTERNAL_POPUP_MENU) |
| void RenderFrameImpl::DidHideExternalPopupMenu() { |
| // We need to clear external_popup_menu_ as soon as ExternalPopupMenu::close |
| // is called. Otherwise, createExternalPopupMenu() for new popup will fail. |
| external_popup_menu_.reset(); |
| } |
| #endif |
| |
| bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) { |
| // Forward Page IPCs to the RenderView. |
| if ((IPC_MESSAGE_CLASS(msg) == PageMsgStart)) { |
| if (render_view()) |
| return render_view()->OnMessageReceived(msg); |
| |
| return false; |
| } |
| |
| // We may get here while detaching, when the WebFrame has been deleted. Do |
| // not process any messages in this state. |
| if (!frame_) |
| return false; |
| |
| DCHECK(!frame_->document().isNull()); |
| |
| GetContentClient()->SetActiveURL(frame_->document().url()); |
| |
| for (auto& observer : observers_) { |
| if (observer.OnMessageReceived(msg)) |
| return true; |
| } |
| |
| bool handled = true; |
| IPC_BEGIN_MESSAGE_MAP(RenderFrameImpl, msg) |
| IPC_MESSAGE_HANDLER(FrameMsg_Navigate, OnNavigate) |
| IPC_MESSAGE_HANDLER(FrameMsg_BeforeUnload, OnBeforeUnload) |
| IPC_MESSAGE_HANDLER(FrameMsg_SwapOut, OnSwapOut) |
| IPC_MESSAGE_HANDLER(FrameMsg_SwapIn, OnSwapIn) |
| IPC_MESSAGE_HANDLER(FrameMsg_Delete, OnDeleteFrame) |
| IPC_MESSAGE_HANDLER(FrameMsg_Stop, OnStop) |
| IPC_MESSAGE_HANDLER(FrameMsg_ContextMenuClosed, OnContextMenuClosed) |
| IPC_MESSAGE_HANDLER(FrameMsg_CustomContextMenuAction, |
| OnCustomContextMenuAction) |
| #if BUILDFLAG(ENABLE_PLUGINS) |
| IPC_MESSAGE_HANDLER(FrameMsg_SetPepperVolume, OnSetPepperVolume) |
| #endif |
| IPC_MESSAGE_HANDLER(InputMsg_Undo, OnUndo) |
| IPC_MESSAGE_HANDLER(InputMsg_Redo, OnRedo) |
| IPC_MESSAGE_HANDLER(InputMsg_Cut, OnCut) |
| IPC_MESSAGE_HANDLER(InputMsg_Copy, OnCopy) |
| IPC_MESSAGE_HANDLER(InputMsg_Paste, OnPaste) |
| IPC_MESSAGE_HANDLER(InputMsg_PasteAndMatchStyle, OnPasteAndMatchStyle) |
| IPC_MESSAGE_HANDLER(InputMsg_Delete, OnDelete) |
| IPC_MESSAGE_HANDLER(InputMsg_SelectAll, OnSelectAll) |
| IPC_MESSAGE_HANDLER(InputMsg_SelectRange, OnSelectRange) |
| IPC_MESSAGE_HANDLER(InputMsg_AdjustSelectionByCharacterOffset, |
| OnAdjustSelectionByCharacterOffset) |
| IPC_MESSAGE_HANDLER(InputMsg_CollapseSelection, OnCollapseSelection) |
| IPC_MESSAGE_HANDLER(InputMsg_MoveRangeSelectionExtent, |
| OnMoveRangeSelectionExtent) |
| IPC_MESSAGE_HANDLER(InputMsg_Replace, OnReplace) |
| IPC_MESSAGE_HANDLER(InputMsg_ReplaceMisspelling, OnReplaceMisspelling) |
| IPC_MESSAGE_HANDLER(FrameMsg_CopyImageAt, OnCopyImageAt) |
| IPC_MESSAGE_HANDLER(FrameMsg_SaveImageAt, OnSaveImageAt) |
| IPC_MESSAGE_HANDLER(InputMsg_ExtendSelectionAndDelete, |
| OnExtendSelectionAndDelete) |
| IPC_MESSAGE_HANDLER(InputMsg_DeleteSurroundingText, OnDeleteSurroundingText) |
| IPC_MESSAGE_HANDLER(InputMsg_DeleteSurroundingTextInCodePoints, |
| OnDeleteSurroundingTextInCodePoints) |
| IPC_MESSAGE_HANDLER(InputMsg_SetCompositionFromExistingText, |
| OnSetCompositionFromExistingText) |
| IPC_MESSAGE_HANDLER(InputMsg_SetEditableSelectionOffsets, |
| OnSetEditableSelectionOffsets) |
| IPC_MESSAGE_HANDLER(InputMsg_ExecuteNoValueEditCommand, |
| OnExecuteNoValueEditCommand) |
| IPC_MESSAGE_HANDLER(FrameMsg_AddMessageToConsole, OnAddMessageToConsole) |
| IPC_MESSAGE_HANDLER(FrameMsg_JavaScriptExecuteRequest, |
| OnJavaScriptExecuteRequest) |
| IPC_MESSAGE_HANDLER(FrameMsg_JavaScriptExecuteRequestForTests, |
| OnJavaScriptExecuteRequestForTests) |
| IPC_MESSAGE_HANDLER(FrameMsg_JavaScriptExecuteRequestInIsolatedWorld, |
| OnJavaScriptExecuteRequestInIsolatedWorld) |
| IPC_MESSAGE_HANDLER(FrameMsg_VisualStateRequest, |
| OnVisualStateRequest) |
| IPC_MESSAGE_HANDLER(FrameMsg_Reload, OnReload) |
| IPC_MESSAGE_HANDLER(FrameMsg_ReloadLoFiImages, OnReloadLoFiImages) |
| IPC_MESSAGE_HANDLER(FrameMsg_TextSurroundingSelectionRequest, |
| OnTextSurroundingSelectionRequest) |
| IPC_MESSAGE_HANDLER(FrameMsg_SetAccessibilityMode, |
| OnSetAccessibilityMode) |
| IPC_MESSAGE_HANDLER(AccessibilityMsg_SnapshotTree, |
| OnSnapshotAccessibilityTree) |
| IPC_MESSAGE_HANDLER(FrameMsg_ExtractSmartClipData, OnExtractSmartClipData) |
| IPC_MESSAGE_HANDLER(FrameMsg_UpdateOpener, OnUpdateOpener) |
| IPC_MESSAGE_HANDLER(FrameMsg_CommitNavigation, OnCommitNavigation) |
| IPC_MESSAGE_HANDLER(FrameMsg_DidUpdateSandboxFlags, OnDidUpdateSandboxFlags) |
| IPC_MESSAGE_HANDLER(FrameMsg_SetFrameOwnerProperties, |
| OnSetFrameOwnerProperties) |
| IPC_MESSAGE_HANDLER(FrameMsg_AdvanceFocus, OnAdvanceFocus) |
| IPC_MESSAGE_HANDLER(FrameMsg_SetFocusedFrame, OnSetFocusedFrame) |
| IPC_MESSAGE_HANDLER(FrameMsg_SetTextTrackSettings, |
| OnTextTrackSettingsChanged) |
| IPC_MESSAGE_HANDLER(FrameMsg_PostMessageEvent, OnPostMessageEvent) |
| IPC_MESSAGE_HANDLER(FrameMsg_FailedNavigation, OnFailedNavigation) |
| IPC_MESSAGE_HANDLER(FrameMsg_GetSavableResourceLinks, |
| OnGetSavableResourceLinks) |
| IPC_MESSAGE_HANDLER(FrameMsg_GetSerializedHtmlWithLocalLinks, |
| OnGetSerializedHtmlWithLocalLinks) |
| IPC_MESSAGE_HANDLER(FrameMsg_SerializeAsMHTML, OnSerializeAsMHTML) |
| IPC_MESSAGE_HANDLER(FrameMsg_Find, OnFind) |
| IPC_MESSAGE_HANDLER(FrameMsg_ClearActiveFindMatch, OnClearActiveFindMatch) |
| IPC_MESSAGE_HANDLER(FrameMsg_StopFinding, OnStopFinding) |
| IPC_MESSAGE_HANDLER(FrameMsg_EnableViewSourceMode, OnEnableViewSourceMode) |
| IPC_MESSAGE_HANDLER(FrameMsg_SuppressFurtherDialogs, |
| OnSuppressFurtherDialogs) |
| IPC_MESSAGE_HANDLER(FrameMsg_RunFileChooserResponse, OnFileChooserResponse) |
| IPC_MESSAGE_HANDLER(FrameMsg_ClearFocusedElement, OnClearFocusedElement) |
| IPC_MESSAGE_HANDLER(FrameMsg_BlinkFeatureUsageReport, |
| OnBlinkFeatureUsageReport) |
| IPC_MESSAGE_HANDLER(FrameMsg_MixedContentFound, OnMixedContentFound) |
| #if defined(OS_ANDROID) |
| IPC_MESSAGE_HANDLER(FrameMsg_ActivateNearestFindResult, |
| OnActivateNearestFindResult) |
| IPC_MESSAGE_HANDLER(FrameMsg_GetNearestFindResult, |
| OnGetNearestFindResult) |
| IPC_MESSAGE_HANDLER(FrameMsg_FindMatchRects, OnFindMatchRects) |
| #endif |
| |
| #if defined(USE_EXTERNAL_POPUP_MENU) |
| #if defined(OS_MACOSX) |
| IPC_MESSAGE_HANDLER(FrameMsg_SelectPopupMenuItem, OnSelectPopupMenuItem) |
| #else |
| IPC_MESSAGE_HANDLER(FrameMsg_SelectPopupMenuItems, OnSelectPopupMenuItems) |
| #endif |
| #endif |
| |
| #if defined(OS_MACOSX) |
| IPC_MESSAGE_HANDLER(InputMsg_CopyToFindPboard, OnCopyToFindPboard) |
| #endif |
| IPC_END_MESSAGE_MAP() |
| |
| return handled; |
| } |
| |
| void RenderFrameImpl::OnAssociatedInterfaceRequest( |
| const std::string& interface_name, |
| mojo::ScopedInterfaceEndpointHandle handle) { |
| associated_interfaces_.BindRequest(interface_name, std::move(handle)); |
| } |
| |
| void RenderFrameImpl::OnNavigate( |
| const CommonNavigationParams& common_params, |
| const StartNavigationParams& start_params, |
| const RequestNavigationParams& request_params) { |
| RenderThreadImpl* render_thread_impl = RenderThreadImpl::current(); |
| // Can be NULL in tests. |
| if (render_thread_impl) |
| render_thread_impl->GetRendererScheduler()->OnNavigationStarted(); |
| DCHECK(!IsBrowserSideNavigationEnabled()); |
| TRACE_EVENT2("navigation,rail", "RenderFrameImpl::OnNavigate", "id", |
| routing_id_, "url", common_params.url.possibly_invalid_spec()); |
| NavigateInternal(common_params, start_params, request_params, |
| std::unique_ptr<StreamOverrideParameters>()); |
| } |
| |
| void RenderFrameImpl::BindEngagement( |
| blink::mojom::EngagementClientAssociatedRequest request) { |
| engagement_binding_.Bind(std::move(request)); |
| } |
| |
| void RenderFrameImpl::BindFrame(mojom::FrameRequest request, |
| mojom::FrameHostPtr host) { |
| frame_binding_.Bind(std::move(request)); |
| frame_host_ = std::move(host); |
| frame_host_->GetInterfaceProvider( |
| std::move(pending_remote_interface_provider_request_)); |
| } |
| |
| void RenderFrameImpl::BindFrameBindingsControl( |
| mojom::FrameBindingsControlAssociatedRequest request) { |
| frame_bindings_control_binding_.Bind(std::move(request)); |
| } |
| |
| ManifestManager* RenderFrameImpl::manifest_manager() { |
| return manifest_manager_; |
| } |
| |
| void RenderFrameImpl::SetPendingNavigationParams( |
| std::unique_ptr<NavigationParams> navigation_params) { |
| pending_navigation_params_ = std::move(navigation_params); |
| } |
| |
| void RenderFrameImpl::OnBeforeUnload(bool is_reload) { |
| TRACE_EVENT1("navigation,rail", "RenderFrameImpl::OnBeforeUnload", |
| "id", routing_id_); |
| // Save the routing_id, as the RenderFrameImpl can be deleted in |
| // dispatchBeforeUnloadEvent. See https://crbug.com/666714 for details. |
| int routing_id = routing_id_; |
| |
| base::TimeTicks before_unload_start_time = base::TimeTicks::Now(); |
| |
| // TODO(clamy): Ensure BeforeUnload is dispatched to all subframes, even when |
| // --site-per-process is enabled. |dispatchBeforeUnloadEvent| will only |
| // execute the BeforeUnload event in this frame and local child frames. It |
| // should also be dispatched to out-of-process child frames. |
| bool proceed = frame_->dispatchBeforeUnloadEvent(is_reload); |
| |
| base::TimeTicks before_unload_end_time = base::TimeTicks::Now(); |
| RenderThread::Get()->Send(new FrameHostMsg_BeforeUnload_ACK( |
| routing_id, proceed, before_unload_start_time, before_unload_end_time)); |
| } |
| |
| void RenderFrameImpl::OnSwapOut( |
| int proxy_routing_id, |
| bool is_loading, |
| const FrameReplicationState& replicated_frame_state) { |
| TRACE_EVENT1("navigation,rail", "RenderFrameImpl::OnSwapOut", |
| "id", routing_id_); |
| RenderFrameProxy* proxy = NULL; |
| |
| // This codepath should only be hit for subframes when in --site-per-process. |
| CHECK(is_main_frame_ || SiteIsolationPolicy::AreCrossProcessFramesPossible()); |
| |
| // Swap this RenderFrame out so the frame can navigate to a page rendered by |
| // a different process. This involves running the unload handler and |
| // clearing the page. We also allow this process to exit if there are no |
| // other active RenderFrames in it. |
| |
| // Send an UpdateState message before we get deleted. |
| SendUpdateState(); |
| |
| // There should always be a proxy to replace this RenderFrame. Create it now |
| // so its routing id is registered for receiving IPC messages. |
| CHECK_NE(proxy_routing_id, MSG_ROUTING_NONE); |
| proxy = RenderFrameProxy::CreateProxyToReplaceFrame( |
| this, proxy_routing_id, replicated_frame_state.scope); |
| |
| // Synchronously run the unload handler before sending the ACK. |
| // TODO(creis): Call dispatchUnloadEvent unconditionally here to support |
| // unload on subframes as well. |
| if (is_main_frame_) |
| frame_->dispatchUnloadEvent(); |
| |
| // Swap out and stop sending any IPC messages that are not ACKs. |
| if (is_main_frame_) |
| render_view_->SetSwappedOut(true); |
| |
| RenderViewImpl* render_view = render_view_; |
| bool is_main_frame = is_main_frame_; |
| int routing_id = GetRoutingID(); |
| |
| // Now that all of the cleanup is complete and the browser side is notified, |
| // start using the RenderFrameProxy. |
| // |
| // The swap call deletes this RenderFrame via frameDetached. Do not access |
| // any members after this call. |
| // |
| // TODO(creis): WebFrame::swap() can return false. Most of those cases |
| // should be due to the frame being detached during unload (in which case |
| // the necessary cleanup has happened anyway), but it might be possible for |
| // it to return false without detaching. Catch any cases that the |
| // RenderView's main_render_frame_ isn't cleared below (whether swap returns |
| // false or not), to track down https://crbug.com/575245. |
| bool success = frame_->swap(proxy->web_frame()); |
| |
| // For main frames, the swap should have cleared the RenderView's pointer to |
| // this frame. |
| if (is_main_frame) { |
| base::debug::SetCrashKeyValue("swapout_frame_id", |
| base::IntToString(routing_id)); |
| base::debug::SetCrashKeyValue("swapout_proxy_id", |
| base::IntToString(proxy->routing_id())); |
| base::debug::SetCrashKeyValue( |
| "swapout_view_id", base::IntToString(render_view->GetRoutingID())); |
| CHECK(!render_view->main_render_frame_); |
| } |
| |
| if (!success) { |
| // The swap can fail when the frame is detached during swap (this can |
| // happen while running the unload handlers). When that happens, delete |
| // the proxy. |
| proxy->frameDetached(blink::WebRemoteFrameClient::DetachType::Swap); |
| return; |
| } |
| |
| if (is_loading) |
| proxy->OnDidStartLoading(); |
| |
| // Initialize the WebRemoteFrame with the replication state passed by the |
| // process that is now rendering the frame. |
| proxy->SetReplicatedState(replicated_frame_state); |
| |
| // Safe to exit if no one else is using the process. |
| // TODO(nasko): Remove the dependency on RenderViewImpl here and ref count |
| // the process based on the lifetime of this RenderFrameImpl object. |
| if (is_main_frame) |
| render_view->WasSwappedOut(); |
| |
| // Notify the browser that this frame was swapped. Use the RenderThread |
| // directly because |this| is deleted. |
| RenderThread::Get()->Send(new FrameHostMsg_SwapOut_ACK(routing_id)); |
| } |
| |
| void RenderFrameImpl::OnSwapIn() { |
| SwapIn(); |
| } |
| |
| void RenderFrameImpl::OnDeleteFrame() { |
| // TODO(nasko): If this message is received right after a commit has |
| // swapped a RenderFrameProxy with this RenderFrame, the proxy needs to be |
| // recreated in addition to the RenderFrame being deleted. |
| // See https://crbug.com/569683 for details. |
| in_browser_initiated_detach_ = true; |
| |
| // This will result in a call to RendeFrameImpl::frameDetached, which |
| // deletes the object. Do not access |this| after detach. |
| frame_->detach(); |
| } |
| |
| void RenderFrameImpl::OnContextMenuClosed( |
| const CustomContextMenuContext& custom_context) { |
| if (custom_context.request_id) { |
| // External request, should be in our map. |
| ContextMenuClient* client = |
| pending_context_menus_.Lookup(custom_context.request_id); |
| if (client) { |
| client->OnMenuClosed(custom_context.request_id); |
| pending_context_menus_.Remove(custom_context.request_id); |
| } |
| } else { |
| if (custom_context.link_followed.is_valid()) |
| frame_->sendPings(custom_context.link_followed); |
| } |
| |
| render_view()->webview()->didCloseContextMenu(); |
| } |
| |
| void RenderFrameImpl::OnCustomContextMenuAction( |
| const CustomContextMenuContext& custom_context, |
| unsigned action) { |
| if (custom_context.request_id) { |
| // External context menu request, look in our map. |
| ContextMenuClient* client = |
| pending_context_menus_.Lookup(custom_context.request_id); |
| if (client) |
| client->OnMenuAction(custom_context.request_id, action); |
| } else { |
| // Internal request, forward to WebKit. |
| render_view_->webview()->performCustomContextMenuAction(action); |
| } |
| } |
| |
| void RenderFrameImpl::OnUndo() { |
| frame_->executeCommand(WebString::fromUTF8("Undo")); |
| } |
| |
| void RenderFrameImpl::OnRedo() { |
| frame_->executeCommand(WebString::fromUTF8("Redo")); |
| } |
| |
| void RenderFrameImpl::OnCut() { |
| base::AutoReset<bool> handling_select_range(&handling_select_range_, true); |
| frame_->executeCommand(WebString::fromUTF8("Cut")); |
| } |
| |
| void RenderFrameImpl::OnCopy() { |
| base::AutoReset<bool> handling_select_range(&handling_select_range_, true); |
| frame_->executeCommand(WebString::fromUTF8("Copy")); |
| } |
| |
| void RenderFrameImpl::OnPaste() { |
| base::AutoReset<bool> handling_select_range(&handling_select_range_, true); |
| base::AutoReset<bool> handling_paste(&is_pasting_, true); |
| frame_->executeCommand(WebString::fromUTF8("Paste")); |
| } |
| |
| void RenderFrameImpl::OnPasteAndMatchStyle() { |
| base::AutoReset<bool> handling_select_range(&handling_select_range_, true); |
| frame_->executeCommand(WebString::fromUTF8("PasteAndMatchStyle")); |
| } |
| |
| #if defined(OS_MACOSX) |
| void RenderFrameImpl::OnCopyToFindPboard() { |
| // Since the find pasteboard supports only plain text, this can be simpler |
| // than the |OnCopy()| case. |
| if (frame_->hasSelection()) { |
| base::string16 selection = frame_->selectionAsText().utf16(); |
| RenderThread::Get()->Send( |
| new ClipboardHostMsg_FindPboardWriteStringAsync(selection)); |
| } |
| } |
| #endif |
| |
| void RenderFrameImpl::OnDelete() { |
| frame_->executeCommand(WebString::fromUTF8("Delete")); |
| } |
| |
| void RenderFrameImpl::OnSelectAll() { |
| base::AutoReset<bool> handling_select_range(&handling_select_range_, true); |
| frame_->executeCommand(WebString::fromUTF8("SelectAll")); |
| } |
| |
| void RenderFrameImpl::OnSelectRange(const gfx::Point& base, |
| const gfx::Point& extent) { |
| // This IPC is dispatched by RenderWidgetHost, so use its routing id. |
| Send(new InputHostMsg_SelectRange_ACK(GetRenderWidget()->routing_id())); |
| |
| base::AutoReset<bool> handling_select_range(&handling_select_range_, true); |
| frame_->selectRange(render_view_->ConvertWindowPointToViewport(base), |
| render_view_->ConvertWindowPointToViewport(extent)); |
| } |
| |
| void RenderFrameImpl::OnAdjustSelectionByCharacterOffset(int start_adjust, |
| int end_adjust) { |
| WebRange range = GetRenderWidget()->GetWebWidget()->caretOrSelectionRange(); |
| if (range.isNull()) |
| return; |
| |
| // Sanity checks to disallow empty and out of range selections. |
| if (start_adjust - end_adjust > range.length() || |
| range.startOffset() + start_adjust < 0) |
| return; |
| |
| base::AutoReset<bool> handling_select_range(&handling_select_range_, true); |
| |
| // A negative adjust amount moves the selection towards the beginning of |
| // the document, a positive amount moves the selection towards the end of |
| // the document. |
| frame_->selectRange(WebRange(range.startOffset() + start_adjust, |
| range.length() + end_adjust - start_adjust)); |
| } |
| |
| void RenderFrameImpl::OnCollapseSelection() { |
| const WebRange& range = |
| GetRenderWidget()->GetWebWidget()->caretOrSelectionRange(); |
| if (range.isNull()) |
| return; |
| |
| base::AutoReset<bool> handling_select_range(&handling_select_range_, true); |
| frame_->selectRange(WebRange(range.endOffset(), 0)); |
| } |
| |
| void RenderFrameImpl::OnMoveRangeSelectionExtent(const gfx::Point& point) { |
| // This IPC is dispatched by RenderWidgetHost, so use its routing id. |
| Send(new InputHostMsg_MoveRangeSelectionExtent_ACK( |
| GetRenderWidget()->routing_id())); |
| |
| base::AutoReset<bool> handling_select_range(&handling_select_range_, true); |
| frame_->moveRangeSelectionExtent( |
| render_view_->ConvertWindowPointToViewport(point)); |
| } |
| |
| void RenderFrameImpl::OnReplace(const base::string16& text) { |
| if (!frame_->hasSelection()) |
| frame_->selectWordAroundCaret(); |
| |
| frame_->replaceSelection(WebString::fromUTF16(text)); |
| SyncSelectionIfRequired(); |
| } |
| |
| void RenderFrameImpl::OnReplaceMisspelling(const base::string16& text) { |
| if (!frame_->hasSelection()) |
| return; |
| |
| frame_->replaceMisspelledRange(WebString::fromUTF16(text)); |
| } |
| |
| void RenderFrameImpl::OnCopyImageAt(int x, int y) { |
| blink::WebFloatRect viewport_position(x, y, 0, 0); |
| GetRenderWidget()->convertWindowToViewport(&viewport_position); |
| frame_->copyImageAt(WebPoint(viewport_position.x, viewport_position.y)); |
| } |
| |
| void RenderFrameImpl::OnSaveImageAt(int x, int y) { |
| blink::WebFloatRect viewport_position(x, y, 0, 0); |
| GetRenderWidget()->convertWindowToViewport(&viewport_position); |
| frame_->saveImageAt(WebPoint(viewport_position.x, viewport_position.y)); |
| } |
| |
| void RenderFrameImpl::OnAddMessageToConsole(ConsoleMessageLevel level, |
| const std::string& message) { |
| AddMessageToConsole(level, message); |
| } |
| |
| void RenderFrameImpl::OnJavaScriptExecuteRequest( |
| const base::string16& jscript, |
| int id, |
| bool notify_result) { |
| TRACE_EVENT_INSTANT0("test_tracing", "OnJavaScriptExecuteRequest", |
| TRACE_EVENT_SCOPE_THREAD); |
| |
| v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); |
| v8::Local<v8::Value> result = frame_->executeScriptAndReturnValue( |
| WebScriptSource(WebString::fromUTF16(jscript))); |
| |
| HandleJavascriptExecutionResult(jscript, id, notify_result, result); |
| } |
| |
| void RenderFrameImpl::OnJavaScriptExecuteRequestForTests( |
| const base::string16& jscript, |
| int id, |
| bool notify_result, |
| bool has_user_gesture) { |
| TRACE_EVENT_INSTANT0("test_tracing", "OnJavaScriptExecuteRequestForTests", |
| TRACE_EVENT_SCOPE_THREAD); |
| |
| // A bunch of tests expect to run code in the context of a user gesture, which |
| // can grant additional privileges (e.g. the ability to create popups). |
| std::unique_ptr<blink::WebScopedUserGesture> gesture( |
| has_user_gesture ? new blink::WebScopedUserGesture(frame_) : nullptr); |
| v8::HandleScope handle_scope(blink::mainThreadIsolate()); |
| v8::Local<v8::Value> result = frame_->executeScriptAndReturnValue( |
| WebScriptSource(WebString::fromUTF16(jscript))); |
| |
| HandleJavascriptExecutionResult(jscript, id, notify_result, result); |
| } |
| |
| void RenderFrameImpl::OnJavaScriptExecuteRequestInIsolatedWorld( |
| const base::string16& jscript, |
| int id, |
| bool notify_result, |
| int world_id) { |
| TRACE_EVENT_INSTANT0("test_tracing", |
| "OnJavaScriptExecuteRequestInIsolatedWorld", |
| TRACE_EVENT_SCOPE_THREAD); |
| |
| if (world_id <= ISOLATED_WORLD_ID_GLOBAL || |
| world_id > ISOLATED_WORLD_ID_MAX) { |
| // Return if the world_id is not valid. world_id is passed as a plain int |
| // over IPC and needs to be verified here, in the IPC endpoint. |
| NOTREACHED(); |
| return; |
| } |
| |
| v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); |
| WebScriptSource script = WebScriptSource(WebString::fromUTF16(jscript)); |
| JavaScriptIsolatedWorldRequest* request = new JavaScriptIsolatedWorldRequest( |
| id, notify_result, routing_id_, weak_factory_.GetWeakPtr()); |
| frame_->requestExecuteScriptInIsolatedWorld(world_id, &script, 1, false, |
| request); |
| } |
| |
| RenderFrameImpl::JavaScriptIsolatedWorldRequest::JavaScriptIsolatedWorldRequest( |
| int id, |
| bool notify_result, |
| int routing_id, |
| base::WeakPtr<RenderFrameImpl> render_frame_impl) |
| : id_(id), |
| notify_result_(notify_result), |
| routing_id_(routing_id), |
| render_frame_impl_(render_frame_impl) { |
| } |
| |
| RenderFrameImpl::JavaScriptIsolatedWorldRequest:: |
| ~JavaScriptIsolatedWorldRequest() { |
| } |
| |
| void RenderFrameImpl::JavaScriptIsolatedWorldRequest::completed( |
| const blink::WebVector<v8::Local<v8::Value>>& result) { |
| if (!render_frame_impl_.get()) { |
| return; |
| } |
| |
| if (notify_result_) { |
| base::ListValue list; |
| if (!result.isEmpty()) { |
| // It's safe to always use the main world context when converting |
| // here. V8ValueConverterImpl shouldn't actually care about the |
| // context scope, and it switches to v8::Object's creation context |
| // when encountered. (from extensions/renderer/script_injection.cc) |
| v8::Local<v8::Context> context = |
| render_frame_impl_.get()->frame_->mainWorldScriptContext(); |
| v8::Context::Scope context_scope(context); |
| V8ValueConverterImpl converter; |
| converter.SetDateAllowed(true); |
| converter.SetRegExpAllowed(true); |
| for (const auto& value : result) { |
| std::unique_ptr<base::Value> result_value( |
| converter.FromV8Value(value, context)); |
| list.Append(result_value ? std::move(result_value) |
| : base::Value::CreateNullValue()); |
| } |
| } else { |
| list.Set(0, base::Value::CreateNullValue()); |
| } |
| render_frame_impl_.get()->Send( |
| new FrameHostMsg_JavaScriptExecuteResponse(routing_id_, id_, list)); |
| } |
| |
| delete this; |
| } |
| |
| void RenderFrameImpl::HandleJavascriptExecutionResult( |
| const base::string16& jscript, |
| int id, |
| bool notify_result, |
| v8::Local<v8::Value> result) { |
| if (notify_result) { |
| base::ListValue list; |
| if (!result.IsEmpty()) { |
| v8::Local<v8::Context> context = frame_->mainWorldScriptContext(); |
| v8::Context::Scope context_scope(context); |
| V8ValueConverterImpl converter; |
| converter.SetDateAllowed(true); |
| converter.SetRegExpAllowed(true); |
| std::unique_ptr<base::Value> result_value( |
| converter.FromV8Value(result, context)); |
| list.Set(0, result_value ? std::move(result_value) |
| : base::Value::CreateNullValue()); |
| } else { |
| list.Set(0, base::Value::CreateNullValue()); |
| } |
| Send(new FrameHostMsg_JavaScriptExecuteResponse(routing_id_, id, list)); |
| } |
| } |
| |
| void RenderFrameImpl::OnVisualStateRequest(uint64_t id) { |
| GetRenderWidget()->QueueMessage( |
| new FrameHostMsg_VisualStateResponse(routing_id_, id), |
| MESSAGE_DELIVERY_POLICY_WITH_VISUAL_STATE); |
| } |
| |
| void RenderFrameImpl::OnSetEditableSelectionOffsets(int start, int end) { |
| base::AutoReset<bool> handling_select_range(&handling_select_range_, true); |
| ImeEventGuard guard(GetRenderWidget()); |
| frame_->setEditableSelectionOffsets(start, end); |
| } |
| |
| void RenderFrameImpl::OnSetCompositionFromExistingText( |
| int start, int end, |
| const std::vector<blink::WebCompositionUnderline>& underlines) { |
| ImeEventGuard guard(GetRenderWidget()); |
| frame_->setCompositionFromExistingText(start, end, underlines); |
| } |
| |
| void RenderFrameImpl::OnExecuteNoValueEditCommand(const std::string& name) { |
| frame_->executeCommand(WebString::fromUTF8(name)); |
| } |
| |
| void RenderFrameImpl::OnExtendSelectionAndDelete(int before, int after) { |
| ImeEventGuard guard(GetRenderWidget()); |
| frame_->extendSelectionAndDelete(before, after); |
| } |
| |
| void RenderFrameImpl::OnDeleteSurroundingText(int before, int after) { |
| ImeEventGuard guard(GetRenderWidget()); |
| frame_->deleteSurroundingText(before, after); |
| } |
| |
| void RenderFrameImpl::OnDeleteSurroundingTextInCodePoints(int before, |
| int after) { |
| ImeEventGuard guard(GetRenderWidget()); |
| frame_->deleteSurroundingTextInCodePoints(before, after); |
| } |
| |
| void RenderFrameImpl::OnSetAccessibilityMode(AccessibilityMode new_mode) { |
| if (accessibility_mode_ == new_mode) |
| return; |
| accessibility_mode_ = new_mode; |
| if (render_accessibility_) { |
| // Note: this isn't called automatically by the destructor because |
| // there'd be no point in calling it in frame teardown, only if there's |
| // an accessibility mode change but the frame is persisting. |
| render_accessibility_->DisableAccessibility(); |
| |
| delete render_accessibility_; |
| render_accessibility_ = NULL; |
| } |
| |
| if (accessibility_mode_ & ACCESSIBILITY_MODE_FLAG_WEB_CONTENTS) { |
| render_accessibility_ = new RenderAccessibilityImpl( |
| this, accessibility_mode_); |
| } |
| |
| for (auto& observer : observers_) |
| observer.AccessibilityModeChanged(); |
| } |
| |
| void RenderFrameImpl::OnSnapshotAccessibilityTree(int callback_id) { |
| AXContentTreeUpdate response; |
| RenderAccessibilityImpl::SnapshotAccessibilityTree(this, &response); |
| Send(new AccessibilityHostMsg_SnapshotResponse( |
| routing_id_, callback_id, response)); |
| } |
| |
| void RenderFrameImpl::OnExtractSmartClipData(uint32_t id, |
| const gfx::Rect& rect) { |
| blink::WebString clip_text; |
| blink::WebString clip_html; |
| GetWebFrame()->extractSmartClipData(rect, clip_text, clip_html); |
| Send(new FrameHostMsg_SmartClipDataExtracted( |
| routing_id_, id, clip_text.utf16(), clip_html.utf16())); |
| } |
| |
| void RenderFrameImpl::OnUpdateOpener(int opener_routing_id) { |
| WebFrame* opener = ResolveOpener(opener_routing_id); |
| frame_->setOpener(opener); |
| } |
| |
| void RenderFrameImpl::OnDidUpdateSandboxFlags(blink::WebSandboxFlags flags) { |
| frame_->setFrameOwnerSandboxFlags(flags); |
| } |
| |
| void RenderFrameImpl::OnSetFrameOwnerProperties( |
| const FrameOwnerProperties& frame_owner_properties) { |
| DCHECK(frame_); |
| frame_->setFrameOwnerProperties( |
| ConvertFrameOwnerPropertiesToWebFrameOwnerProperties( |
| frame_owner_properties)); |
| } |
| |
| void RenderFrameImpl::OnAdvanceFocus(blink::WebFocusType type, |
| int32_t source_routing_id) { |
| RenderFrameProxy* source_frame = |
| RenderFrameProxy::FromRoutingID(source_routing_id); |
| if (!source_frame) |
| return; |
| |
| render_view_->webview()->advanceFocusAcrossFrames( |
| type, source_frame->web_frame(), frame_); |
| } |
| |
| void RenderFrameImpl::OnSetFocusedFrame() { |
| // This uses focusDocumentView rather than setFocusedFrame so that focus/blur |
| // events are properly dispatched on any currently focused elements. |
| render_view_->webview()->focusDocumentView(frame_); |
| } |
| |
| void RenderFrameImpl::OnTextTrackSettingsChanged( |
| const FrameMsg_TextTrackSettings_Params& params) { |
| DCHECK(!frame_->parent()); |
| if (!render_view_->webview()) |
| return; |
| |
| if (params.text_tracks_enabled) { |
| render_view_->webview()->settings()->setTextTrackKindUserPreference( |
| WebSettings::TextTrackKindUserPreference::Captions); |
| } else { |
| render_view_->webview()->settings()->setTextTrackKindUserPreference( |
| WebSettings::TextTrackKindUserPreference::Default); |
| } |
| render_view_->webview()->settings()->setTextTrackBackgroundColor( |
| WebString::fromUTF8(params.text_track_background_color)); |
| render_view_->webview()->settings()->setTextTrackFontFamily( |
| WebString::fromUTF8(params.text_track_font_family)); |
| render_view_->webview()->settings()->setTextTrackFontStyle( |
| WebString::fromUTF8(params.text_track_font_style)); |
| render_view_->webview()->settings()->setTextTrackFontVariant( |
| WebString::fromUTF8(params.text_track_font_variant)); |
| render_view_->webview()->settings()->setTextTrackTextColor( |
| WebString::fromUTF8(params.text_track_text_color)); |
| render_view_->webview()->settings()->setTextTrackTextShadow( |
| WebString::fromUTF8(params.text_track_text_shadow)); |
| render_view_->webview()->settings()->setTextTrackTextSize( |
| WebString::fromUTF8(params.text_track_text_size)); |
| } |
| |
| void RenderFrameImpl::OnPostMessageEvent( |
| const FrameMsg_PostMessage_Params& params) { |
| // Find the source frame if it exists. |
| WebFrame* source_frame = NULL; |
| if (params.source_routing_id != MSG_ROUTING_NONE) { |
| RenderFrameProxy* source_proxy = |
| RenderFrameProxy::FromRoutingID(params.source_routing_id); |
| if (source_proxy) |
| source_frame = source_proxy->web_frame(); |
| } |
| |
| // If the message contained MessagePorts, create the corresponding endpoints. |
| blink::WebMessagePortChannelArray channels = |
| WebMessagePortChannelImpl::CreateFromMessagePorts(params.message_ports); |
| |
| WebSerializedScriptValue serialized_script_value; |
| if (params.is_data_raw_string) { |
| v8::HandleScope handle_scope(blink::mainThreadIsolate()); |
| v8::Local<v8::Context> context = frame_->mainWorldScriptContext(); |
| v8::Context::Scope context_scope(context); |
| V8ValueConverterImpl converter; |
| converter.SetDateAllowed(true); |
| converter.SetRegExpAllowed(true); |
| std::unique_ptr<base::Value> value(new base::Value(params.data)); |
| v8::Local<v8::Value> result_value = converter.ToV8Value(value.get(), |
| context); |
| serialized_script_value = WebSerializedScriptValue::serialize(result_value); |
| } else { |
| serialized_script_value = |
| WebSerializedScriptValue::fromString(WebString::fromUTF16(params.data)); |
| } |
| |
| // We must pass in the target_origin to do the security check on this side, |
| // since it may have changed since the original postMessage call was made. |
| WebSecurityOrigin target_origin; |
| if (!params.target_origin.empty()) { |
| target_origin = WebSecurityOrigin::createFromString( |
| WebString::fromUTF16(params.target_origin)); |
| } |
| |
| WebDOMMessageEvent msg_event(serialized_script_value, |
| WebString::fromUTF16(params.source_origin), |
| source_frame, |
| frame_->document(), |
| std::move(channels)); |
| frame_->dispatchMessageEventWithOriginCheck(target_origin, msg_event); |
| } |
| |
| void RenderFrameImpl::OnReload(bool bypass_cache) { |
| frame_->reload(bypass_cache ? WebFrameLoadType::ReloadBypassingCache |
| : WebFrameLoadType::ReloadMainResource); |
| } |
| |
| void RenderFrameImpl::OnReloadLoFiImages() { |
| previews_state_ = PREVIEWS_NO_TRANSFORM; |
| GetWebFrame()->reloadLoFiImages(); |
| } |
| |
| void RenderFrameImpl::OnTextSurroundingSelectionRequest(uint32_t max_length) { |
| blink::WebSurroundingText surroundingText; |
| surroundingText.initializeFromCurrentSelection(frame_, max_length); |
| |
| if (surroundingText.isNull()) { |
| // |surroundingText| might not be correctly initialized, for example if |
| // |frame_->selectionRange().isNull()|, in other words, if there was no |
| // selection. |
| Send(new FrameHostMsg_TextSurroundingSelectionResponse( |
| routing_id_, base::string16(), 0, 0)); |
| return; |
| } |
| |
| Send(new FrameHostMsg_TextSurroundingSelectionResponse( |
| routing_id_, surroundingText.textContent().utf16(), |
| surroundingText.startOffsetInTextContent(), |
| surroundingText.endOffsetInTextContent())); |
| } |
| |
| bool RenderFrameImpl::RunJavaScriptDialog(JavaScriptDialogType type, |
| const base::string16& message, |
| const base::string16& default_value, |
| const GURL& frame_url, |
| base::string16* result) { |
| // Don't allow further dialogs if we are waiting to swap out, since the |
| // ScopedPageLoadDeferrer in our stack prevents it. |
| if (suppress_further_dialogs_) |
| return false; |
| |
| int32_t message_length = static_cast<int32_t>(message.length()); |
| if (WebUserGestureIndicator::processedUserGestureSinceLoad(frame_)) { |
| UMA_HISTOGRAM_COUNTS("JSDialogs.CharacterCount.UserGestureSinceLoad", |
| message_length); |
| } else { |
| UMA_HISTOGRAM_COUNTS("JSDialogs.CharacterCount.NoUserGestureSinceLoad", |
| message_length); |
| } |
| |
| bool success = false; |
| base::string16 result_temp; |
| if (!result) |
| result = &result_temp; |
| |
| Send(new FrameHostMsg_RunJavaScriptDialog(routing_id_, message, default_value, |
| frame_url, type, &success, result)); |
| return success; |
| } |
| |
| bool RenderFrameImpl::ScheduleFileChooser( |
| const FileChooserParams& params, |
| blink::WebFileChooserCompletion* completion) { |
| static const size_t kMaximumPendingFileChooseRequests = 4; |
| |
| // Do not open the file dialog in a hidden RenderFrame. |
| if (IsHidden()) |
| return false; |
| |
| if (file_chooser_completions_.size() > kMaximumPendingFileChooseRequests) { |
| // This sanity check prevents too many file choose requests from getting |
| // queued which could DoS the user. Getting these is most likely a |
| // programming error (there are many ways to DoS the user so it's not |
| // considered a "real" security check), either in JS requesting many file |
| // choosers to pop up, or in a plugin. |
| // |
| // TODO(brettw): We might possibly want to require a user gesture to open |
| // a file picker, which will address this issue in a better way. |
| return false; |
| } |
| |
| file_chooser_completions_.push_back( |
| base::MakeUnique<PendingFileChooser>(params, completion)); |
| if (file_chooser_completions_.size() == 1) { |
| // Actually show the browse dialog when this is the first request. |
| Send(new FrameHostMsg_RunFileChooser(routing_id_, params)); |
| } |
| return true; |
| } |
| |
| void RenderFrameImpl::LoadNavigationErrorPage( |
| const WebURLRequest& failed_request, |
| const WebURLError& error, |
| bool replace, |
| HistoryEntry* entry) { |
| std::string error_html; |
| GetContentClient()->renderer()->GetNavigationErrorStrings( |
| this, failed_request, error, &error_html, nullptr); |
| |
| blink::WebFrameLoadType frame_load_type = |
| entry ? blink::WebFrameLoadType::BackForward |
| : blink::WebFrameLoadType::Standard; |
| const blink::WebHistoryItem& history_item = |
| entry ? entry->root() : blink::WebHistoryItem(); |
| |
| // Requests blocked by the X-Frame-Options HTTP response header don't display |
| // error pages but a blank page instead. |
| // TODO(alexmos, mkwst, arthursonzogni): This block can be removed once error |
| // pages are refactored. See crbug.com/588314 and crbug.com/622385. |
| if (error.reason == net::ERR_BLOCKED_BY_RESPONSE) { |
| frame_->loadData("", WebString::fromUTF8("text/html"), |
| WebString::fromUTF8("UTF-8"), GURL("data:,"), WebURL(), |
| replace, frame_load_type, history_item, |
| blink::WebHistoryDifferentDocumentLoad, false); |
| return; |
| } |
| |
| frame_->loadData(error_html, WebString::fromUTF8("text/html"), |
| WebString::fromUTF8("UTF-8"), GURL(kUnreachableWebDataURL), |
| error.unreachableURL, replace, frame_load_type, history_item, |
| blink::WebHistoryDifferentDocumentLoad, false); |
| } |
| |
| void RenderFrameImpl::DidMeaningfulLayout( |
| blink::WebMeaningfulLayout layout_type) { |
| for (auto& observer : observers_) |
| observer.DidMeaningfulLayout(layout_type); |
| } |
| |
| void RenderFrameImpl::DidCommitCompositorFrame() { |
| if (BrowserPluginManager::Get()) |
| BrowserPluginManager::Get()->DidCommitCompositorFrame(GetRoutingID()); |
| for (auto& observer : observers_) |
| observer.DidCommitCompositorFrame(); |
| } |
| |
| void RenderFrameImpl::DidCommitAndDrawCompositorFrame() { |
| #if BUILDFLAG(ENABLE_PLUGINS) |
| // Notify all instances that we painted. The same caveats apply as for |
| // ViewFlushedPaint regarding instances closing themselves, so we take |
| // similar precautions. |
| PepperPluginSet plugins = active_pepper_instances_; |
| for (auto* plugin : plugins) { |
| if (active_pepper_instances_.find(plugin) != active_pepper_instances_.end()) |
| plugin->ViewInitiatedPaint(); |
| } |
| #endif |
| } |
| |
| RenderView* RenderFrameImpl::GetRenderView() { |
| return render_view_; |
| } |
| |
| RenderAccessibility* RenderFrameImpl::GetRenderAccessibility() { |
| return render_accessibility_; |
| } |
| |
| int RenderFrameImpl::GetRoutingID() { |
| return routing_id_; |
| } |
| |
| blink::WebLocalFrame* RenderFrameImpl::GetWebFrame() { |
| DCHECK(frame_); |
| return frame_; |
| } |
| |
| WebPreferences& RenderFrameImpl::GetWebkitPreferences() { |
| return render_view_->GetWebkitPreferences(); |
| } |
| |
| int RenderFrameImpl::ShowContextMenu(ContextMenuClient* client, |
| const ContextMenuParams& params) { |
| DCHECK(client); // A null client means "internal" when we issue callbacks. |
| ContextMenuParams our_params(params); |
| |
| blink::WebRect position_in_window(params.x, params.y, 0, 0); |
| GetRenderWidget()->convertViewportToWindow(&position_in_window); |
| our_params.x = position_in_window.x; |
| our_params.y = position_in_window.y; |
| |
| our_params.custom_context.request_id = pending_context_menus_.Add(client); |
| Send(new FrameHostMsg_ContextMenu(routing_id_, our_params)); |
| return our_params.custom_context.request_id; |
| } |
| |
| void RenderFrameImpl::CancelContextMenu(int request_id) { |
| DCHECK(pending_context_menus_.Lookup(request_id)); |
| pending_context_menus_.Remove(request_id); |
| } |
| |
| blink::WebPlugin* RenderFrameImpl::CreatePlugin( |
| blink::WebFrame* frame, |
| const WebPluginInfo& info, |
| const blink::WebPluginParams& params, |
| std::unique_ptr<content::PluginInstanceThrottler> throttler) { |
| DCHECK_EQ(frame_, frame); |
| #if BUILDFLAG(ENABLE_PLUGINS) |
| if (info.type == WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN) { |
| return BrowserPluginManager::Get()->CreateBrowserPlugin( |
| this, GetContentClient() |
| ->renderer() |
| ->CreateBrowserPluginDelegate(this, params.mimeType.utf8(), |
| GURL(params.url)) |
| ->GetWeakPtr()); |
| } |
| |
| bool pepper_plugin_was_registered = false; |
| scoped_refptr<PluginModule> pepper_module(PluginModule::Create( |
| this, info, &pepper_plugin_was_registered)); |
| if (pepper_plugin_was_registered) { |
| if (pepper_module.get()) { |
| return new PepperWebPluginImpl( |
| pepper_module.get(), params, this, |
| base::WrapUnique( |
| static_cast<PluginInstanceThrottlerImpl*>(throttler.release()))); |
| } |
| } |
| #if defined(OS_CHROMEOS) |
| LOG(WARNING) << "Pepper module/plugin creation failed."; |
| #endif |
| #endif |
| return NULL; |
| } |
| |
| void RenderFrameImpl::LoadURLExternally(const blink::WebURLRequest& request, |
| blink::WebNavigationPolicy policy) { |
| loadURLExternally(request, policy, WebString(), false); |
| } |
| |
| void RenderFrameImpl::loadErrorPage(int reason) { |
| blink::WebURLError error; |
| error.unreachableURL = frame_->document().url(); |
| error.domain = WebString::fromUTF8(net::kErrorDomain); |
| error.reason = reason; |
| |
| std::string error_html; |
| GetContentClient()->renderer()->GetNavigationErrorStrings( |
| this, frame_->dataSource()->getRequest(), error, &error_html, nullptr); |
| |
| frame_->loadData(error_html, WebString::fromUTF8("text/html"), |
| WebString::fromUTF8("UTF-8"), GURL(kUnreachableWebDataURL), |
| error.unreachableURL, true, |
| blink::WebFrameLoadType::Standard, blink::WebHistoryItem(), |
| blink::WebHistoryDifferentDocumentLoad, true); |
| } |
| |
| void RenderFrameImpl::ExecuteJavaScript(const base::string16& javascript) { |
| OnJavaScriptExecuteRequest(javascript, 0, false); |
| } |
| |
| service_manager::InterfaceRegistry* RenderFrameImpl::GetInterfaceRegistry() { |
| return interface_registry_.get(); |
| } |
| |
| service_manager::InterfaceProvider* RenderFrameImpl::GetRemoteInterfaces() { |
| return remote_interfaces_.get(); |
| } |
| |
| AssociatedInterfaceRegistry* |
| RenderFrameImpl::GetAssociatedInterfaceRegistry() { |
| return &associated_interfaces_; |
| } |
| |
| AssociatedInterfaceProvider* |
| RenderFrameImpl::GetRemoteAssociatedInterfaces() { |
| if (!remote_associated_interfaces_) { |
| ChildThreadImpl* thread = ChildThreadImpl::current(); |
| if (thread) { |
| mojom::AssociatedInterfaceProviderAssociatedPtr remote_interfaces; |
| thread->GetRemoteRouteProvider()->GetRoute( |
| routing_id_, mojo::MakeRequest(&remote_interfaces)); |
| remote_associated_interfaces_.reset( |
| new AssociatedInterfaceProviderImpl(std::move(remote_interfaces))); |
| } else { |
| // In some tests the thread may be null, |
| // so set up a self-contained interface provider instead. |
| remote_associated_interfaces_.reset( |
| new AssociatedInterfaceProviderImpl()); |
| } |
| } |
| return remote_associated_interfaces_.get(); |
| } |
| |
| #if BUILDFLAG(ENABLE_PLUGINS) |
| void RenderFrameImpl::RegisterPeripheralPlugin( |
| const url::Origin& content_origin, |
| const base::Closure& unthrottle_callback) { |
| return plugin_power_saver_helper_->RegisterPeripheralPlugin( |
| content_origin, unthrottle_callback); |
| } |
| |
| RenderFrame::PeripheralContentStatus |
| RenderFrameImpl::GetPeripheralContentStatus( |
| const url::Origin& main_frame_origin, |
| const url::Origin& content_origin, |
| const gfx::Size& unobscured_size, |
| RecordPeripheralDecision record_decision) const { |
| return plugin_power_saver_helper_->GetPeripheralContentStatus( |
| main_frame_origin, content_origin, unobscured_size, record_decision); |
| } |
| |
| void RenderFrameImpl::WhitelistContentOrigin( |
| const url::Origin& content_origin) { |
| return plugin_power_saver_helper_->WhitelistContentOrigin(content_origin); |
| } |
| |
| void RenderFrameImpl::PluginDidStartLoading() { |
| didStartLoading(true); |
| } |
| |
| void RenderFrameImpl::PluginDidStopLoading() { |
| didStopLoading(); |
| } |
| #endif // BUILDFLAG(ENABLE_PLUGINS) |
| |
| bool RenderFrameImpl::IsFTPDirectoryListing() { |
| WebURLResponseExtraDataImpl* extra_data = |
| GetExtraDataFromResponse(frame_->dataSource()->response()); |
| return extra_data ? extra_data->is_ftp_directory_listing() : false; |
| } |
| |
| void RenderFrameImpl::AttachGuest(int element_instance_id) { |
| BrowserPluginManager::Get()->Attach(element_instance_id); |
| } |
| |
| void RenderFrameImpl::DetachGuest(int element_instance_id) { |
| BrowserPluginManager::Get()->Detach(element_instance_id); |
| } |
| |
| void RenderFrameImpl::SetSelectedText(const base::string16& selection_text, |
| size_t offset, |
| const gfx::Range& range) { |
| Send(new FrameHostMsg_SelectionChanged(routing_id_, selection_text, |
| static_cast<uint32_t>(offset), range)); |
| } |
| |
| void RenderFrameImpl::EnsureMojoBuiltinsAreAvailable( |
| v8::Isolate* isolate, |
| v8::Local<v8::Context> context) { |
| gin::ModuleRegistry* registry = gin::ModuleRegistry::From(context); |
| if (registry->available_modules().count(mojo::edk::js::Core::kModuleName)) |
| return; |
| |
| v8::HandleScope handle_scope(isolate); |
| |
| registry->AddBuiltinModule(isolate, gin::Console::kModuleName, |
| gin::Console::GetModule(isolate)); |
| registry->AddBuiltinModule(isolate, mojo::edk::js::Core::kModuleName, |
| mojo::edk::js::Core::GetModule(isolate)); |
| registry->AddBuiltinModule(isolate, mojo::edk::js::Support::kModuleName, |
| mojo::edk::js::Support::GetModule(isolate)); |
| registry->AddBuiltinModule( |
| isolate, InterfaceProviderJsWrapper::kPerFrameModuleName, |
| InterfaceProviderJsWrapper::Create( |
| isolate, context, remote_interfaces_.get()) |
| .ToV8()); |
| registry->AddBuiltinModule( |
| isolate, InterfaceProviderJsWrapper::kPerProcessModuleName, |
| InterfaceProviderJsWrapper::Create( |
| isolate, context, RenderThread::Get()->GetRemoteInterfaces()) |
| .ToV8()); |
| } |
| |
| void RenderFrameImpl::AddMessageToConsole(ConsoleMessageLevel level, |
| const std::string& message) { |
| blink::WebConsoleMessage::Level target_level = |
| blink::WebConsoleMessage::LevelInfo; |
| switch (level) { |
| case CONSOLE_MESSAGE_LEVEL_VERBOSE: |
| target_level = blink::WebConsoleMessage::LevelVerbose; |
| break; |
| case CONSOLE_MESSAGE_LEVEL_INFO: |
| target_level = blink::WebConsoleMessage::LevelInfo; |
| break; |
| case CONSOLE_MESSAGE_LEVEL_WARNING: |
| target_level = blink::WebConsoleMessage::LevelWarning; |
| break; |
| case CONSOLE_MESSAGE_LEVEL_ERROR: |
| target_level = blink::WebConsoleMessage::LevelError; |
| break; |
| } |
| |
| blink::WebConsoleMessage wcm(target_level, WebString::fromUTF8(message)); |
| frame_->addMessageToConsole(wcm); |
| } |
| |
| PreviewsState RenderFrameImpl::GetPreviewsState() const { |
| return previews_state_; |
| } |
| |
| bool RenderFrameImpl::IsPasting() const { |
| return is_pasting_; |
| } |
| |
| // blink::mojom::EngagementClient implementation ------------------------------- |
| |
| void RenderFrameImpl::SetEngagementLevel(const url::Origin& origin, |
| blink::mojom::EngagementLevel level) { |
| // Set the engagement level on |frame_| if its origin matches the one we have |
| // been provided with. |
| if (frame_ && url::Origin(frame_->getSecurityOrigin()) == origin) { |
| frame_->setEngagementLevel(level); |
| return; |
| } |
| |
| engagement_level_ = std::make_pair(origin, level); |
| } |
| |
| // mojom::Frame implementation ------------------------------------------------- |
| |
| void RenderFrameImpl::GetInterfaceProvider( |
| service_manager::mojom::InterfaceProviderRequest request) { |
| service_manager::ServiceInfo child_info = |
| ChildThreadImpl::current()->GetChildServiceInfo(); |
| service_manager::ServiceInfo browser_info = |
| ChildThreadImpl::current()->GetBrowserServiceInfo(); |
| |
| service_manager::InterfaceProviderSpec child_spec, browser_spec; |
| // TODO(beng): CHECK these return true. |
| service_manager::GetInterfaceProviderSpec( |
| mojom::kNavigation_FrameSpec, child_info.interface_provider_specs, |
| &child_spec); |
| service_manager::GetInterfaceProviderSpec( |
| mojom::kNavigation_FrameSpec, browser_info.interface_provider_specs, |
| &browser_spec); |
| interface_registry_->Bind(std::move(request), child_info.identity, child_spec, |
| browser_info.identity, browser_spec); |
| } |
| |
| void RenderFrameImpl::AllowBindings(int32_t enabled_bindings_flags) { |
| if (IsMainFrame() && (enabled_bindings_flags & BINDINGS_POLICY_WEB_UI) && |
| !(enabled_bindings_ & BINDINGS_POLICY_WEB_UI)) { |
| // TODO(sammc): Move WebUIExtensionData to be a RenderFrameObserver. |
| // WebUIExtensionData deletes itself when |render_view_| is destroyed. |
| new WebUIExtensionData(render_view_); |
| } |
| |
| enabled_bindings_ |= enabled_bindings_flags; |
| |
| // Keep track of the total bindings accumulated in this process. |
| RenderProcess::current()->AddBindings(enabled_bindings_flags); |
| |
| MaybeEnableMojoBindings(); |
| } |
| |
| // mojom::HostZoom implementation ---------------------------------------------- |
| |
| void RenderFrameImpl::SetHostZoomLevel(const GURL& url, double zoom_level) { |
| // TODO(wjmaclean): We should see if this restriction is really necessary, |
| // since it isn't enforced in other parts of the page zoom system (e.g. |
| // when a users changes the zoom of a currently displayed page). Android |
| // has no UI for this, so in theory the following code would normally just use |
| // the default zoom anyways. |
| #if !defined(OS_ANDROID) |
| // On Android, page zoom isn't used, and in case of WebView, text zoom is used |
| // for legacy WebView text scaling emulation. Thus, the code that resets |
| // the zoom level from this map will be effectively resetting text zoom level. |
| host_zoom_levels_[url] = zoom_level; |
| #endif |
| } |
| |
| // blink::WebFrameClient implementation ---------------------------------------- |
| |
| blink::WebPlugin* RenderFrameImpl::createPlugin( |
| blink::WebLocalFrame* frame, |
| const blink::WebPluginParams& params) { |
| DCHECK_EQ(frame_, frame); |
| blink::WebPlugin* plugin = NULL; |
| if (GetContentClient()->renderer()->OverrideCreatePlugin( |
| this, frame, params, &plugin)) { |
| return plugin; |
| } |
| |
| if (params.mimeType.containsOnlyASCII() && |
| params.mimeType.ascii() == kBrowserPluginMimeType) { |
| return BrowserPluginManager::Get()->CreateBrowserPlugin( |
| this, GetContentClient() |
| ->renderer() |
| ->CreateBrowserPluginDelegate(this, kBrowserPluginMimeType, |
| GURL(params.url)) |
| ->GetWeakPtr()); |
| } |
| |
| #if BUILDFLAG(ENABLE_PLUGINS) |
| WebPluginInfo info; |
| std::string mime_type; |
| bool found = false; |
| Send(new FrameHostMsg_GetPluginInfo( |
| routing_id_, params.url, frame->top()->getSecurityOrigin(), |
| params.mimeType.utf8(), &found, &info, &mime_type)); |
| if (!found) |
| return NULL; |
| |
| WebPluginParams params_to_use = params; |
| params_to_use.mimeType = WebString::fromUTF8(mime_type); |
| return CreatePlugin(frame, info, params_to_use, nullptr /* throttler */); |
| #else |
| return NULL; |
| #endif // BUILDFLAG(ENABLE_PLUGINS) |
| } |
| |
| blink::WebMediaPlayer* RenderFrameImpl::createMediaPlayer( |
| const blink::WebMediaPlayerSource& source, |
| WebMediaPlayerClient* client, |
| WebMediaPlayerEncryptedMediaClient* encrypted_client, |
| WebContentDecryptionModule* initial_cdm, |
| const blink::WebString& sink_id) { |
| blink::WebMediaStream web_stream = |
| GetWebMediaStreamFromWebMediaPlayerSource(source); |
| if (!web_stream.isNull()) |
| return CreateWebMediaPlayerForMediaStream(client, sink_id, |
| frame_->getSecurityOrigin()); |
| |
| // If |source| was not a MediaStream, it must be a URL. |
| // TODO(guidou): Fix this when support for other srcObject types is added. |
| DCHECK(source.isURL()); |
| blink::WebURL url = source.getAsURL(); |
| |
| RenderThreadImpl* render_thread = RenderThreadImpl::current(); |
| // Render thread may not exist in tests, returning nullptr if it does not. |
| if (!render_thread) |
| return nullptr; |
| |
| scoped_refptr<media::SwitchableAudioRendererSink> audio_renderer_sink = |
| AudioDeviceFactory::NewSwitchableAudioRendererSink( |
| AudioDeviceFactory::kSourceMediaElement, routing_id_, 0, |
| sink_id.utf8(), frame_->getSecurityOrigin()); |
| // We need to keep a reference to the context provider (see crbug.com/610527) |
| // but media/ can't depend on cc/, so for now, just keep a reference in the |
| // callback. |
| // TODO(piman): replace media::Context3D to scoped_refptr<ContextProvider> in |
| // media/ once ContextProvider is in gpu/. |
| media::WebMediaPlayerParams::Context3DCB context_3d_cb = base::Bind( |
| &GetSharedMainThreadContext3D, |
| RenderThreadImpl::current()->SharedMainThreadContextProvider()); |
| |
| scoped_refptr<media::MediaLog> media_log( |
| new RenderMediaLog(url::Origin(frame_->getSecurityOrigin()).GetURL())); |
| |
| bool embedded_media_experience_enabled = false; |
| #if defined(OS_ANDROID) |
| if (!UseMediaPlayerRenderer(url) && !media_surface_manager_) |
| media_surface_manager_ = new RendererSurfaceViewManager(this); |
| embedded_media_experience_enabled = |
| GetWebkitPreferences().embedded_media_experience_enabled; |
| #endif // defined(OS_ANDROID) |
| |
| #if BUILDFLAG(ENABLE_MEDIA_REMOTING) |
| media::mojom::RemotingSourcePtr remoting_source; |
| media::mojom::RemotingSourceRequest remoting_source_request(&remoting_source); |
| media::mojom::RemoterPtr remoter; |
| GetRemoterFactory()->Create(std::move(remoting_source), |
| mojo::MakeRequest(&remoter)); |
| using RemotingController = media::remoting::RendererController; |
| std::unique_ptr<RemotingController> remoting_controller( |
| new RemotingController(new media::remoting::SharedSession( |
| std::move(remoting_source_request), std::move(remoter)))); |
| base::WeakPtr<media::MediaObserver> media_observer = |
| remoting_controller->GetWeakPtr(); |
| #else |
| base::WeakPtr<media::MediaObserver> media_observer = nullptr; |
| #endif |
| |
| media::WebMediaPlayerParams params( |
| base::Bind(&ContentRendererClient::DeferMediaLoad, |
| base::Unretained(GetContentClient()->renderer()), |
| static_cast<RenderFrame*>(this), |
| GetWebMediaPlayerDelegate()->has_played_media()), |
| audio_renderer_sink, media_log, render_thread->GetMediaThreadTaskRunner(), |
| render_thread->GetWorkerTaskRunner(), |
| render_thread->compositor_task_runner(), context_3d_cb, |
| base::Bind(&v8::Isolate::AdjustAmountOfExternalAllocatedMemory, |
| base::Unretained(blink::mainThreadIsolate())), |
| initial_cdm, media_surface_manager_, media_observer, |
| // TODO(avayvod, asvitkine): Query the value directly when it is available |
| // in the renderer process. See https://crbug.com/681160. |
| GetWebkitPreferences().max_keyframe_distance_to_disable_background_video, |
| GetWebkitPreferences().enable_instant_source_buffer_gc, |
| GetContentClient()->renderer()->AllowMediaSuspend(), |
| embedded_media_experience_enabled); |
| |
| bool use_fallback_path = false; |
| #if defined(OS_ANDROID) |
| use_fallback_path = UseMediaPlayerRenderer(url); |
| #endif // defined(OS_ANDROID) |
| |
| std::unique_ptr<media::RendererFactory> media_renderer_factory; |
| if (use_fallback_path) { |
| #if defined(OS_ANDROID) |
| auto mojo_renderer_factory = base::MakeUnique<media::MojoRendererFactory>( |
| media::MojoRendererFactory::GetGpuFactoriesCB(), |
| GetRemoteInterfaces()->get()); |
| |
| media_renderer_factory = base::MakeUnique<MediaPlayerRendererClientFactory>( |
| render_thread->compositor_task_runner(), |
| std::move(mojo_renderer_factory), |
| base::Bind(&StreamTextureWrapperImpl::Create, |
| render_thread->EnableStreamTextureCopy(), |
| render_thread->GetStreamTexureFactory(), |
| base::ThreadTaskRunnerHandle::Get())); |
| #endif // defined(OS_ANDROID) |
| } else { |
| #if defined(ENABLE_MOJO_RENDERER) |
| #if BUILDFLAG(ENABLE_RUNTIME_MEDIA_RENDERER_SELECTION) |
| if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kDisableMojoRenderer)) { |
| media_renderer_factory = base::MakeUnique<media::DefaultRendererFactory>( |
| media_log, GetDecoderFactory(), |
| base::Bind(&RenderThreadImpl::GetGpuFactories, |
| base::Unretained(render_thread))); |
| } |
| #endif // BUILDFLAG(ENABLE_RUNTIME_MEDIA_RENDERER_SELECTION) |
| if (!media_renderer_factory) { |
| media_renderer_factory = base::MakeUnique<media::MojoRendererFactory>( |
| base::Bind(&RenderThreadImpl::GetGpuFactories, |
| base::Unretained(render_thread)), |
| GetMediaInterfaceProvider()); |
| } |
| #else |
| media_renderer_factory = base::MakeUnique<media::DefaultRendererFactory>( |
| media_log, GetDecoderFactory(), |
| base::Bind(&RenderThreadImpl::GetGpuFactories, |
| base::Unretained(render_thread))); |
| #endif // defined(ENABLE_MOJO_RENDERER) |
| } |
| |
| #if BUILDFLAG(ENABLE_MEDIA_REMOTING) |
| auto* const remoting_controller_ptr = remoting_controller.get(); |
| media_renderer_factory = |
| base::MakeUnique<media::remoting::AdaptiveRendererFactory>( |
| std::move(media_renderer_factory), std::move(remoting_controller)); |
| #endif |
| |
| if (!url_index_.get() || url_index_->frame() != frame_) |
| url_index_.reset(new media::UrlIndex(frame_)); |
| |
| media::WebMediaPlayerImpl* media_player = new media::WebMediaPlayerImpl( |
| frame_, client, encrypted_client, GetWebMediaPlayerDelegate(), |
| std::move(media_renderer_factory), url_index_, params); |
| |
| #if defined(OS_ANDROID) // WMPI_CAST |
| media_player->SetMediaPlayerManager(GetMediaPlayerManager()); |
| media_player->SetDeviceScaleFactor(render_view_->GetDeviceScaleFactor()); |
| media_player->SetUseFallbackPath(use_fallback_path); |
| #endif // defined(OS_ANDROID) |
| |
| #if BUILDFLAG(ENABLE_MEDIA_REMOTING) |
| remoting_controller_ptr->SetDownloadPosterCallback(base::Bind( |
| &SingleImageDownloader::DownloadImage, weak_factory_.GetWeakPtr())); |
| #endif |
| return media_player; |
| } |
| |
| blink::WebApplicationCacheHost* RenderFrameImpl::createApplicationCacheHost( |
| blink::WebApplicationCacheHostClient* client) { |
| if (!frame_ || !frame_->view()) |
| return NULL; |
| |
| DocumentState* document_state = |
| frame_->provisionalDataSource() |
| ? DocumentState::FromDataSource(frame_->provisionalDataSource()) |
| : DocumentState::FromDataSource(frame_->dataSource()); |
| |
| NavigationStateImpl* navigation_state = |
| static_cast<NavigationStateImpl*>(document_state->navigation_state()); |
| |
| return new RendererWebApplicationCacheHostImpl( |
| RenderViewImpl::FromWebView(frame_->view()), client, |
| RenderThreadImpl::current()->appcache_dispatcher()->backend_proxy(), |
| navigation_state->request_params().appcache_host_id); |
| } |
| |
| blink::WebWorkerContentSettingsClientProxy* |
| RenderFrameImpl::createWorkerContentSettingsClientProxy() { |
| if (!frame_ || !frame_->view()) |
| return NULL; |
| return GetContentClient()->renderer()->CreateWorkerContentSettingsClientProxy( |
| this, frame_); |
| } |
| |
| WebExternalPopupMenu* RenderFrameImpl::createExternalPopupMenu( |
| const WebPopupMenuInfo& popup_menu_info, |
| WebExternalPopupMenuClient* popup_menu_client) { |
| #if defined(USE_EXTERNAL_POPUP_MENU) |
| // An IPC message is sent to the browser to build and display the actual |
| // popup. The user could have time to click a different select by the time |
| // the popup is shown. In that case external_popup_menu_ is non NULL. |
| // By returning NULL in that case, we instruct Blink to cancel that new |
| // popup. So from the user perspective, only the first one will show, and |
| // will have to close the first one before another one can be shown. |
| if (external_popup_menu_) |
| return NULL; |
| external_popup_menu_.reset( |
| new ExternalPopupMenu(this, popup_menu_info, popup_menu_client)); |
| if (render_view_->screen_metrics_emulator_) { |
| render_view_->SetExternalPopupOriginAdjustmentsForEmulation( |
| external_popup_menu_.get(), |
|