| // Copyright 2017 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 "headless/lib/renderer/headless_render_frame_controller_impl.h" |
| |
| #include "content/public/common/isolated_world_ids.h" |
| #include "services/service_manager/public/cpp/bind_source_info.h" |
| #include "services/service_manager/public/cpp/binder_registry.h" |
| #include "services/service_manager/public/cpp/interface_provider.h" |
| #include "v8/include/v8-inspector.h" |
| |
| namespace headless { |
| |
| HeadlessRenderFrameControllerImpl::HeadlessRenderFrameControllerImpl( |
| content::RenderFrame* render_frame) |
| : content::RenderFrameObserver(render_frame), |
| render_frame_(render_frame), |
| weak_ptr_factory_(this) { |
| render_frame->GetInterfaceRegistry()->AddInterface(base::Bind( |
| &HeadlessRenderFrameControllerImpl::OnRenderFrameControllerRequest, |
| base::Unretained(this))); |
| } |
| |
| HeadlessRenderFrameControllerImpl::~HeadlessRenderFrameControllerImpl() {} |
| |
| void HeadlessRenderFrameControllerImpl::OnRenderFrameControllerRequest( |
| const service_manager::BindSourceInfo& source_info, |
| headless::HeadlessRenderFrameControllerRequest request) { |
| headless_render_frame_controller_bindings_.AddBinding(this, |
| std::move(request)); |
| } |
| |
| void HeadlessRenderFrameControllerImpl::InstallTabSocket( |
| int32_t execution_context_id, |
| InstallTabSocketCallback callback) { |
| auto find_it = tab_socket_bindings_.find(execution_context_id); |
| if (find_it == tab_socket_bindings_.end()) { |
| LOG(WARNING) << "InstallTabSocket failed, unknown execution_context_id " |
| << execution_context_id; |
| std::move(callback).Run(false); |
| } else { |
| std::move(callback).Run(find_it->second.InitializeTabSocketBindings()); |
| } |
| } |
| |
| void HeadlessRenderFrameControllerImpl::InstallMainWorldTabSocket( |
| InstallMainWorldTabSocketCallback callback) { |
| // Check any pre-existing script contexts. |
| for (auto& pair : tab_socket_bindings_) { |
| if (pair.second.world_id() == content::ISOLATED_WORLD_ID_GLOBAL) { |
| std::move(callback).Run( |
| pair.second.InitializeTabSocketBindings() ? pair.first : -1); |
| return; |
| } |
| } |
| pending_install_main_world_tab_socket_callback_ = std::move(callback); |
| } |
| |
| void HeadlessRenderFrameControllerImpl::SendMessageToTabSocket( |
| const std::string& message, |
| int32_t world_id) { |
| auto find_it = tab_socket_bindings_.find(world_id); |
| if (find_it == tab_socket_bindings_.end()) { |
| LOG(WARNING) << "Dropping message for " << world_id |
| << " because the world doesn't exist."; |
| return; |
| } |
| |
| find_it->second.OnMessageFromEmbedder(message); |
| } |
| |
| void HeadlessRenderFrameControllerImpl::DidCreateScriptContext( |
| v8::Local<v8::Context> context, |
| int world_id) { |
| int v8_execution_context_id = |
| v8_inspector::V8ContextInfo::executionContextId(context); |
| auto find_it = tab_socket_bindings_.find(v8_execution_context_id); |
| if (find_it != tab_socket_bindings_.end()) |
| tab_socket_bindings_.erase(find_it); |
| |
| auto emplace_result = tab_socket_bindings_.emplace( |
| std::piecewise_construct, std::forward_as_tuple(v8_execution_context_id), |
| std::forward_as_tuple(this, render_frame_, context, world_id)); |
| |
| // If main world tab socket bindings have been requested and this is the main |
| // world then install the bindings. |
| if (world_id == content::ISOLATED_WORLD_ID_GLOBAL && |
| !pending_install_main_world_tab_socket_callback_.is_null()) { |
| std::move(pending_install_main_world_tab_socket_callback_) |
| .Run(emplace_result.first->second.InitializeTabSocketBindings() |
| ? emplace_result.first->first |
| : -1); |
| pending_install_main_world_tab_socket_callback_ = |
| InstallMainWorldTabSocketCallback(); |
| } |
| } |
| |
| void HeadlessRenderFrameControllerImpl::WillReleaseScriptContext( |
| v8::Local<v8::Context> context, |
| int world_id) { |
| tab_socket_bindings_.erase( |
| v8_inspector::V8ContextInfo::executionContextId(context)); |
| } |
| |
| void HeadlessRenderFrameControllerImpl::OnDestruct() { |
| delete this; |
| } |
| |
| headless::TabSocketPtr& |
| HeadlessRenderFrameControllerImpl::EnsureTabSocketPtr() { |
| if (!tab_socket_ptr_.is_bound()) { |
| render_frame_->GetRemoteInterfaces()->GetInterface( |
| mojo::MakeRequest(&tab_socket_ptr_)); |
| } |
| return tab_socket_ptr_; |
| } |
| |
| } // namespace headless |