| // Copyright 2021 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "content/browser/xr/service/xr_frame_sink_client_impl.h" | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include "base/functional/callback.h" | 
 | #include "build/build_config.h" | 
 | #include "components/viz/host/host_frame_sink_manager.h" | 
 | #include "content/browser/browser_thread_impl.h" | 
 | #include "content/browser/compositor/surface_utils.h" | 
 | #include "content/browser/renderer_host/render_frame_host_impl.h" | 
 | #include "content/browser/renderer_host/render_widget_host_view_base.h" | 
 | #include "content/public/browser/browser_task_traits.h" | 
 | #include "content/public/browser/browser_thread.h" | 
 | #include "content/public/browser/render_frame_host.h" | 
 | #include "services/viz/privileged/mojom/compositing/frame_sink_manager.mojom.h" | 
 |  | 
 | #if BUILDFLAG(IS_ANDROID) | 
 | #include "content/browser/renderer_host/render_widget_host_view_android.h" | 
 | #endif | 
 |  | 
 | namespace content { | 
 | XrFrameSinkClientImpl::XrFrameSinkClientImpl(int32_t render_process_id, | 
 |                                              int32_t render_frame_id) | 
 |     : ui_thread_task_runner_(GetUIThreadTaskRunner({})), | 
 |       render_process_id_(render_process_id), | 
 |       render_frame_id_(render_frame_id) { | 
 |   DCHECK(IsOnUiThread()) | 
 |       << "XrFrameSinkClientImpl must be constructed on the UI thread."; | 
 | } | 
 |  | 
 | XrFrameSinkClientImpl::~XrFrameSinkClientImpl() { | 
 |   DCHECK(IsOnUiThread()) | 
 |       << "XrFrameSinkClientImpl must be destructed on the UI thread."; | 
 |   if (!initialized_) | 
 |     return; | 
 |  | 
 |   SurfaceDestroyed(); | 
 | } | 
 |  | 
 | bool XrFrameSinkClientImpl::IsOnUiThread() const { | 
 |   return ui_thread_task_runner_->BelongsToCurrentThread(); | 
 | } | 
 |  | 
 | void XrFrameSinkClientImpl::SurfaceDestroyed() { | 
 |   DCHECK(IsOnUiThread()); | 
 |   if (!initialized_) | 
 |     return; | 
 |  | 
 |   auto* frame_sink_manager = GetHostFrameSinkManager(); | 
 |  | 
 |   // Since this code can be run during destruction, it's theoretically possible, | 
 |   // though unlikely, that the FrameSinkManager no longer exists. | 
 |   if (frame_sink_manager) | 
 |     frame_sink_manager->InvalidateFrameSinkId(root_frame_sink_id_, this, {}); | 
 |  | 
 |   // Reset the initialized state and the root FrameSinkId to an invalid value. | 
 |   initialized_ = false; | 
 |   root_frame_sink_id_ = viz::FrameSinkId(); | 
 | } | 
 |  | 
 | std::optional<viz::SurfaceId> XrFrameSinkClientImpl::GetDOMSurface() { | 
 |   base::AutoLock lock(dom_surface_lock_); | 
 |   return dom_surface_id_; | 
 | } | 
 |  | 
 | viz::FrameSinkId XrFrameSinkClientImpl::FrameSinkId() { | 
 |   return root_frame_sink_id_; | 
 | } | 
 |  | 
 | void XrFrameSinkClientImpl::InitializeRootCompositorFrameSink( | 
 |     viz::mojom::RootCompositorFrameSinkParamsPtr root_params, | 
 |     device::DomOverlaySetup dom_setup, | 
 |     base::OnceClosure on_initialized) { | 
 |   DCHECK(!initialized_); | 
 |   DVLOG(1) << __func__; | 
 |  | 
 |   ui_thread_task_runner_->PostTask( | 
 |       FROM_HERE, | 
 |       base::BindOnce(&XrFrameSinkClientImpl::InitializeOnUiThread, | 
 |                      weak_ptr_factory_.GetWeakPtr(), std::move(root_params), | 
 |                      dom_setup, std::move(on_initialized))); | 
 | } | 
 |  | 
 | void XrFrameSinkClientImpl::InitializeOnUiThread( | 
 |     viz::mojom::RootCompositorFrameSinkParamsPtr root_params, | 
 |     device::DomOverlaySetup dom_setup, | 
 |     base::OnceClosure on_initialized) { | 
 |   // AllocateFrameSinkId needs to be called from the UI thread. | 
 |   DCHECK(IsOnUiThread()); | 
 |   DVLOG(1) << __func__; | 
 |  | 
 |   root_frame_sink_id_ = AllocateFrameSinkId(); | 
 |   root_params->frame_sink_id = root_frame_sink_id_; | 
 |  | 
 |   GetHostFrameSinkManager()->RegisterFrameSinkId( | 
 |       root_params->frame_sink_id, this, viz::ReportFirstSurfaceActivation::kNo); | 
 |   GetHostFrameSinkManager()->CreateRootCompositorFrameSink( | 
 |       std::move(root_params)); | 
 |  | 
 |   if (dom_setup != device::DomOverlaySetup::kNone) { | 
 |     ConfigureDOMOverlay(); | 
 |   } | 
 |  | 
 |   initialized_ = true; | 
 |   std::move(on_initialized).Run(); | 
 | } | 
 |  | 
 | void XrFrameSinkClientImpl::ConfigureDOMOverlay() { | 
 |   DCHECK(IsOnUiThread()); | 
 |   base::AutoLock lock(dom_surface_lock_); | 
 |  | 
 |   // This is left outside of the OS_ANDROID ifdef to prevent warnings about the | 
 |   // render_process_id and render_frame_id from being unused. Since we check | 
 |   // the render_frame_host for an early return, it is in fact used. | 
 |   RenderFrameHostImpl* render_frame_host = | 
 |       RenderFrameHostImpl::FromID(render_process_id_, render_frame_id_); | 
 |   if (!render_frame_host) | 
 |     return; | 
 |  | 
 |   RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>( | 
 |       render_frame_host->GetOutermostMainFrameOrEmbedder()->GetView()); | 
 |   CHECK(!root_view || !root_view->IsRenderWidgetHostViewChildFrame()); | 
 |  | 
 | // Since we don't have the ability to get updates to the surface id on non- | 
 | // Android OS's, we let it stay null, which callers can use to as a signal that | 
 | // DOMOverlay will not work. | 
 | #if BUILDFLAG(IS_ANDROID) | 
 |   RenderWidgetHostViewAndroid* view = | 
 |       static_cast<RenderWidgetHostViewAndroid*>(root_view); | 
 |   if (!view) | 
 |     return; | 
 |  | 
 |   // The returned CallbackListSubscription manages the lifetime of this callback | 
 |   // and thus makes Unretained safe. | 
 |   surface_id_changed_subscription_ = | 
 |       view->SubscribeToSurfaceIdChanges(base::BindRepeating( | 
 |           &XrFrameSinkClientImpl::OnSurfaceIdUpdated, base::Unretained(this))); | 
 |   dom_surface_id_ = view->GetCurrentSurfaceId(); | 
 | #endif | 
 |  | 
 |   if (dom_surface_id_ && dom_surface_id_->is_valid()) { | 
 |     GetHostFrameSinkManager()->RegisterFrameSinkHierarchy( | 
 |         root_frame_sink_id_, dom_surface_id_->frame_sink_id()); | 
 |   } | 
 | } | 
 |  | 
 | void XrFrameSinkClientImpl::OnSurfaceIdUpdated( | 
 |     const viz::SurfaceId& dom_surface_id) { | 
 |   base::AutoLock lock(dom_surface_lock_); | 
 |   dom_surface_id_ = dom_surface_id; | 
 | } | 
 |  | 
 | }  // namespace content |