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] *
371 SetViewportMetrics(kFlutterImplicitViewId, metrics);
373 parent_viewport_watcher_->GetLayout(
374 fit::bind_member(
this, &PlatformView::OnGetLayout));
377void PlatformView::OnParentViewportStatus(
378 fuchsia::ui::composition::ParentViewportStatus status) {
381 parent_viewport_status_ = status;
382 parent_viewport_watcher_->GetStatus(
383 fit::bind_member(
this, &PlatformView::OnParentViewportStatus));
386void PlatformView::OnChildViewStatus(
388 fuchsia::ui::composition::ChildViewStatus status) {
389 FML_DCHECK(child_view_info_.count(content_id) == 1);
391 std::ostringstream out;
392 out <<
"{" <<
"\"method\":\"View.viewStateChanged\"," <<
"\"args\":{"
393 <<
" \"viewId\":" << child_view_info_.at(content_id).view_id
395 <<
" \"is_rendering\":true,"
398 auto call = out.str();
400 std::unique_ptr<flutter::PlatformMessage>
message =
401 std::make_unique<flutter::PlatformMessage>(
402 "flutter/platform_views",
404 DispatchPlatformMessage(std::move(
message));
406 child_view_info_.at(content_id)
407 .child_view_watcher->GetStatus(
408 [
this, content_id](fuchsia::ui::composition::ChildViewStatus status) {
409 OnChildViewStatus(content_id, status);
413void PlatformView::OnChildViewViewRef(uint64_t content_id,
415 fuchsia::ui::views::ViewRef view_ref) {
416 FML_CHECK(child_view_info_.count(content_id) == 1);
418 fuchsia::ui::views::ViewRef view_ref_clone;
419 fidl::Clone(view_ref, &view_ref_clone);
421 focus_delegate_->OnChildViewViewRef(
view_id, std::move(view_ref));
423 pointer_injector_delegate_->OnCreateView(
view_id, std::move(view_ref_clone));
424 OnChildViewConnected(content_id);
427void PlatformView::OnCreateView(
ViewCallback on_view_created,
431 auto on_view_bound = [weak = weak_factory_.GetWeakPtr(),
432 platform_task_runner =
435 fuchsia::ui::composition::ContentId content_id,
436 fuchsia::ui::composition::ChildViewWatcherHandle
437 child_view_watcher_handle) {
439 FML_CHECK(weak->child_view_info_.count(content_id.value) == 0);
443 watcher_handle = std::move(child_view_watcher_handle)]()
mutable {
446 <<
"View bound to PlatformView after PlatformView was "
447 "destroyed; ignoring.";
453 fuchsia::ui::composition::ChildViewWatcherPtr child_view_watcher =
454 watcher_handle.Bind();
457 child_view_watcher.set_error_handler([weak,
view_id, content_id](
458 zx_status_t status) {
460 <<
"Child disconnected. ChildViewWatcher status: " << status;
463 FML_LOG(WARNING) <<
"View bound to PlatformView after "
465 "destroyed; ignoring.";
470 weak->pointer_injector_delegate_->OnDestroyView(
view_id);
472 weak->OnChildViewDisconnected(content_id.value);
475 weak->child_view_info_.emplace(
476 std::piecewise_construct, std::forward_as_tuple(content_id.value),
477 std::forward_as_tuple(
view_id, std::move(child_view_watcher)));
479 weak->child_view_info_.at(content_id.value)
480 .child_view_watcher->GetStatus(
481 [weak,
id = content_id.value](
482 fuchsia::ui::composition::ChildViewStatus status) {
483 weak->OnChildViewStatus(
id, status);
486 weak->child_view_info_.at(content_id.value)
487 .child_view_watcher->GetViewRef(
488 [weak, content_id = content_id.value,
489 view_id](fuchsia::ui::views::ViewRef view_ref) {
490 weak->OnChildViewViewRef(content_id,
view_id,
491 std::move(view_ref));
496 on_create_view_callback_(view_id_raw, std::move(on_view_created),
497 std::move(on_view_bound), hit_testable, focusable);
500void PlatformView::OnDisposeView(int64_t view_id_raw) {
501 auto on_view_unbound =
502 [weak = weak_factory_.GetWeakPtr(),
503 platform_task_runner =
task_runners_.GetPlatformTaskRunner(),
504 view_id_raw](fuchsia::ui::composition::ContentId content_id) {
505 platform_task_runner->PostTask([weak, content_id, view_id_raw]() {
508 <<
"View unbound from PlatformView after PlatformView"
509 "was destroyed; ignoring.";
513 FML_DCHECK(weak->child_view_info_.count(content_id.value) == 1);
514 weak->OnChildViewDisconnected(content_id.value);
515 weak->child_view_info_.erase(content_id.value);
516 weak->focus_delegate_->OnDisposeChildView(view_id_raw);
517 weak->pointer_injector_delegate_->OnDestroyView(view_id_raw);
520 on_destroy_view_callback_(view_id_raw, std::move(on_view_unbound));
523void PlatformView::OnChildViewConnected(uint64_t content_id) {
524 FML_CHECK(child_view_info_.count(content_id) == 1);
525 std::ostringstream out;
526 out <<
"{" <<
"\"method\":\"View.viewConnected\"," <<
"\"args\":{"
527 <<
" \"viewId\":" << child_view_info_.at(content_id).view_id <<
" }"
529 auto call = out.str();
531 std::unique_ptr<flutter::PlatformMessage>
message =
532 std::make_unique<flutter::PlatformMessage>(
533 "flutter/platform_views",
535 DispatchPlatformMessage(std::move(
message));
538void PlatformView::OnChildViewDisconnected(uint64_t content_id) {
539 FML_CHECK(child_view_info_.count(content_id) == 1);
540 std::ostringstream out;
541 out <<
"{" <<
"\"method\":\"View.viewDisconnected\"," <<
"\"args\":{"
542 <<
" \"viewId\":" << child_view_info_.at(content_id).view_id <<
" }"
544 auto call = out.str();
546 std::unique_ptr<flutter::PlatformMessage>
message =
547 std::make_unique<flutter::PlatformMessage>(
548 "flutter/platform_views",
550 DispatchPlatformMessage(std::move(
message));
553bool PlatformView::OnHandlePointerEvent(
554 const fuchsia::ui::input::PointerEvent& pointer) {
555 TRACE_EVENT0(
"flutter",
"PlatformView::OnHandlePointerEvent");
558 trace_flow_id_t trace_id =
562 const float pixel_ratio =
563 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
566 pointer_data.
Clear();
567 pointer_data.
time_stamp = pointer.event_time / 1000;
570 pointer_data.
device = pointer.pointer_id;
572 pointer_data.
physical_x = pointer.x * pixel_ratio;
573 pointer_data.
physical_y = pointer.y * pixel_ratio;
575 pointer_data.
buttons =
static_cast<uint64_t
>(pointer.buttons);
577 switch (pointer_data.
change) {
580 auto clamped_pointer = ClampToViewSpace(pointer.x, pointer.y);
581 pointer_data.
physical_x = clamped_pointer[0] * pixel_ratio;
582 pointer_data.
physical_y = clamped_pointer[1] * pixel_ratio;
584 down_pointers_.insert(pointer_data.
device);
589 down_pointers_.erase(pointer_data.
device);
592 if (down_pointers_.count(pointer_data.
device) == 0) {
597 if (down_pointers_.count(pointer_data.
device) != 0) {
598 FML_LOG(ERROR) <<
"Received add event for down pointer.";
602 if (down_pointers_.count(pointer_data.
device) != 0) {
603 FML_LOG(ERROR) <<
"Received remove event for down pointer.";
607 if (down_pointers_.count(pointer_data.
device) != 0) {
608 FML_LOG(ERROR) <<
"Received hover event for down pointer.";
614 FML_DLOG(ERROR) <<
"Unexpectedly received pointer pan/zoom event";
618 auto packet = std::make_unique<flutter::PointerDataPacket>(1);
619 packet->SetPointerData(0, pointer_data);
620 DispatchPointerDataPacket(std::move(packet));
625std::unique_ptr<flutter::VsyncWaiter> PlatformView::CreateVSyncWaiter() {
626 return std::make_unique<flutter_runner::VsyncWaiter>(
627 await_vsync_callback_, await_vsync_for_secondary_callback_callback_,
632std::unique_ptr<flutter::Surface> PlatformView::CreateRenderingSurface() {
633 return on_create_surface_callback_ ? on_create_surface_callback_() : nullptr;
637std::shared_ptr<flutter::ExternalViewEmbedder>
638PlatformView::CreateExternalViewEmbedder() {
639 return external_view_embedder_;
643void PlatformView::HandlePlatformMessage(
644 std::unique_ptr<flutter::PlatformMessage>
message) {
649 auto found = platform_message_handlers_.find(
channel);
650 if (found == platform_message_handlers_.end()) {
651 const bool already_errored = unregistered_channels_.count(
channel);
652 if (!already_errored) {
654 <<
"Platform view received message on channel '" <<
message->channel()
655 <<
"' with no registered handler. An empty response will be "
656 "generated. Please implement the native message handler. This "
657 "message will appear only once per channel.";
658 unregistered_channels_.insert(
channel);
663 auto response =
message->response();
664 bool response_handled = found->second(std::move(
message));
667 if (response && !response_handled) {
670 response->CompleteEmpty();
675void PlatformView::SetSemanticsEnabled(
bool enabled) {
678 SetAccessibilityFeatures(
static_cast<int32_t
>(
681 SetAccessibilityFeatures(0);
686void PlatformView::UpdateSemantics(
690 const float pixel_ratio =
691 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
693 on_semantics_node_update_callback_(update, pixel_ratio);
697bool PlatformView::HandleAccessibilityChannelPlatformMessage(
698 std::unique_ptr<flutter::PlatformMessage>
message) {
703 std::unique_ptr<flutter::EncodableValue> decoded =
710 if (
type ==
"announce") {
716 on_request_announce_callback_(
text);
724bool PlatformView::HandleFlutterPlatformChannelPlatformMessage(
725 std::unique_ptr<flutter::PlatformMessage>
message) {
734bool PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage(
735 std::unique_ptr<flutter::PlatformMessage>
message) {
738 rapidjson::Document document;
739 document.Parse(
reinterpret_cast<const char*
>(
data.GetMapping()),
741 if (document.HasParseError() || !document.IsObject()) {
742 FML_LOG(ERROR) <<
"Could not parse document";
745 auto root = document.GetObject();
746 auto method_member = root.FindMember(
"method");
747 if (method_member == root.MemberEnd() || !method_member->value.IsString()) {
750 std::string method(method_member->value.GetString());
752 if (method ==
"View.enableWireframe") {
753 auto args_it = root.FindMember(
"args");
754 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
755 FML_LOG(ERROR) <<
"No arguments found.";
758 const auto&
args = args_it->value;
760 auto enable =
args.FindMember(
"enable");
761 if (!enable->value.IsBool()) {
762 FML_LOG(ERROR) <<
"Argument 'enable' is not a bool";
766 wireframe_enabled_callback_(enable->value.GetBool());
767 }
else if (method ==
"View.create") {
768 auto args_it = root.FindMember(
"args");
769 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
770 FML_LOG(ERROR) <<
"No arguments found.";
773 const auto&
args = args_it->value;
776 if (!
view_id->value.IsUint64()) {
777 FML_LOG(ERROR) <<
"Argument 'viewId' is not a int64";
781 auto hit_testable =
args.FindMember(
"hitTestable");
782 if (!hit_testable->value.IsBool()) {
783 FML_LOG(ERROR) <<
"Argument 'hitTestable' is not a bool";
787 auto focusable =
args.FindMember(
"focusable");
788 if (!focusable->value.IsBool()) {
789 FML_LOG(ERROR) <<
"Argument 'focusable' is not a bool";
794 [platform_task_runner =
task_runners_.GetPlatformTaskRunner(),
798 if (message->response()) {
799 message->response()->Complete(std::make_unique<fml::DataMapping>(
800 std::vector<uint8_t>({
'[',
'0',
']'})));
803 OnCreateView(std::move(on_view_created),
view_id->value.GetUint64(),
804 hit_testable->value.GetBool(), focusable->value.GetBool());
806 }
else if (method ==
"View.update") {
807 auto args_it = root.FindMember(
"args");
808 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
809 FML_LOG(ERROR) <<
"No arguments found.";
812 const auto&
args = args_it->value;
815 if (!
view_id->value.IsUint64()) {
816 FML_LOG(ERROR) <<
"Argument 'viewId' is not a int64";
820 auto hit_testable =
args.FindMember(
"hitTestable");
821 if (!hit_testable->value.IsBool()) {
822 FML_LOG(ERROR) <<
"Argument 'hitTestable' is not a bool";
826 auto focusable =
args.FindMember(
"focusable");
827 if (!focusable->value.IsBool()) {
828 FML_LOG(ERROR) <<
"Argument 'focusable' is not a bool";
832 SkRect view_occlusion_hint_raw = SkRect::MakeEmpty();
833 auto view_occlusion_hint =
args.FindMember(
"viewOcclusionHintLTRB");
834 if (view_occlusion_hint !=
args.MemberEnd()) {
835 if (view_occlusion_hint->value.IsArray()) {
836 const auto& view_occlusion_hint_array =
837 view_occlusion_hint->value.GetArray();
838 if (view_occlusion_hint_array.Size() == 4) {
839 bool parse_error =
false;
840 for (
int i = 0;
i < 4;
i++) {
841 auto& array_val = view_occlusion_hint_array[
i];
842 if (!array_val.IsDouble()) {
843 FML_LOG(ERROR) <<
"Argument 'viewOcclusionHintLTRB' element " <<
i
844 <<
" is not a double";
851 view_occlusion_hint_raw =
852 SkRect::MakeLTRB(view_occlusion_hint_array[0].GetDouble(),
853 view_occlusion_hint_array[1].GetDouble(),
854 view_occlusion_hint_array[2].GetDouble(),
855 view_occlusion_hint_array[3].GetDouble());
859 <<
"Argument 'viewOcclusionHintLTRB' expected size 4; got "
860 << view_occlusion_hint_array.Size();
864 <<
"Argument 'viewOcclusionHintLTRB' is not a double array";
867 FML_LOG(WARNING) <<
"Argument 'viewOcclusionHintLTRB' is missing";
870 on_update_view_callback_(
871 view_id->value.GetUint64(), view_occlusion_hint_raw,
872 hit_testable->value.GetBool(), focusable->value.GetBool());
874 message->response()->Complete(std::make_unique<fml::DataMapping>(
875 std::vector<uint8_t>({
'[',
'0',
']'})));
878 }
else if (method ==
"View.dispose") {
879 auto args_it = root.FindMember(
"args");
880 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
881 FML_LOG(ERROR) <<
"No arguments found.";
884 const auto&
args = args_it->value;
887 if (!
view_id->value.IsUint64()) {
888 FML_LOG(ERROR) <<
"Argument 'viewId' is not a int64";
892 OnDisposeView(
view_id->value.GetUint64());
894 message->response()->Complete(std::make_unique<fml::DataMapping>(
895 std::vector<uint8_t>({
'[',
'0',
']'})));
898 }
else if (method.rfind(
"View.focus", 0) == 0) {
899 return focus_delegate_->HandlePlatformMessage(root,
message->response());
900 }
else if (method.rfind(PointerInjectorDelegate::kPointerInjectorMethodPrefix,
902 return pointer_injector_delegate_->HandlePlatformMessage(
905 FML_LOG(ERROR) <<
"Unknown " <<
message->channel() <<
" method " << method;
911bool PlatformView::HandleFuchsiaShaderWarmupChannelPlatformMessage(
912 OnShaderWarmupCallback on_shader_warmup_callback,
913 std::unique_ptr<flutter::PlatformMessage>
message) {
916 if (!on_shader_warmup_callback) {
917 FML_LOG(ERROR) <<
"No shader warmup callback set!";
918 std::string result =
"[0]";
920 std::make_unique<fml::DataMapping>(std::vector<uint8_t>(
921 (
const uint8_t*)result.c_str(),
922 (
const uint8_t*)result.c_str() + result.length())));
927 rapidjson::Document document;
928 document.Parse(
reinterpret_cast<const char*
>(
data.GetMapping()),
930 if (document.HasParseError() || !document.IsObject()) {
931 FML_LOG(ERROR) <<
"Could not parse document";
934 auto root = document.GetObject();
935 auto method = root.FindMember(
"method");
936 if (method == root.MemberEnd() || !method->value.IsString() ||
937 method->value !=
"WarmupSkps") {
938 FML_LOG(ERROR) <<
"Invalid method name";
942 auto args_it = root.FindMember(
"args");
943 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
944 FML_LOG(ERROR) <<
"No arguments found.";
948 auto shaders_it = root[
"args"].FindMember(
"shaders");
949 if (shaders_it == root[
"args"].MemberEnd() || !shaders_it->value.IsArray()) {
950 FML_LOG(ERROR) <<
"No shaders found.";
954 auto width_it = root[
"args"].FindMember(
"width");
955 auto height_it = root[
"args"].FindMember(
"height");
956 if (width_it == root[
"args"].MemberEnd() || !width_it->value.IsNumber()) {
957 FML_LOG(ERROR) <<
"Invalid width";
960 if (height_it == root[
"args"].MemberEnd() || !height_it->value.IsNumber()) {
961 FML_LOG(ERROR) <<
"Invalid height";
964 auto width = width_it->value.GetUint64();
965 auto height = height_it->value.GetUint64();
967 std::vector<std::string> skp_paths;
968 const auto& shaders = shaders_it->value;
969 for (rapidjson::Value::ConstValueIterator itr = shaders.Begin();
970 itr != shaders.End(); ++itr) {
971 skp_paths.push_back((*itr).GetString());
974 auto completion_callback = [response =
975 message->response()](uint32_t num_successes) {
976 std::ostringstream result_stream;
977 result_stream <<
"[" << num_successes <<
"]";
979 std::string result(result_stream.str());
981 response->Complete(std::make_unique<fml::DataMapping>(std::vector<uint8_t>(
982 (
const uint8_t*)result.c_str(),
983 (
const uint8_t*)result.c_str() + result.length())));
986 on_shader_warmup_callback(skp_paths, completion_callback,
width,
height);
992bool PlatformView::HandleFuchsiaInputTestChannelPlatformMessage(
993 std::unique_ptr<flutter::PlatformMessage>
message) {
997 rapidjson::Document document;
998 document.Parse(
reinterpret_cast<const char*
>(
data.GetMapping()),
1000 if (document.HasParseError() || !document.IsObject()) {
1001 FML_LOG(ERROR) <<
"Could not parse document";
1004 auto root = document.GetObject();
1005 auto method = root.FindMember(
"method");
1006 if (method == root.MemberEnd() || !method->value.IsString()) {
1007 FML_LOG(ERROR) <<
"Missing method";
1011 FML_LOG(INFO) <<
"fuchsia/input_test: method=" << method->value.GetString();
1013 if (method->value ==
"TouchInputListener.ReportTouchInput") {
1014 if (!touch_input_listener_) {
1015 FML_LOG(ERROR) <<
"TouchInputListener not found.";
1019 fuchsia::ui::test::input::TouchInputListenerReportTouchInputRequest request;
1020 CallWithMember<double>(
1021 root,
"local_x", [&](
double local_x) { request.set_local_x(local_x); });
1022 CallWithMember<double>(
1023 root,
"local_y", [&](
double local_y) { request.set_local_y(local_y); });
1024 CallWithMember<int64_t>(root,
"time_received", [&](uint64_t time_received) {
1025 request.set_time_received(time_received);
1027 CallWithMember<std::string>(root,
"component_name",
1028 [&](std::string component_name) {
1029 request.set_component_name(component_name);
1032 touch_input_listener_->ReportTouchInput(std::move(request));
1036 if (method->value ==
"KeyboardInputListener.ReportTextInput") {
1037 if (!keyboard_input_listener_) {
1038 FML_LOG(ERROR) <<
"KeyboardInputListener not found.";
1042 fuchsia::ui::test::input::KeyboardInputListenerReportTextInputRequest
1044 CallWithMember<std::string>(
1045 root,
"text", [&](std::string
text) { request.set_text(
text); });
1047 keyboard_input_listener_->ReportTextInput(std::move(request));
1051 if (method->value ==
"MouseInputListener.ReportMouseInput") {
1052 if (!mouse_input_listener_) {
1053 FML_LOG(ERROR) <<
"MouseInputListener not found.";
1057 fuchsia::ui::test::input::MouseInputListenerReportMouseInputRequest request;
1058 CallWithMember<double>(
1059 root,
"local_x", [&](
double local_x) { request.set_local_x(local_x); });
1060 CallWithMember<double>(
1061 root,
"local_y", [&](
double local_y) { request.set_local_y(local_y); });
1062 CallWithMember<int64_t>(root,
"time_received", [&](uint64_t time_received) {
1063 request.set_time_received(time_received);
1065 CallWithMember<std::string>(root,
"component_name",
1066 [&](std::string component_name) {
1067 request.set_component_name(component_name);
1069 CallWithMember<int>(root,
"buttons", [&](
int button_mask) {
1070 std::vector<fuchsia::ui::test::input::MouseButton> buttons;
1071 if (button_mask & 1) {
1072 buttons.push_back(fuchsia::ui::test::input::MouseButton::FIRST);
1074 if (button_mask & 2) {
1075 buttons.push_back(fuchsia::ui::test::input::MouseButton::SECOND);
1077 if (button_mask & 4) {
1078 buttons.push_back(fuchsia::ui::test::input::MouseButton::THIRD);
1080 request.set_buttons(buttons);
1082 CallWithMember<std::string>(root,
"phase", [&](std::string phase) {
1083 if (phase ==
"add") {
1084 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::ADD);
1085 }
else if (phase ==
"hover") {
1086 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::HOVER);
1087 }
else if (phase ==
"down") {
1088 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::DOWN);
1089 }
else if (phase ==
"move") {
1090 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::MOVE);
1091 }
else if (phase ==
"up") {
1092 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::UP);
1094 FML_LOG(ERROR) <<
"Unexpected mouse phase: " << phase;
1097 CallWithMember<double>(
1098 root,
"wheel_x_physical_pixel", [&](
double wheel_x_physical_pixel) {
1099 request.set_wheel_x_physical_pixel(wheel_x_physical_pixel);
1101 CallWithMember<double>(
1102 root,
"wheel_y_physical_pixel", [&](
double wheel_y_physical_pixel) {
1103 request.set_wheel_y_physical_pixel(wheel_y_physical_pixel);
1106 mouse_input_listener_->ReportMouseInput(std::move(request));
1110 FML_LOG(ERROR) <<
"fuchsia/input_test: unrecognized method "
1111 << method->value.GetString();
1116bool PlatformView::HandleFuchsiaChildViewChannelPlatformMessage(
1117 std::unique_ptr<flutter::PlatformMessage>
message) {
1120 if (
message->data().GetSize() != 1 ||
1121 (
message->data().GetMapping()[0] !=
'1')) {
1123 <<
" data must be singularly '1'.";
1131 <<
" must have a response callback.";
1135 if (!dart_application_svc_) {
1136 FML_LOG(ERROR) <<
"No service directory.";
1140 fuchsia::ui::app::ViewProviderHandle view_provider_handle;
1141 zx_status_t status =
1142 dart_application_svc_->Connect(view_provider_handle.NewRequest());
1143 if (status != ZX_OK) {
1144 FML_LOG(ERROR) <<
"Failed to connect to view provider.";
1147 fuchsia::ui::app::ViewProviderPtr view_provider;
1148 view_provider.Bind(std::move(view_provider_handle));
1152 zx::channel view_tokens[2];
1153 fuchsia::ui::views::ViewportCreationToken viewport_creation_token;
1154 fuchsia::ui::views::ViewCreationToken view_creation_token;
1155 status = zx::channel::create(0, &viewport_creation_token.value,
1156 &view_creation_token.value);
1157 if (status != ZX_OK) {
1158 FML_LOG(ERROR) <<
"Creating view tokens: " << zx_status_get_string(status);
1162 fuchsia::ui::app::CreateView2Args create_view_args;
1163 create_view_args.set_view_creation_token(std::move(view_creation_token));
1164 view_provider->CreateView2(std::move(create_view_args));
1166 view_id = std::move(viewport_creation_token.value);
1169 message->response()->Complete(
1170 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 GBytes * message
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)