5#define RAPIDJSON_HAS_STDSTRING 1
9#include <fuchsia/ui/app/cpp/fidl.h>
10#include <zircon/status.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"
34template <
typename T,
typename O,
typename F>
35bool CallWithMember(O obj,
const char* member_name, F func) {
36 auto it = obj.FindMember(member_name);
37 if (it == obj.MemberEnd()) {
40 if (!it->value.template Is<T>()) {
43 func(it->value.template Get<T>());
61 fuchsia::ui::views::ViewRef view_ref,
62 std::shared_ptr<flutter::ExternalViewEmbedder> external_view_embedder,
63 fuchsia::ui::input::ImeServiceHandle ime_service,
64 fuchsia::ui::input3::KeyboardHandle keyboard,
65 fuchsia::ui::pointer::TouchSourceHandle touch_source,
66 fuchsia::ui::pointer::MouseSourceHandle mouse_source,
67 fuchsia::ui::views::FocuserHandle focuser,
68 fuchsia::ui::views::ViewRefFocusedHandle view_ref_focused,
69 fuchsia::ui::composition::ParentViewportWatcherHandle
70 parent_viewport_watcher,
71 fuchsia::ui::pointerinjector::RegistryHandle pointerinjector_registry,
82 await_vsync_for_secondary_callback_callback,
83 std::shared_ptr<sys::ServiceDirectory> dart_application_svc)
85 external_view_embedder_(external_view_embedder),
91 std::move(mouse_source))),
92 wireframe_enabled_callback_(
std::move(wireframe_enabled_callback)),
93 on_update_view_callback_(
std::move(on_update_view_callback)),
94 on_create_surface_callback_(
std::move(on_create_surface_callback)),
95 on_semantics_node_update_callback_(
96 std::move(on_semantics_node_update_callback)),
97 on_request_announce_callback_(
std::move(on_request_announce_callback)),
98 on_create_view_callback_(
std::move(on_create_view_callback)),
99 on_destroy_view_callback_(
std::move(on_destroy_view_callback)),
100 on_shader_warmup_callback_(
std::move(on_shader_warmup_callback)),
101 await_vsync_callback_(await_vsync_callback),
102 await_vsync_for_secondary_callback_callback_(
103 await_vsync_for_secondary_callback_callback),
104 dart_application_svc_(dart_application_svc),
105 parent_viewport_watcher_(parent_viewport_watcher.Bind()),
106 weak_factory_(this) {
107 fuchsia::ui::views::ViewRef view_ref_clone;
108 fidl::Clone(view_ref, &view_ref_clone);
111 std::make_unique<TextDelegate>(
112 std::move(view_ref), std::move(ime_service), std::move(keyboard),
113 [weak = weak_factory_.GetWeakPtr()](
114 std::unique_ptr<flutter::PlatformMessage>
message) {
117 <<
"PlatformView use-after-free attempted. Ignoring.";
119 weak->delegate_.OnPlatformViewDispatchPlatformMessage(
124 focus_delegate_->WatchLoop([weak = weak_factory_.GetWeakPtr()](
bool focused) {
126 FML_LOG(WARNING) <<
"PlatformView use-after-free attempted. Ignoring.";
132 if (focused && weak->text_delegate_->HasTextState()) {
133 weak->text_delegate_->ActivateIme();
134 }
else if (!focused) {
135 weak->text_delegate_->DeactivateIme();
140 pointer_delegate_->WatchLoop([weak = weak_factory_.GetWeakPtr()](
141 std::vector<flutter::PointerData> events) {
143 FML_LOG(WARNING) <<
"PlatformView use-after-free attempted. Ignoring.";
147 if (events.empty()) {
152 const float pixel_ratio = weak->view_pixel_ratio_.value_or(1.f);
153 auto packet = std::make_unique<flutter::PointerDataPacket>(events.size());
154 for (
size_t i = 0;
i < events.size(); ++
i) {
155 auto&
event = events[
i];
159 event.physical_x =
event.physical_x * pixel_ratio;
160 event.physical_y =
event.physical_y * pixel_ratio;
161 packet->SetPointerData(
i, event);
163 weak->DispatchPointerDataPacket(std::move(packet));
167 pointer_injector_delegate_ = std::make_unique<PointerInjectorDelegate>(
168 std::move(pointerinjector_registry), std::move(view_ref_clone));
171 if (dart_application_svc) {
173 fuchsia::ui::test::input::TouchInputListenerHandle touch_input_listener;
174 zx_status_t touch_input_listener_status =
176 ->Connect<fuchsia::ui::test::input::TouchInputListener>(
177 touch_input_listener.NewRequest());
178 if (touch_input_listener_status != ZX_OK) {
180 <<
"fuchsia::ui::test::input::TouchInputListener connection failed: "
181 << zx_status_get_string(touch_input_listener_status);
183 touch_input_listener_.Bind(std::move(touch_input_listener));
187 fuchsia::ui::test::input::KeyboardInputListenerHandle
188 keyboard_input_listener;
189 zx_status_t keyboard_input_listener_status =
191 ->Connect<fuchsia::ui::test::input::KeyboardInputListener>(
192 keyboard_input_listener.NewRequest());
193 if (keyboard_input_listener_status != ZX_OK) {
194 FML_LOG(WARNING) <<
"fuchsia::ui::test::input::KeyboardInputListener "
195 "connection failed: "
196 << zx_status_get_string(keyboard_input_listener_status);
198 keyboard_input_listener_.Bind(std::move(keyboard_input_listener));
201 fuchsia::ui::test::input::MouseInputListenerHandle mouse_input_listener;
202 zx_status_t mouse_input_listener_status =
204 ->Connect<fuchsia::ui::test::input::MouseInputListener>(
205 mouse_input_listener.NewRequest());
206 if (mouse_input_listener_status != ZX_OK) {
208 <<
"fuchsia::ui::test::input::MouseInputListener connection failed: "
209 << zx_status_get_string(mouse_input_listener_status);
211 mouse_input_listener_.Bind(std::move(mouse_input_listener));
216 RegisterPlatformMessageHandlers();
218 parent_viewport_watcher_.set_error_handler([](zx_status_t status) {
219 FML_LOG(ERROR) <<
"Interface error on: ParentViewportWatcher status: "
223 parent_viewport_watcher_->GetLayout(
225 parent_viewport_watcher_->GetStatus(
229PlatformView::~PlatformView() =
default;
231void PlatformView::RegisterPlatformMessageHandlers() {
233 std::bind(&PlatformView::HandleFlutterPlatformChannelPlatformMessage,
234 this, std::placeholders::_1);
236 std::bind(&TextDelegate::HandleFlutterTextInputChannelPlatformMessage,
237 text_delegate_.get(), std::placeholders::_1);
239 std::bind(&PlatformView::HandleAccessibilityChannelPlatformMessage,
this,
240 std::placeholders::_1);
242 std::bind(&PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage,
243 this, std::placeholders::_1);
245 std::bind(&HandleFuchsiaShaderWarmupChannelPlatformMessage,
246 on_shader_warmup_callback_, std::placeholders::_1);
248 std::bind(&PlatformView::HandleFuchsiaInputTestChannelPlatformMessage,
249 this, std::placeholders::_1);
251 std::bind(&PlatformView::HandleFuchsiaChildViewChannelPlatformMessage,
252 this, std::placeholders::_1);
256 fuchsia::ui::input::PointerEventPhase phase) {
258 case fuchsia::ui::input::PointerEventPhase::ADD:
260 case fuchsia::ui::input::PointerEventPhase::HOVER:
262 case fuchsia::ui::input::PointerEventPhase::DOWN:
264 case fuchsia::ui::input::PointerEventPhase::MOVE:
266 case fuchsia::ui::input::PointerEventPhase::UP:
268 case fuchsia::ui::input::PointerEventPhase::REMOVE:
270 case fuchsia::ui::input::PointerEventPhase::CANCEL:
278 fuchsia::ui::input::PointerEventType
type) {
280 case fuchsia::ui::input::PointerEventType::TOUCH:
282 case fuchsia::ui::input::PointerEventType::MOUSE:
293 memcpy(&ia, &fa,
sizeof(uint32_t));
294 memcpy(&ib, &fb,
sizeof(uint32_t));
295 return (((uint64_t)ia) << 32) | ib;
300std::array<float, 2> PlatformView::ClampToViewSpace(
const float x,
301 const float y)
const {
302 if (!view_logical_size_.has_value() || !view_logical_origin_.has_value()) {
306 const auto origin = view_logical_origin_.value();
307 const auto size = view_logical_size_.value();
308 const float min_x = origin[0];
309 const float max_x = origin[0] +
size[0];
310 const float min_y = origin[1];
311 const float max_y = origin[1] +
size[1];
312 if (min_x <=
x &&
x < max_x && min_y <=
y &&
y < max_y) {
318 const float max_x_inclusive = max_x - std::numeric_limits<float>::epsilon();
319 const float max_y_inclusive = max_y - std::numeric_limits<float>::epsilon();
320 const float& clamped_x = std::clamp(
x, min_x, max_x_inclusive);
321 const float& clamped_y = std::clamp(
y, min_y, max_y_inclusive);
322 FML_LOG(INFO) <<
"Clamped (" <<
x <<
", " <<
y <<
") to (" << clamped_x
323 <<
", " << clamped_y <<
").";
324 return {clamped_x, clamped_y};
327void PlatformView::OnGetLayout(fuchsia::ui::composition::LayoutInfo info) {
328 view_logical_size_ = {
static_cast<float>(info.logical_size().width),
329 static_cast<float>(info.logical_size().height)};
331 if (info.has_device_pixel_ratio()) {
333 FML_DCHECK(info.device_pixel_ratio().x == info.device_pixel_ratio().y);
334 view_pixel_ratio_ = info.device_pixel_ratio().x;
337 float pixel_ratio = view_pixel_ratio_ ? *view_pixel_ratio_ : 1.0f;
340 std::round(view_logical_size_.value()[0] *
342 std::round(view_logical_size_.value()[1] *
344 std::round(view_logical_size_.value()[0] *
346 std::round(view_logical_size_.value()[0] *
348 std::round(view_logical_size_.value()[1] *
350 std::round(view_logical_size_.value()[1] *
374 SetViewportMetrics(kFlutterImplicitViewId, metrics);
376 parent_viewport_watcher_->GetLayout(
377 fit::bind_member(
this, &PlatformView::OnGetLayout));
380void PlatformView::OnParentViewportStatus(
381 fuchsia::ui::composition::ParentViewportStatus status) {
384 parent_viewport_status_ = status;
385 parent_viewport_watcher_->GetStatus(
386 fit::bind_member(
this, &PlatformView::OnParentViewportStatus));
389void PlatformView::OnChildViewStatus(
391 fuchsia::ui::composition::ChildViewStatus status) {
392 FML_DCHECK(child_view_info_.count(content_id) == 1);
394 std::ostringstream out;
395 out <<
"{" <<
"\"method\":\"View.viewStateChanged\"," <<
"\"args\":{"
396 <<
" \"viewId\":" << child_view_info_.at(content_id).view_id
398 <<
" \"is_rendering\":true,"
401 auto call = out.str();
403 std::unique_ptr<flutter::PlatformMessage>
message =
404 std::make_unique<flutter::PlatformMessage>(
405 "flutter/platform_views",
407 DispatchPlatformMessage(std::move(
message));
409 child_view_info_.at(content_id)
410 .child_view_watcher->GetStatus(
411 [
this, content_id](fuchsia::ui::composition::ChildViewStatus status) {
412 OnChildViewStatus(content_id, status);
416void PlatformView::OnChildViewViewRef(uint64_t content_id,
418 fuchsia::ui::views::ViewRef view_ref) {
419 FML_CHECK(child_view_info_.count(content_id) == 1);
421 fuchsia::ui::views::ViewRef view_ref_clone;
422 fidl::Clone(view_ref, &view_ref_clone);
424 focus_delegate_->OnChildViewViewRef(
view_id, std::move(view_ref));
426 pointer_injector_delegate_->OnCreateView(
view_id, std::move(view_ref_clone));
427 OnChildViewConnected(content_id);
430void PlatformView::OnCreateView(
ViewCallback on_view_created,
434 auto on_view_bound = [weak = weak_factory_.GetWeakPtr(),
435 platform_task_runner =
438 fuchsia::ui::composition::ContentId content_id,
439 fuchsia::ui::composition::ChildViewWatcherHandle
440 child_view_watcher_handle) {
442 FML_CHECK(weak->child_view_info_.count(content_id.value) == 0);
446 watcher_handle = std::move(child_view_watcher_handle)]()
mutable {
449 <<
"View bound to PlatformView after PlatformView was "
450 "destroyed; ignoring.";
456 fuchsia::ui::composition::ChildViewWatcherPtr child_view_watcher =
457 watcher_handle.Bind();
460 child_view_watcher.set_error_handler([weak,
view_id, content_id](
461 zx_status_t status) {
463 <<
"Child disconnected. ChildViewWatcher status: " << status;
466 FML_LOG(WARNING) <<
"View bound to PlatformView after "
468 "destroyed; ignoring.";
473 weak->pointer_injector_delegate_->OnDestroyView(
view_id);
475 weak->OnChildViewDisconnected(content_id.value);
478 weak->child_view_info_.emplace(
479 std::piecewise_construct, std::forward_as_tuple(content_id.value),
480 std::forward_as_tuple(
view_id, std::move(child_view_watcher)));
482 weak->child_view_info_.at(content_id.value)
483 .child_view_watcher->GetStatus(
484 [weak,
id = content_id.value](
485 fuchsia::ui::composition::ChildViewStatus status) {
486 weak->OnChildViewStatus(
id, status);
489 weak->child_view_info_.at(content_id.value)
490 .child_view_watcher->GetViewRef(
491 [weak, content_id = content_id.value,
492 view_id](fuchsia::ui::views::ViewRef view_ref) {
493 weak->OnChildViewViewRef(content_id,
view_id,
494 std::move(view_ref));
499 on_create_view_callback_(view_id_raw, std::move(on_view_created),
500 std::move(on_view_bound), hit_testable, focusable);
503void PlatformView::OnDisposeView(int64_t view_id_raw) {
504 auto on_view_unbound =
505 [weak = weak_factory_.GetWeakPtr(),
506 platform_task_runner =
task_runners_.GetPlatformTaskRunner(),
507 view_id_raw](fuchsia::ui::composition::ContentId content_id) {
508 platform_task_runner->PostTask([weak, content_id, view_id_raw]() {
511 <<
"View unbound from PlatformView after PlatformView"
512 "was destroyed; ignoring.";
516 FML_DCHECK(weak->child_view_info_.count(content_id.value) == 1);
517 weak->OnChildViewDisconnected(content_id.value);
518 weak->child_view_info_.erase(content_id.value);
519 weak->focus_delegate_->OnDisposeChildView(view_id_raw);
520 weak->pointer_injector_delegate_->OnDestroyView(view_id_raw);
523 on_destroy_view_callback_(view_id_raw, std::move(on_view_unbound));
526void PlatformView::OnChildViewConnected(uint64_t content_id) {
527 FML_CHECK(child_view_info_.count(content_id) == 1);
528 std::ostringstream out;
529 out <<
"{" <<
"\"method\":\"View.viewConnected\"," <<
"\"args\":{"
530 <<
" \"viewId\":" << child_view_info_.at(content_id).view_id <<
" }"
532 auto call = out.str();
534 std::unique_ptr<flutter::PlatformMessage>
message =
535 std::make_unique<flutter::PlatformMessage>(
536 "flutter/platform_views",
538 DispatchPlatformMessage(std::move(
message));
541void PlatformView::OnChildViewDisconnected(uint64_t content_id) {
542 FML_CHECK(child_view_info_.count(content_id) == 1);
543 std::ostringstream out;
544 out <<
"{" <<
"\"method\":\"View.viewDisconnected\"," <<
"\"args\":{"
545 <<
" \"viewId\":" << child_view_info_.at(content_id).view_id <<
" }"
547 auto call = out.str();
549 std::unique_ptr<flutter::PlatformMessage>
message =
550 std::make_unique<flutter::PlatformMessage>(
551 "flutter/platform_views",
553 DispatchPlatformMessage(std::move(
message));
556bool PlatformView::OnHandlePointerEvent(
557 const fuchsia::ui::input::PointerEvent& pointer) {
558 TRACE_EVENT0(
"flutter",
"PlatformView::OnHandlePointerEvent");
561 trace_flow_id_t trace_id =
565 const float pixel_ratio =
566 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
569 pointer_data.
Clear();
570 pointer_data.
time_stamp = pointer.event_time / 1000;
573 pointer_data.
device = pointer.pointer_id;
575 pointer_data.
physical_x = pointer.x * pixel_ratio;
576 pointer_data.
physical_y = pointer.y * pixel_ratio;
578 pointer_data.
buttons =
static_cast<uint64_t
>(pointer.buttons);
580 switch (pointer_data.
change) {
583 auto clamped_pointer = ClampToViewSpace(pointer.x, pointer.y);
584 pointer_data.
physical_x = clamped_pointer[0] * pixel_ratio;
585 pointer_data.
physical_y = clamped_pointer[1] * pixel_ratio;
587 down_pointers_.insert(pointer_data.
device);
592 down_pointers_.erase(pointer_data.
device);
595 if (down_pointers_.count(pointer_data.
device) == 0) {
600 if (down_pointers_.count(pointer_data.
device) != 0) {
601 FML_LOG(ERROR) <<
"Received add event for down pointer.";
605 if (down_pointers_.count(pointer_data.
device) != 0) {
606 FML_LOG(ERROR) <<
"Received remove event for down pointer.";
610 if (down_pointers_.count(pointer_data.
device) != 0) {
611 FML_LOG(ERROR) <<
"Received hover event for down pointer.";
617 FML_DLOG(ERROR) <<
"Unexpectedly received pointer pan/zoom event";
621 auto packet = std::make_unique<flutter::PointerDataPacket>(1);
622 packet->SetPointerData(0, pointer_data);
623 DispatchPointerDataPacket(std::move(packet));
628std::unique_ptr<flutter::VsyncWaiter> PlatformView::CreateVSyncWaiter() {
629 return std::make_unique<flutter_runner::VsyncWaiter>(
630 await_vsync_callback_, await_vsync_for_secondary_callback_callback_,
635std::unique_ptr<flutter::Surface> PlatformView::CreateRenderingSurface() {
636 return on_create_surface_callback_ ? on_create_surface_callback_() : nullptr;
640std::shared_ptr<flutter::ExternalViewEmbedder>
641PlatformView::CreateExternalViewEmbedder() {
642 return external_view_embedder_;
646void PlatformView::HandlePlatformMessage(
647 std::unique_ptr<flutter::PlatformMessage>
message) {
652 auto found = platform_message_handlers_.find(
channel);
653 if (found == platform_message_handlers_.end()) {
654 const bool already_errored = unregistered_channels_.count(
channel);
655 if (!already_errored) {
657 <<
"Platform view received message on channel '" <<
message->channel()
658 <<
"' with no registered handler. An empty response will be "
659 "generated. Please implement the native message handler. This "
660 "message will appear only once per channel.";
661 unregistered_channels_.insert(
channel);
666 auto response =
message->response();
667 bool response_handled = found->second(std::move(
message));
670 if (response && !response_handled) {
673 response->CompleteEmpty();
678void PlatformView::SetSemanticsEnabled(
bool enabled) {
681 SetAccessibilityFeatures(
static_cast<int32_t
>(
684 SetAccessibilityFeatures(0);
689void PlatformView::UpdateSemantics(
693 const float pixel_ratio =
694 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
696 on_semantics_node_update_callback_(update, pixel_ratio);
700bool PlatformView::HandleAccessibilityChannelPlatformMessage(
701 std::unique_ptr<flutter::PlatformMessage>
message) {
706 std::unique_ptr<flutter::EncodableValue> decoded =
713 if (
type ==
"announce") {
719 on_request_announce_callback_(
text);
727bool PlatformView::HandleFlutterPlatformChannelPlatformMessage(
728 std::unique_ptr<flutter::PlatformMessage>
message) {
737bool PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage(
738 std::unique_ptr<flutter::PlatformMessage>
message) {
741 rapidjson::Document document;
742 document.Parse(
reinterpret_cast<const char*
>(
data.GetMapping()),
744 if (document.HasParseError() || !document.IsObject()) {
745 FML_LOG(ERROR) <<
"Could not parse document";
748 auto root = document.GetObject();
749 auto method_member = root.FindMember(
"method");
750 if (method_member == root.MemberEnd() || !method_member->value.IsString()) {
753 std::string method(method_member->value.GetString());
755 if (method ==
"View.enableWireframe") {
756 auto args_it = root.FindMember(
"args");
757 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
758 FML_LOG(ERROR) <<
"No arguments found.";
761 const auto&
args = args_it->value;
763 auto enable =
args.FindMember(
"enable");
764 if (!enable->value.IsBool()) {
765 FML_LOG(ERROR) <<
"Argument 'enable' is not a bool";
769 wireframe_enabled_callback_(enable->value.GetBool());
770 }
else if (method ==
"View.create") {
771 auto args_it = root.FindMember(
"args");
772 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
773 FML_LOG(ERROR) <<
"No arguments found.";
776 const auto&
args = args_it->value;
779 if (!
view_id->value.IsUint64()) {
780 FML_LOG(ERROR) <<
"Argument 'viewId' is not a int64";
784 auto hit_testable =
args.FindMember(
"hitTestable");
785 if (!hit_testable->value.IsBool()) {
786 FML_LOG(ERROR) <<
"Argument 'hitTestable' is not a bool";
790 auto focusable =
args.FindMember(
"focusable");
791 if (!focusable->value.IsBool()) {
792 FML_LOG(ERROR) <<
"Argument 'focusable' is not a bool";
797 [platform_task_runner =
task_runners_.GetPlatformTaskRunner(),
801 if (message->response()) {
802 message->response()->Complete(std::make_unique<fml::DataMapping>(
803 std::vector<uint8_t>({
'[',
'0',
']'})));
806 OnCreateView(std::move(on_view_created),
view_id->value.GetUint64(),
807 hit_testable->value.GetBool(), focusable->value.GetBool());
809 }
else if (method ==
"View.update") {
810 auto args_it = root.FindMember(
"args");
811 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
812 FML_LOG(ERROR) <<
"No arguments found.";
815 const auto&
args = args_it->value;
818 if (!
view_id->value.IsUint64()) {
819 FML_LOG(ERROR) <<
"Argument 'viewId' is not a int64";
823 auto hit_testable =
args.FindMember(
"hitTestable");
824 if (!hit_testable->value.IsBool()) {
825 FML_LOG(ERROR) <<
"Argument 'hitTestable' is not a bool";
829 auto focusable =
args.FindMember(
"focusable");
830 if (!focusable->value.IsBool()) {
831 FML_LOG(ERROR) <<
"Argument 'focusable' is not a bool";
835 SkRect view_occlusion_hint_raw = SkRect::MakeEmpty();
836 auto view_occlusion_hint =
args.FindMember(
"viewOcclusionHintLTRB");
837 if (view_occlusion_hint !=
args.MemberEnd()) {
838 if (view_occlusion_hint->value.IsArray()) {
839 const auto& view_occlusion_hint_array =
840 view_occlusion_hint->value.GetArray();
841 if (view_occlusion_hint_array.Size() == 4) {
842 bool parse_error =
false;
843 for (
int i = 0;
i < 4;
i++) {
844 auto& array_val = view_occlusion_hint_array[
i];
845 if (!array_val.IsDouble()) {
846 FML_LOG(ERROR) <<
"Argument 'viewOcclusionHintLTRB' element " <<
i
847 <<
" is not a double";
854 view_occlusion_hint_raw =
855 SkRect::MakeLTRB(view_occlusion_hint_array[0].GetDouble(),
856 view_occlusion_hint_array[1].GetDouble(),
857 view_occlusion_hint_array[2].GetDouble(),
858 view_occlusion_hint_array[3].GetDouble());
862 <<
"Argument 'viewOcclusionHintLTRB' expected size 4; got "
863 << view_occlusion_hint_array.Size();
867 <<
"Argument 'viewOcclusionHintLTRB' is not a double array";
870 FML_LOG(WARNING) <<
"Argument 'viewOcclusionHintLTRB' is missing";
873 on_update_view_callback_(
874 view_id->value.GetUint64(), view_occlusion_hint_raw,
875 hit_testable->value.GetBool(), focusable->value.GetBool());
877 message->response()->Complete(std::make_unique<fml::DataMapping>(
878 std::vector<uint8_t>({
'[',
'0',
']'})));
881 }
else if (method ==
"View.dispose") {
882 auto args_it = root.FindMember(
"args");
883 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
884 FML_LOG(ERROR) <<
"No arguments found.";
887 const auto&
args = args_it->value;
890 if (!
view_id->value.IsUint64()) {
891 FML_LOG(ERROR) <<
"Argument 'viewId' is not a int64";
895 OnDisposeView(
view_id->value.GetUint64());
897 message->response()->Complete(std::make_unique<fml::DataMapping>(
898 std::vector<uint8_t>({
'[',
'0',
']'})));
901 }
else if (method.rfind(
"View.focus", 0) == 0) {
902 return focus_delegate_->HandlePlatformMessage(document,
904 }
else if (method.rfind(PointerInjectorDelegate::kPointerInjectorMethodPrefix,
906 return pointer_injector_delegate_->HandlePlatformMessage(
907 document,
message->response());
909 FML_LOG(ERROR) <<
"Unknown " <<
message->channel() <<
" method " << method;
915bool PlatformView::HandleFuchsiaShaderWarmupChannelPlatformMessage(
916 OnShaderWarmupCallback on_shader_warmup_callback,
917 std::unique_ptr<flutter::PlatformMessage>
message) {
920 if (!on_shader_warmup_callback) {
921 FML_LOG(ERROR) <<
"No shader warmup callback set!";
922 std::string result =
"[0]";
924 std::make_unique<fml::DataMapping>(std::vector<uint8_t>(
925 (
const uint8_t*)result.c_str(),
926 (
const uint8_t*)result.c_str() + result.length())));
931 rapidjson::Document document;
932 document.Parse(
reinterpret_cast<const char*
>(
data.GetMapping()),
934 if (document.HasParseError() || !document.IsObject()) {
935 FML_LOG(ERROR) <<
"Could not parse document";
938 auto root = document.GetObject();
939 auto method = root.FindMember(
"method");
940 if (method == root.MemberEnd() || !method->value.IsString() ||
941 method->value !=
"WarmupSkps") {
942 FML_LOG(ERROR) <<
"Invalid method name";
946 auto args_it = root.FindMember(
"args");
947 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
948 FML_LOG(ERROR) <<
"No arguments found.";
952 auto shaders_it = root[
"args"].FindMember(
"shaders");
953 if (shaders_it == root[
"args"].MemberEnd() || !shaders_it->value.IsArray()) {
954 FML_LOG(ERROR) <<
"No shaders found.";
958 auto width_it = root[
"args"].FindMember(
"width");
959 auto height_it = root[
"args"].FindMember(
"height");
960 if (width_it == root[
"args"].MemberEnd() || !width_it->value.IsNumber()) {
961 FML_LOG(ERROR) <<
"Invalid width";
964 if (height_it == root[
"args"].MemberEnd() || !height_it->value.IsNumber()) {
965 FML_LOG(ERROR) <<
"Invalid height";
968 auto width = width_it->value.GetUint64();
969 auto height = height_it->value.GetUint64();
971 std::vector<std::string> skp_paths;
972 const auto& shaders = shaders_it->value;
973 for (rapidjson::Value::ConstValueIterator itr = shaders.Begin();
974 itr != shaders.End(); ++itr) {
975 skp_paths.push_back((*itr).GetString());
978 auto completion_callback = [response =
979 message->response()](uint32_t num_successes) {
980 std::ostringstream result_stream;
981 result_stream <<
"[" << num_successes <<
"]";
983 std::string result(result_stream.str());
985 response->Complete(std::make_unique<fml::DataMapping>(std::vector<uint8_t>(
986 (
const uint8_t*)result.c_str(),
987 (
const uint8_t*)result.c_str() + result.length())));
990 on_shader_warmup_callback(skp_paths, completion_callback,
width,
height);
996bool PlatformView::HandleFuchsiaInputTestChannelPlatformMessage(
997 std::unique_ptr<flutter::PlatformMessage>
message) {
1001 rapidjson::Document document;
1002 document.Parse(
reinterpret_cast<const char*
>(
data.GetMapping()),
1004 if (document.HasParseError() || !document.IsObject()) {
1005 FML_LOG(ERROR) <<
"Could not parse document";
1008 auto root = document.GetObject();
1009 auto method = root.FindMember(
"method");
1010 if (method == root.MemberEnd() || !method->value.IsString()) {
1011 FML_LOG(ERROR) <<
"Missing method";
1015 FML_LOG(INFO) <<
"fuchsia/input_test: method=" << method->value.GetString();
1017 if (method->value ==
"TouchInputListener.ReportTouchInput") {
1018 if (!touch_input_listener_) {
1019 FML_LOG(ERROR) <<
"TouchInputListener not found.";
1023 fuchsia::ui::test::input::TouchInputListenerReportTouchInputRequest request;
1024 CallWithMember<double>(
1025 root,
"local_x", [&](
double local_x) { request.set_local_x(local_x); });
1026 CallWithMember<double>(
1027 root,
"local_y", [&](
double local_y) { request.set_local_y(local_y); });
1028 CallWithMember<int64_t>(root,
"time_received", [&](uint64_t time_received) {
1029 request.set_time_received(time_received);
1031 CallWithMember<std::string>(root,
"component_name",
1032 [&](std::string component_name) {
1033 request.set_component_name(component_name);
1036 touch_input_listener_->ReportTouchInput(std::move(request));
1040 if (method->value ==
"KeyboardInputListener.ReportTextInput") {
1041 if (!keyboard_input_listener_) {
1042 FML_LOG(ERROR) <<
"KeyboardInputListener not found.";
1046 fuchsia::ui::test::input::KeyboardInputListenerReportTextInputRequest
1048 CallWithMember<std::string>(
1049 root,
"text", [&](std::string
text) { request.set_text(
text); });
1051 keyboard_input_listener_->ReportTextInput(std::move(request));
1055 if (method->value ==
"MouseInputListener.ReportMouseInput") {
1056 if (!mouse_input_listener_) {
1057 FML_LOG(ERROR) <<
"MouseInputListener not found.";
1061 fuchsia::ui::test::input::MouseInputListenerReportMouseInputRequest request;
1062 CallWithMember<double>(
1063 root,
"local_x", [&](
double local_x) { request.set_local_x(local_x); });
1064 CallWithMember<double>(
1065 root,
"local_y", [&](
double local_y) { request.set_local_y(local_y); });
1066 CallWithMember<int64_t>(root,
"time_received", [&](uint64_t time_received) {
1067 request.set_time_received(time_received);
1069 CallWithMember<std::string>(root,
"component_name",
1070 [&](std::string component_name) {
1071 request.set_component_name(component_name);
1073 CallWithMember<int>(root,
"buttons", [&](
int button_mask) {
1074 std::vector<fuchsia::ui::test::input::MouseButton> buttons;
1075 if (button_mask & 1) {
1076 buttons.push_back(fuchsia::ui::test::input::MouseButton::FIRST);
1078 if (button_mask & 2) {
1079 buttons.push_back(fuchsia::ui::test::input::MouseButton::SECOND);
1081 if (button_mask & 4) {
1082 buttons.push_back(fuchsia::ui::test::input::MouseButton::THIRD);
1084 request.set_buttons(buttons);
1086 CallWithMember<std::string>(root,
"phase", [&](std::string phase) {
1087 if (phase ==
"add") {
1088 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::ADD);
1089 }
else if (phase ==
"hover") {
1090 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::HOVER);
1091 }
else if (phase ==
"down") {
1092 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::DOWN);
1093 }
else if (phase ==
"move") {
1094 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::MOVE);
1095 }
else if (phase ==
"up") {
1096 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::UP);
1098 FML_LOG(ERROR) <<
"Unexpected mouse phase: " << phase;
1101 CallWithMember<double>(
1102 root,
"wheel_x_physical_pixel", [&](
double wheel_x_physical_pixel) {
1103 request.set_wheel_x_physical_pixel(wheel_x_physical_pixel);
1105 CallWithMember<double>(
1106 root,
"wheel_y_physical_pixel", [&](
double wheel_y_physical_pixel) {
1107 request.set_wheel_y_physical_pixel(wheel_y_physical_pixel);
1110 mouse_input_listener_->ReportMouseInput(std::move(request));
1114 FML_LOG(ERROR) <<
"fuchsia/input_test: unrecognized method "
1115 << method->value.GetString();
1120bool PlatformView::HandleFuchsiaChildViewChannelPlatformMessage(
1121 std::unique_ptr<flutter::PlatformMessage>
message) {
1124 if (
message->data().GetSize() != 1 ||
1125 (
message->data().GetMapping()[0] !=
'1')) {
1127 <<
" data must be singularly '1'.";
1135 <<
" must have a response callback.";
1139 if (!dart_application_svc_) {
1140 FML_LOG(ERROR) <<
"No service directory.";
1144 fuchsia::ui::app::ViewProviderHandle view_provider_handle;
1145 zx_status_t status =
1146 dart_application_svc_->Connect(view_provider_handle.NewRequest());
1147 if (status != ZX_OK) {
1148 FML_LOG(ERROR) <<
"Failed to connect to view provider.";
1151 fuchsia::ui::app::ViewProviderPtr view_provider;
1152 view_provider.Bind(std::move(view_provider_handle));
1156 zx::channel view_tokens[2];
1157 fuchsia::ui::views::ViewportCreationToken viewport_creation_token;
1158 fuchsia::ui::views::ViewCreationToken view_creation_token;
1159 status = zx::channel::create(0, &viewport_creation_token.value,
1160 &view_creation_token.value);
1161 if (status != ZX_OK) {
1162 FML_LOG(ERROR) <<
"Creating view tokens: " << zx_status_get_string(status);
1166 fuchsia::ui::app::CreateView2Args create_view_args;
1167 create_view_args.set_view_creation_token(std::move(view_creation_token));
1168 view_provider->CreateView2(std::move(create_view_args));
1170 view_id = std::move(viewport_creation_token.value);
1173 message->response()->Complete(
1174 std::make_unique<fml::DataMapping>(std::to_string(
view_id.release())
std::unique_ptr< T > DecodeMessage(const uint8_t *binary_message, const size_t message_size) const
static const StandardMessageCodec & GetInstance(const StandardCodecSerializer *serializer=nullptr)
static MallocMapping Copy(const T *begin, const T *end)
TaskRunners task_runners_
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
G_BEGIN_DECLS FlutterViewId view_id
#define FML_DLOG(severity)
#define FML_LOG(severity)
#define FML_CHECK(condition)
#define FML_DCHECK(condition)
NSString *const kFlutterPlatformChannel
static NSString *const kTextInputChannel
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
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all 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
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
std::map< EncodableValue, EncodableValue > EncodableMap
internal::CopyableLambda< T > MakeCopyable(T lambda)
impeller::ShaderType type
#define TRACE_EVENT0(category_group, name)
#define TRACE_FLOW_END(category, name, id)