Index: ui/android/delegated_frame_host_android.cc |
diff --git a/ui/android/delegated_frame_host_android.cc b/ui/android/delegated_frame_host_android.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6e786dc9adb2d85cff2a0f62c5c29714d9189906 |
--- /dev/null |
+++ b/ui/android/delegated_frame_host_android.cc |
@@ -0,0 +1,245 @@ |
+// Copyright 2016 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 "ui/android/delegated_frame_host_android.h" |
+ |
+#include "base/logging.h" |
+#include "cc/layers/solid_color_layer.h" |
+#include "cc/layers/surface_layer.h" |
+#include "cc/output/compositor_frame.h" |
+#include "cc/output/copy_output_result.h" |
+#include "cc/surfaces/surface.h" |
+#include "cc/surfaces/surface_id.h" |
+#include "cc/surfaces/surface_id_allocator.h" |
+#include "cc/surfaces/surface_manager.h" |
+#include "ui/android/context_provider_factory.h" |
+#include "ui/android/view_android.h" |
+#include "ui/android/window_android_compositor.h" |
+#include "ui/gfx/android/device_display_info.h" |
+#include "ui/gfx/geometry/dip_util.h" |
+ |
+namespace ui { |
+ |
+namespace { |
+ |
+void SatisfyCallback(cc::SurfaceManager* manager, |
+ const cc::SurfaceSequence& sequence) { |
+ std::vector<uint32_t> sequences; |
+ sequences.push_back(sequence.sequence); |
+ manager->DidSatisfySequences(sequence.client_id, &sequences); |
+} |
+ |
+void RequireCallback(cc::SurfaceManager* manager, |
+ const cc::SurfaceId& id, |
+ const cc::SurfaceSequence& sequence) { |
+ cc::Surface* surface = manager->GetSurfaceForId(id); |
+ if (!surface) { |
+ LOG(ERROR) << "Attempting to require callback on nonexistent surface"; |
+ return; |
+ } |
+ surface->AddDestructionDependency(sequence); |
+} |
+ |
+scoped_refptr<cc::SurfaceLayer> CreateSurfaceLayer( |
+ cc::SurfaceManager* surface_manager, |
+ cc::SurfaceId surface_id, |
+ const gfx::Size surface_size) { |
+ // manager must outlive compositors using it. |
+ scoped_refptr<cc::SurfaceLayer> layer = cc::SurfaceLayer::Create( |
+ base::Bind(&SatisfyCallback, base::Unretained(surface_manager)), |
+ base::Bind(&RequireCallback, base::Unretained(surface_manager))); |
+ layer->SetSurfaceId(surface_id, 1.f, surface_size); |
+ layer->SetBounds(surface_size); |
+ layer->SetIsDrawable(true); |
+ layer->SetContentsOpaque(true); |
+ |
+ return layer; |
+} |
+ |
+void CopyOutputRequestCallback( |
+ scoped_refptr<cc::Layer> readback_layer, |
+ cc::CopyOutputRequest::CopyOutputRequestCallback result_callback, |
+ std::unique_ptr<cc::CopyOutputResult> copy_output_result) { |
+ readback_layer->RemoveFromParent(); |
+ result_callback.Run(std::move(copy_output_result)); |
+} |
+ |
+} // namespace |
+ |
+DelegatedFrameHostAndroid::DelegatedFrameHostAndroid( |
+ ui::ViewAndroid* view, |
+ SkColor background_color, |
+ ReturnResourcesCallback return_resources_callback) |
+ : view_(view), |
+ return_resources_callback_(return_resources_callback), |
+ background_layer_(cc::SolidColorLayer::Create()) { |
+ DCHECK(view_); |
+ DCHECK(!return_resources_callback_.is_null()); |
+ |
+ surface_manager_ = |
+ ui::ContextProviderFactory::GetInstance()->GetSurfaceManager(); |
+ surface_id_allocator_.reset(new cc::SurfaceIdAllocator( |
+ ui::ContextProviderFactory::GetInstance()->AllocateSurfaceClientId())); |
+ surface_manager_->RegisterSurfaceClientId(surface_id_allocator_->client_id()); |
+ |
+ background_layer_->SetBackgroundColor(background_color); |
+ view_->GetLayer()->AddChild(background_layer_); |
+ UpdateBackgroundLayer(); |
+} |
+ |
+DelegatedFrameHostAndroid::~DelegatedFrameHostAndroid() { |
+ DestroyDelegatedContent(); |
+ surface_factory_.reset(); |
+ surface_manager_->InvalidateSurfaceClientId( |
+ surface_id_allocator_->client_id()); |
+ background_layer_->RemoveFromParent(); |
+} |
+ |
+DelegatedFrameHostAndroid::FrameData::FrameData() = default; |
+ |
+DelegatedFrameHostAndroid::FrameData::~FrameData() = default; |
+ |
+void DelegatedFrameHostAndroid::SubmitCompositorFrame( |
+ cc::CompositorFrame frame, |
+ cc::SurfaceFactory::DrawCallback draw_callback) { |
+ if (!surface_factory_) { |
+ surface_factory_ = |
+ base::WrapUnique(new cc::SurfaceFactory(surface_manager_, this)); |
+ } |
+ |
+ cc::RenderPass* root_pass = |
+ frame.delegated_frame_data->render_pass_list.back().get(); |
+ gfx::Size surface_size = root_pass->output_rect.size(); |
+ |
+ if (!current_frame_ || surface_size != current_frame_->surface_size || |
+ current_frame_->location_bar_content_translation != |
+ frame.metadata.location_bar_content_translation || |
+ current_frame_->viewport_selection != frame.metadata.selection) { |
+ DestroyDelegatedContent(); |
+ DCHECK(!content_layer_); |
+ DCHECK(!current_frame_); |
+ |
+ current_frame_ = base::MakeUnique<FrameData>(); |
+ current_frame_->surface_id = surface_id_allocator_->GenerateId(); |
+ surface_factory_->Create(current_frame_->surface_id); |
+ |
+ current_frame_->surface_size = surface_size; |
+ current_frame_->location_bar_content_translation = |
+ frame.metadata.location_bar_content_translation; |
+ current_frame_->viewport_selection = frame.metadata.selection; |
+ content_layer_ = |
+ CreateSurfaceLayer(surface_manager_, current_frame_->surface_id, |
+ current_frame_->surface_size); |
+ view_->GetLayer()->AddChild(content_layer_); |
+ UpdateBackgroundLayer(); |
+ } |
+ |
+ surface_factory_->SubmitCompositorFrame(current_frame_->surface_id, |
+ std::move(frame), draw_callback); |
+} |
+ |
+uint32_t DelegatedFrameHostAndroid::GetSurfaceClientId() const { |
+ return surface_id_allocator_->client_id(); |
+} |
+ |
+void DelegatedFrameHostAndroid::RequestCopyOfSurface( |
+ WindowAndroidCompositor* compositor, |
+ const gfx::Rect& src_subrect_in_pixel, |
+ cc::CopyOutputRequest::CopyOutputRequestCallback result_callback) { |
+ DCHECK(current_frame_); |
+ DCHECK(!result_callback.is_null()); |
+ |
+ scoped_refptr<cc::Layer> readback_layer = |
+ CreateSurfaceLayer(surface_manager_, current_frame_->surface_id, |
+ current_frame_->surface_size); |
+ readback_layer->SetHideLayerAndSubtree(true); |
+ compositor->AttachLayerForReadback(readback_layer); |
+ std::unique_ptr<cc::CopyOutputRequest> copy_output_request = |
+ cc::CopyOutputRequest::CreateRequest(base::Bind( |
+ &CopyOutputRequestCallback, readback_layer, result_callback)); |
+ |
+ if (!src_subrect_in_pixel.IsEmpty()) |
+ copy_output_request->set_area(src_subrect_in_pixel); |
+ |
+ surface_factory_->RequestCopyOfSurface(current_frame_->surface_id, |
+ std::move(copy_output_request)); |
+} |
+ |
+void DelegatedFrameHostAndroid::DestroyDelegatedContent() { |
+ if (!current_frame_) |
+ return; |
+ |
+ DCHECK(surface_factory_.get()); |
+ DCHECK(content_layer_); |
+ |
+ content_layer_->RemoveFromParent(); |
+ content_layer_ = nullptr; |
+ surface_factory_->Destroy(current_frame_->surface_id); |
+ current_frame_.reset(); |
+ |
+ UpdateBackgroundLayer(); |
+} |
+ |
+bool DelegatedFrameHostAndroid::HasDelegatedContent() const { |
+ return current_frame_.get() != nullptr; |
+} |
+ |
+void DelegatedFrameHostAndroid::OutputSurfaceChanged() { |
+ DestroyDelegatedContent(); |
+ surface_factory_.reset(); |
+} |
+ |
+void DelegatedFrameHostAndroid::UpdateBackgroundColor(SkColor color) { |
+ background_layer_->SetBackgroundColor(color); |
+} |
+ |
+void DelegatedFrameHostAndroid::SetContentsOpaque(bool opaque) { |
+ if (!content_layer_) |
+ return; |
+ content_layer_->SetContentsOpaque(opaque); |
+} |
+ |
+void DelegatedFrameHostAndroid::UpdateContainerSizeinDIP( |
+ const gfx::Size& size_in_dip) { |
+ container_size_in_dip_ = size_in_dip; |
+ background_layer_->SetBounds(gfx::ConvertSizeToPixel( |
+ gfx::DeviceDisplayInfo().GetDIPScale(), container_size_in_dip_)); |
+ UpdateBackgroundLayer(); |
+} |
+ |
+void DelegatedFrameHostAndroid::ReturnResources( |
+ const cc::ReturnedResourceArray& resources) { |
+ return_resources_callback_.Run(resources); |
+} |
+ |
+void DelegatedFrameHostAndroid::SetBeginFrameSource( |
+ cc::BeginFrameSource* begin_frame_source) { |
+ // TODO(tansell): Hook this up. |
+} |
+ |
+void DelegatedFrameHostAndroid::UpdateBackgroundLayer() { |
+ // The background layer draws in 2 cases: |
+ // 1) When we don't have any content from the renderer. |
+ // 2) When the bounds of the content received from the renderer does not match |
+ // the desired content bounds. |
+ bool background_is_drawable = false; |
+ |
+ if (current_frame_) { |
+ float device_scale_factor = gfx::DeviceDisplayInfo().GetDIPScale(); |
+ gfx::Size content_size_in_dip = gfx::ConvertSizeToDIP( |
+ device_scale_factor, current_frame_->surface_size); |
+ content_size_in_dip.set_height( |
+ content_size_in_dip.height() + |
+ current_frame_->location_bar_content_translation.y()); |
+ background_is_drawable = |
+ content_size_in_dip.width() < container_size_in_dip_.width() || |
+ content_size_in_dip.height() < container_size_in_dip_.height(); |
+ } else { |
+ background_is_drawable = true; |
+ } |
+ |
+ background_layer_->SetIsDrawable(background_is_drawable); |
+} |
+ |
+} // namespace ui |