Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
platform_view.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#define RAPIDJSON_HAS_STDSTRING 1
6
7#include "platform_view.h"
8
9#include <fuchsia/ui/app/cpp/fidl.h>
10#include <zircon/status.h>
11
12#include <algorithm>
13#include <cstring>
14#include <limits>
15#include <sstream>
16
17#include "flutter/fml/logging.h"
22#include "third_party/rapidjson/include/rapidjson/document.h"
23#include "third_party/rapidjson/include/rapidjson/stringbuffer.h"
24#include "third_party/rapidjson/include/rapidjson/writer.h"
25
27#include "logging.h"
30#include "text_delegate.h"
31#include "vsync_waiter.h"
32
33namespace {
34// Helper to extract a given member with a given type from a rapidjson object.
35template <typename T, typename O, typename F>
36bool CallWithMember(O obj, const char* member_name, F func) {
37 auto it = obj.FindMember(member_name);
38 if (it == obj.MemberEnd()) {
39 return false;
40 }
41 if (!it->value.template Is<T>()) {
42 return false;
43 }
44 func(it->value.template Get<T>());
45 return true;
46}
47} // namespace
48
49namespace flutter_runner {
50
51static constexpr char kFlutterPlatformChannel[] = "flutter/platform";
52static constexpr char kAccessibilityChannel[] = "flutter/accessibility";
53static constexpr char kFlutterPlatformViewsChannel[] = "flutter/platform_views";
54static constexpr char kFuchsiaShaderWarmupChannel[] = "fuchsia/shader_warmup";
55static constexpr char kFuchsiaInputTestChannel[] = "fuchsia/input_test";
56static constexpr char kFuchsiaChildViewChannel[] = "fuchsia/child_view";
57static constexpr int64_t kFlutterImplicitViewId = 0ll;
58
61 flutter::TaskRunners task_runners,
62 fuchsia::ui::views::ViewRef view_ref,
63 std::shared_ptr<flutter::ExternalViewEmbedder> external_view_embedder,
64 fuchsia::ui::input::ImeServiceHandle ime_service,
65 fuchsia::ui::input3::KeyboardHandle keyboard,
66 fuchsia::ui::pointer::TouchSourceHandle touch_source,
67 fuchsia::ui::pointer::MouseSourceHandle mouse_source,
68 fuchsia::ui::views::FocuserHandle focuser,
69 fuchsia::ui::views::ViewRefFocusedHandle view_ref_focused,
70 fuchsia::ui::composition::ParentViewportWatcherHandle
71 parent_viewport_watcher,
72 fuchsia::ui::pointerinjector::RegistryHandle pointerinjector_registry,
73 OnEnableWireframeCallback wireframe_enabled_callback,
74 OnCreateViewCallback on_create_view_callback,
75 OnUpdateViewCallback on_update_view_callback,
76 OnDestroyViewCallback on_destroy_view_callback,
77 OnCreateSurfaceCallback on_create_surface_callback,
78 OnSemanticsNodeUpdateCallback on_semantics_node_update_callback,
79 OnRequestAnnounceCallback on_request_announce_callback,
80 OnShaderWarmupCallback on_shader_warmup_callback,
81 AwaitVsyncCallback await_vsync_callback,
83 await_vsync_for_secondary_callback_callback,
84 std::shared_ptr<sys::ServiceDirectory> dart_application_svc)
85 : flutter::PlatformView(delegate, std::move(task_runners)),
86 external_view_embedder_(external_view_embedder),
87 focus_delegate_(
88 std::make_shared<FocusDelegate>(std::move(view_ref_focused),
89 std::move(focuser))),
90 pointer_delegate_(
91 std::make_shared<PointerDelegate>(std::move(touch_source),
92 std::move(mouse_source))),
93 wireframe_enabled_callback_(std::move(wireframe_enabled_callback)),
94 on_update_view_callback_(std::move(on_update_view_callback)),
95 on_create_surface_callback_(std::move(on_create_surface_callback)),
96 on_semantics_node_update_callback_(
97 std::move(on_semantics_node_update_callback)),
98 on_request_announce_callback_(std::move(on_request_announce_callback)),
99 on_create_view_callback_(std::move(on_create_view_callback)),
100 on_destroy_view_callback_(std::move(on_destroy_view_callback)),
101 on_shader_warmup_callback_(std::move(on_shader_warmup_callback)),
102 await_vsync_callback_(await_vsync_callback),
103 await_vsync_for_secondary_callback_callback_(
104 await_vsync_for_secondary_callback_callback),
105 dart_application_svc_(dart_application_svc),
106 parent_viewport_watcher_(parent_viewport_watcher.Bind()),
107 weak_factory_(this) {
108 fuchsia::ui::views::ViewRef view_ref_clone;
109 fidl::Clone(view_ref, &view_ref_clone);
110
111 text_delegate_ =
112 std::make_unique<TextDelegate>(
113 std::move(view_ref), std::move(ime_service), std::move(keyboard),
114 [weak = weak_factory_.GetWeakPtr()](
115 std::unique_ptr<flutter::PlatformMessage> message) {
116 if (!weak) {
117 FML_LOG(WARNING)
118 << "PlatformView use-after-free attempted. Ignoring.";
119 }
120 weak->delegate_.OnPlatformViewDispatchPlatformMessage(
121 std::move(message));
122 });
123
124 // Begin watching for focus changes.
125 focus_delegate_->WatchLoop([weak = weak_factory_.GetWeakPtr()](bool focused) {
126 if (!weak) {
127 FML_LOG(WARNING) << "PlatformView use-after-free attempted. Ignoring.";
128 return;
129 }
130
131 // Ensure last_text_state_ is set to make sure Flutter actually wants
132 // an IME.
133 if (focused && weak->text_delegate_->HasTextState()) {
134 weak->text_delegate_->ActivateIme();
135 } else if (!focused) {
136 weak->text_delegate_->DeactivateIme();
137 }
138 });
139
140 // Begin watching for pointer events.
141 pointer_delegate_->WatchLoop([weak = weak_factory_.GetWeakPtr()](
142 std::vector<flutter::PointerData> events) {
143 if (!weak) {
144 FML_LOG(WARNING) << "PlatformView use-after-free attempted. Ignoring.";
145 return;
146 }
147
148 if (events.empty()) {
149 return; // No work, bounce out.
150 }
151
152 // If pixel ratio hasn't been set, use a default value of 1.
153 const float pixel_ratio = weak->view_pixel_ratio_.value_or(1.f);
154 auto packet = std::make_unique<flutter::PointerDataPacket>(events.size());
155 for (size_t i = 0; i < events.size(); ++i) {
156 auto& event = events[i];
157 // Translate logical to physical coordinates, as per
158 // flutter::PointerData contract. Done here because pixel ratio comes
159 // from the graphics API.
160 event.physical_x = event.physical_x * pixel_ratio;
161 event.physical_y = event.physical_y * pixel_ratio;
162 packet->SetPointerData(i, event);
163 }
164 weak->DispatchPointerDataPacket(std::move(packet));
165 });
166
167 // Configure the pointer injector delegate.
168 pointer_injector_delegate_ = std::make_unique<PointerInjectorDelegate>(
169 std::move(pointerinjector_registry), std::move(view_ref_clone));
170
171 // This is only used by the integration tests.
172 if (dart_application_svc) {
173 // Connect to TouchInputListener
174 fuchsia::ui::test::input::TouchInputListenerHandle touch_input_listener;
175 zx_status_t touch_input_listener_status =
176 dart_application_svc
177 ->Connect<fuchsia::ui::test::input::TouchInputListener>(
178 touch_input_listener.NewRequest());
179 if (touch_input_listener_status != ZX_OK) {
180 FML_LOG(WARNING)
181 << "fuchsia::ui::test::input::TouchInputListener connection failed: "
182 << zx_status_get_string(touch_input_listener_status);
183 } else {
184 touch_input_listener_.Bind(std::move(touch_input_listener));
185 }
186
187 // Connect to KeyboardInputListener
188 fuchsia::ui::test::input::KeyboardInputListenerHandle
189 keyboard_input_listener;
190 zx_status_t keyboard_input_listener_status =
191 dart_application_svc
192 ->Connect<fuchsia::ui::test::input::KeyboardInputListener>(
193 keyboard_input_listener.NewRequest());
194 if (keyboard_input_listener_status != ZX_OK) {
195 FML_LOG(WARNING) << "fuchsia::ui::test::input::KeyboardInputListener "
196 "connection failed: "
197 << zx_status_get_string(keyboard_input_listener_status);
198 } else {
199 keyboard_input_listener_.Bind(std::move(keyboard_input_listener));
200 }
201 // Connect to MouseInputListener
202 fuchsia::ui::test::input::MouseInputListenerHandle mouse_input_listener;
203 zx_status_t mouse_input_listener_status =
204 dart_application_svc
205 ->Connect<fuchsia::ui::test::input::MouseInputListener>(
206 mouse_input_listener.NewRequest());
207 if (mouse_input_listener_status != ZX_OK) {
208 FML_LOG(WARNING)
209 << "fuchsia::ui::test::input::MouseInputListener connection failed: "
210 << zx_status_get_string(mouse_input_listener_status);
211 } else {
212 mouse_input_listener_.Bind(std::move(mouse_input_listener));
213 }
214 }
215
216 // Finally! Register the native platform message handlers.
217 RegisterPlatformMessageHandlers();
218
219 parent_viewport_watcher_.set_error_handler([](zx_status_t status) {
220 FML_LOG(ERROR) << "Interface error on: ParentViewportWatcher status: "
221 << status;
222 });
223
224 parent_viewport_watcher_->GetLayout(
225 fit::bind_member(this, &PlatformView::OnGetLayout));
226 parent_viewport_watcher_->GetStatus(
227 fit::bind_member(this, &PlatformView::OnParentViewportStatus));
228}
229
230PlatformView::~PlatformView() = default;
231
232void PlatformView::RegisterPlatformMessageHandlers() {
233 platform_message_handlers_[kFlutterPlatformChannel] =
234 std::bind(&PlatformView::HandleFlutterPlatformChannelPlatformMessage,
235 this, std::placeholders::_1);
236 platform_message_handlers_[kTextInputChannel] =
237 std::bind(&TextDelegate::HandleFlutterTextInputChannelPlatformMessage,
238 text_delegate_.get(), std::placeholders::_1);
239 platform_message_handlers_[kAccessibilityChannel] =
240 std::bind(&PlatformView::HandleAccessibilityChannelPlatformMessage, this,
241 std::placeholders::_1);
242 platform_message_handlers_[kFlutterPlatformViewsChannel] =
243 std::bind(&PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage,
244 this, std::placeholders::_1);
245 platform_message_handlers_[kFuchsiaShaderWarmupChannel] =
246 std::bind(&HandleFuchsiaShaderWarmupChannelPlatformMessage,
247 on_shader_warmup_callback_, std::placeholders::_1);
248 platform_message_handlers_[kFuchsiaInputTestChannel] =
249 std::bind(&PlatformView::HandleFuchsiaInputTestChannelPlatformMessage,
250 this, std::placeholders::_1);
251 platform_message_handlers_[kFuchsiaChildViewChannel] =
252 std::bind(&PlatformView::HandleFuchsiaChildViewChannelPlatformMessage,
253 this, std::placeholders::_1);
254}
255
257 fuchsia::ui::input::PointerEventPhase phase) {
258 switch (phase) {
259 case fuchsia::ui::input::PointerEventPhase::ADD:
261 case fuchsia::ui::input::PointerEventPhase::HOVER:
263 case fuchsia::ui::input::PointerEventPhase::DOWN:
265 case fuchsia::ui::input::PointerEventPhase::MOVE:
267 case fuchsia::ui::input::PointerEventPhase::UP:
269 case fuchsia::ui::input::PointerEventPhase::REMOVE:
271 case fuchsia::ui::input::PointerEventPhase::CANCEL:
273 default:
275 }
276}
277
279 fuchsia::ui::input::PointerEventType type) {
280 switch (type) {
281 case fuchsia::ui::input::PointerEventType::TOUCH:
283 case fuchsia::ui::input::PointerEventType::MOUSE:
285 default:
287 }
288}
289
290// TODO(SCN-1278): Remove this.
291// Turns two floats (high bits, low bits) into a 64-bit uint.
292static trace_flow_id_t PointerTraceHACK(float fa, float fb) {
293 uint32_t ia, ib;
294 memcpy(&ia, &fa, sizeof(uint32_t));
295 memcpy(&ib, &fb, sizeof(uint32_t));
296 return (((uint64_t)ia) << 32) | ib;
297}
298
299// For certain scenarios that must avoid floating-point drift, compute a
300// coordinate that falls within the logical view bounding box.
301std::array<float, 2> PlatformView::ClampToViewSpace(const float x,
302 const float y) const {
303 if (!view_logical_size_.has_value() || !view_logical_origin_.has_value()) {
304 return {x, y}; // If we can't do anything, return the original values.
305 }
306
307 const auto origin = view_logical_origin_.value();
308 const auto size = view_logical_size_.value();
309 const float min_x = origin[0];
310 const float max_x = origin[0] + size[0];
311 const float min_y = origin[1];
312 const float max_y = origin[1] + size[1];
313 if (min_x <= x && x < max_x && min_y <= y && y < max_y) {
314 return {x, y}; // No clamping to perform.
315 }
316
317 // View boundary is [min_x, max_x) x [min_y, max_y). Note that min is
318 // inclusive, but max is exclusive - so we subtract epsilon.
319 const float max_x_inclusive = max_x - std::numeric_limits<float>::epsilon();
320 const float max_y_inclusive = max_y - std::numeric_limits<float>::epsilon();
321 const float& clamped_x = std::clamp(x, min_x, max_x_inclusive);
322 const float& clamped_y = std::clamp(y, min_y, max_y_inclusive);
323 FML_LOG(INFO) << "Clamped (" << x << ", " << y << ") to (" << clamped_x
324 << ", " << clamped_y << ").";
325 return {clamped_x, clamped_y};
326}
327
328void PlatformView::OnGetLayout(fuchsia::ui::composition::LayoutInfo info) {
329 view_logical_size_ = {static_cast<float>(info.logical_size().width),
330 static_cast<float>(info.logical_size().height)};
331
332 if (info.has_device_pixel_ratio()) {
333 // Both values should be identical for the Vec2 for DPR.
334 FML_DCHECK(info.device_pixel_ratio().x == info.device_pixel_ratio().y);
335 view_pixel_ratio_ = info.device_pixel_ratio().x;
336 }
337
338 float pixel_ratio = view_pixel_ratio_ ? *view_pixel_ratio_ : 1.0f;
340 pixel_ratio, // device_pixel_ratio
341 std::round(view_logical_size_.value()[0] *
342 pixel_ratio), // physical_width
343 std::round(view_logical_size_.value()[1] *
344 pixel_ratio), // physical_height
345 std::round(view_logical_size_.value()[0] *
346 pixel_ratio), // physical_min_width_constraint
347 std::round(view_logical_size_.value()[0] *
348 pixel_ratio), // physical_max_width_constraint
349 std::round(view_logical_size_.value()[1] *
350 pixel_ratio), // physical_min_height_constraint
351 std::round(view_logical_size_.value()[1] *
352 pixel_ratio), // physical_max_height_constraint
353 0.0f, // physical_padding_top
354 0.0f, // physical_padding_right
355 0.0f, // physical_padding_bottom
356 0.0f, // physical_padding_left
357 0.0f, // physical_view_inset_top
358 0.0f, // physical_view_inset_right
359 0.0f, // physical_view_inset_bottom
360 0.0f, // physical_view_inset_left
361 0.0f, // p_physical_system_gesture_inset_top
362 0.0f, // p_physical_system_gesture_inset_right
363 0.0f, // p_physical_system_gesture_inset_bottom
364 0.0f, // p_physical_system_gesture_inset_left,
365 -1.0, // p_physical_touch_slop,
366 {}, // p_physical_display_features_bounds
367 {}, // p_physical_display_features_type
368 {}, // p_physical_display_features_state
369 0, // p_display_id
370 -1.0, // p_physical_display_corner_radius_top_left
371 -1.0, // p_physical_display_corner_radius_top_right
372 -1.0, // p_physical_display_corner_radius_bottom_right
373 -1.0, // p_physical_display_corner_radius_bottom_left
374 };
375 SetViewportMetrics(kFlutterImplicitViewId, metrics);
376
377 parent_viewport_watcher_->GetLayout(
378 fit::bind_member(this, &PlatformView::OnGetLayout));
379}
380
381void PlatformView::OnParentViewportStatus(
382 fuchsia::ui::composition::ParentViewportStatus status) {
383 // TODO(fxbug.dev/116001): Investigate if it is useful to send hidden/shown
384 // signals.
385 parent_viewport_status_ = status;
386 parent_viewport_watcher_->GetStatus(
387 fit::bind_member(this, &PlatformView::OnParentViewportStatus));
388}
389
390void PlatformView::OnChildViewStatus(
391 uint64_t content_id,
392 fuchsia::ui::composition::ChildViewStatus status) {
393 FML_DCHECK(child_view_info_.count(content_id) == 1);
394
395 std::ostringstream out;
396 out << "{" << "\"method\":\"View.viewStateChanged\"," << "\"args\":{"
397 << " \"viewId\":" << child_view_info_.at(content_id).view_id
398 << "," // ViewId
399 << " \"is_rendering\":true," // IsViewRendering
400 << " \"state\":true" // IsViewRendering
401 << " }" << "}";
402 auto call = out.str();
403
404 std::unique_ptr<flutter::PlatformMessage> message =
405 std::make_unique<flutter::PlatformMessage>(
406 "flutter/platform_views",
407 fml::MallocMapping::Copy(call.c_str(), call.size()), nullptr);
408 DispatchPlatformMessage(std::move(message));
409
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);
414 });
415}
416
417void PlatformView::OnChildViewViewRef(uint64_t content_id,
418 uint64_t view_id,
419 fuchsia::ui::views::ViewRef view_ref) {
420 FML_CHECK(child_view_info_.count(content_id) == 1);
421
422 fuchsia::ui::views::ViewRef view_ref_clone;
423 fidl::Clone(view_ref, &view_ref_clone);
424
425 focus_delegate_->OnChildViewViewRef(view_id, std::move(view_ref));
426
427 pointer_injector_delegate_->OnCreateView(view_id, std::move(view_ref_clone));
428 OnChildViewConnected(content_id);
429}
430
431void PlatformView::OnCreateView(ViewCallback on_view_created,
432 int64_t view_id_raw,
433 bool hit_testable,
434 bool focusable) {
435 auto on_view_bound = [weak = weak_factory_.GetWeakPtr(),
436 platform_task_runner =
437 task_runners_.GetPlatformTaskRunner(),
438 view_id = view_id_raw](
439 fuchsia::ui::composition::ContentId content_id,
440 fuchsia::ui::composition::ChildViewWatcherHandle
441 child_view_watcher_handle) {
442 FML_CHECK(weak);
443 FML_CHECK(weak->child_view_info_.count(content_id.value) == 0);
444
445 platform_task_runner->PostTask(fml::MakeCopyable(
446 [weak, view_id, content_id,
447 watcher_handle = std::move(child_view_watcher_handle)]() mutable {
448 if (!weak) {
449 FML_LOG(WARNING)
450 << "View bound to PlatformView after PlatformView was "
451 "destroyed; ignoring.";
452 return;
453 }
454
455 // Bind the child view watcher to the platform thread so that the FIDL
456 // calls are handled on the platform thread.
457 fuchsia::ui::composition::ChildViewWatcherPtr child_view_watcher =
458 watcher_handle.Bind();
459 FML_CHECK(child_view_watcher);
460
461 child_view_watcher.set_error_handler([weak, view_id, content_id](
462 zx_status_t status) {
463 FML_LOG(WARNING)
464 << "Child disconnected. ChildViewWatcher status: " << status;
465
466 if (!weak) {
467 FML_LOG(WARNING) << "View bound to PlatformView after "
468 "PlatformView was "
469 "destroyed; ignoring.";
470 return;
471 }
472
473 // Disconnected views cannot listen to pointer events.
474 weak->pointer_injector_delegate_->OnDestroyView(view_id);
475
476 weak->OnChildViewDisconnected(content_id.value);
477 });
478
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)));
482
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);
488 });
489
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));
496 });
497 }));
498 };
499
500 on_create_view_callback_(view_id_raw, std::move(on_view_created),
501 std::move(on_view_bound), hit_testable, focusable);
502}
503
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]() {
510 if (!weak) {
511 FML_LOG(WARNING)
512 << "View unbound from PlatformView after PlatformView"
513 "was destroyed; ignoring.";
514 return;
515 }
516
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);
522 });
523 };
524 on_destroy_view_callback_(view_id_raw, std::move(on_view_unbound));
525}
526
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 << " }"
532 << "}";
533 auto call = out.str();
534
535 std::unique_ptr<flutter::PlatformMessage> message =
536 std::make_unique<flutter::PlatformMessage>(
537 "flutter/platform_views",
538 fml::MallocMapping::Copy(call.c_str(), call.size()), nullptr);
539 DispatchPlatformMessage(std::move(message));
540}
541
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 << " }"
547 << "}";
548 auto call = out.str();
549
550 std::unique_ptr<flutter::PlatformMessage> message =
551 std::make_unique<flutter::PlatformMessage>(
552 "flutter/platform_views",
553 fml::MallocMapping::Copy(call.c_str(), call.size()), nullptr);
554 DispatchPlatformMessage(std::move(message));
555}
556
557bool PlatformView::OnHandlePointerEvent(
558 const fuchsia::ui::input::PointerEvent& pointer) {
559 TRACE_EVENT0("flutter", "PlatformView::OnHandlePointerEvent");
560
561 // TODO(SCN-1278): Use proper trace_id for tracing flow.
562 trace_flow_id_t trace_id =
563 PointerTraceHACK(pointer.radius_major, pointer.radius_minor);
564 TRACE_FLOW_END("input", "dispatch_event_to_client", trace_id);
565
566 const float pixel_ratio =
567 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
568
569 flutter::PointerData pointer_data;
570 pointer_data.Clear();
571 pointer_data.time_stamp = pointer.event_time / 1000;
572 pointer_data.change = GetChangeFromPointerEventPhase(pointer.phase);
573 pointer_data.kind = GetKindFromPointerType(pointer.type);
574 pointer_data.device = pointer.pointer_id;
575 // Pointer events are in logical pixels, so scale to physical.
576 pointer_data.physical_x = pointer.x * pixel_ratio;
577 pointer_data.physical_y = pointer.y * pixel_ratio;
578 // Buttons are single bit values starting with kMousePrimaryButton = 1.
579 pointer_data.buttons = static_cast<uint64_t>(pointer.buttons);
580
581 switch (pointer_data.change) {
583 // Make the pointer start in the view space, despite numerical drift.
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;
587
588 down_pointers_.insert(pointer_data.device);
589 break;
590 }
593 down_pointers_.erase(pointer_data.device);
594 break;
596 if (down_pointers_.count(pointer_data.device) == 0) {
598 }
599 break;
601 if (down_pointers_.count(pointer_data.device) != 0) {
602 FML_LOG(ERROR) << "Received add event for down pointer.";
603 }
604 break;
606 if (down_pointers_.count(pointer_data.device) != 0) {
607 FML_LOG(ERROR) << "Received remove event for down pointer.";
608 }
609 break;
611 if (down_pointers_.count(pointer_data.device) != 0) {
612 FML_LOG(ERROR) << "Received hover event for down pointer.";
613 }
614 break;
618 FML_DLOG(ERROR) << "Unexpectedly received pointer pan/zoom event";
619 break;
620 }
621
622 auto packet = std::make_unique<flutter::PointerDataPacket>(1);
623 packet->SetPointerData(0, pointer_data);
624 DispatchPointerDataPacket(std::move(packet));
625 return true;
626}
627
628// |flutter::PlatformView|
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_,
633}
634
635// |flutter::PlatformView|
636std::unique_ptr<flutter::Surface> PlatformView::CreateRenderingSurface() {
637 return on_create_surface_callback_ ? on_create_surface_callback_() : nullptr;
638}
639
640// |flutter::PlatformView|
641std::shared_ptr<flutter::ExternalViewEmbedder>
642PlatformView::CreateExternalViewEmbedder() {
643 return external_view_embedder_;
644}
645
646// |flutter::PlatformView|
647void PlatformView::HandlePlatformMessage(
648 std::unique_ptr<flutter::PlatformMessage> message) {
649 if (!message) {
650 return;
651 }
652 const std::string channel = message->channel();
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) {
657 FML_LOG(INFO)
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);
663 }
665 return;
666 }
667 auto response = message->response();
668 bool response_handled = found->second(std::move(message));
669
670 // Ensure all responses are completed.
671 if (response && !response_handled) {
672 // response_handled should be true if the response was completed.
673 FML_DCHECK(!response->is_complete());
674 response->CompleteEmpty();
675 }
676}
677
678// |flutter::PlatformView|
679void PlatformView::SetSemanticsEnabled(bool enabled) {
681 if (enabled) {
682 SetAccessibilityFeatures(static_cast<int32_t>(
684 } else {
685 SetAccessibilityFeatures(0);
686 }
687}
688
689// |flutter::PlatformView|
690void PlatformView::UpdateSemantics(
691 int64_t view_id,
694 const float pixel_ratio =
695 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
696
697 on_semantics_node_update_callback_(update, pixel_ratio);
698}
699
700// Channel handler for kAccessibilityChannel
701bool PlatformView::HandleAccessibilityChannelPlatformMessage(
702 std::unique_ptr<flutter::PlatformMessage> message) {
703 FML_DCHECK(message->channel() == kAccessibilityChannel);
704
705 const flutter::StandardMessageCodec& standard_message_codec =
707 std::unique_ptr<flutter::EncodableValue> decoded =
708 standard_message_codec.DecodeMessage(message->data().GetMapping(),
709 message->data().GetSize());
710
711 flutter::EncodableMap map = std::get<flutter::EncodableMap>(*decoded);
712 std::string type =
713 std::get<std::string>(map.at(flutter::EncodableValue("type")));
714 if (type == "announce") {
715 flutter::EncodableMap data_map = std::get<flutter::EncodableMap>(
716 map.at(flutter::EncodableValue("data")));
717 std::string text =
718 std::get<std::string>(data_map.at(flutter::EncodableValue("message")));
719
720 on_request_announce_callback_(text);
721 }
722
723 // Complete with an empty response.
724 return false;
725}
726
727// Channel handler for kFlutterPlatformChannel
728bool PlatformView::HandleFlutterPlatformChannelPlatformMessage(
729 std::unique_ptr<flutter::PlatformMessage> message) {
731
732 // Fuchsia does not handle any platform messages at this time.
733
734 // Complete with an empty response.
735 return false;
736}
737
738bool PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage(
739 std::unique_ptr<flutter::PlatformMessage> message) {
740 FML_DCHECK(message->channel() == kFlutterPlatformViewsChannel);
741 const auto& data = message->data();
742 rapidjson::Document document;
743 document.Parse(reinterpret_cast<const char*>(data.GetMapping()),
744 data.GetSize());
745 if (document.HasParseError() || !document.IsObject()) {
746 FML_LOG(ERROR) << "Could not parse document";
747 return false;
748 }
749 auto root = document.GetObject();
750 auto method_member = root.FindMember("method");
751 if (method_member == root.MemberEnd() || !method_member->value.IsString()) {
752 return false;
753 }
754 std::string method(method_member->value.GetString());
755
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.";
760 return false;
761 }
762 const auto& args = args_it->value;
763
764 auto enable = args.FindMember("enable");
765 if (!enable->value.IsBool()) {
766 FML_LOG(ERROR) << "Argument 'enable' is not a bool";
767 return false;
768 }
769
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.";
775 return false;
776 }
777 const auto& args = args_it->value;
778
779 auto view_id = args.FindMember("viewId");
780 if (!view_id->value.IsUint64()) {
781 FML_LOG(ERROR) << "Argument 'viewId' is not a int64";
782 return false;
783 }
784
785 auto hit_testable = args.FindMember("hitTestable");
786 if (!hit_testable->value.IsBool()) {
787 FML_LOG(ERROR) << "Argument 'hitTestable' is not a bool";
788 return false;
789 }
790
791 auto focusable = args.FindMember("focusable");
792 if (!focusable->value.IsBool()) {
793 FML_LOG(ERROR) << "Argument 'focusable' is not a bool";
794 return false;
795 }
796
797 auto on_view_created = fml::MakeCopyable(
798 [platform_task_runner = task_runners_.GetPlatformTaskRunner(),
799 message = std::move(message)]() {
800 // The client is waiting for view creation. Send an empty response
801 // back to signal the view was created.
802 if (message->response()) {
803 message->response()->Complete(std::make_unique<fml::DataMapping>(
804 std::vector<uint8_t>({'[', '0', ']'})));
805 }
806 });
807 OnCreateView(std::move(on_view_created), view_id->value.GetUint64(),
808 hit_testable->value.GetBool(), focusable->value.GetBool());
809 return true;
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.";
814 return false;
815 }
816 const auto& args = args_it->value;
817
818 auto view_id = args.FindMember("viewId");
819 if (!view_id->value.IsUint64()) {
820 FML_LOG(ERROR) << "Argument 'viewId' is not a int64";
821 return false;
822 }
823
824 auto hit_testable = args.FindMember("hitTestable");
825 if (!hit_testable->value.IsBool()) {
826 FML_LOG(ERROR) << "Argument 'hitTestable' is not a bool";
827 return false;
828 }
829
830 auto focusable = args.FindMember("focusable");
831 if (!focusable->value.IsBool()) {
832 FML_LOG(ERROR) << "Argument 'focusable' is not a bool";
833 return false;
834 }
835
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";
849 parse_error = true;
850 break;
851 }
852 }
853
854 if (!parse_error) {
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());
860 }
861 } else {
862 FML_LOG(ERROR)
863 << "Argument 'viewOcclusionHintLTRB' expected size 4; got "
864 << view_occlusion_hint_array.Size();
865 }
866 } else {
867 FML_LOG(ERROR)
868 << "Argument 'viewOcclusionHintLTRB' is not a double array";
869 }
870 } else {
871 FML_LOG(WARNING) << "Argument 'viewOcclusionHintLTRB' is missing";
872 }
873
874 on_update_view_callback_(
875 view_id->value.GetUint64(), view_occlusion_hint_raw,
876 hit_testable->value.GetBool(), focusable->value.GetBool());
877 if (message->response()) {
878 message->response()->Complete(std::make_unique<fml::DataMapping>(
879 std::vector<uint8_t>({'[', '0', ']'})));
880 return true;
881 }
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.";
886 return false;
887 }
888 const auto& args = args_it->value;
889
890 auto view_id = args.FindMember("viewId");
891 if (!view_id->value.IsUint64()) {
892 FML_LOG(ERROR) << "Argument 'viewId' is not a int64";
893 return false;
894 }
895
896 OnDisposeView(view_id->value.GetUint64());
897 if (message->response()) {
898 message->response()->Complete(std::make_unique<fml::DataMapping>(
899 std::vector<uint8_t>({'[', '0', ']'})));
900 return true;
901 }
902 } else if (method.rfind("View.focus", 0) == 0) {
903 return focus_delegate_->HandlePlatformMessage(root, message->response());
904 } else if (method.rfind(PointerInjectorDelegate::kPointerInjectorMethodPrefix,
905 0) == 0) {
906 return pointer_injector_delegate_->HandlePlatformMessage(
907 root, message->response());
908 } else {
909 FML_LOG(ERROR) << "Unknown " << message->channel() << " method " << method;
910 }
911 // Complete with an empty response by default.
912 return false;
913}
914
915bool PlatformView::HandleFuchsiaShaderWarmupChannelPlatformMessage(
916 OnShaderWarmupCallback on_shader_warmup_callback,
917 std::unique_ptr<flutter::PlatformMessage> message) {
918 FML_DCHECK(message->channel() == kFuchsiaShaderWarmupChannel);
919
920 if (!on_shader_warmup_callback) {
921 FML_LOG(ERROR) << "No shader warmup callback set!";
922 std::string result = "[0]";
923 message->response()->Complete(
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())));
927 return true;
928 }
929
930 const auto& data = message->data();
931 rapidjson::Document document;
932 document.Parse(reinterpret_cast<const char*>(data.GetMapping()),
933 data.GetSize());
934 if (document.HasParseError() || !document.IsObject()) {
935 FML_LOG(ERROR) << "Could not parse document";
936 return false;
937 }
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";
943 return false;
944 }
945
946 auto args_it = root.FindMember("args");
947 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
948 FML_LOG(ERROR) << "No arguments found.";
949 return false;
950 }
951
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.";
955 return false;
956 }
957
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";
962 return false;
963 }
964 if (height_it == root["args"].MemberEnd() || !height_it->value.IsNumber()) {
965 FML_LOG(ERROR) << "Invalid height";
966 return false;
967 }
968 auto width = width_it->value.GetUint64();
969 auto height = height_it->value.GetUint64();
970
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());
976 }
977
978 auto completion_callback = [response =
979 message->response()](uint32_t num_successes) {
980 std::ostringstream result_stream;
981 result_stream << "[" << num_successes << "]";
982
983 std::string result(result_stream.str());
984
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())));
988 };
989
990 on_shader_warmup_callback(skp_paths, completion_callback, width, height);
991 // The response has already been completed by us.
992 return true;
993}
994
995// Channel handler for kFuchsiaInputTestChannel
996bool PlatformView::HandleFuchsiaInputTestChannelPlatformMessage(
997 std::unique_ptr<flutter::PlatformMessage> message) {
998 FML_DCHECK(message->channel() == kFuchsiaInputTestChannel);
999
1000 const auto& data = message->data();
1001 rapidjson::Document document;
1002 document.Parse(reinterpret_cast<const char*>(data.GetMapping()),
1003 data.GetSize());
1004 if (document.HasParseError() || !document.IsObject()) {
1005 FML_LOG(ERROR) << "Could not parse document";
1006 return false;
1007 }
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";
1012 return false;
1013 }
1014
1015 FML_LOG(INFO) << "fuchsia/input_test: method=" << method->value.GetString();
1016
1017 if (method->value == "TouchInputListener.ReportTouchInput") {
1018 if (!touch_input_listener_) {
1019 FML_LOG(ERROR) << "TouchInputListener not found.";
1020 return false;
1021 }
1022
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);
1030 });
1031 CallWithMember<std::string>(root, "component_name",
1032 [&](std::string component_name) {
1033 request.set_component_name(component_name);
1034 });
1035
1036 touch_input_listener_->ReportTouchInput(std::move(request));
1037 return true;
1038 }
1039
1040 if (method->value == "KeyboardInputListener.ReportTextInput") {
1041 if (!keyboard_input_listener_) {
1042 FML_LOG(ERROR) << "KeyboardInputListener not found.";
1043 return false;
1044 }
1045
1046 fuchsia::ui::test::input::KeyboardInputListenerReportTextInputRequest
1047 request;
1048 CallWithMember<std::string>(
1049 root, "text", [&](std::string text) { request.set_text(text); });
1050
1051 keyboard_input_listener_->ReportTextInput(std::move(request));
1052 return true;
1053 }
1054
1055 if (method->value == "MouseInputListener.ReportMouseInput") {
1056 if (!mouse_input_listener_) {
1057 FML_LOG(ERROR) << "MouseInputListener not found.";
1058 return false;
1059 }
1060
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);
1068 });
1069 CallWithMember<std::string>(root, "component_name",
1070 [&](std::string component_name) {
1071 request.set_component_name(component_name);
1072 });
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);
1077 }
1078 if (button_mask & 2) {
1079 buttons.push_back(fuchsia::ui::test::input::MouseButton::SECOND);
1080 }
1081 if (button_mask & 4) {
1082 buttons.push_back(fuchsia::ui::test::input::MouseButton::THIRD);
1083 }
1084 request.set_buttons(buttons);
1085 });
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);
1097 } else {
1098 FML_LOG(ERROR) << "Unexpected mouse phase: " << phase;
1099 }
1100 });
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);
1104 });
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);
1108 });
1109
1110 mouse_input_listener_->ReportMouseInput(std::move(request));
1111 return true;
1112 }
1113
1114 FML_LOG(ERROR) << "fuchsia/input_test: unrecognized method "
1115 << method->value.GetString();
1116 return false;
1117}
1118
1119// Channel handler for kFuchsiaChildViewChannel
1120bool PlatformView::HandleFuchsiaChildViewChannelPlatformMessage(
1121 std::unique_ptr<flutter::PlatformMessage> message) {
1122 FML_DCHECK(message->channel() == kFuchsiaChildViewChannel);
1123
1124 if (message->data().GetSize() != 1 ||
1125 (message->data().GetMapping()[0] != '1')) {
1127 << " data must be singularly '1'.";
1128 return false;
1129 }
1130
1131 FML_DCHECK(message->data().GetMapping()[0] == '1');
1132
1133 if (!message->response()) {
1135 << " must have a response callback.";
1136 return false;
1137 }
1138
1139 if (!dart_application_svc_) {
1140 FML_LOG(ERROR) << "No service directory.";
1141 return false;
1142 }
1143
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.";
1149 return false;
1150 }
1151 fuchsia::ui::app::ViewProviderPtr view_provider;
1152 view_provider.Bind(std::move(view_provider_handle));
1153
1154 zx::handle view_id;
1155
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);
1163 return false;
1164 }
1165
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));
1169
1170 view_id = std::move(viewport_creation_token.value);
1171
1172 if (view_id) {
1173 message->response()->Complete(
1174 std::make_unique<fml::DataMapping>(std::to_string(view_id.release())
1175
1176 ));
1177 return true;
1178 } else {
1179 return false;
1180 }
1181}
1182
1183} // namespace flutter_runner
GLenum type
std::unique_ptr< T > DecodeMessage(const uint8_t *binary_message, const size_t message_size) const
Used to forward events from the platform view to interested subsystems. This forwarding is done by th...
virtual void SetSemanticsEnabled(bool enabled)
Used by embedder to notify the running isolate hosted by the engine on the UI thread that the accessi...
virtual void HandlePlatformMessage(std::unique_ptr< PlatformMessage > message)
Overridden by embedders to perform actions in response to platform messages sent from the framework t...
static const StandardMessageCodec & GetInstance(const StandardCodecSerializer *serializer=nullptr)
void OnParentViewportStatus(fuchsia::ui::composition::ParentViewportStatus status)
void OnGetLayout(fuchsia::ui::composition::LayoutInfo info)
PlatformView(flutter::PlatformView::Delegate &delegate, flutter::TaskRunners task_runners, fuchsia::ui::views::ViewRef view_ref, std::shared_ptr< flutter::ExternalViewEmbedder > external_view_embedder, fuchsia::ui::input::ImeServiceHandle ime_service, fuchsia::ui::input3::KeyboardHandle keyboard, fuchsia::ui::pointer::TouchSourceHandle touch_source, fuchsia::ui::pointer::MouseSourceHandle mouse_source, fuchsia::ui::views::FocuserHandle focuser, fuchsia::ui::views::ViewRefFocusedHandle view_ref_focused, fuchsia::ui::composition::ParentViewportWatcherHandle parent_viewport_watcher, fuchsia::ui::pointerinjector::RegistryHandle pointerinjector_registry, OnEnableWireframeCallback wireframe_enabled_callback, OnCreateViewCallback on_create_view_callback, OnUpdateViewCallback on_update_view_callback, OnDestroyViewCallback on_destroy_view_callback, OnCreateSurfaceCallback on_create_surface_callback, OnSemanticsNodeUpdateCallback on_semantics_node_update_callback, OnRequestAnnounceCallback on_request_announce_callback, OnShaderWarmupCallback on_shader_warmup_callback, AwaitVsyncCallback await_vsync_callback, AwaitVsyncForSecondaryCallbackCallback await_vsync_for_secondary_callback_callback, std::shared_ptr< sys::ServiceDirectory > dart_application_svc)
static MallocMapping Copy(const T *begin, const T *end)
Definition mapping.h:162
int32_t x
TaskRunners task_runners_
const char * message
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const gchar * channel
G_BEGIN_DECLS FlutterViewId view_id
#define FML_DLOG(severity)
Definition logging.h:121
#define FML_LOG(severity)
Definition logging.h:101
#define FML_CHECK(condition)
Definition logging.h:104
#define FML_DCHECK(condition)
Definition logging.h:122
std::u16string text
NSString *const kFlutterPlatformChannel
static NSString *const kTextInputChannel
double y
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)
Definition ref_ptr.h:261
int32_t height
int32_t width
std::shared_ptr< const fml::Mapping > data
#define TRACE_EVENT0(category_group, name)
#define TRACE_FLOW_END(category, name, id)