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"
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()) {
41 if (!it->value.template Is<T>()) {
44 func(it->value.template Get<T>());
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,
83 await_vsync_for_secondary_callback_callback,
84 std::shared_ptr<sys::ServiceDirectory> dart_application_svc)
86 external_view_embedder_(external_view_embedder),
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);
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) {
118 <<
"PlatformView use-after-free attempted. Ignoring.";
120 weak->delegate_.OnPlatformViewDispatchPlatformMessage(
125 focus_delegate_->WatchLoop([weak = weak_factory_.GetWeakPtr()](
bool focused) {
127 FML_LOG(WARNING) <<
"PlatformView use-after-free attempted. Ignoring.";
133 if (focused && weak->text_delegate_->HasTextState()) {
134 weak->text_delegate_->ActivateIme();
135 }
else if (!focused) {
136 weak->text_delegate_->DeactivateIme();
141 pointer_delegate_->WatchLoop([weak = weak_factory_.GetWeakPtr()](
142 std::vector<flutter::PointerData> events) {
144 FML_LOG(WARNING) <<
"PlatformView use-after-free attempted. Ignoring.";
148 if (events.empty()) {
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];
160 event.physical_x =
event.physical_x * pixel_ratio;
161 event.physical_y =
event.physical_y * pixel_ratio;
162 packet->SetPointerData(
i, event);
164 weak->DispatchPointerDataPacket(std::move(packet));
168 pointer_injector_delegate_ = std::make_unique<PointerInjectorDelegate>(
169 std::move(pointerinjector_registry), std::move(view_ref_clone));
172 if (dart_application_svc) {
174 fuchsia::ui::test::input::TouchInputListenerHandle touch_input_listener;
175 zx_status_t touch_input_listener_status =
177 ->Connect<fuchsia::ui::test::input::TouchInputListener>(
178 touch_input_listener.NewRequest());
179 if (touch_input_listener_status != ZX_OK) {
181 <<
"fuchsia::ui::test::input::TouchInputListener connection failed: "
182 << zx_status_get_string(touch_input_listener_status);
184 touch_input_listener_.Bind(std::move(touch_input_listener));
188 fuchsia::ui::test::input::KeyboardInputListenerHandle
189 keyboard_input_listener;
190 zx_status_t keyboard_input_listener_status =
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);
199 keyboard_input_listener_.Bind(std::move(keyboard_input_listener));
202 fuchsia::ui::test::input::MouseInputListenerHandle mouse_input_listener;
203 zx_status_t mouse_input_listener_status =
205 ->Connect<fuchsia::ui::test::input::MouseInputListener>(
206 mouse_input_listener.NewRequest());
207 if (mouse_input_listener_status != ZX_OK) {
209 <<
"fuchsia::ui::test::input::MouseInputListener connection failed: "
210 << zx_status_get_string(mouse_input_listener_status);
212 mouse_input_listener_.Bind(std::move(mouse_input_listener));
217 RegisterPlatformMessageHandlers();
219 parent_viewport_watcher_.set_error_handler([](zx_status_t status) {
220 FML_LOG(ERROR) <<
"Interface error on: ParentViewportWatcher status: "
224 parent_viewport_watcher_->GetLayout(
226 parent_viewport_watcher_->GetStatus(
230PlatformView::~PlatformView() =
default;
232void PlatformView::RegisterPlatformMessageHandlers() {
234 std::bind(&PlatformView::HandleFlutterPlatformChannelPlatformMessage,
235 this, std::placeholders::_1);
237 std::bind(&TextDelegate::HandleFlutterTextInputChannelPlatformMessage,
238 text_delegate_.get(), std::placeholders::_1);
240 std::bind(&PlatformView::HandleAccessibilityChannelPlatformMessage,
this,
241 std::placeholders::_1);
243 std::bind(&PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage,
244 this, std::placeholders::_1);
246 std::bind(&HandleFuchsiaShaderWarmupChannelPlatformMessage,
247 on_shader_warmup_callback_, std::placeholders::_1);
249 std::bind(&PlatformView::HandleFuchsiaInputTestChannelPlatformMessage,
250 this, std::placeholders::_1);
252 std::bind(&PlatformView::HandleFuchsiaChildViewChannelPlatformMessage,
253 this, std::placeholders::_1);
257 fuchsia::ui::input::PointerEventPhase 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:
279 fuchsia::ui::input::PointerEventType
type) {
281 case fuchsia::ui::input::PointerEventType::TOUCH:
283 case fuchsia::ui::input::PointerEventType::MOUSE:
294 memcpy(&ia, &fa,
sizeof(uint32_t));
295 memcpy(&ib, &fb,
sizeof(uint32_t));
296 return (((uint64_t)ia) << 32) | ib;
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()) {
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) {
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};
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)};
332 if (info.has_device_pixel_ratio()) {
334 FML_DCHECK(info.device_pixel_ratio().x == info.device_pixel_ratio().y);
335 view_pixel_ratio_ = info.device_pixel_ratio().x;
338 float pixel_ratio = view_pixel_ratio_ ? *view_pixel_ratio_ : 1.0f;
341 std::round(view_logical_size_.value()[0] *
343 std::round(view_logical_size_.value()[1] *
345 std::round(view_logical_size_.value()[0] *
347 std::round(view_logical_size_.value()[0] *
349 std::round(view_logical_size_.value()[1] *
351 std::round(view_logical_size_.value()[1] *
375 SetViewportMetrics(kFlutterImplicitViewId, metrics);
377 parent_viewport_watcher_->GetLayout(
378 fit::bind_member(
this, &PlatformView::OnGetLayout));
381void PlatformView::OnParentViewportStatus(
382 fuchsia::ui::composition::ParentViewportStatus status) {
385 parent_viewport_status_ = status;
386 parent_viewport_watcher_->GetStatus(
387 fit::bind_member(
this, &PlatformView::OnParentViewportStatus));
390void PlatformView::OnChildViewStatus(
392 fuchsia::ui::composition::ChildViewStatus status) {
393 FML_DCHECK(child_view_info_.count(content_id) == 1);
395 std::ostringstream out;
396 out <<
"{" <<
"\"method\":\"View.viewStateChanged\"," <<
"\"args\":{"
397 <<
" \"viewId\":" << child_view_info_.at(content_id).view_id
399 <<
" \"is_rendering\":true,"
402 auto call = out.str();
404 std::unique_ptr<flutter::PlatformMessage>
message =
405 std::make_unique<flutter::PlatformMessage>(
406 "flutter/platform_views",
408 DispatchPlatformMessage(std::move(
message));
410 child_view_info_.at(content_id)
411 .child_view_watcher->GetStatus(
412 [
this, content_id](fuchsia::ui::composition::ChildViewStatus status) {
413 OnChildViewStatus(content_id, status);
417void PlatformView::OnChildViewViewRef(uint64_t content_id,
419 fuchsia::ui::views::ViewRef view_ref) {
420 FML_CHECK(child_view_info_.count(content_id) == 1);
422 fuchsia::ui::views::ViewRef view_ref_clone;
423 fidl::Clone(view_ref, &view_ref_clone);
425 focus_delegate_->OnChildViewViewRef(
view_id, std::move(view_ref));
427 pointer_injector_delegate_->OnCreateView(
view_id, std::move(view_ref_clone));
428 OnChildViewConnected(content_id);
431void PlatformView::OnCreateView(
ViewCallback on_view_created,
435 auto on_view_bound = [weak = weak_factory_.GetWeakPtr(),
436 platform_task_runner =
439 fuchsia::ui::composition::ContentId content_id,
440 fuchsia::ui::composition::ChildViewWatcherHandle
441 child_view_watcher_handle) {
443 FML_CHECK(weak->child_view_info_.count(content_id.value) == 0);
447 watcher_handle = std::move(child_view_watcher_handle)]()
mutable {
450 <<
"View bound to PlatformView after PlatformView was "
451 "destroyed; ignoring.";
457 fuchsia::ui::composition::ChildViewWatcherPtr child_view_watcher =
458 watcher_handle.Bind();
461 child_view_watcher.set_error_handler([weak,
view_id, content_id](
462 zx_status_t status) {
464 <<
"Child disconnected. ChildViewWatcher status: " << status;
467 FML_LOG(WARNING) <<
"View bound to PlatformView after "
469 "destroyed; ignoring.";
474 weak->pointer_injector_delegate_->OnDestroyView(
view_id);
476 weak->OnChildViewDisconnected(content_id.value);
479 weak->child_view_info_.emplace(
480 std::piecewise_construct, std::forward_as_tuple(content_id.value),
481 std::forward_as_tuple(
view_id, std::move(child_view_watcher)));
483 weak->child_view_info_.at(content_id.value)
484 .child_view_watcher->GetStatus(
485 [weak,
id = content_id.value](
486 fuchsia::ui::composition::ChildViewStatus status) {
487 weak->OnChildViewStatus(
id, status);
490 weak->child_view_info_.at(content_id.value)
491 .child_view_watcher->GetViewRef(
492 [weak, content_id = content_id.value,
493 view_id](fuchsia::ui::views::ViewRef view_ref) {
494 weak->OnChildViewViewRef(content_id,
view_id,
495 std::move(view_ref));
500 on_create_view_callback_(view_id_raw, std::move(on_view_created),
501 std::move(on_view_bound), hit_testable, focusable);
504void PlatformView::OnDisposeView(int64_t view_id_raw) {
505 auto on_view_unbound =
506 [weak = weak_factory_.GetWeakPtr(),
507 platform_task_runner =
task_runners_.GetPlatformTaskRunner(),
508 view_id_raw](fuchsia::ui::composition::ContentId content_id) {
509 platform_task_runner->PostTask([weak, content_id, view_id_raw]() {
512 <<
"View unbound from PlatformView after PlatformView"
513 "was destroyed; ignoring.";
517 FML_DCHECK(weak->child_view_info_.count(content_id.value) == 1);
518 weak->OnChildViewDisconnected(content_id.value);
519 weak->child_view_info_.erase(content_id.value);
520 weak->focus_delegate_->OnDisposeChildView(view_id_raw);
521 weak->pointer_injector_delegate_->OnDestroyView(view_id_raw);
524 on_destroy_view_callback_(view_id_raw, std::move(on_view_unbound));
527void PlatformView::OnChildViewConnected(uint64_t content_id) {
528 FML_CHECK(child_view_info_.count(content_id) == 1);
529 std::ostringstream out;
530 out <<
"{" <<
"\"method\":\"View.viewConnected\"," <<
"\"args\":{"
531 <<
" \"viewId\":" << child_view_info_.at(content_id).view_id <<
" }"
533 auto call = out.str();
535 std::unique_ptr<flutter::PlatformMessage>
message =
536 std::make_unique<flutter::PlatformMessage>(
537 "flutter/platform_views",
539 DispatchPlatformMessage(std::move(
message));
542void PlatformView::OnChildViewDisconnected(uint64_t content_id) {
543 FML_CHECK(child_view_info_.count(content_id) == 1);
544 std::ostringstream out;
545 out <<
"{" <<
"\"method\":\"View.viewDisconnected\"," <<
"\"args\":{"
546 <<
" \"viewId\":" << child_view_info_.at(content_id).view_id <<
" }"
548 auto call = out.str();
550 std::unique_ptr<flutter::PlatformMessage>
message =
551 std::make_unique<flutter::PlatformMessage>(
552 "flutter/platform_views",
554 DispatchPlatformMessage(std::move(
message));
557bool PlatformView::OnHandlePointerEvent(
558 const fuchsia::ui::input::PointerEvent& pointer) {
559 TRACE_EVENT0(
"flutter",
"PlatformView::OnHandlePointerEvent");
562 trace_flow_id_t trace_id =
566 const float pixel_ratio =
567 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
570 pointer_data.
Clear();
571 pointer_data.
time_stamp = pointer.event_time / 1000;
574 pointer_data.
device = pointer.pointer_id;
576 pointer_data.
physical_x = pointer.x * pixel_ratio;
577 pointer_data.
physical_y = pointer.y * pixel_ratio;
579 pointer_data.
buttons =
static_cast<uint64_t
>(pointer.buttons);
581 switch (pointer_data.
change) {
584 auto clamped_pointer = ClampToViewSpace(pointer.x, pointer.y);
585 pointer_data.
physical_x = clamped_pointer[0] * pixel_ratio;
586 pointer_data.
physical_y = clamped_pointer[1] * pixel_ratio;
588 down_pointers_.insert(pointer_data.
device);
593 down_pointers_.erase(pointer_data.
device);
596 if (down_pointers_.count(pointer_data.
device) == 0) {
601 if (down_pointers_.count(pointer_data.
device) != 0) {
602 FML_LOG(ERROR) <<
"Received add event for down pointer.";
606 if (down_pointers_.count(pointer_data.
device) != 0) {
607 FML_LOG(ERROR) <<
"Received remove event for down pointer.";
611 if (down_pointers_.count(pointer_data.
device) != 0) {
612 FML_LOG(ERROR) <<
"Received hover event for down pointer.";
618 FML_DLOG(ERROR) <<
"Unexpectedly received pointer pan/zoom event";
622 auto packet = std::make_unique<flutter::PointerDataPacket>(1);
623 packet->SetPointerData(0, pointer_data);
624 DispatchPointerDataPacket(std::move(packet));
629std::unique_ptr<flutter::VsyncWaiter> PlatformView::CreateVSyncWaiter() {
630 return std::make_unique<flutter_runner::VsyncWaiter>(
631 await_vsync_callback_, await_vsync_for_secondary_callback_callback_,
636std::unique_ptr<flutter::Surface> PlatformView::CreateRenderingSurface() {
637 return on_create_surface_callback_ ? on_create_surface_callback_() : nullptr;
641std::shared_ptr<flutter::ExternalViewEmbedder>
642PlatformView::CreateExternalViewEmbedder() {
643 return external_view_embedder_;
647void PlatformView::HandlePlatformMessage(
648 std::unique_ptr<flutter::PlatformMessage>
message) {
653 auto found = platform_message_handlers_.find(
channel);
654 if (found == platform_message_handlers_.end()) {
655 const bool already_errored = unregistered_channels_.count(
channel);
656 if (!already_errored) {
658 <<
"Platform view received message on channel '" <<
message->channel()
659 <<
"' with no registered handler. An empty response will be "
660 "generated. Please implement the native message handler. This "
661 "message will appear only once per channel.";
662 unregistered_channels_.insert(
channel);
667 auto response =
message->response();
668 bool response_handled = found->second(std::move(
message));
671 if (response && !response_handled) {
674 response->CompleteEmpty();
679void PlatformView::SetSemanticsEnabled(
bool enabled) {
682 SetAccessibilityFeatures(
static_cast<int32_t
>(
685 SetAccessibilityFeatures(0);
690void PlatformView::UpdateSemantics(
694 const float pixel_ratio =
695 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
697 on_semantics_node_update_callback_(update, pixel_ratio);
701bool PlatformView::HandleAccessibilityChannelPlatformMessage(
702 std::unique_ptr<flutter::PlatformMessage>
message) {
707 std::unique_ptr<flutter::EncodableValue> decoded =
714 if (
type ==
"announce") {
720 on_request_announce_callback_(
text);
728bool PlatformView::HandleFlutterPlatformChannelPlatformMessage(
729 std::unique_ptr<flutter::PlatformMessage>
message) {
738bool PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage(
739 std::unique_ptr<flutter::PlatformMessage>
message) {
742 rapidjson::Document document;
743 document.Parse(
reinterpret_cast<const char*
>(
data.GetMapping()),
745 if (document.HasParseError() || !document.IsObject()) {
746 FML_LOG(ERROR) <<
"Could not parse document";
749 auto root = document.GetObject();
750 auto method_member = root.FindMember(
"method");
751 if (method_member == root.MemberEnd() || !method_member->value.IsString()) {
754 std::string method(method_member->value.GetString());
756 if (method ==
"View.enableWireframe") {
757 auto args_it = root.FindMember(
"args");
758 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
759 FML_LOG(ERROR) <<
"No arguments found.";
762 const auto&
args = args_it->value;
764 auto enable =
args.FindMember(
"enable");
765 if (!enable->value.IsBool()) {
766 FML_LOG(ERROR) <<
"Argument 'enable' is not a bool";
770 wireframe_enabled_callback_(enable->value.GetBool());
771 }
else if (method ==
"View.create") {
772 auto args_it = root.FindMember(
"args");
773 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
774 FML_LOG(ERROR) <<
"No arguments found.";
777 const auto&
args = args_it->value;
780 if (!
view_id->value.IsUint64()) {
781 FML_LOG(ERROR) <<
"Argument 'viewId' is not a int64";
785 auto hit_testable =
args.FindMember(
"hitTestable");
786 if (!hit_testable->value.IsBool()) {
787 FML_LOG(ERROR) <<
"Argument 'hitTestable' is not a bool";
791 auto focusable =
args.FindMember(
"focusable");
792 if (!focusable->value.IsBool()) {
793 FML_LOG(ERROR) <<
"Argument 'focusable' is not a bool";
798 [platform_task_runner =
task_runners_.GetPlatformTaskRunner(),
802 if (message->response()) {
803 message->response()->Complete(std::make_unique<fml::DataMapping>(
804 std::vector<uint8_t>({
'[',
'0',
']'})));
807 OnCreateView(std::move(on_view_created),
view_id->value.GetUint64(),
808 hit_testable->value.GetBool(), focusable->value.GetBool());
810 }
else if (method ==
"View.update") {
811 auto args_it = root.FindMember(
"args");
812 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
813 FML_LOG(ERROR) <<
"No arguments found.";
816 const auto&
args = args_it->value;
819 if (!
view_id->value.IsUint64()) {
820 FML_LOG(ERROR) <<
"Argument 'viewId' is not a int64";
824 auto hit_testable =
args.FindMember(
"hitTestable");
825 if (!hit_testable->value.IsBool()) {
826 FML_LOG(ERROR) <<
"Argument 'hitTestable' is not a bool";
830 auto focusable =
args.FindMember(
"focusable");
831 if (!focusable->value.IsBool()) {
832 FML_LOG(ERROR) <<
"Argument 'focusable' is not a bool";
836 SkRect view_occlusion_hint_raw = SkRect::MakeEmpty();
837 auto view_occlusion_hint =
args.FindMember(
"viewOcclusionHintLTRB");
838 if (view_occlusion_hint !=
args.MemberEnd()) {
839 if (view_occlusion_hint->value.IsArray()) {
840 const auto& view_occlusion_hint_array =
841 view_occlusion_hint->value.GetArray();
842 if (view_occlusion_hint_array.Size() == 4) {
843 bool parse_error =
false;
844 for (
int i = 0;
i < 4;
i++) {
845 auto& array_val = view_occlusion_hint_array[
i];
846 if (!array_val.IsDouble()) {
847 FML_LOG(ERROR) <<
"Argument 'viewOcclusionHintLTRB' element " <<
i
848 <<
" is not a double";
855 view_occlusion_hint_raw =
856 SkRect::MakeLTRB(view_occlusion_hint_array[0].GetDouble(),
857 view_occlusion_hint_array[1].GetDouble(),
858 view_occlusion_hint_array[2].GetDouble(),
859 view_occlusion_hint_array[3].GetDouble());
863 <<
"Argument 'viewOcclusionHintLTRB' expected size 4; got "
864 << view_occlusion_hint_array.Size();
868 <<
"Argument 'viewOcclusionHintLTRB' is not a double array";
871 FML_LOG(WARNING) <<
"Argument 'viewOcclusionHintLTRB' is missing";
874 on_update_view_callback_(
875 view_id->value.GetUint64(), view_occlusion_hint_raw,
876 hit_testable->value.GetBool(), focusable->value.GetBool());
878 message->response()->Complete(std::make_unique<fml::DataMapping>(
879 std::vector<uint8_t>({
'[',
'0',
']'})));
882 }
else if (method ==
"View.dispose") {
883 auto args_it = root.FindMember(
"args");
884 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
885 FML_LOG(ERROR) <<
"No arguments found.";
888 const auto&
args = args_it->value;
891 if (!
view_id->value.IsUint64()) {
892 FML_LOG(ERROR) <<
"Argument 'viewId' is not a int64";
896 OnDisposeView(
view_id->value.GetUint64());
898 message->response()->Complete(std::make_unique<fml::DataMapping>(
899 std::vector<uint8_t>({
'[',
'0',
']'})));
902 }
else if (method.rfind(
"View.focus", 0) == 0) {
903 return focus_delegate_->HandlePlatformMessage(root,
message->response());
904 }
else if (method.rfind(PointerInjectorDelegate::kPointerInjectorMethodPrefix,
906 return pointer_injector_delegate_->HandlePlatformMessage(
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
std::map< EncodableValue, EncodableValue > EncodableMap
internal::CopyableLambda< T > MakeCopyable(T lambda)
std::shared_ptr< const fml::Mapping > data
#define TRACE_EVENT0(category_group, name)
#define TRACE_FLOW_END(category, name, id)