| // Copyright 2014 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 "services/sky/document_view.h" |
| |
| #include "base/bind.h" |
| #include "base/location.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/strings/string_util.h" |
| #include "base/thread_task_runner_handle.h" |
| #include "mojo/converters/geometry/geometry_type_converters.h" |
| #include "mojo/converters/input_events/input_events_type_converters.h" |
| #include "mojo/public/cpp/application/connect.h" |
| #include "mojo/public/cpp/system/data_pipe.h" |
| #include "mojo/public/interfaces/application/shell.mojom.h" |
| #include "mojo/services/surfaces/cpp/surfaces_utils.h" |
| #include "mojo/services/surfaces/interfaces/quads.mojom.h" |
| #include "services/asset_bundle/asset_unpacker_job.h" |
| #include "services/sky/compositor/layer_host.h" |
| #include "services/sky/compositor/rasterizer_bitmap.h" |
| #include "services/sky/compositor/rasterizer_ganesh.h" |
| #include "services/sky/compositor/texture_layer.h" |
| #include "services/sky/converters/input_event_types.h" |
| #include "services/sky/dart_library_provider_impl.h" |
| #include "services/sky/internals.h" |
| #include "services/sky/runtime_flags.h" |
| #include "skia/ext/refptr.h" |
| #include "sky/compositor/paint_context.h" |
| #include "sky/engine/public/platform/Platform.h" |
| #include "sky/engine/public/platform/WebInputEvent.h" |
| #include "sky/engine/public/web/Sky.h" |
| #include "third_party/skia/include/core/SkCanvas.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| #include "third_party/skia/include/core/SkDevice.h" |
| |
| using mojo::asset_bundle::AssetUnpackerJob; |
| |
| namespace sky { |
| namespace { |
| |
| const char kSnapshotKey[] = "snapshot_blob.bin"; |
| |
| } // namespace |
| |
| DocumentView::DocumentView( |
| mojo::InterfaceRequest<mojo::ServiceProvider> exported_services, |
| mojo::ServiceProviderPtr imported_services, |
| mojo::URLResponsePtr response, |
| mojo::Shell* shell) |
| : response_(response.Pass()), |
| exported_services_(exported_services.Pass()), |
| imported_services_(imported_services.Pass()), |
| shell_(shell), |
| bitmap_rasterizer_(nullptr), |
| event_dispatcher_binding_(this), |
| weak_factory_(this) { |
| InitServiceRegistry(); |
| InitViewport(); |
| } |
| |
| DocumentView::~DocumentView() { |
| } |
| |
| base::WeakPtr<DocumentView> DocumentView::GetWeakPtr() { |
| return weak_factory_.GetWeakPtr(); |
| } |
| |
| void DocumentView::InitViewport() { |
| mojo::ServiceProviderPtr viewport_service_provider; |
| shell_->ConnectToApplication("mojo:native_viewport_service", |
| mojo::GetProxy(&viewport_service_provider), |
| nullptr); |
| mojo::ConnectToService(viewport_service_provider.get(), &viewport_service_); |
| viewport_service_.set_connection_error_handler( |
| base::Bind(&DocumentView::OnViewportConnectionError, |
| base::Unretained(this))); |
| |
| mojo::NativeViewportEventDispatcherPtr dispatcher; |
| event_dispatcher_binding_.Bind(GetProxy(&dispatcher)); |
| viewport_service_->SetEventDispatcher(dispatcher.Pass()); |
| |
| // Match the Nexus 5 aspect ratio initially. |
| auto size = mojo::Size::New(); |
| size->width = 320; |
| size->height = 640; |
| |
| auto requested_configuration = mojo::SurfaceConfiguration::New(); |
| |
| viewport_service_->Create(size.Clone(), |
| requested_configuration.Pass(), |
| base::Bind(&DocumentView::OnViewportCreated, |
| base::Unretained(this))); |
| } |
| |
| void DocumentView::OnViewportConnectionError() { |
| delete this; |
| } |
| |
| void DocumentView::OnViewportCreated(mojo::ViewportMetricsPtr metrics) { |
| viewport_service_->Show(); |
| mojo::ContextProviderPtr onscreen_context_provider; |
| viewport_service_->GetContextProvider(GetProxy(&onscreen_context_provider)); |
| |
| mojo::ServiceProviderPtr surfaces_service_provider; |
| shell_->ConnectToApplication("mojo:surfaces_service", |
| mojo::GetProxy(&surfaces_service_provider), |
| nullptr); |
| mojo::DisplayFactoryPtr display_factory; |
| mojo::ConnectToService(surfaces_service_provider.get(), &display_factory); |
| display_factory->Create(onscreen_context_provider.Pass(), |
| nullptr, GetProxy(&display_)); |
| |
| Load(response_.Pass()); |
| UpdateViewportMetrics(metrics.Pass()); |
| RequestUpdatedViewportMetrics(); |
| } |
| |
| void DocumentView::OnViewportMetricsChanged(mojo::ViewportMetricsPtr metrics) { |
| UpdateViewportMetrics(metrics.Pass()); |
| RequestUpdatedViewportMetrics(); |
| } |
| |
| void DocumentView::RequestUpdatedViewportMetrics() { |
| viewport_service_->RequestMetrics( |
| base::Bind(&DocumentView::OnViewportMetricsChanged, |
| base::Unretained(this))); |
| } |
| |
| void DocumentView::LoadFromSnapshotStream( |
| String name, mojo::ScopedDataPipeConsumerHandle snapshot) { |
| if (sky_view_) { |
| sky_view_->RunFromSnapshot(name, snapshot.Pass()); |
| } |
| } |
| |
| void DocumentView::Load(mojo::URLResponsePtr response) { |
| sky_view_ = blink::SkyView::Create(this); |
| layer_host_.reset(new LayerHost(this)); |
| root_layer_ = make_scoped_refptr(new TextureLayer(this)); |
| root_layer_->set_rasterizer(CreateRasterizer()); |
| layer_host_->SetRootLayer(root_layer_); |
| |
| String name = String::fromUTF8(response->url); |
| sky_view_->CreateView(name); |
| AssetUnpackerJob* unpacker = new AssetUnpackerJob( |
| mojo::GetProxy(&root_bundle_), |
| base::MessageLoop::current()->task_runner()); |
| unpacker->Unpack(response->body.Pass()); |
| root_bundle_->GetAsStream(kSnapshotKey, |
| base::Bind(&DocumentView::LoadFromSnapshotStream, |
| weak_factory_.GetWeakPtr(), name)); |
| } |
| |
| scoped_ptr<Rasterizer> DocumentView::CreateRasterizer() { |
| if (!RuntimeFlags::Get().testing()) |
| return make_scoped_ptr(new RasterizerGanesh(layer_host_.get())); |
| // TODO(abarth): If we have more than one layer, we'll need to re-think how |
| // we capture pixels for testing; |
| DCHECK(!bitmap_rasterizer_); |
| bitmap_rasterizer_ = new RasterizerBitmap(layer_host_.get()); |
| return make_scoped_ptr(bitmap_rasterizer_); |
| } |
| |
| void DocumentView::GetPixelsForTesting(std::vector<unsigned char>* pixels) { |
| DCHECK(RuntimeFlags::Get().testing()) << "Requires testing runtime flag"; |
| DCHECK(root_layer_) << "The root layer owns the rasterizer"; |
| return bitmap_rasterizer_->GetPixelsForTesting(pixels); |
| } |
| |
| mojo::ScopedMessagePipeHandle DocumentView::TakeRootBundleHandle() { |
| return root_bundle_.PassInterface().PassHandle(); |
| } |
| |
| mojo::ScopedMessagePipeHandle DocumentView::TakeServicesProvidedToEmbedder() { |
| // TODO(jeffbrown): Stubbed out until we migrate from native viewport |
| // to a new view system that supports embedding again. |
| return mojo::ScopedMessagePipeHandle(); |
| } |
| |
| mojo::ScopedMessagePipeHandle DocumentView::TakeServicesProvidedByEmbedder() { |
| // TODO(jeffbrown): Stubbed out until we migrate from native viewport |
| // to a new view system that supports embedding again. |
| return mojo::ScopedMessagePipeHandle(); |
| } |
| |
| mojo::ScopedMessagePipeHandle DocumentView::TakeServiceRegistry() { |
| return service_registry_.PassInterface().PassHandle(); |
| } |
| |
| mojo::Shell* DocumentView::GetShell() { |
| return shell_; |
| } |
| |
| void DocumentView::BeginFrame(base::TimeTicks frame_time) { |
| if (sky_view_) { |
| std::unique_ptr<compositor::LayerTree> layer_tree = sky_view_->BeginFrame(frame_time); |
| if (layer_tree) |
| current_layer_tree_ = std::move(layer_tree); |
| root_layer_->SetSize(sky_view_->display_metrics().physical_size); |
| } |
| } |
| |
| void DocumentView::OnSurfaceIdAvailable(mojo::SurfaceIdPtr surface_id) { |
| mojo::FramePtr frame = mojo::Frame::New(); |
| frame->resources.resize(0u); |
| |
| mojo::Rect bounds; |
| bounds.width = viewport_metrics_->size->width; |
| bounds.height = viewport_metrics_->size->height; |
| mojo::PassPtr pass = mojo::CreateDefaultPass(1, bounds); |
| pass->shared_quad_states.push_back(mojo::CreateDefaultSQS( |
| *viewport_metrics_->size)); |
| |
| mojo::QuadPtr quad = mojo::Quad::New(); |
| quad->material = mojo::Material::SURFACE_CONTENT; |
| quad->rect = bounds.Clone(); |
| quad->opaque_rect = bounds.Clone(); |
| quad->visible_rect = bounds.Clone(); |
| quad->shared_quad_state_index = 0u; |
| quad->surface_quad_state = mojo::SurfaceQuadState::New(); |
| quad->surface_quad_state->surface = surface_id.Pass(); |
| |
| pass->quads.push_back(quad.Pass()); |
| frame->passes.push_back(pass.Pass()); |
| |
| display_->SubmitFrame(frame.Pass(), base::Bind(&base::DoNothing)); |
| } |
| |
| void DocumentView::PaintContents(SkCanvas* canvas, const gfx::Rect& clip) { |
| if (current_layer_tree_) { |
| compositor::PaintContext::ScopedFrame frame = |
| paint_context_.AcquireFrame(*canvas); |
| current_layer_tree_->root_layer()->Paint(frame); |
| } |
| } |
| |
| void DocumentView::DidCreateIsolate(Dart_Isolate isolate) { |
| Internals::Create(isolate, this); |
| } |
| |
| mojo::NavigatorHost* DocumentView::NavigatorHost() { |
| return navigator_host_.get(); |
| } |
| |
| void DocumentView::UpdateViewportMetrics( |
| mojo::ViewportMetricsPtr viewport_metrics) { |
| viewport_metrics_ = viewport_metrics.Pass(); |
| |
| if (sky_view_) { |
| blink::SkyDisplayMetrics metrics; |
| metrics.physical_size = blink::WebSize( |
| viewport_metrics_->size->width, |
| viewport_metrics_->size->height); |
| metrics.device_pixel_ratio = viewport_metrics_->device_pixel_ratio; |
| sky_view_->SetDisplayMetrics(metrics); |
| } |
| } |
| |
| void DocumentView::OnEvent(mojo::EventPtr event, |
| const mojo::Callback<void()>& callback) { |
| HandleInputEvent(event.Pass()); |
| callback.Run(); |
| } |
| |
| void DocumentView::HandleInputEvent(mojo::EventPtr event) { |
| if (!viewport_metrics_) |
| return; |
| float device_pixel_ratio = viewport_metrics_->device_pixel_ratio; |
| scoped_ptr<blink::WebInputEvent> web_event = |
| ConvertEvent(event, device_pixel_ratio); |
| if (!web_event) |
| return; |
| |
| if (sky_view_) |
| sky_view_->HandleInputEvent(*web_event); |
| } |
| |
| void DocumentView::StartDebuggerInspectorBackend() { |
| // FIXME: Do we need this for dart? |
| } |
| |
| void DocumentView::InitServiceRegistry() { |
| if (imported_services_) |
| mojo::ConnectToService(imported_services_.get(), &service_registry_); |
| } |
| |
| void DocumentView::ScheduleFrame() { |
| DCHECK(sky_view_); |
| layer_host_->SetNeedsAnimate(); |
| } |
| |
| void DocumentView::Render(std::unique_ptr<compositor::LayerTree> layer_tree) { |
| } |
| |
| } // namespace sky |