5#define RAPIDJSON_HAS_STDSTRING 1
9#include <fuchsia/ui/app/cpp/fidl.h>
10#include <zircon/status.h>
17#include "flutter/fml/logging.h"
18#include "flutter/fml/make_copyable.h"
19#include "flutter/lib/ui/window/pointer_data.h"
20#include "flutter/shell/platform/common/client_wrapper/include/flutter/encodable_value.h"
21#include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_message_codec.h"
22#include "third_party/rapidjson/include/rapidjson/document.h"
23#include "third_party/rapidjson/include/rapidjson/stringbuffer.h"
24#include "third_party/rapidjson/include/rapidjson/writer.h"
26#include "flutter/fml/make_copyable.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(
225 fit::bind_member(
this, &PlatformView::OnGetLayout));
226 parent_viewport_watcher_->GetStatus(
227 fit::bind_member(
this, &PlatformView::OnParentViewportStatus));
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) {
261 case fuchsia::ui::input::PointerEventPhase::HOVER:
263 case fuchsia::ui::input::PointerEventPhase::DOWN:
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()) {
335 view_pixel_ratio_ =
info.device_pixel_ratio().x;
338 float pixel_ratio = view_pixel_ratio_ ? *view_pixel_ratio_ : 1.0f;
365 parent_viewport_watcher_->GetLayout(
366 fit::bind_member(
this, &PlatformView::OnGetLayout));
369void PlatformView::OnParentViewportStatus(
370 fuchsia::ui::composition::ParentViewportStatus status) {
373 parent_viewport_status_ = status;
374 parent_viewport_watcher_->GetStatus(
375 fit::bind_member(
this, &PlatformView::OnParentViewportStatus));
378void PlatformView::OnChildViewStatus(
380 fuchsia::ui::composition::ChildViewStatus status) {
381 FML_DCHECK(child_view_info_.count(content_id) == 1);
383 std::ostringstream
out;
384 out <<
"{" <<
"\"method\":\"View.viewStateChanged\"," <<
"\"args\":{"
385 <<
" \"viewId\":" << child_view_info_.at(content_id).view_id
387 <<
" \"is_rendering\":true,"
392 std::unique_ptr<flutter::PlatformMessage>
message =
393 std::make_unique<flutter::PlatformMessage>(
394 "flutter/platform_views",
398 child_view_info_.at(content_id)
399 .child_view_watcher->GetStatus(
400 [
this, content_id](fuchsia::ui::composition::ChildViewStatus status) {
401 OnChildViewStatus(content_id, status);
405void PlatformView::OnChildViewViewRef(uint64_t content_id,
407 fuchsia::ui::views::ViewRef view_ref) {
408 FML_CHECK(child_view_info_.count(content_id) == 1);
410 fuchsia::ui::views::ViewRef view_ref_clone;
411 fidl::Clone(view_ref, &view_ref_clone);
413 focus_delegate_->OnChildViewViewRef(view_id, std::move(view_ref));
415 pointer_injector_delegate_->OnCreateView(view_id, std::move(view_ref_clone));
416 OnChildViewConnected(content_id);
419void PlatformView::OnCreateView(
ViewCallback on_view_created,
423 auto on_view_bound = [weak = weak_factory_.GetWeakPtr(),
424 platform_task_runner =
426 view_id = view_id_raw](
427 fuchsia::ui::composition::ContentId content_id,
428 fuchsia::ui::composition::ChildViewWatcherHandle
429 child_view_watcher_handle) {
431 FML_CHECK(weak->child_view_info_.count(content_id.value) == 0);
434 [weak, view_id, content_id,
435 watcher_handle = std::move(child_view_watcher_handle)]()
mutable {
438 <<
"View bound to PlatformView after PlatformView was "
439 "destroyed; ignoring.";
445 fuchsia::ui::composition::ChildViewWatcherPtr child_view_watcher =
446 watcher_handle.Bind();
449 child_view_watcher.set_error_handler([weak, view_id, content_id](
450 zx_status_t status) {
452 <<
"Child disconnected. ChildViewWatcher status: " << status;
455 FML_LOG(WARNING) <<
"View bound to PlatformView after "
457 "destroyed; ignoring.";
462 weak->pointer_injector_delegate_->OnDestroyView(view_id);
464 weak->OnChildViewDisconnected(content_id.value);
467 weak->child_view_info_.emplace(
468 std::piecewise_construct, std::forward_as_tuple(content_id.value),
469 std::forward_as_tuple(view_id, std::move(child_view_watcher)));
471 weak->child_view_info_.at(content_id.value)
472 .child_view_watcher->GetStatus(
473 [weak,
id = content_id.value](
474 fuchsia::ui::composition::ChildViewStatus status) {
475 weak->OnChildViewStatus(
id, status);
478 weak->child_view_info_.at(content_id.value)
479 .child_view_watcher->GetViewRef(
480 [weak, content_id = content_id.value,
481 view_id](fuchsia::ui::views::ViewRef view_ref) {
482 weak->OnChildViewViewRef(content_id, view_id,
483 std::move(view_ref));
488 on_create_view_callback_(view_id_raw, std::move(on_view_created),
489 std::move(on_view_bound), hit_testable, focusable);
492void PlatformView::OnDisposeView(int64_t view_id_raw) {
493 auto on_view_unbound =
494 [weak = weak_factory_.GetWeakPtr(),
495 platform_task_runner =
task_runners_.GetPlatformTaskRunner(),
496 view_id_raw](fuchsia::ui::composition::ContentId content_id) {
497 platform_task_runner->PostTask([weak, content_id, view_id_raw]() {
500 <<
"View unbound from PlatformView after PlatformView"
501 "was destroyed; ignoring.";
505 FML_DCHECK(weak->child_view_info_.count(content_id.value) == 1);
506 weak->OnChildViewDisconnected(content_id.value);
507 weak->child_view_info_.erase(content_id.value);
508 weak->focus_delegate_->OnDisposeChildView(view_id_raw);
509 weak->pointer_injector_delegate_->OnDestroyView(view_id_raw);
512 on_destroy_view_callback_(view_id_raw, std::move(on_view_unbound));
515void PlatformView::OnChildViewConnected(uint64_t content_id) {
516 FML_CHECK(child_view_info_.count(content_id) == 1);
517 std::ostringstream
out;
518 out <<
"{" <<
"\"method\":\"View.viewConnected\"," <<
"\"args\":{"
519 <<
" \"viewId\":" << child_view_info_.at(content_id).view_id <<
" }"
523 std::unique_ptr<flutter::PlatformMessage>
message =
524 std::make_unique<flutter::PlatformMessage>(
525 "flutter/platform_views",
530void PlatformView::OnChildViewDisconnected(uint64_t content_id) {
531 FML_CHECK(child_view_info_.count(content_id) == 1);
532 std::ostringstream
out;
533 out <<
"{" <<
"\"method\":\"View.viewDisconnected\"," <<
"\"args\":{"
534 <<
" \"viewId\":" << child_view_info_.at(content_id).view_id <<
" }"
538 std::unique_ptr<flutter::PlatformMessage>
message =
539 std::make_unique<flutter::PlatformMessage>(
540 "flutter/platform_views",
545bool PlatformView::OnHandlePointerEvent(
546 const fuchsia::ui::input::PointerEvent& pointer) {
547 TRACE_EVENT0(
"flutter",
"PlatformView::OnHandlePointerEvent");
550 trace_flow_id_t trace_id =
554 const float pixel_ratio =
555 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
558 pointer_data.
Clear();
559 pointer_data.
time_stamp = pointer.event_time / 1000;
562 pointer_data.
device = pointer.pointer_id;
564 pointer_data.
physical_x = pointer.x * pixel_ratio;
565 pointer_data.
physical_y = pointer.y * pixel_ratio;
567 pointer_data.
buttons =
static_cast<uint64_t
>(pointer.buttons);
569 switch (pointer_data.
change) {
572 auto clamped_pointer = ClampToViewSpace(pointer.x, pointer.y);
573 pointer_data.
physical_x = clamped_pointer[0] * pixel_ratio;
574 pointer_data.
physical_y = clamped_pointer[1] * pixel_ratio;
576 down_pointers_.insert(pointer_data.
device);
581 down_pointers_.erase(pointer_data.
device);
584 if (down_pointers_.count(pointer_data.
device) == 0) {
589 if (down_pointers_.count(pointer_data.
device) != 0) {
590 FML_LOG(
ERROR) <<
"Received add event for down pointer.";
594 if (down_pointers_.count(pointer_data.
device) != 0) {
595 FML_LOG(
ERROR) <<
"Received remove event for down pointer.";
599 if (down_pointers_.count(pointer_data.
device) != 0) {
600 FML_LOG(
ERROR) <<
"Received hover event for down pointer.";
606 FML_DLOG(
ERROR) <<
"Unexpectedly received pointer pan/zoom event";
610 auto packet = std::make_unique<flutter::PointerDataPacket>(1);
611 packet->SetPointerData(0, pointer_data);
617std::unique_ptr<flutter::VsyncWaiter> PlatformView::CreateVSyncWaiter() {
618 return std::make_unique<flutter_runner::VsyncWaiter>(
619 await_vsync_callback_, await_vsync_for_secondary_callback_callback_,
624std::unique_ptr<flutter::Surface> PlatformView::CreateRenderingSurface() {
625 return on_create_surface_callback_ ? on_create_surface_callback_() : nullptr;
629std::shared_ptr<flutter::ExternalViewEmbedder>
630PlatformView::CreateExternalViewEmbedder() {
631 return external_view_embedder_;
635void PlatformView::HandlePlatformMessage(
636 std::unique_ptr<flutter::PlatformMessage>
message) {
640 const std::string channel =
message->channel();
641 auto found = platform_message_handlers_.find(channel);
642 if (found == platform_message_handlers_.end()) {
643 const bool already_errored = unregistered_channels_.count(channel);
644 if (!already_errored) {
646 <<
"Platform view received message on channel '" <<
message->channel()
647 <<
"' with no registered handler. An empty response will be "
648 "generated. Please implement the native message handler. This "
649 "message will appear only once per channel.";
650 unregistered_channels_.insert(channel);
655 auto response =
message->response();
656 bool response_handled = found->second(std::move(
message));
659 if (response && !response_handled) {
662 response->CompleteEmpty();
678void PlatformView::UpdateSemantics(
681 const float pixel_ratio =
682 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
684 on_semantics_node_update_callback_(
update, pixel_ratio);
688bool PlatformView::HandleAccessibilityChannelPlatformMessage(
689 std::unique_ptr<flutter::PlatformMessage>
message) {
694 std::unique_ptr<flutter::EncodableValue> decoded =
701 if (
type ==
"announce") {
707 on_request_announce_callback_(
text);
715bool PlatformView::HandleFlutterPlatformChannelPlatformMessage(
716 std::unique_ptr<flutter::PlatformMessage>
message) {
725bool PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage(
726 std::unique_ptr<flutter::PlatformMessage>
message) {
729 rapidjson::Document document;
730 document.Parse(
reinterpret_cast<const char*
>(
data.GetMapping()),
732 if (document.HasParseError() || !document.IsObject()) {
736 auto root = document.GetObject();
737 auto method_member =
root.FindMember(
"method");
738 if (method_member ==
root.MemberEnd() || !method_member->value.IsString()) {
741 std::string method(method_member->value.GetString());
743 if (method ==
"View.enableWireframe") {
744 auto args_it =
root.FindMember(
"args");
745 if (args_it ==
root.MemberEnd() || !args_it->value.IsObject()) {
749 const auto&
args = args_it->value;
751 auto enable =
args.FindMember(
"enable");
752 if (!enable->value.IsBool()) {
757 wireframe_enabled_callback_(enable->value.GetBool());
758 }
else if (method ==
"View.create") {
759 auto args_it =
root.FindMember(
"args");
760 if (args_it ==
root.MemberEnd() || !args_it->value.IsObject()) {
764 const auto&
args = args_it->value;
766 auto view_id =
args.FindMember(
"viewId");
767 if (!view_id->value.IsUint64()) {
772 auto hit_testable =
args.FindMember(
"hitTestable");
773 if (!hit_testable->value.IsBool()) {
774 FML_LOG(
ERROR) <<
"Argument 'hitTestable' is not a bool";
778 auto focusable =
args.FindMember(
"focusable");
779 if (!focusable->value.IsBool()) {
785 [platform_task_runner =
task_runners_.GetPlatformTaskRunner(),
789 if (message->response()) {
790 message->response()->Complete(std::make_unique<fml::DataMapping>(
791 std::vector<uint8_t>({
'[',
'0',
']'})));
794 OnCreateView(std::move(on_view_created), view_id->value.GetUint64(),
795 hit_testable->value.GetBool(), focusable->value.GetBool());
797 }
else if (method ==
"View.update") {
798 auto args_it =
root.FindMember(
"args");
799 if (args_it ==
root.MemberEnd() || !args_it->value.IsObject()) {
803 const auto&
args = args_it->value;
805 auto view_id =
args.FindMember(
"viewId");
806 if (!view_id->value.IsUint64()) {
811 auto hit_testable =
args.FindMember(
"hitTestable");
812 if (!hit_testable->value.IsBool()) {
813 FML_LOG(
ERROR) <<
"Argument 'hitTestable' is not a bool";
817 auto focusable =
args.FindMember(
"focusable");
818 if (!focusable->value.IsBool()) {
824 auto view_occlusion_hint =
args.FindMember(
"viewOcclusionHintLTRB");
825 if (view_occlusion_hint !=
args.MemberEnd()) {
826 if (view_occlusion_hint->value.IsArray()) {
827 const auto& view_occlusion_hint_array =
828 view_occlusion_hint->value.GetArray();
829 if (view_occlusion_hint_array.Size() == 4) {
830 bool parse_error =
false;
831 for (
int i = 0;
i < 4;
i++) {
832 auto& array_val = view_occlusion_hint_array[
i];
833 if (!array_val.IsDouble()) {
834 FML_LOG(
ERROR) <<
"Argument 'viewOcclusionHintLTRB' element " <<
i
835 <<
" is not a double";
842 view_occlusion_hint_raw =
844 view_occlusion_hint_array[1].GetDouble(),
845 view_occlusion_hint_array[2].GetDouble(),
846 view_occlusion_hint_array[3].GetDouble());
850 <<
"Argument 'viewOcclusionHintLTRB' expected size 4; got "
851 << view_occlusion_hint_array.Size();
855 <<
"Argument 'viewOcclusionHintLTRB' is not a double array";
858 FML_LOG(WARNING) <<
"Argument 'viewOcclusionHintLTRB' is missing";
861 on_update_view_callback_(
862 view_id->value.GetUint64(), view_occlusion_hint_raw,
863 hit_testable->value.GetBool(), focusable->value.GetBool());
865 message->response()->Complete(std::make_unique<fml::DataMapping>(
866 std::vector<uint8_t>({
'[',
'0',
']'})));
869 }
else if (method ==
"View.dispose") {
870 auto args_it =
root.FindMember(
"args");
871 if (args_it ==
root.MemberEnd() || !args_it->value.IsObject()) {
875 const auto&
args = args_it->value;
877 auto view_id =
args.FindMember(
"viewId");
878 if (!view_id->value.IsUint64()) {
883 OnDisposeView(view_id->value.GetUint64());
885 message->response()->Complete(std::make_unique<fml::DataMapping>(
886 std::vector<uint8_t>({
'[',
'0',
']'})));
889 }
else if (method.rfind(
"View.focus", 0) == 0) {
890 return focus_delegate_->HandlePlatformMessage(
root,
message->response());
891 }
else if (method.rfind(PointerInjectorDelegate::kPointerInjectorMethodPrefix,
893 return pointer_injector_delegate_->HandlePlatformMessage(
902bool PlatformView::HandleFuchsiaShaderWarmupChannelPlatformMessage(
904 std::unique_ptr<flutter::PlatformMessage>
message) {
907 if (!on_shader_warmup_callback) {
909 std::string
result =
"[0]";
911 std::make_unique<fml::DataMapping>(std::vector<uint8_t>(
912 (
const uint8_t*)
result.c_str(),
918 rapidjson::Document document;
919 document.Parse(
reinterpret_cast<const char*
>(
data.GetMapping()),
921 if (document.HasParseError() || !document.IsObject()) {
925 auto root = document.GetObject();
926 auto method =
root.FindMember(
"method");
927 if (method ==
root.MemberEnd() || !method->value.IsString() ||
928 method->value !=
"WarmupSkps") {
933 auto args_it =
root.FindMember(
"args");
934 if (args_it ==
root.MemberEnd() || !args_it->value.IsObject()) {
939 auto shaders_it =
root[
"args"].FindMember(
"shaders");
940 if (shaders_it ==
root[
"args"].MemberEnd() || !shaders_it->value.IsArray()) {
945 auto width_it =
root[
"args"].FindMember(
"width");
946 auto height_it =
root[
"args"].FindMember(
"height");
947 if (width_it ==
root[
"args"].MemberEnd() || !width_it->value.IsNumber()) {
951 if (height_it ==
root[
"args"].MemberEnd() || !height_it->value.IsNumber()) {
955 auto width = width_it->value.GetUint64();
956 auto height = height_it->value.GetUint64();
958 std::vector<std::string> skp_paths;
959 const auto& shaders = shaders_it->value;
960 for (rapidjson::Value::ConstValueIterator itr = shaders.Begin();
961 itr != shaders.End(); ++itr) {
962 skp_paths.push_back((*itr).GetString());
965 auto completion_callback = [response =
966 message->response()](uint32_t num_successes) {
967 std::ostringstream result_stream;
968 result_stream <<
"[" << num_successes <<
"]";
970 std::string
result(result_stream.str());
972 response->Complete(std::make_unique<fml::DataMapping>(std::vector<uint8_t>(
973 (
const uint8_t*)
result.c_str(),
977 on_shader_warmup_callback(skp_paths, completion_callback,
width,
height);
983bool PlatformView::HandleFuchsiaInputTestChannelPlatformMessage(
984 std::unique_ptr<flutter::PlatformMessage>
message) {
988 rapidjson::Document document;
989 document.Parse(
reinterpret_cast<const char*
>(
data.GetMapping()),
991 if (document.HasParseError() || !document.IsObject()) {
995 auto root = document.GetObject();
996 auto method =
root.FindMember(
"method");
997 if (method ==
root.MemberEnd() || !method->value.IsString()) {
1002 FML_LOG(INFO) <<
"fuchsia/input_test: method=" << method->value.GetString();
1004 if (method->value ==
"TouchInputListener.ReportTouchInput") {
1005 if (!touch_input_listener_) {
1010 fuchsia::ui::test::input::TouchInputListenerReportTouchInputRequest request;
1011 CallWithMember<double>(
1012 root,
"local_x", [&](
double local_x) { request.set_local_x(local_x); });
1013 CallWithMember<double>(
1014 root,
"local_y", [&](
double local_y) { request.set_local_y(local_y); });
1015 CallWithMember<int64_t>(
root,
"time_received", [&](uint64_t time_received) {
1016 request.set_time_received(time_received);
1018 CallWithMember<std::string>(
root,
"component_name",
1019 [&](std::string component_name) {
1020 request.set_component_name(component_name);
1023 touch_input_listener_->ReportTouchInput(std::move(request));
1027 if (method->value ==
"KeyboardInputListener.ReportTextInput") {
1028 if (!keyboard_input_listener_) {
1033 fuchsia::ui::test::input::KeyboardInputListenerReportTextInputRequest
1035 CallWithMember<std::string>(
1036 root,
"text", [&](std::string
text) { request.set_text(
text); });
1038 keyboard_input_listener_->ReportTextInput(std::move(request));
1042 if (method->value ==
"MouseInputListener.ReportMouseInput") {
1043 if (!mouse_input_listener_) {
1048 fuchsia::ui::test::input::MouseInputListenerReportMouseInputRequest request;
1049 CallWithMember<double>(
1050 root,
"local_x", [&](
double local_x) { request.set_local_x(local_x); });
1051 CallWithMember<double>(
1052 root,
"local_y", [&](
double local_y) { request.set_local_y(local_y); });
1053 CallWithMember<int64_t>(
root,
"time_received", [&](uint64_t time_received) {
1054 request.set_time_received(time_received);
1056 CallWithMember<std::string>(
root,
"component_name",
1057 [&](std::string component_name) {
1058 request.set_component_name(component_name);
1060 CallWithMember<int>(
root,
"buttons", [&](
int button_mask) {
1061 std::vector<fuchsia::ui::test::input::MouseButton> buttons;
1062 if (button_mask & 1) {
1063 buttons.push_back(fuchsia::ui::test::input::MouseButton::FIRST);
1065 if (button_mask & 2) {
1066 buttons.push_back(fuchsia::ui::test::input::MouseButton::SECOND);
1068 if (button_mask & 4) {
1069 buttons.push_back(fuchsia::ui::test::input::MouseButton::THIRD);
1071 request.set_buttons(buttons);
1073 CallWithMember<std::string>(
root,
"phase", [&](std::string phase) {
1074 if (phase ==
"add") {
1076 }
else if (phase ==
"hover") {
1077 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::HOVER);
1078 }
else if (phase ==
"down") {
1079 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::DOWN);
1080 }
else if (phase ==
"move") {
1082 }
else if (phase ==
"up") {
1083 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::UP);
1088 CallWithMember<double>(
1089 root,
"wheel_x_physical_pixel", [&](
double wheel_x_physical_pixel) {
1090 request.set_wheel_x_physical_pixel(wheel_x_physical_pixel);
1092 CallWithMember<double>(
1093 root,
"wheel_y_physical_pixel", [&](
double wheel_y_physical_pixel) {
1094 request.set_wheel_y_physical_pixel(wheel_y_physical_pixel);
1097 mouse_input_listener_->ReportMouseInput(std::move(request));
1101 FML_LOG(
ERROR) <<
"fuchsia/input_test: unrecognized method "
1102 << method->value.GetString();
1107bool PlatformView::HandleFuchsiaChildViewChannelPlatformMessage(
1108 std::unique_ptr<flutter::PlatformMessage>
message) {
1111 if (
message->data().GetSize() != 1 ||
1112 (
message->data().GetMapping()[0] !=
'1')) {
1114 <<
" data must be singularly '1'.";
1122 <<
" must have a response callback.";
1126 if (!dart_application_svc_) {
1131 fuchsia::ui::app::ViewProviderHandle view_provider_handle;
1132 zx_status_t status =
1133 dart_application_svc_->Connect(view_provider_handle.NewRequest());
1134 if (status != ZX_OK) {
1135 FML_LOG(
ERROR) <<
"Failed to connect to view provider.";
1138 fuchsia::ui::app::ViewProviderPtr view_provider;
1139 view_provider.Bind(std::move(view_provider_handle));
1143 zx::channel view_tokens[2];
1144 fuchsia::ui::views::ViewportCreationToken viewport_creation_token;
1145 fuchsia::ui::views::ViewCreationToken view_creation_token;
1147 &view_creation_token.value);
1148 if (status != ZX_OK) {
1149 FML_LOG(
ERROR) <<
"Creating view tokens: " << zx_status_get_string(status);
1153 fuchsia::ui::app::CreateView2Args create_view_args;
1154 create_view_args.set_view_creation_token(std::move(view_creation_token));
1155 view_provider->CreateView2(std::move(create_view_args));
1157 view_id = std::move(viewport_creation_token.value);
1160 message->response()->Complete(
1161 std::make_unique<fml::DataMapping>(
std::to_string(view_id.release())
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
for(const auto glyph :glyphs)
static void round(SkPoint *p)
static unsigned clamp(SkFixed fx, int max)
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)
static constexpr FlutterViewId kFlutterImplicitViewId
TaskRunners task_runners_
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
#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
static void DispatchPointerDataPacket(JNIEnv *env, jobject jcaller, jlong shell_holder, jobject buffer, jint position)
std::unordered_map< int32_t, SemanticsNode > SemanticsNodeUpdates
std::unordered_map< int32_t, CustomAccessibilityAction > CustomAccessibilityActionUpdates
static void SetSemanticsEnabled(JNIEnv *env, jobject jcaller, jlong shell_holder, jboolean enabled)
static void DispatchPlatformMessage(JNIEnv *env, jobject jcaller, jlong shell_holder, jstring channel, jobject message, jint position, jint responseId)
static void SetViewportMetrics(JNIEnv *env, jobject jcaller, jlong shell_holder, jfloat devicePixelRatio, jint physicalWidth, jint physicalHeight, jint physicalPaddingTop, jint physicalPaddingRight, jint physicalPaddingBottom, jint physicalPaddingLeft, jint physicalViewInsetTop, jint physicalViewInsetRight, jint physicalViewInsetBottom, jint physicalViewInsetLeft, jint systemGestureInsetTop, jint systemGestureInsetRight, jint systemGestureInsetBottom, jint systemGestureInsetLeft, jint physicalTouchSlop, jintArray javaDisplayFeaturesBounds, jintArray javaDisplayFeaturesType, jintArray javaDisplayFeaturesState)
std::map< EncodableValue, EncodableValue > EncodableMap
static void SetAccessibilityFeatures(JNIEnv *env, jobject jcaller, jlong shell_holder, jint flags)
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
internal::CopyableLambda< T > MakeCopyable(T lambda)
static bool Bind(PassBindingsCacheMTL &pass, ShaderStage stage, size_t bind_index, const BufferView &view)
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>
static SkString to_string(int n)
static constexpr SkRect MakeEmpty()
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
std::shared_ptr< const fml::Mapping > data
#define TRACE_EVENT0(category_group, name)
#define TRACE_FLOW_END(category, name, id)