OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "sky/viewer/document_view.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/location.h" | |
9 #include "base/single_thread_task_runner.h" | |
10 #include "base/strings/string_util.h" | |
11 #include "base/thread_task_runner_handle.h" | |
12 #include "mojo/converters/geometry/geometry_type_converters.h" | |
13 #include "mojo/converters/input_events/input_events_type_converters.h" | |
14 #include "mojo/public/cpp/application/connect.h" | |
15 #include "mojo/public/cpp/system/data_pipe.h" | |
16 #include "mojo/public/interfaces/application/shell.mojom.h" | |
17 #include "mojo/services/view_manager/public/cpp/view.h" | |
18 #include "mojo/services/view_manager/public/cpp/view_manager.h" | |
19 #include "mojo/services/view_manager/public/interfaces/view_manager.mojom.h" | |
20 #include "skia/ext/refptr.h" | |
21 #include "sky/engine/public/platform/Platform.h" | |
22 #include "sky/engine/public/platform/WebHTTPHeaderVisitor.h" | |
23 #include "sky/engine/public/platform/WebInputEvent.h" | |
24 #include "sky/engine/public/platform/WebScreenInfo.h" | |
25 #include "sky/engine/public/web/Sky.h" | |
26 #include "sky/services/platform/url_request_types.h" | |
27 #include "sky/viewer/compositor/layer.h" | |
28 #include "sky/viewer/compositor/layer_host.h" | |
29 #include "sky/viewer/compositor/rasterizer_bitmap.h" | |
30 #include "sky/viewer/compositor/rasterizer_ganesh.h" | |
31 #include "sky/viewer/converters/input_event_types.h" | |
32 #include "sky/viewer/dart_library_provider_impl.h" | |
33 #include "sky/viewer/internals.h" | |
34 #include "sky/viewer/runtime_flags.h" | |
35 #include "third_party/skia/include/core/SkCanvas.h" | |
36 #include "third_party/skia/include/core/SkColor.h" | |
37 #include "third_party/skia/include/core/SkDevice.h" | |
38 #include "ui/events/gestures/gesture_recognizer.h" | |
39 | |
40 namespace sky { | |
41 namespace { | |
42 | |
43 ui::EventType ConvertEventTypeToUIEventType(blink::WebInputEvent::Type type) { | |
44 if (type == blink::WebInputEvent::PointerDown) | |
45 return ui::ET_TOUCH_PRESSED; | |
46 if (type == blink::WebInputEvent::PointerUp) | |
47 return ui::ET_TOUCH_RELEASED; | |
48 if (type == blink::WebInputEvent::PointerMove) | |
49 return ui::ET_TOUCH_MOVED; | |
50 DCHECK(type == blink::WebInputEvent::PointerCancel); | |
51 return ui::ET_TOUCH_CANCELLED; | |
52 } | |
53 | |
54 scoped_ptr<ui::TouchEvent> ConvertToUITouchEvent( | |
55 const blink::WebInputEvent& event, | |
56 float device_pixel_ratio) { | |
57 if (!blink::WebInputEvent::isPointerEventType(event.type)) | |
58 return nullptr; | |
59 const blink::WebPointerEvent& pointer_event = | |
60 static_cast<const blink::WebPointerEvent&>(event); | |
61 return make_scoped_ptr(new ui::TouchEvent( | |
62 ConvertEventTypeToUIEventType(event.type), | |
63 gfx::PointF(pointer_event.x * device_pixel_ratio, | |
64 pointer_event.y * device_pixel_ratio), | |
65 pointer_event.pointer, | |
66 base::TimeDelta::FromMillisecondsD(pointer_event.timeStampMS))); | |
67 } | |
68 | |
69 scoped_ptr<DartLibraryProviderImpl::PrefetchedLibrary> | |
70 CreatePrefetchedLibraryIfNeeded(const String& name, | |
71 mojo::URLResponsePtr response) { | |
72 scoped_ptr<DartLibraryProviderImpl::PrefetchedLibrary> prefetched; | |
73 if (response->status_code == 200) { | |
74 prefetched.reset(new DartLibraryProviderImpl::PrefetchedLibrary()); | |
75 prefetched->name = name; | |
76 prefetched->pipe = response->body.Pass(); | |
77 } | |
78 return prefetched.Pass(); | |
79 } | |
80 | |
81 } // namespace | |
82 | |
83 DocumentView::DocumentView( | |
84 mojo::InterfaceRequest<mojo::ServiceProvider> services, | |
85 mojo::ServiceProviderPtr exported_services, | |
86 mojo::URLResponsePtr response, | |
87 mojo::Shell* shell) | |
88 : response_(response.Pass()), | |
89 exported_services_(services.Pass()), | |
90 imported_services_(exported_services.Pass()), | |
91 shell_(shell), | |
92 root_(nullptr), | |
93 view_manager_client_factory_(shell_, this), | |
94 bitmap_rasterizer_(nullptr), | |
95 weak_factory_(this) { | |
96 exported_services_.AddService(&view_manager_client_factory_); | |
97 InitServiceRegistry(); | |
98 } | |
99 | |
100 DocumentView::~DocumentView() { | |
101 if (root_) | |
102 root_->RemoveObserver(this); | |
103 ui::GestureRecognizer::Get()->CleanupStateForConsumer(this); | |
104 } | |
105 | |
106 base::WeakPtr<DocumentView> DocumentView::GetWeakPtr() { | |
107 return weak_factory_.GetWeakPtr(); | |
108 } | |
109 | |
110 void DocumentView::OnEmbed( | |
111 mojo::View* root, | |
112 mojo::InterfaceRequest<mojo::ServiceProvider> services_provided_to_embedder, | |
113 mojo::ServiceProviderPtr services_provided_by_embedder) { | |
114 root_ = root; | |
115 | |
116 if (services_provided_by_embedder.get()) { | |
117 mojo::ConnectToService(services_provided_by_embedder.get(), | |
118 &navigator_host_); | |
119 if (RuntimeFlags::Get().testing()) | |
120 mojo::ConnectToService(services_provided_by_embedder.get(), | |
121 &test_harness_); | |
122 } | |
123 | |
124 services_provided_to_embedder_ = services_provided_to_embedder.Pass(); | |
125 services_provided_by_embedder_ = services_provided_by_embedder.Pass(); | |
126 | |
127 Load(response_.Pass()); | |
128 | |
129 UpdateRootSizeAndViewportMetrics(root_->bounds()); | |
130 | |
131 root_->AddObserver(this); | |
132 } | |
133 | |
134 void DocumentView::OnViewManagerDisconnected(mojo::ViewManager* view_manager) { | |
135 // TODO(aa): Need to figure out how shutdown works. | |
136 } | |
137 void DocumentView::Load(mojo::URLResponsePtr response) { | |
138 String name = String::fromUTF8(response->url); | |
139 library_provider_.reset(new DartLibraryProviderImpl( | |
140 blink::Platform::current()->networkService(), | |
141 CreatePrefetchedLibraryIfNeeded(name, response.Pass()))); | |
142 sky_view_ = blink::SkyView::Create(this); | |
143 layer_host_.reset(new LayerHost(this)); | |
144 root_layer_ = make_scoped_refptr(new Layer(this)); | |
145 root_layer_->set_rasterizer(CreateRasterizer()); | |
146 layer_host_->SetRootLayer(root_layer_); | |
147 | |
148 sky_view_->RunFromLibrary(name, library_provider_.get()); | |
149 } | |
150 | |
151 scoped_ptr<Rasterizer> DocumentView::CreateRasterizer() { | |
152 if (!RuntimeFlags::Get().testing()) | |
153 return make_scoped_ptr(new RasterizerGanesh(layer_host_.get())); | |
154 // TODO(abarth): If we have more than one layer, we'll need to re-think how | |
155 // we capture pixels for testing; | |
156 DCHECK(!bitmap_rasterizer_); | |
157 bitmap_rasterizer_ = new RasterizerBitmap(layer_host_.get()); | |
158 return make_scoped_ptr(bitmap_rasterizer_); | |
159 } | |
160 | |
161 void DocumentView::GetPixelsForTesting(std::vector<unsigned char>* pixels) { | |
162 DCHECK(RuntimeFlags::Get().testing()) << "Requires testing runtime flag"; | |
163 DCHECK(root_layer_) << "The root layer owns the rasterizer"; | |
164 return bitmap_rasterizer_->GetPixelsForTesting(pixels); | |
165 } | |
166 | |
167 TestHarnessPtr DocumentView::TakeTestHarness() { | |
168 return test_harness_.Pass(); | |
169 } | |
170 | |
171 mojo::ScopedMessagePipeHandle DocumentView::TakeServicesProvidedToEmbedder() { | |
172 return services_provided_to_embedder_.PassMessagePipe(); | |
173 } | |
174 | |
175 mojo::ScopedMessagePipeHandle DocumentView::TakeServicesProvidedByEmbedder() { | |
176 return services_provided_by_embedder_.PassInterface().PassHandle(); | |
177 } | |
178 | |
179 mojo::ScopedMessagePipeHandle DocumentView::TakeServiceRegistry() { | |
180 return service_registry_.PassInterface().PassHandle(); | |
181 } | |
182 | |
183 mojo::Shell* DocumentView::GetShell() { | |
184 return shell_; | |
185 } | |
186 | |
187 void DocumentView::BeginFrame(base::TimeTicks frame_time) { | |
188 if (sky_view_) { | |
189 sky_view_->BeginFrame(frame_time); | |
190 root_layer_->SetSize(sky_view_->display_metrics().physical_size); | |
191 } | |
192 } | |
193 | |
194 void DocumentView::OnSurfaceIdAvailable(mojo::SurfaceIdPtr surface_id) { | |
195 if (root_) | |
196 root_->SetSurfaceId(surface_id.Pass()); | |
197 } | |
198 | |
199 void DocumentView::PaintContents(SkCanvas* canvas, const gfx::Rect& clip) { | |
200 blink::WebRect rect(clip.x(), clip.y(), clip.width(), clip.height()); | |
201 | |
202 if (sky_view_) { | |
203 skia::RefPtr<SkPicture> picture = sky_view_->Paint(); | |
204 canvas->clear(SK_ColorBLACK); | |
205 canvas->scale(GetDevicePixelRatio(), GetDevicePixelRatio()); | |
206 if (picture) | |
207 canvas->drawPicture(picture.get()); | |
208 } | |
209 } | |
210 | |
211 float DocumentView::GetDevicePixelRatio() const { | |
212 if (root_) | |
213 return root_->viewport_metrics().device_pixel_ratio; | |
214 return 1.f; | |
215 } | |
216 | |
217 void DocumentView::DidCreateIsolate(Dart_Isolate isolate) { | |
218 Internals::Create(isolate, this); | |
219 } | |
220 | |
221 mojo::NavigatorHost* DocumentView::NavigatorHost() { | |
222 return navigator_host_.get(); | |
223 } | |
224 | |
225 void DocumentView::OnViewBoundsChanged(mojo::View* view, | |
226 const mojo::Rect& old_bounds, | |
227 const mojo::Rect& new_bounds) { | |
228 DCHECK_EQ(view, root_); | |
229 UpdateRootSizeAndViewportMetrics(new_bounds); | |
230 } | |
231 | |
232 void DocumentView::OnViewViewportMetricsChanged( | |
233 mojo::View* view, | |
234 const mojo::ViewportMetrics& old_metrics, | |
235 const mojo::ViewportMetrics& new_metrics) { | |
236 DCHECK_EQ(view, root_); | |
237 | |
238 UpdateRootSizeAndViewportMetrics(root_->bounds()); | |
239 } | |
240 | |
241 void DocumentView::UpdateRootSizeAndViewportMetrics( | |
242 const mojo::Rect& new_bounds) { | |
243 float device_pixel_ratio = GetDevicePixelRatio(); | |
244 | |
245 if (sky_view_) { | |
246 blink::SkyDisplayMetrics metrics; | |
247 mojo::Rect bounds = root_->bounds(); | |
248 metrics.physical_size = blink::WebSize(bounds.width, bounds.height); | |
249 metrics.device_pixel_ratio = device_pixel_ratio; | |
250 sky_view_->SetDisplayMetrics(metrics); | |
251 return; | |
252 } | |
253 } | |
254 | |
255 void DocumentView::OnViewFocusChanged(mojo::View* gained_focus, | |
256 mojo::View* lost_focus) { | |
257 } | |
258 | |
259 void DocumentView::OnViewDestroyed(mojo::View* view) { | |
260 DCHECK_EQ(view, root_); | |
261 | |
262 root_ = nullptr; | |
263 } | |
264 | |
265 void DocumentView::OnViewInputEvent( | |
266 mojo::View* view, const mojo::EventPtr& event) { | |
267 float device_pixel_ratio = GetDevicePixelRatio(); | |
268 scoped_ptr<blink::WebInputEvent> web_event = | |
269 ConvertEvent(event, device_pixel_ratio); | |
270 if (!web_event) | |
271 return; | |
272 | |
273 ui::GestureRecognizer* recognizer = ui::GestureRecognizer::Get(); | |
274 scoped_ptr<ui::TouchEvent> touch_event = | |
275 ConvertToUITouchEvent(*web_event, device_pixel_ratio); | |
276 if (touch_event) | |
277 recognizer->ProcessTouchEventPreDispatch(*touch_event, this); | |
278 | |
279 bool handled = false; | |
280 | |
281 if (sky_view_) | |
282 sky_view_->HandleInputEvent(*web_event); | |
283 | |
284 if (touch_event) { | |
285 ui::EventResult result = handled ? ui::ER_UNHANDLED : ui::ER_UNHANDLED; | |
286 if (auto gestures = recognizer->ProcessTouchEventPostDispatch( | |
287 *touch_event, result, this)) { | |
288 for (auto& gesture : *gestures) { | |
289 scoped_ptr<blink::WebInputEvent> gesture_event = | |
290 ConvertEvent(*gesture, device_pixel_ratio); | |
291 if (gesture_event) { | |
292 if (sky_view_) | |
293 sky_view_->HandleInputEvent(*gesture_event); | |
294 } | |
295 } | |
296 } | |
297 } | |
298 } | |
299 | |
300 void DocumentView::StartDebuggerInspectorBackend() { | |
301 // FIXME: Do we need this for dart? | |
302 } | |
303 | |
304 void DocumentView::InitServiceRegistry() { | |
305 mojo::ConnectToService(imported_services_.get(), &service_registry_); | |
306 mojo::Array<mojo::String> interface_names(1); | |
307 interface_names[0] = mojo::ViewManagerClient::Name_; | |
308 mojo::ServiceProviderImpl* sp_impl(new mojo::ServiceProviderImpl()); | |
309 sp_impl->AddService(&view_manager_client_factory_); | |
310 mojo::ServiceProviderPtr sp; | |
311 service_registry_service_provider_binding_.reset( | |
312 new mojo::StrongBinding<mojo::ServiceProvider>(sp_impl, &sp)); | |
313 service_registry_->AddServices(interface_names.Pass(), sp.Pass()); | |
314 } | |
315 | |
316 void DocumentView::ScheduleFrame() { | |
317 DCHECK(sky_view_); | |
318 layer_host_->SetNeedsAnimate(); | |
319 } | |
320 | |
321 } // namespace sky | |
OLD | NEW |