Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
platform_view.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter 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#define RAPIDJSON_HAS_STDSTRING 1
6
7#include "platform_view.h"
8
9#include <fuchsia/ui/app/cpp/fidl.h>
10#include <zircon/status.h>
11
12#include <algorithm>
13#include <cstring>
14#include <limits>
15#include <sstream>
16
17#include "flutter/fml/logging.h"
18#include "flutter/fml/make_copyable.h"
19#include "flutter/lib/ui/window/pointer_data.h"
20#include "flutter/shell/platform/common/client_wrapper/include/flutter/encodable_value.h"
21#include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_message_codec.h"
22#include "third_party/rapidjson/include/rapidjson/document.h"
23#include "third_party/rapidjson/include/rapidjson/stringbuffer.h"
24#include "third_party/rapidjson/include/rapidjson/writer.h"
25
26#include "flutter/fml/make_copyable.h"
27#include "logging.h"
30#include "text_delegate.h"
31#include "vsync_waiter.h"
32
33namespace {
34// Helper to extract a given member with a given type from a rapidjson object.
35template <typename T, typename O, typename F>
36bool CallWithMember(O obj, const char* member_name, F func) {
37 auto it = obj.FindMember(member_name);
38 if (it == obj.MemberEnd()) {
39 return false;
40 }
41 if (!it->value.template Is<T>()) {
42 return false;
43 }
44 func(it->value.template Get<T>());
45 return true;
46}
47} // namespace
48
49namespace flutter_runner {
50
51static constexpr char kFlutterPlatformChannel[] = "flutter/platform";
52static constexpr char kAccessibilityChannel[] = "flutter/accessibility";
53static constexpr char kFlutterPlatformViewsChannel[] = "flutter/platform_views";
54static constexpr char kFuchsiaShaderWarmupChannel[] = "fuchsia/shader_warmup";
55static constexpr char kFuchsiaInputTestChannel[] = "fuchsia/input_test";
56static constexpr char kFuchsiaChildViewChannel[] = "fuchsia/child_view";
57static constexpr int64_t kFlutterImplicitViewId = 0ll;
58
61 flutter::TaskRunners task_runners,
62 fuchsia::ui::views::ViewRef view_ref,
63 std::shared_ptr<flutter::ExternalViewEmbedder> external_view_embedder,
64 fuchsia::ui::input::ImeServiceHandle ime_service,
65 fuchsia::ui::input3::KeyboardHandle keyboard,
66 fuchsia::ui::pointer::TouchSourceHandle touch_source,
67 fuchsia::ui::pointer::MouseSourceHandle mouse_source,
68 fuchsia::ui::views::FocuserHandle focuser,
69 fuchsia::ui::views::ViewRefFocusedHandle view_ref_focused,
70 fuchsia::ui::composition::ParentViewportWatcherHandle
71 parent_viewport_watcher,
72 fuchsia::ui::pointerinjector::RegistryHandle pointerinjector_registry,
73 OnEnableWireframeCallback wireframe_enabled_callback,
74 OnCreateViewCallback on_create_view_callback,
75 OnUpdateViewCallback on_update_view_callback,
76 OnDestroyViewCallback on_destroy_view_callback,
77 OnCreateSurfaceCallback on_create_surface_callback,
78 OnSemanticsNodeUpdateCallback on_semantics_node_update_callback,
79 OnRequestAnnounceCallback on_request_announce_callback,
80 OnShaderWarmupCallback on_shader_warmup_callback,
81 AwaitVsyncCallback await_vsync_callback,
83 await_vsync_for_secondary_callback_callback,
84 std::shared_ptr<sys::ServiceDirectory> dart_application_svc)
85 : flutter::PlatformView(delegate, std::move(task_runners)),
86 external_view_embedder_(external_view_embedder),
87 focus_delegate_(
88 std::make_shared<FocusDelegate>(std::move(view_ref_focused),
89 std::move(focuser))),
90 pointer_delegate_(
91 std::make_shared<PointerDelegate>(std::move(touch_source),
92 std::move(mouse_source))),
93 wireframe_enabled_callback_(std::move(wireframe_enabled_callback)),
94 on_update_view_callback_(std::move(on_update_view_callback)),
95 on_create_surface_callback_(std::move(on_create_surface_callback)),
96 on_semantics_node_update_callback_(
97 std::move(on_semantics_node_update_callback)),
98 on_request_announce_callback_(std::move(on_request_announce_callback)),
99 on_create_view_callback_(std::move(on_create_view_callback)),
100 on_destroy_view_callback_(std::move(on_destroy_view_callback)),
101 on_shader_warmup_callback_(std::move(on_shader_warmup_callback)),
102 await_vsync_callback_(await_vsync_callback),
103 await_vsync_for_secondary_callback_callback_(
104 await_vsync_for_secondary_callback_callback),
105 dart_application_svc_(dart_application_svc),
106 parent_viewport_watcher_(parent_viewport_watcher.Bind()),
107 weak_factory_(this) {
108 fuchsia::ui::views::ViewRef view_ref_clone;
109 fidl::Clone(view_ref, &view_ref_clone);
110
111 text_delegate_ =
112 std::make_unique<TextDelegate>(
113 std::move(view_ref), std::move(ime_service), std::move(keyboard),
114 [weak = weak_factory_.GetWeakPtr()](
115 std::unique_ptr<flutter::PlatformMessage> message) {
116 if (!weak) {
117 FML_LOG(WARNING)
118 << "PlatformView use-after-free attempted. Ignoring.";
119 }
120 weak->delegate_.OnPlatformViewDispatchPlatformMessage(
121 std::move(message));
122 });
123
124 // Begin watching for focus changes.
125 focus_delegate_->WatchLoop([weak = weak_factory_.GetWeakPtr()](bool focused) {
126 if (!weak) {
127 FML_LOG(WARNING) << "PlatformView use-after-free attempted. Ignoring.";
128 return;
129 }
130
131 // Ensure last_text_state_ is set to make sure Flutter actually wants
132 // an IME.
133 if (focused && weak->text_delegate_->HasTextState()) {
134 weak->text_delegate_->ActivateIme();
135 } else if (!focused) {
136 weak->text_delegate_->DeactivateIme();
137 }
138 });
139
140 // Begin watching for pointer events.
141 pointer_delegate_->WatchLoop([weak = weak_factory_.GetWeakPtr()](
142 std::vector<flutter::PointerData> events) {
143 if (!weak) {
144 FML_LOG(WARNING) << "PlatformView use-after-free attempted. Ignoring.";
145 return;
146 }
147
148 if (events.empty()) {
149 return; // No work, bounce out.
150 }
151
152 // If pixel ratio hasn't been set, use a default value of 1.
153 const float pixel_ratio = weak->view_pixel_ratio_.value_or(1.f);
154 auto packet = std::make_unique<flutter::PointerDataPacket>(events.size());
155 for (size_t i = 0; i < events.size(); ++i) {
156 auto& event = events[i];
157 // Translate logical to physical coordinates, as per
158 // flutter::PointerData contract. Done here because pixel ratio comes
159 // from the graphics API.
160 event.physical_x = event.physical_x * pixel_ratio;
161 event.physical_y = event.physical_y * pixel_ratio;
162 packet->SetPointerData(i, event);
163 }
164 weak->DispatchPointerDataPacket(std::move(packet));
165 });
166
167 // Configure the pointer injector delegate.
168 pointer_injector_delegate_ = std::make_unique<PointerInjectorDelegate>(
169 std::move(pointerinjector_registry), std::move(view_ref_clone));
170
171 // This is only used by the integration tests.
172 if (dart_application_svc) {
173 // Connect to TouchInputListener
174 fuchsia::ui::test::input::TouchInputListenerHandle touch_input_listener;
175 zx_status_t touch_input_listener_status =
176 dart_application_svc
177 ->Connect<fuchsia::ui::test::input::TouchInputListener>(
178 touch_input_listener.NewRequest());
179 if (touch_input_listener_status != ZX_OK) {
180 FML_LOG(WARNING)
181 << "fuchsia::ui::test::input::TouchInputListener connection failed: "
182 << zx_status_get_string(touch_input_listener_status);
183 } else {
184 touch_input_listener_.Bind(std::move(touch_input_listener));
185 }
186
187 // Connect to KeyboardInputListener
188 fuchsia::ui::test::input::KeyboardInputListenerHandle
189 keyboard_input_listener;
190 zx_status_t keyboard_input_listener_status =
191 dart_application_svc
192 ->Connect<fuchsia::ui::test::input::KeyboardInputListener>(
193 keyboard_input_listener.NewRequest());
194 if (keyboard_input_listener_status != ZX_OK) {
195 FML_LOG(WARNING) << "fuchsia::ui::test::input::KeyboardInputListener "
196 "connection failed: "
197 << zx_status_get_string(keyboard_input_listener_status);
198 } else {
199 keyboard_input_listener_.Bind(std::move(keyboard_input_listener));
200 }
201 // Connect to MouseInputListener
202 fuchsia::ui::test::input::MouseInputListenerHandle mouse_input_listener;
203 zx_status_t mouse_input_listener_status =
204 dart_application_svc
205 ->Connect<fuchsia::ui::test::input::MouseInputListener>(
206 mouse_input_listener.NewRequest());
207 if (mouse_input_listener_status != ZX_OK) {
208 FML_LOG(WARNING)
209 << "fuchsia::ui::test::input::MouseInputListener connection failed: "
210 << zx_status_get_string(mouse_input_listener_status);
211 } else {
212 mouse_input_listener_.Bind(std::move(mouse_input_listener));
213 }
214 }
215
216 // Finally! Register the native platform message handlers.
217 RegisterPlatformMessageHandlers();
218
219 parent_viewport_watcher_.set_error_handler([](zx_status_t status) {
220 FML_LOG(ERROR) << "Interface error on: ParentViewportWatcher status: "
221 << status;
222 });
223
224 parent_viewport_watcher_->GetLayout(
225 fit::bind_member(this, &PlatformView::OnGetLayout));
226 parent_viewport_watcher_->GetStatus(
227 fit::bind_member(this, &PlatformView::OnParentViewportStatus));
228}
229
230PlatformView::~PlatformView() = default;
231
232void PlatformView::RegisterPlatformMessageHandlers() {
233 platform_message_handlers_[kFlutterPlatformChannel] =
234 std::bind(&PlatformView::HandleFlutterPlatformChannelPlatformMessage,
235 this, std::placeholders::_1);
236 platform_message_handlers_[kTextInputChannel] =
237 std::bind(&TextDelegate::HandleFlutterTextInputChannelPlatformMessage,
238 text_delegate_.get(), std::placeholders::_1);
239 platform_message_handlers_[kAccessibilityChannel] =
240 std::bind(&PlatformView::HandleAccessibilityChannelPlatformMessage, this,
241 std::placeholders::_1);
242 platform_message_handlers_[kFlutterPlatformViewsChannel] =
243 std::bind(&PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage,
244 this, std::placeholders::_1);
245 platform_message_handlers_[kFuchsiaShaderWarmupChannel] =
246 std::bind(&HandleFuchsiaShaderWarmupChannelPlatformMessage,
247 on_shader_warmup_callback_, std::placeholders::_1);
248 platform_message_handlers_[kFuchsiaInputTestChannel] =
249 std::bind(&PlatformView::HandleFuchsiaInputTestChannelPlatformMessage,
250 this, std::placeholders::_1);
251 platform_message_handlers_[kFuchsiaChildViewChannel] =
252 std::bind(&PlatformView::HandleFuchsiaChildViewChannelPlatformMessage,
253 this, std::placeholders::_1);
254}
255
257 fuchsia::ui::input::PointerEventPhase phase) {
258 switch (phase) {
259 case fuchsia::ui::input::PointerEventPhase::ADD:
261 case fuchsia::ui::input::PointerEventPhase::HOVER:
263 case fuchsia::ui::input::PointerEventPhase::DOWN:
265 case fuchsia::ui::input::PointerEventPhase::MOVE:
267 case fuchsia::ui::input::PointerEventPhase::UP:
269 case fuchsia::ui::input::PointerEventPhase::REMOVE:
271 case fuchsia::ui::input::PointerEventPhase::CANCEL:
273 default:
275 }
276}
277
279 fuchsia::ui::input::PointerEventType type) {
280 switch (type) {
281 case fuchsia::ui::input::PointerEventType::TOUCH:
283 case fuchsia::ui::input::PointerEventType::MOUSE:
285 default:
287 }
288}
289
290// TODO(SCN-1278): Remove this.
291// Turns two floats (high bits, low bits) into a 64-bit uint.
292static trace_flow_id_t PointerTraceHACK(float fa, float fb) {
293 uint32_t ia, ib;
294 memcpy(&ia, &fa, sizeof(uint32_t));
295 memcpy(&ib, &fb, sizeof(uint32_t));
296 return (((uint64_t)ia) << 32) | ib;
297}
298
299// For certain scenarios that must avoid floating-point drift, compute a
300// coordinate that falls within the logical view bounding box.
301std::array<float, 2> PlatformView::ClampToViewSpace(const float x,
302 const float y) const {
303 if (!view_logical_size_.has_value() || !view_logical_origin_.has_value()) {
304 return {x, y}; // If we can't do anything, return the original values.
305 }
306
307 const auto origin = view_logical_origin_.value();
308 const auto size = view_logical_size_.value();
309 const float min_x = origin[0];
310 const float max_x = origin[0] + size[0];
311 const float min_y = origin[1];
312 const float max_y = origin[1] + size[1];
313 if (min_x <= x && x < max_x && min_y <= y && y < max_y) {
314 return {x, y}; // No clamping to perform.
315 }
316
317 // View boundary is [min_x, max_x) x [min_y, max_y). Note that min is
318 // inclusive, but max is exclusive - so we subtract epsilon.
319 const float max_x_inclusive = max_x - std::numeric_limits<float>::epsilon();
320 const float max_y_inclusive = max_y - std::numeric_limits<float>::epsilon();
321 const float& clamped_x = std::clamp(x, min_x, max_x_inclusive);
322 const float& clamped_y = std::clamp(y, min_y, max_y_inclusive);
323 FML_LOG(INFO) << "Clamped (" << x << ", " << y << ") to (" << clamped_x
324 << ", " << clamped_y << ").";
325 return {clamped_x, clamped_y};
326}
327
328void PlatformView::OnGetLayout(fuchsia::ui::composition::LayoutInfo info) {
329 view_logical_size_ = {static_cast<float>(info.logical_size().width),
330 static_cast<float>(info.logical_size().height)};
331
332 if (info.has_device_pixel_ratio()) {
333 // Both values should be identical for the Vec2 for DPR.
334 FML_DCHECK(info.device_pixel_ratio().x == info.device_pixel_ratio().y);
335 view_pixel_ratio_ = info.device_pixel_ratio().x;
336 }
337
338 float pixel_ratio = view_pixel_ratio_ ? *view_pixel_ratio_ : 1.0f;
340 pixel_ratio, // device_pixel_ratio
341 std::round(view_logical_size_.value()[0] *
342 pixel_ratio), // physical_width
343 std::round(view_logical_size_.value()[1] *
344 pixel_ratio), // physical_height
345 0.0f, // physical_padding_top
346 0.0f, // physical_padding_right
347 0.0f, // physical_padding_bottom
348 0.0f, // physical_padding_left
349 0.0f, // physical_view_inset_top
350 0.0f, // physical_view_inset_right
351 0.0f, // physical_view_inset_bottom
352 0.0f, // physical_view_inset_left
353 0.0f, // p_physical_system_gesture_inset_top
354 0.0f, // p_physical_system_gesture_inset_right
355 0.0f, // p_physical_system_gesture_inset_bottom
356 0.0f, // p_physical_system_gesture_inset_left,
357 -1.0, // p_physical_touch_slop,
358 {}, // p_physical_display_features_bounds
359 {}, // p_physical_display_features_type
360 {}, // p_physical_display_features_state
361 0, // p_display_id
362 };
363 SetViewportMetrics(kFlutterImplicitViewId, metrics);
364
365 parent_viewport_watcher_->GetLayout(
366 fit::bind_member(this, &PlatformView::OnGetLayout));
367}
368
369void PlatformView::OnParentViewportStatus(
370 fuchsia::ui::composition::ParentViewportStatus status) {
371 // TODO(fxbug.dev/116001): Investigate if it is useful to send hidden/shown
372 // signals.
373 parent_viewport_status_ = status;
374 parent_viewport_watcher_->GetStatus(
375 fit::bind_member(this, &PlatformView::OnParentViewportStatus));
376}
377
378void PlatformView::OnChildViewStatus(
379 uint64_t content_id,
380 fuchsia::ui::composition::ChildViewStatus status) {
381 FML_DCHECK(child_view_info_.count(content_id) == 1);
382
383 std::ostringstream out;
384 out << "{" << "\"method\":\"View.viewStateChanged\"," << "\"args\":{"
385 << " \"viewId\":" << child_view_info_.at(content_id).view_id
386 << "," // ViewId
387 << " \"is_rendering\":true," // IsViewRendering
388 << " \"state\":true" // IsViewRendering
389 << " }" << "}";
390 auto call = out.str();
391
392 std::unique_ptr<flutter::PlatformMessage> message =
393 std::make_unique<flutter::PlatformMessage>(
394 "flutter/platform_views",
395 fml::MallocMapping::Copy(call.c_str(), call.size()), nullptr);
396 DispatchPlatformMessage(std::move(message));
397
398 child_view_info_.at(content_id)
399 .child_view_watcher->GetStatus(
400 [this, content_id](fuchsia::ui::composition::ChildViewStatus status) {
401 OnChildViewStatus(content_id, status);
402 });
403}
404
405void PlatformView::OnChildViewViewRef(uint64_t content_id,
406 uint64_t view_id,
407 fuchsia::ui::views::ViewRef view_ref) {
408 FML_CHECK(child_view_info_.count(content_id) == 1);
409
410 fuchsia::ui::views::ViewRef view_ref_clone;
411 fidl::Clone(view_ref, &view_ref_clone);
412
413 focus_delegate_->OnChildViewViewRef(view_id, std::move(view_ref));
414
415 pointer_injector_delegate_->OnCreateView(view_id, std::move(view_ref_clone));
416 OnChildViewConnected(content_id);
417}
418
419void PlatformView::OnCreateView(ViewCallback on_view_created,
420 int64_t view_id_raw,
421 bool hit_testable,
422 bool focusable) {
423 auto on_view_bound = [weak = weak_factory_.GetWeakPtr(),
424 platform_task_runner =
425 task_runners_.GetPlatformTaskRunner(),
426 view_id = view_id_raw](
427 fuchsia::ui::composition::ContentId content_id,
428 fuchsia::ui::composition::ChildViewWatcherHandle
429 child_view_watcher_handle) {
430 FML_CHECK(weak);
431 FML_CHECK(weak->child_view_info_.count(content_id.value) == 0);
432
433 platform_task_runner->PostTask(fml::MakeCopyable(
434 [weak, view_id, content_id,
435 watcher_handle = std::move(child_view_watcher_handle)]() mutable {
436 if (!weak) {
437 FML_LOG(WARNING)
438 << "View bound to PlatformView after PlatformView was "
439 "destroyed; ignoring.";
440 return;
441 }
442
443 // Bind the child view watcher to the platform thread so that the FIDL
444 // calls are handled on the platform thread.
445 fuchsia::ui::composition::ChildViewWatcherPtr child_view_watcher =
446 watcher_handle.Bind();
447 FML_CHECK(child_view_watcher);
448
449 child_view_watcher.set_error_handler([weak, view_id, content_id](
450 zx_status_t status) {
451 FML_LOG(WARNING)
452 << "Child disconnected. ChildViewWatcher status: " << status;
453
454 if (!weak) {
455 FML_LOG(WARNING) << "View bound to PlatformView after "
456 "PlatformView was "
457 "destroyed; ignoring.";
458 return;
459 }
460
461 // Disconnected views cannot listen to pointer events.
462 weak->pointer_injector_delegate_->OnDestroyView(view_id);
463
464 weak->OnChildViewDisconnected(content_id.value);
465 });
466
467 weak->child_view_info_.emplace(
468 std::piecewise_construct, std::forward_as_tuple(content_id.value),
469 std::forward_as_tuple(view_id, std::move(child_view_watcher)));
470
471 weak->child_view_info_.at(content_id.value)
472 .child_view_watcher->GetStatus(
473 [weak, id = content_id.value](
474 fuchsia::ui::composition::ChildViewStatus status) {
475 weak->OnChildViewStatus(id, status);
476 });
477
478 weak->child_view_info_.at(content_id.value)
479 .child_view_watcher->GetViewRef(
480 [weak, content_id = content_id.value,
481 view_id](fuchsia::ui::views::ViewRef view_ref) {
482 weak->OnChildViewViewRef(content_id, view_id,
483 std::move(view_ref));
484 });
485 }));
486 };
487
488 on_create_view_callback_(view_id_raw, std::move(on_view_created),
489 std::move(on_view_bound), hit_testable, focusable);
490}
491
492void PlatformView::OnDisposeView(int64_t view_id_raw) {
493 auto on_view_unbound =
494 [weak = weak_factory_.GetWeakPtr(),
495 platform_task_runner = task_runners_.GetPlatformTaskRunner(),
496 view_id_raw](fuchsia::ui::composition::ContentId content_id) {
497 platform_task_runner->PostTask([weak, content_id, view_id_raw]() {
498 if (!weak) {
499 FML_LOG(WARNING)
500 << "View unbound from PlatformView after PlatformView"
501 "was destroyed; ignoring.";
502 return;
503 }
504
505 FML_DCHECK(weak->child_view_info_.count(content_id.value) == 1);
506 weak->OnChildViewDisconnected(content_id.value);
507 weak->child_view_info_.erase(content_id.value);
508 weak->focus_delegate_->OnDisposeChildView(view_id_raw);
509 weak->pointer_injector_delegate_->OnDestroyView(view_id_raw);
510 });
511 };
512 on_destroy_view_callback_(view_id_raw, std::move(on_view_unbound));
513}
514
515void PlatformView::OnChildViewConnected(uint64_t content_id) {
516 FML_CHECK(child_view_info_.count(content_id) == 1);
517 std::ostringstream out;
518 out << "{" << "\"method\":\"View.viewConnected\"," << "\"args\":{"
519 << " \"viewId\":" << child_view_info_.at(content_id).view_id << " }"
520 << "}";
521 auto call = out.str();
522
523 std::unique_ptr<flutter::PlatformMessage> message =
524 std::make_unique<flutter::PlatformMessage>(
525 "flutter/platform_views",
526 fml::MallocMapping::Copy(call.c_str(), call.size()), nullptr);
527 DispatchPlatformMessage(std::move(message));
528}
529
530void PlatformView::OnChildViewDisconnected(uint64_t content_id) {
531 FML_CHECK(child_view_info_.count(content_id) == 1);
532 std::ostringstream out;
533 out << "{" << "\"method\":\"View.viewDisconnected\"," << "\"args\":{"
534 << " \"viewId\":" << child_view_info_.at(content_id).view_id << " }"
535 << "}";
536 auto call = out.str();
537
538 std::unique_ptr<flutter::PlatformMessage> message =
539 std::make_unique<flutter::PlatformMessage>(
540 "flutter/platform_views",
541 fml::MallocMapping::Copy(call.c_str(), call.size()), nullptr);
542 DispatchPlatformMessage(std::move(message));
543}
544
545bool PlatformView::OnHandlePointerEvent(
546 const fuchsia::ui::input::PointerEvent& pointer) {
547 TRACE_EVENT0("flutter", "PlatformView::OnHandlePointerEvent");
548
549 // TODO(SCN-1278): Use proper trace_id for tracing flow.
550 trace_flow_id_t trace_id =
551 PointerTraceHACK(pointer.radius_major, pointer.radius_minor);
552 TRACE_FLOW_END("input", "dispatch_event_to_client", trace_id);
553
554 const float pixel_ratio =
555 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
556
557 flutter::PointerData pointer_data;
558 pointer_data.Clear();
559 pointer_data.time_stamp = pointer.event_time / 1000;
560 pointer_data.change = GetChangeFromPointerEventPhase(pointer.phase);
561 pointer_data.kind = GetKindFromPointerType(pointer.type);
562 pointer_data.device = pointer.pointer_id;
563 // Pointer events are in logical pixels, so scale to physical.
564 pointer_data.physical_x = pointer.x * pixel_ratio;
565 pointer_data.physical_y = pointer.y * pixel_ratio;
566 // Buttons are single bit values starting with kMousePrimaryButton = 1.
567 pointer_data.buttons = static_cast<uint64_t>(pointer.buttons);
568
569 switch (pointer_data.change) {
571 // Make the pointer start in the view space, despite numerical drift.
572 auto clamped_pointer = ClampToViewSpace(pointer.x, pointer.y);
573 pointer_data.physical_x = clamped_pointer[0] * pixel_ratio;
574 pointer_data.physical_y = clamped_pointer[1] * pixel_ratio;
575
576 down_pointers_.insert(pointer_data.device);
577 break;
578 }
581 down_pointers_.erase(pointer_data.device);
582 break;
584 if (down_pointers_.count(pointer_data.device) == 0) {
586 }
587 break;
589 if (down_pointers_.count(pointer_data.device) != 0) {
590 FML_LOG(ERROR) << "Received add event for down pointer.";
591 }
592 break;
594 if (down_pointers_.count(pointer_data.device) != 0) {
595 FML_LOG(ERROR) << "Received remove event for down pointer.";
596 }
597 break;
599 if (down_pointers_.count(pointer_data.device) != 0) {
600 FML_LOG(ERROR) << "Received hover event for down pointer.";
601 }
602 break;
606 FML_DLOG(ERROR) << "Unexpectedly received pointer pan/zoom event";
607 break;
608 }
609
610 auto packet = std::make_unique<flutter::PointerDataPacket>(1);
611 packet->SetPointerData(0, pointer_data);
612 DispatchPointerDataPacket(std::move(packet));
613 return true;
614}
615
616// |flutter::PlatformView|
617std::unique_ptr<flutter::VsyncWaiter> PlatformView::CreateVSyncWaiter() {
618 return std::make_unique<flutter_runner::VsyncWaiter>(
619 await_vsync_callback_, await_vsync_for_secondary_callback_callback_,
621}
622
623// |flutter::PlatformView|
624std::unique_ptr<flutter::Surface> PlatformView::CreateRenderingSurface() {
625 return on_create_surface_callback_ ? on_create_surface_callback_() : nullptr;
626}
627
628// |flutter::PlatformView|
629std::shared_ptr<flutter::ExternalViewEmbedder>
630PlatformView::CreateExternalViewEmbedder() {
631 return external_view_embedder_;
632}
633
634// |flutter::PlatformView|
635void PlatformView::HandlePlatformMessage(
636 std::unique_ptr<flutter::PlatformMessage> message) {
637 if (!message) {
638 return;
639 }
640 const std::string channel = message->channel();
641 auto found = platform_message_handlers_.find(channel);
642 if (found == platform_message_handlers_.end()) {
643 const bool already_errored = unregistered_channels_.count(channel);
644 if (!already_errored) {
645 FML_LOG(INFO)
646 << "Platform view received message on channel '" << message->channel()
647 << "' with no registered handler. An empty response will be "
648 "generated. Please implement the native message handler. This "
649 "message will appear only once per channel.";
650 unregistered_channels_.insert(channel);
651 }
653 return;
654 }
655 auto response = message->response();
656 bool response_handled = found->second(std::move(message));
657
658 // Ensure all responses are completed.
659 if (response && !response_handled) {
660 // response_handled should be true if the response was completed.
661 FML_DCHECK(!response->is_complete());
662 response->CompleteEmpty();
663 }
664}
665
666// |flutter::PlatformView|
667void PlatformView::SetSemanticsEnabled(bool enabled) {
669 if (enabled) {
670 SetAccessibilityFeatures(static_cast<int32_t>(
672 } else {
673 SetAccessibilityFeatures(0);
674 }
675}
676
677// |flutter::PlatformView|
678void PlatformView::UpdateSemantics(
681 const float pixel_ratio =
682 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
683
684 on_semantics_node_update_callback_(update, pixel_ratio);
685}
686
687// Channel handler for kAccessibilityChannel
688bool PlatformView::HandleAccessibilityChannelPlatformMessage(
689 std::unique_ptr<flutter::PlatformMessage> message) {
690 FML_DCHECK(message->channel() == kAccessibilityChannel);
691
692 const flutter::StandardMessageCodec& standard_message_codec =
694 std::unique_ptr<flutter::EncodableValue> decoded =
695 standard_message_codec.DecodeMessage(message->data().GetMapping(),
696 message->data().GetSize());
697
698 flutter::EncodableMap map = std::get<flutter::EncodableMap>(*decoded);
699 std::string type =
700 std::get<std::string>(map.at(flutter::EncodableValue("type")));
701 if (type == "announce") {
702 flutter::EncodableMap data_map = std::get<flutter::EncodableMap>(
703 map.at(flutter::EncodableValue("data")));
704 std::string text =
705 std::get<std::string>(data_map.at(flutter::EncodableValue("message")));
706
707 on_request_announce_callback_(text);
708 }
709
710 // Complete with an empty response.
711 return false;
712}
713
714// Channel handler for kFlutterPlatformChannel
715bool PlatformView::HandleFlutterPlatformChannelPlatformMessage(
716 std::unique_ptr<flutter::PlatformMessage> message) {
718
719 // Fuchsia does not handle any platform messages at this time.
720
721 // Complete with an empty response.
722 return false;
723}
724
725bool PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage(
726 std::unique_ptr<flutter::PlatformMessage> message) {
727 FML_DCHECK(message->channel() == kFlutterPlatformViewsChannel);
728 const auto& data = message->data();
729 rapidjson::Document document;
730 document.Parse(reinterpret_cast<const char*>(data.GetMapping()),
731 data.GetSize());
732 if (document.HasParseError() || !document.IsObject()) {
733 FML_LOG(ERROR) << "Could not parse document";
734 return false;
735 }
736 auto root = document.GetObject();
737 auto method_member = root.FindMember("method");
738 if (method_member == root.MemberEnd() || !method_member->value.IsString()) {
739 return false;
740 }
741 std::string method(method_member->value.GetString());
742
743 if (method == "View.enableWireframe") {
744 auto args_it = root.FindMember("args");
745 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
746 FML_LOG(ERROR) << "No arguments found.";
747 return false;
748 }
749 const auto& args = args_it->value;
750
751 auto enable = args.FindMember("enable");
752 if (!enable->value.IsBool()) {
753 FML_LOG(ERROR) << "Argument 'enable' is not a bool";
754 return false;
755 }
756
757 wireframe_enabled_callback_(enable->value.GetBool());
758 } else if (method == "View.create") {
759 auto args_it = root.FindMember("args");
760 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
761 FML_LOG(ERROR) << "No arguments found.";
762 return false;
763 }
764 const auto& args = args_it->value;
765
766 auto view_id = args.FindMember("viewId");
767 if (!view_id->value.IsUint64()) {
768 FML_LOG(ERROR) << "Argument 'viewId' is not a int64";
769 return false;
770 }
771
772 auto hit_testable = args.FindMember("hitTestable");
773 if (!hit_testable->value.IsBool()) {
774 FML_LOG(ERROR) << "Argument 'hitTestable' is not a bool";
775 return false;
776 }
777
778 auto focusable = args.FindMember("focusable");
779 if (!focusable->value.IsBool()) {
780 FML_LOG(ERROR) << "Argument 'focusable' is not a bool";
781 return false;
782 }
783
784 auto on_view_created = fml::MakeCopyable(
785 [platform_task_runner = task_runners_.GetPlatformTaskRunner(),
786 message = std::move(message)]() {
787 // The client is waiting for view creation. Send an empty response
788 // back to signal the view was created.
789 if (message->response()) {
790 message->response()->Complete(std::make_unique<fml::DataMapping>(
791 std::vector<uint8_t>({'[', '0', ']'})));
792 }
793 });
794 OnCreateView(std::move(on_view_created), view_id->value.GetUint64(),
795 hit_testable->value.GetBool(), focusable->value.GetBool());
796 return true;
797 } else if (method == "View.update") {
798 auto args_it = root.FindMember("args");
799 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
800 FML_LOG(ERROR) << "No arguments found.";
801 return false;
802 }
803 const auto& args = args_it->value;
804
805 auto view_id = args.FindMember("viewId");
806 if (!view_id->value.IsUint64()) {
807 FML_LOG(ERROR) << "Argument 'viewId' is not a int64";
808 return false;
809 }
810
811 auto hit_testable = args.FindMember("hitTestable");
812 if (!hit_testable->value.IsBool()) {
813 FML_LOG(ERROR) << "Argument 'hitTestable' is not a bool";
814 return false;
815 }
816
817 auto focusable = args.FindMember("focusable");
818 if (!focusable->value.IsBool()) {
819 FML_LOG(ERROR) << "Argument 'focusable' is not a bool";
820 return false;
821 }
822
823 SkRect view_occlusion_hint_raw = SkRect::MakeEmpty();
824 auto view_occlusion_hint = args.FindMember("viewOcclusionHintLTRB");
825 if (view_occlusion_hint != args.MemberEnd()) {
826 if (view_occlusion_hint->value.IsArray()) {
827 const auto& view_occlusion_hint_array =
828 view_occlusion_hint->value.GetArray();
829 if (view_occlusion_hint_array.Size() == 4) {
830 bool parse_error = false;
831 for (int i = 0; i < 4; i++) {
832 auto& array_val = view_occlusion_hint_array[i];
833 if (!array_val.IsDouble()) {
834 FML_LOG(ERROR) << "Argument 'viewOcclusionHintLTRB' element " << i
835 << " is not a double";
836 parse_error = true;
837 break;
838 }
839 }
840
841 if (!parse_error) {
842 view_occlusion_hint_raw =
843 SkRect::MakeLTRB(view_occlusion_hint_array[0].GetDouble(),
844 view_occlusion_hint_array[1].GetDouble(),
845 view_occlusion_hint_array[2].GetDouble(),
846 view_occlusion_hint_array[3].GetDouble());
847 }
848 } else {
850 << "Argument 'viewOcclusionHintLTRB' expected size 4; got "
851 << view_occlusion_hint_array.Size();
852 }
853 } else {
855 << "Argument 'viewOcclusionHintLTRB' is not a double array";
856 }
857 } else {
858 FML_LOG(WARNING) << "Argument 'viewOcclusionHintLTRB' is missing";
859 }
860
861 on_update_view_callback_(
862 view_id->value.GetUint64(), view_occlusion_hint_raw,
863 hit_testable->value.GetBool(), focusable->value.GetBool());
864 if (message->response()) {
865 message->response()->Complete(std::make_unique<fml::DataMapping>(
866 std::vector<uint8_t>({'[', '0', ']'})));
867 return true;
868 }
869 } else if (method == "View.dispose") {
870 auto args_it = root.FindMember("args");
871 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
872 FML_LOG(ERROR) << "No arguments found.";
873 return false;
874 }
875 const auto& args = args_it->value;
876
877 auto view_id = args.FindMember("viewId");
878 if (!view_id->value.IsUint64()) {
879 FML_LOG(ERROR) << "Argument 'viewId' is not a int64";
880 return false;
881 }
882
883 OnDisposeView(view_id->value.GetUint64());
884 if (message->response()) {
885 message->response()->Complete(std::make_unique<fml::DataMapping>(
886 std::vector<uint8_t>({'[', '0', ']'})));
887 return true;
888 }
889 } else if (method.rfind("View.focus", 0) == 0) {
890 return focus_delegate_->HandlePlatformMessage(root, message->response());
891 } else if (method.rfind(PointerInjectorDelegate::kPointerInjectorMethodPrefix,
892 0) == 0) {
893 return pointer_injector_delegate_->HandlePlatformMessage(
894 root, message->response());
895 } else {
896 FML_LOG(ERROR) << "Unknown " << message->channel() << " method " << method;
897 }
898 // Complete with an empty response by default.
899 return false;
900}
901
902bool PlatformView::HandleFuchsiaShaderWarmupChannelPlatformMessage(
903 OnShaderWarmupCallback on_shader_warmup_callback,
904 std::unique_ptr<flutter::PlatformMessage> message) {
905 FML_DCHECK(message->channel() == kFuchsiaShaderWarmupChannel);
906
907 if (!on_shader_warmup_callback) {
908 FML_LOG(ERROR) << "No shader warmup callback set!";
909 std::string result = "[0]";
910 message->response()->Complete(
911 std::make_unique<fml::DataMapping>(std::vector<uint8_t>(
912 (const uint8_t*)result.c_str(),
913 (const uint8_t*)result.c_str() + result.length())));
914 return true;
915 }
916
917 const auto& data = message->data();
918 rapidjson::Document document;
919 document.Parse(reinterpret_cast<const char*>(data.GetMapping()),
920 data.GetSize());
921 if (document.HasParseError() || !document.IsObject()) {
922 FML_LOG(ERROR) << "Could not parse document";
923 return false;
924 }
925 auto root = document.GetObject();
926 auto method = root.FindMember("method");
927 if (method == root.MemberEnd() || !method->value.IsString() ||
928 method->value != "WarmupSkps") {
929 FML_LOG(ERROR) << "Invalid method name";
930 return false;
931 }
932
933 auto args_it = root.FindMember("args");
934 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
935 FML_LOG(ERROR) << "No arguments found.";
936 return false;
937 }
938
939 auto shaders_it = root["args"].FindMember("shaders");
940 if (shaders_it == root["args"].MemberEnd() || !shaders_it->value.IsArray()) {
941 FML_LOG(ERROR) << "No shaders found.";
942 return false;
943 }
944
945 auto width_it = root["args"].FindMember("width");
946 auto height_it = root["args"].FindMember("height");
947 if (width_it == root["args"].MemberEnd() || !width_it->value.IsNumber()) {
948 FML_LOG(ERROR) << "Invalid width";
949 return false;
950 }
951 if (height_it == root["args"].MemberEnd() || !height_it->value.IsNumber()) {
952 FML_LOG(ERROR) << "Invalid height";
953 return false;
954 }
955 auto width = width_it->value.GetUint64();
956 auto height = height_it->value.GetUint64();
957
958 std::vector<std::string> skp_paths;
959 const auto& shaders = shaders_it->value;
960 for (rapidjson::Value::ConstValueIterator itr = shaders.Begin();
961 itr != shaders.End(); ++itr) {
962 skp_paths.push_back((*itr).GetString());
963 }
964
965 auto completion_callback = [response =
966 message->response()](uint32_t num_successes) {
967 std::ostringstream result_stream;
968 result_stream << "[" << num_successes << "]";
969
970 std::string result(result_stream.str());
971
972 response->Complete(std::make_unique<fml::DataMapping>(std::vector<uint8_t>(
973 (const uint8_t*)result.c_str(),
974 (const uint8_t*)result.c_str() + result.length())));
975 };
976
977 on_shader_warmup_callback(skp_paths, completion_callback, width, height);
978 // The response has already been completed by us.
979 return true;
980}
981
982// Channel handler for kFuchsiaInputTestChannel
983bool PlatformView::HandleFuchsiaInputTestChannelPlatformMessage(
984 std::unique_ptr<flutter::PlatformMessage> message) {
985 FML_DCHECK(message->channel() == kFuchsiaInputTestChannel);
986
987 const auto& data = message->data();
988 rapidjson::Document document;
989 document.Parse(reinterpret_cast<const char*>(data.GetMapping()),
990 data.GetSize());
991 if (document.HasParseError() || !document.IsObject()) {
992 FML_LOG(ERROR) << "Could not parse document";
993 return false;
994 }
995 auto root = document.GetObject();
996 auto method = root.FindMember("method");
997 if (method == root.MemberEnd() || !method->value.IsString()) {
998 FML_LOG(ERROR) << "Missing method";
999 return false;
1000 }
1001
1002 FML_LOG(INFO) << "fuchsia/input_test: method=" << method->value.GetString();
1003
1004 if (method->value == "TouchInputListener.ReportTouchInput") {
1005 if (!touch_input_listener_) {
1006 FML_LOG(ERROR) << "TouchInputListener not found.";
1007 return false;
1008 }
1009
1010 fuchsia::ui::test::input::TouchInputListenerReportTouchInputRequest request;
1011 CallWithMember<double>(
1012 root, "local_x", [&](double local_x) { request.set_local_x(local_x); });
1013 CallWithMember<double>(
1014 root, "local_y", [&](double local_y) { request.set_local_y(local_y); });
1015 CallWithMember<int64_t>(root, "time_received", [&](uint64_t time_received) {
1016 request.set_time_received(time_received);
1017 });
1018 CallWithMember<std::string>(root, "component_name",
1019 [&](std::string component_name) {
1020 request.set_component_name(component_name);
1021 });
1022
1023 touch_input_listener_->ReportTouchInput(std::move(request));
1024 return true;
1025 }
1026
1027 if (method->value == "KeyboardInputListener.ReportTextInput") {
1028 if (!keyboard_input_listener_) {
1029 FML_LOG(ERROR) << "KeyboardInputListener not found.";
1030 return false;
1031 }
1032
1033 fuchsia::ui::test::input::KeyboardInputListenerReportTextInputRequest
1034 request;
1035 CallWithMember<std::string>(
1036 root, "text", [&](std::string text) { request.set_text(text); });
1037
1038 keyboard_input_listener_->ReportTextInput(std::move(request));
1039 return true;
1040 }
1041
1042 if (method->value == "MouseInputListener.ReportMouseInput") {
1043 if (!mouse_input_listener_) {
1044 FML_LOG(ERROR) << "MouseInputListener not found.";
1045 return false;
1046 }
1047
1048 fuchsia::ui::test::input::MouseInputListenerReportMouseInputRequest request;
1049 CallWithMember<double>(
1050 root, "local_x", [&](double local_x) { request.set_local_x(local_x); });
1051 CallWithMember<double>(
1052 root, "local_y", [&](double local_y) { request.set_local_y(local_y); });
1053 CallWithMember<int64_t>(root, "time_received", [&](uint64_t time_received) {
1054 request.set_time_received(time_received);
1055 });
1056 CallWithMember<std::string>(root, "component_name",
1057 [&](std::string component_name) {
1058 request.set_component_name(component_name);
1059 });
1060 CallWithMember<int>(root, "buttons", [&](int button_mask) {
1061 std::vector<fuchsia::ui::test::input::MouseButton> buttons;
1062 if (button_mask & 1) {
1063 buttons.push_back(fuchsia::ui::test::input::MouseButton::FIRST);
1064 }
1065 if (button_mask & 2) {
1066 buttons.push_back(fuchsia::ui::test::input::MouseButton::SECOND);
1067 }
1068 if (button_mask & 4) {
1069 buttons.push_back(fuchsia::ui::test::input::MouseButton::THIRD);
1070 }
1071 request.set_buttons(buttons);
1072 });
1073 CallWithMember<std::string>(root, "phase", [&](std::string phase) {
1074 if (phase == "add") {
1075 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::ADD);
1076 } else if (phase == "hover") {
1077 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::HOVER);
1078 } else if (phase == "down") {
1079 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::DOWN);
1080 } else if (phase == "move") {
1081 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::MOVE);
1082 } else if (phase == "up") {
1083 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::UP);
1084 } else {
1085 FML_LOG(ERROR) << "Unexpected mouse phase: " << phase;
1086 }
1087 });
1088 CallWithMember<double>(
1089 root, "wheel_x_physical_pixel", [&](double wheel_x_physical_pixel) {
1090 request.set_wheel_x_physical_pixel(wheel_x_physical_pixel);
1091 });
1092 CallWithMember<double>(
1093 root, "wheel_y_physical_pixel", [&](double wheel_y_physical_pixel) {
1094 request.set_wheel_y_physical_pixel(wheel_y_physical_pixel);
1095 });
1096
1097 mouse_input_listener_->ReportMouseInput(std::move(request));
1098 return true;
1099 }
1100
1101 FML_LOG(ERROR) << "fuchsia/input_test: unrecognized method "
1102 << method->value.GetString();
1103 return false;
1104}
1105
1106// Channel handler for kFuchsiaChildViewChannel
1107bool PlatformView::HandleFuchsiaChildViewChannelPlatformMessage(
1108 std::unique_ptr<flutter::PlatformMessage> message) {
1109 FML_DCHECK(message->channel() == kFuchsiaChildViewChannel);
1110
1111 if (message->data().GetSize() != 1 ||
1112 (message->data().GetMapping()[0] != '1')) {
1114 << " data must be singularly '1'.";
1115 return false;
1116 }
1117
1118 FML_DCHECK(message->data().GetMapping()[0] == '1');
1119
1120 if (!message->response()) {
1122 << " must have a response callback.";
1123 return false;
1124 }
1125
1126 if (!dart_application_svc_) {
1127 FML_LOG(ERROR) << "No service directory.";
1128 return false;
1129 }
1130
1131 fuchsia::ui::app::ViewProviderHandle view_provider_handle;
1132 zx_status_t status =
1133 dart_application_svc_->Connect(view_provider_handle.NewRequest());
1134 if (status != ZX_OK) {
1135 FML_LOG(ERROR) << "Failed to connect to view provider.";
1136 return false;
1137 }
1138 fuchsia::ui::app::ViewProviderPtr view_provider;
1139 view_provider.Bind(std::move(view_provider_handle));
1140
1141 zx::handle view_id;
1142
1143 zx::channel view_tokens[2];
1144 fuchsia::ui::views::ViewportCreationToken viewport_creation_token;
1145 fuchsia::ui::views::ViewCreationToken view_creation_token;
1146 status = zx::channel::create(0, &viewport_creation_token.value,
1147 &view_creation_token.value);
1148 if (status != ZX_OK) {
1149 FML_LOG(ERROR) << "Creating view tokens: " << zx_status_get_string(status);
1150 return false;
1151 }
1152
1153 fuchsia::ui::app::CreateView2Args create_view_args;
1154 create_view_args.set_view_creation_token(std::move(view_creation_token));
1155 view_provider->CreateView2(std::move(create_view_args));
1156
1157 view_id = std::move(viewport_creation_token.value);
1158
1159 if (view_id) {
1160 message->response()->Complete(
1161 std::make_unique<fml::DataMapping>(std::to_string(view_id.release())
1162
1163 ));
1164 return true;
1165 } else {
1166 return false;
1167 }
1168}
1169
1170} // namespace flutter_runner
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
std::unique_ptr< T > DecodeMessage(const uint8_t *binary_message, const size_t message_size) const
Used to forward events from the platform view to interested subsystems. This forwarding is done by th...
virtual void HandlePlatformMessage(std::unique_ptr< PlatformMessage > message)
Overridden by embedders to perform actions in response to platform messages sent from the framework t...
virtual void SetSemanticsEnabled(bool enabled)
Used by embedder to notify the running isolate hosted by the engine on the UI thread that the accessi...
static const StandardMessageCodec & GetInstance(const StandardCodecSerializer *serializer=nullptr)
PlatformView(flutter::PlatformView::Delegate &delegate, flutter::TaskRunners task_runners, fuchsia::ui::views::ViewRef view_ref, std::shared_ptr< flutter::ExternalViewEmbedder > external_view_embedder, fuchsia::ui::input::ImeServiceHandle ime_service, fuchsia::ui::input3::KeyboardHandle keyboard, fuchsia::ui::pointer::TouchSourceHandle touch_source, fuchsia::ui::pointer::MouseSourceHandle mouse_source, fuchsia::ui::views::FocuserHandle focuser, fuchsia::ui::views::ViewRefFocusedHandle view_ref_focused, fuchsia::ui::composition::ParentViewportWatcherHandle parent_viewport_watcher, fuchsia::ui::pointerinjector::RegistryHandle pointerinjector_registry, OnEnableWireframeCallback wireframe_enabled_callback, OnCreateViewCallback on_create_view_callback, OnUpdateViewCallback on_update_view_callback, OnDestroyViewCallback on_destroy_view_callback, OnCreateSurfaceCallback on_create_surface_callback, OnSemanticsNodeUpdateCallback on_semantics_node_update_callback, OnRequestAnnounceCallback on_request_announce_callback, OnShaderWarmupCallback on_shader_warmup_callback, AwaitVsyncCallback await_vsync_callback, AwaitVsyncForSecondaryCallbackCallback await_vsync_for_secondary_callback_callback, std::shared_ptr< sys::ServiceDirectory > dart_application_svc)
void OnGetLayout(fuchsia::ui::composition::LayoutInfo info)
void OnParentViewportStatus(fuchsia::ui::composition::ParentViewportStatus status)
static MallocMapping Copy(const T *begin, const T *end)
Definition mapping.h:162
TaskRunners task_runners_
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent * event
GAsyncResult * result
#define FML_DLOG(severity)
Definition logging.h:102
#define FML_LOG(severity)
Definition logging.h:82
#define FML_CHECK(condition)
Definition logging.h:85
#define FML_DCHECK(condition)
Definition logging.h:103
std::u16string text
Win32Message message
NSString *const kFlutterPlatformChannel
static NSString *const kTextInputChannel
double y
double x
call(args)
Definition dom.py:159
static constexpr char kFuchsiaChildViewChannel[]
std::function< void(const std::vector< std::string > &, std::function< void(uint32_t)>, uint64_t, uint64_t)> OnShaderWarmupCallback
fit::function< void(int64_t, ViewCallback, ViewCreatedCallback, bool, bool)> OnCreateViewCallback
fit::function< void(int64_t, ViewIdCallback)> OnDestroyViewCallback
fit::function< void(int64_t, SkRect, bool, bool)> OnUpdateViewCallback
fit::function< std::unique_ptr< flutter::Surface >()> OnCreateSurfaceCallback
static constexpr char kFuchsiaShaderWarmupChannel[]
std::function< void()> ViewCallback
std::function< void(FireCallbackCallback)> AwaitVsyncForSecondaryCallbackCallback
fit::function< void(flutter::SemanticsNodeUpdates, float)> OnSemanticsNodeUpdateCallback
static flutter::PointerData::DeviceKind GetKindFromPointerType(fuchsia::ui::input::PointerEventType type)
static trace_flow_id_t PointerTraceHACK(float fa, float fb)
static constexpr char kAccessibilityChannel[]
static flutter::PointerData::Change GetChangeFromPointerEventPhase(fuchsia::ui::input::PointerEventPhase phase)
static constexpr char kFuchsiaInputTestChannel[]
static constexpr int64_t kFlutterImplicitViewId
static constexpr char kFlutterPlatformChannel[]
std::function< void(FireCallbackCallback)> AwaitVsyncCallback
static constexpr char kFlutterPlatformViewsChannel[]
fit::function< void(std::string)> OnRequestAnnounceCallback
fit::function< void(bool)> OnEnableWireframeCallback
std::unordered_map< int32_t, SemanticsNode > SemanticsNodeUpdates
std::unordered_map< int32_t, CustomAccessibilityAction > CustomAccessibilityActionUpdates
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
std::map< EncodableValue, EncodableValue > EncodableMap
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition switches.h:259
internal::CopyableLambda< T > MakeCopyable(T lambda)
Definition ref_ptr.h:256
int32_t height
int32_t width
Definition SkMD5.cpp:120
static constexpr SkRect MakeEmpty()
Definition SkRect.h:595
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition SkRect.h:646
#define ERROR(message)
#define TRACE_EVENT0(category_group, name)
#define TRACE_FLOW_END(category, name, id)