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
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
31
32namespace {
33// Helper to extract a given member with a given type from a rapidjson object.
34template <typename T, typename O, typename F>
35bool CallWithMember(O obj, const char* member_name, F func) {
36 auto it = obj.FindMember(member_name);
37 if (it == obj.MemberEnd()) {
38 return false;
39 }
40 if (!it->value.template Is<T>()) {
41 return false;
42 }
43 func(it->value.template Get<T>());
44 return true;
45}
46} // namespace
47
48namespace flutter_runner {
49
50static constexpr char kFlutterPlatformChannel[] = "flutter/platform";
51static constexpr char kAccessibilityChannel[] = "flutter/accessibility";
52static constexpr char kFlutterPlatformViewsChannel[] = "flutter/platform_views";
53static constexpr char kFuchsiaShaderWarmupChannel[] = "fuchsia/shader_warmup";
54static constexpr char kFuchsiaInputTestChannel[] = "fuchsia/input_test";
55static constexpr char kFuchsiaChildViewChannel[] = "fuchsia/child_view";
56static constexpr int64_t kFlutterImplicitViewId = 0ll;
57
60 flutter::TaskRunners task_runners,
61 fuchsia::ui::views::ViewRef view_ref,
62 std::shared_ptr<flutter::ExternalViewEmbedder> external_view_embedder,
63 fuchsia::ui::input::ImeServiceHandle ime_service,
64 fuchsia::ui::input3::KeyboardHandle keyboard,
65 fuchsia::ui::pointer::TouchSourceHandle touch_source,
66 fuchsia::ui::pointer::MouseSourceHandle mouse_source,
67 fuchsia::ui::views::FocuserHandle focuser,
68 fuchsia::ui::views::ViewRefFocusedHandle view_ref_focused,
69 fuchsia::ui::composition::ParentViewportWatcherHandle
70 parent_viewport_watcher,
71 fuchsia::ui::pointerinjector::RegistryHandle pointerinjector_registry,
72 OnEnableWireframeCallback wireframe_enabled_callback,
73 OnCreateViewCallback on_create_view_callback,
74 OnUpdateViewCallback on_update_view_callback,
75 OnDestroyViewCallback on_destroy_view_callback,
76 OnCreateSurfaceCallback on_create_surface_callback,
77 OnSemanticsNodeUpdateCallback on_semantics_node_update_callback,
78 OnRequestAnnounceCallback on_request_announce_callback,
79 OnShaderWarmupCallback on_shader_warmup_callback,
80 AwaitVsyncCallback await_vsync_callback,
82 await_vsync_for_secondary_callback_callback,
83 std::shared_ptr<sys::ServiceDirectory> dart_application_svc)
84 : flutter::PlatformView(delegate, std::move(task_runners)),
85 external_view_embedder_(external_view_embedder),
86 focus_delegate_(
87 std::make_shared<FocusDelegate>(std::move(view_ref_focused),
88 std::move(focuser))),
89 pointer_delegate_(
90 std::make_shared<PointerDelegate>(std::move(touch_source),
91 std::move(mouse_source))),
92 wireframe_enabled_callback_(std::move(wireframe_enabled_callback)),
93 on_update_view_callback_(std::move(on_update_view_callback)),
94 on_create_surface_callback_(std::move(on_create_surface_callback)),
95 on_semantics_node_update_callback_(
96 std::move(on_semantics_node_update_callback)),
97 on_request_announce_callback_(std::move(on_request_announce_callback)),
98 on_create_view_callback_(std::move(on_create_view_callback)),
99 on_destroy_view_callback_(std::move(on_destroy_view_callback)),
100 on_shader_warmup_callback_(std::move(on_shader_warmup_callback)),
101 await_vsync_callback_(await_vsync_callback),
102 await_vsync_for_secondary_callback_callback_(
103 await_vsync_for_secondary_callback_callback),
104 dart_application_svc_(dart_application_svc),
105 parent_viewport_watcher_(parent_viewport_watcher.Bind()),
106 weak_factory_(this) {
107 fuchsia::ui::views::ViewRef view_ref_clone;
108 fidl::Clone(view_ref, &view_ref_clone);
109
110 text_delegate_ =
111 std::make_unique<TextDelegate>(
112 std::move(view_ref), std::move(ime_service), std::move(keyboard),
113 [weak = weak_factory_.GetWeakPtr()](
114 std::unique_ptr<flutter::PlatformMessage> message) {
115 if (!weak) {
116 FML_LOG(WARNING)
117 << "PlatformView use-after-free attempted. Ignoring.";
118 }
119 weak->delegate_.OnPlatformViewDispatchPlatformMessage(
120 std::move(message));
121 });
122
123 // Begin watching for focus changes.
124 focus_delegate_->WatchLoop([weak = weak_factory_.GetWeakPtr()](bool focused) {
125 if (!weak) {
126 FML_LOG(WARNING) << "PlatformView use-after-free attempted. Ignoring.";
127 return;
128 }
129
130 // Ensure last_text_state_ is set to make sure Flutter actually wants
131 // an IME.
132 if (focused && weak->text_delegate_->HasTextState()) {
133 weak->text_delegate_->ActivateIme();
134 } else if (!focused) {
135 weak->text_delegate_->DeactivateIme();
136 }
137 });
138
139 // Begin watching for pointer events.
140 pointer_delegate_->WatchLoop([weak = weak_factory_.GetWeakPtr()](
141 std::vector<flutter::PointerData> events) {
142 if (!weak) {
143 FML_LOG(WARNING) << "PlatformView use-after-free attempted. Ignoring.";
144 return;
145 }
146
147 if (events.empty()) {
148 return; // No work, bounce out.
149 }
150
151 // If pixel ratio hasn't been set, use a default value of 1.
152 const float pixel_ratio = weak->view_pixel_ratio_.value_or(1.f);
153 auto packet = std::make_unique<flutter::PointerDataPacket>(events.size());
154 for (size_t i = 0; i < events.size(); ++i) {
155 auto& event = events[i];
156 // Translate logical to physical coordinates, as per
157 // flutter::PointerData contract. Done here because pixel ratio comes
158 // from the graphics API.
159 event.physical_x = event.physical_x * pixel_ratio;
160 event.physical_y = event.physical_y * pixel_ratio;
161 packet->SetPointerData(i, event);
162 }
163 weak->DispatchPointerDataPacket(std::move(packet));
164 });
165
166 // Configure the pointer injector delegate.
167 pointer_injector_delegate_ = std::make_unique<PointerInjectorDelegate>(
168 std::move(pointerinjector_registry), std::move(view_ref_clone));
169
170 // This is only used by the integration tests.
171 if (dart_application_svc) {
172 // Connect to TouchInputListener
173 fuchsia::ui::test::input::TouchInputListenerHandle touch_input_listener;
174 zx_status_t touch_input_listener_status =
175 dart_application_svc
176 ->Connect<fuchsia::ui::test::input::TouchInputListener>(
177 touch_input_listener.NewRequest());
178 if (touch_input_listener_status != ZX_OK) {
179 FML_LOG(WARNING)
180 << "fuchsia::ui::test::input::TouchInputListener connection failed: "
181 << zx_status_get_string(touch_input_listener_status);
182 } else {
183 touch_input_listener_.Bind(std::move(touch_input_listener));
184 }
185
186 // Connect to KeyboardInputListener
187 fuchsia::ui::test::input::KeyboardInputListenerHandle
188 keyboard_input_listener;
189 zx_status_t keyboard_input_listener_status =
190 dart_application_svc
191 ->Connect<fuchsia::ui::test::input::KeyboardInputListener>(
192 keyboard_input_listener.NewRequest());
193 if (keyboard_input_listener_status != ZX_OK) {
194 FML_LOG(WARNING) << "fuchsia::ui::test::input::KeyboardInputListener "
195 "connection failed: "
196 << zx_status_get_string(keyboard_input_listener_status);
197 } else {
198 keyboard_input_listener_.Bind(std::move(keyboard_input_listener));
199 }
200 // Connect to MouseInputListener
201 fuchsia::ui::test::input::MouseInputListenerHandle mouse_input_listener;
202 zx_status_t mouse_input_listener_status =
203 dart_application_svc
204 ->Connect<fuchsia::ui::test::input::MouseInputListener>(
205 mouse_input_listener.NewRequest());
206 if (mouse_input_listener_status != ZX_OK) {
207 FML_LOG(WARNING)
208 << "fuchsia::ui::test::input::MouseInputListener connection failed: "
209 << zx_status_get_string(mouse_input_listener_status);
210 } else {
211 mouse_input_listener_.Bind(std::move(mouse_input_listener));
212 }
213 }
214
215 // Finally! Register the native platform message handlers.
216 RegisterPlatformMessageHandlers();
217
218 parent_viewport_watcher_.set_error_handler([](zx_status_t status) {
219 FML_LOG(ERROR) << "Interface error on: ParentViewportWatcher status: "
220 << status;
221 });
222
223 parent_viewport_watcher_->GetLayout(
224 fit::bind_member(this, &PlatformView::OnGetLayout));
225 parent_viewport_watcher_->GetStatus(
226 fit::bind_member(this, &PlatformView::OnParentViewportStatus));
227}
228
229PlatformView::~PlatformView() = default;
230
231void PlatformView::RegisterPlatformMessageHandlers() {
232 platform_message_handlers_[kFlutterPlatformChannel] =
233 std::bind(&PlatformView::HandleFlutterPlatformChannelPlatformMessage,
234 this, std::placeholders::_1);
235 platform_message_handlers_[kTextInputChannel] =
236 std::bind(&TextDelegate::HandleFlutterTextInputChannelPlatformMessage,
237 text_delegate_.get(), std::placeholders::_1);
238 platform_message_handlers_[kAccessibilityChannel] =
239 std::bind(&PlatformView::HandleAccessibilityChannelPlatformMessage, this,
240 std::placeholders::_1);
241 platform_message_handlers_[kFlutterPlatformViewsChannel] =
242 std::bind(&PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage,
243 this, std::placeholders::_1);
244 platform_message_handlers_[kFuchsiaShaderWarmupChannel] =
245 std::bind(&HandleFuchsiaShaderWarmupChannelPlatformMessage,
246 on_shader_warmup_callback_, std::placeholders::_1);
247 platform_message_handlers_[kFuchsiaInputTestChannel] =
248 std::bind(&PlatformView::HandleFuchsiaInputTestChannelPlatformMessage,
249 this, std::placeholders::_1);
250 platform_message_handlers_[kFuchsiaChildViewChannel] =
251 std::bind(&PlatformView::HandleFuchsiaChildViewChannelPlatformMessage,
252 this, std::placeholders::_1);
253}
254
256 fuchsia::ui::input::PointerEventPhase phase) {
257 switch (phase) {
258 case fuchsia::ui::input::PointerEventPhase::ADD:
260 case fuchsia::ui::input::PointerEventPhase::HOVER:
262 case fuchsia::ui::input::PointerEventPhase::DOWN:
264 case fuchsia::ui::input::PointerEventPhase::MOVE:
266 case fuchsia::ui::input::PointerEventPhase::UP:
268 case fuchsia::ui::input::PointerEventPhase::REMOVE:
270 case fuchsia::ui::input::PointerEventPhase::CANCEL:
272 default:
274 }
275}
276
278 fuchsia::ui::input::PointerEventType type) {
279 switch (type) {
280 case fuchsia::ui::input::PointerEventType::TOUCH:
282 case fuchsia::ui::input::PointerEventType::MOUSE:
284 default:
286 }
287}
288
289// TODO(SCN-1278): Remove this.
290// Turns two floats (high bits, low bits) into a 64-bit uint.
291static trace_flow_id_t PointerTraceHACK(float fa, float fb) {
292 uint32_t ia, ib;
293 memcpy(&ia, &fa, sizeof(uint32_t));
294 memcpy(&ib, &fb, sizeof(uint32_t));
295 return (((uint64_t)ia) << 32) | ib;
296}
297
298// For certain scenarios that must avoid floating-point drift, compute a
299// coordinate that falls within the logical view bounding box.
300std::array<float, 2> PlatformView::ClampToViewSpace(const float x,
301 const float y) const {
302 if (!view_logical_size_.has_value() || !view_logical_origin_.has_value()) {
303 return {x, y}; // If we can't do anything, return the original values.
304 }
305
306 const auto origin = view_logical_origin_.value();
307 const auto size = view_logical_size_.value();
308 const float min_x = origin[0];
309 const float max_x = origin[0] + size[0];
310 const float min_y = origin[1];
311 const float max_y = origin[1] + size[1];
312 if (min_x <= x && x < max_x && min_y <= y && y < max_y) {
313 return {x, y}; // No clamping to perform.
314 }
315
316 // View boundary is [min_x, max_x) x [min_y, max_y). Note that min is
317 // inclusive, but max is exclusive - so we subtract epsilon.
318 const float max_x_inclusive = max_x - std::numeric_limits<float>::epsilon();
319 const float max_y_inclusive = max_y - std::numeric_limits<float>::epsilon();
320 const float& clamped_x = std::clamp(x, min_x, max_x_inclusive);
321 const float& clamped_y = std::clamp(y, min_y, max_y_inclusive);
322 FML_LOG(INFO) << "Clamped (" << x << ", " << y << ") to (" << clamped_x
323 << ", " << clamped_y << ").";
324 return {clamped_x, clamped_y};
325}
326
327void PlatformView::OnGetLayout(fuchsia::ui::composition::LayoutInfo info) {
328 view_logical_size_ = {static_cast<float>(info.logical_size().width),
329 static_cast<float>(info.logical_size().height)};
330
331 if (info.has_device_pixel_ratio()) {
332 // Both values should be identical for the Vec2 for DPR.
333 FML_DCHECK(info.device_pixel_ratio().x == info.device_pixel_ratio().y);
334 view_pixel_ratio_ = info.device_pixel_ratio().x;
335 }
336
337 float pixel_ratio = view_pixel_ratio_ ? *view_pixel_ratio_ : 1.0f;
339 pixel_ratio, // device_pixel_ratio
340 std::round(view_logical_size_.value()[0] *
341 pixel_ratio), // physical_width
342 std::round(view_logical_size_.value()[1] *
343 pixel_ratio), // physical_height
344 std::round(view_logical_size_.value()[0] *
345 pixel_ratio), // physical_min_width_constraint
346 std::round(view_logical_size_.value()[0] *
347 pixel_ratio), // physical_max_width_constraint
348 std::round(view_logical_size_.value()[1] *
349 pixel_ratio), // physical_min_height_constraint
350 std::round(view_logical_size_.value()[1] *
351 pixel_ratio), // physical_max_height_constraint
352 0.0f, // physical_padding_top
353 0.0f, // physical_padding_right
354 0.0f, // physical_padding_bottom
355 0.0f, // physical_padding_left
356 0.0f, // physical_view_inset_top
357 0.0f, // physical_view_inset_right
358 0.0f, // physical_view_inset_bottom
359 0.0f, // physical_view_inset_left
360 0.0f, // p_physical_system_gesture_inset_top
361 0.0f, // p_physical_system_gesture_inset_right
362 0.0f, // p_physical_system_gesture_inset_bottom
363 0.0f, // p_physical_system_gesture_inset_left,
364 -1.0, // p_physical_touch_slop,
365 {}, // p_physical_display_features_bounds
366 {}, // p_physical_display_features_type
367 {}, // p_physical_display_features_state
368 0, // p_display_id
369 -1.0, // p_physical_display_corner_radius_top_left
370 -1.0, // p_physical_display_corner_radius_top_right
371 -1.0, // p_physical_display_corner_radius_bottom_right
372 -1.0, // p_physical_display_corner_radius_bottom_left
373 };
374 SetViewportMetrics(kFlutterImplicitViewId, metrics);
375
376 parent_viewport_watcher_->GetLayout(
377 fit::bind_member(this, &PlatformView::OnGetLayout));
378}
379
380void PlatformView::OnParentViewportStatus(
381 fuchsia::ui::composition::ParentViewportStatus status) {
382 // TODO(fxbug.dev/116001): Investigate if it is useful to send hidden/shown
383 // signals.
384 parent_viewport_status_ = status;
385 parent_viewport_watcher_->GetStatus(
386 fit::bind_member(this, &PlatformView::OnParentViewportStatus));
387}
388
389void PlatformView::OnChildViewStatus(
390 uint64_t content_id,
391 fuchsia::ui::composition::ChildViewStatus status) {
392 FML_DCHECK(child_view_info_.count(content_id) == 1);
393
394 std::ostringstream out;
395 out << "{" << "\"method\":\"View.viewStateChanged\"," << "\"args\":{"
396 << " \"viewId\":" << child_view_info_.at(content_id).view_id
397 << "," // ViewId
398 << " \"is_rendering\":true," // IsViewRendering
399 << " \"state\":true" // IsViewRendering
400 << " }" << "}";
401 auto call = out.str();
402
403 std::unique_ptr<flutter::PlatformMessage> message =
404 std::make_unique<flutter::PlatformMessage>(
405 "flutter/platform_views",
406 fml::MallocMapping::Copy(call.c_str(), call.size()), nullptr);
407 DispatchPlatformMessage(std::move(message));
408
409 child_view_info_.at(content_id)
410 .child_view_watcher->GetStatus(
411 [this, content_id](fuchsia::ui::composition::ChildViewStatus status) {
412 OnChildViewStatus(content_id, status);
413 });
414}
415
416void PlatformView::OnChildViewViewRef(uint64_t content_id,
417 uint64_t view_id,
418 fuchsia::ui::views::ViewRef view_ref) {
419 FML_CHECK(child_view_info_.count(content_id) == 1);
420
421 fuchsia::ui::views::ViewRef view_ref_clone;
422 fidl::Clone(view_ref, &view_ref_clone);
423
424 focus_delegate_->OnChildViewViewRef(view_id, std::move(view_ref));
425
426 pointer_injector_delegate_->OnCreateView(view_id, std::move(view_ref_clone));
427 OnChildViewConnected(content_id);
428}
429
430void PlatformView::OnCreateView(ViewCallback on_view_created,
431 int64_t view_id_raw,
432 bool hit_testable,
433 bool focusable) {
434 auto on_view_bound = [weak = weak_factory_.GetWeakPtr(),
435 platform_task_runner =
436 task_runners_.GetPlatformTaskRunner(),
437 view_id = view_id_raw](
438 fuchsia::ui::composition::ContentId content_id,
439 fuchsia::ui::composition::ChildViewWatcherHandle
440 child_view_watcher_handle) {
441 FML_CHECK(weak);
442 FML_CHECK(weak->child_view_info_.count(content_id.value) == 0);
443
444 platform_task_runner->PostTask(fml::MakeCopyable(
445 [weak, view_id, content_id,
446 watcher_handle = std::move(child_view_watcher_handle)]() mutable {
447 if (!weak) {
448 FML_LOG(WARNING)
449 << "View bound to PlatformView after PlatformView was "
450 "destroyed; ignoring.";
451 return;
452 }
453
454 // Bind the child view watcher to the platform thread so that the FIDL
455 // calls are handled on the platform thread.
456 fuchsia::ui::composition::ChildViewWatcherPtr child_view_watcher =
457 watcher_handle.Bind();
458 FML_CHECK(child_view_watcher);
459
460 child_view_watcher.set_error_handler([weak, view_id, content_id](
461 zx_status_t status) {
462 FML_LOG(WARNING)
463 << "Child disconnected. ChildViewWatcher status: " << status;
464
465 if (!weak) {
466 FML_LOG(WARNING) << "View bound to PlatformView after "
467 "PlatformView was "
468 "destroyed; ignoring.";
469 return;
470 }
471
472 // Disconnected views cannot listen to pointer events.
473 weak->pointer_injector_delegate_->OnDestroyView(view_id);
474
475 weak->OnChildViewDisconnected(content_id.value);
476 });
477
478 weak->child_view_info_.emplace(
479 std::piecewise_construct, std::forward_as_tuple(content_id.value),
480 std::forward_as_tuple(view_id, std::move(child_view_watcher)));
481
482 weak->child_view_info_.at(content_id.value)
483 .child_view_watcher->GetStatus(
484 [weak, id = content_id.value](
485 fuchsia::ui::composition::ChildViewStatus status) {
486 weak->OnChildViewStatus(id, status);
487 });
488
489 weak->child_view_info_.at(content_id.value)
490 .child_view_watcher->GetViewRef(
491 [weak, content_id = content_id.value,
492 view_id](fuchsia::ui::views::ViewRef view_ref) {
493 weak->OnChildViewViewRef(content_id, view_id,
494 std::move(view_ref));
495 });
496 }));
497 };
498
499 on_create_view_callback_(view_id_raw, std::move(on_view_created),
500 std::move(on_view_bound), hit_testable, focusable);
501}
502
503void PlatformView::OnDisposeView(int64_t view_id_raw) {
504 auto on_view_unbound =
505 [weak = weak_factory_.GetWeakPtr(),
506 platform_task_runner = task_runners_.GetPlatformTaskRunner(),
507 view_id_raw](fuchsia::ui::composition::ContentId content_id) {
508 platform_task_runner->PostTask([weak, content_id, view_id_raw]() {
509 if (!weak) {
510 FML_LOG(WARNING)
511 << "View unbound from PlatformView after PlatformView"
512 "was destroyed; ignoring.";
513 return;
514 }
515
516 FML_DCHECK(weak->child_view_info_.count(content_id.value) == 1);
517 weak->OnChildViewDisconnected(content_id.value);
518 weak->child_view_info_.erase(content_id.value);
519 weak->focus_delegate_->OnDisposeChildView(view_id_raw);
520 weak->pointer_injector_delegate_->OnDestroyView(view_id_raw);
521 });
522 };
523 on_destroy_view_callback_(view_id_raw, std::move(on_view_unbound));
524}
525
526void PlatformView::OnChildViewConnected(uint64_t content_id) {
527 FML_CHECK(child_view_info_.count(content_id) == 1);
528 std::ostringstream out;
529 out << "{" << "\"method\":\"View.viewConnected\"," << "\"args\":{"
530 << " \"viewId\":" << child_view_info_.at(content_id).view_id << " }"
531 << "}";
532 auto call = out.str();
533
534 std::unique_ptr<flutter::PlatformMessage> message =
535 std::make_unique<flutter::PlatformMessage>(
536 "flutter/platform_views",
537 fml::MallocMapping::Copy(call.c_str(), call.size()), nullptr);
538 DispatchPlatformMessage(std::move(message));
539}
540
541void PlatformView::OnChildViewDisconnected(uint64_t content_id) {
542 FML_CHECK(child_view_info_.count(content_id) == 1);
543 std::ostringstream out;
544 out << "{" << "\"method\":\"View.viewDisconnected\"," << "\"args\":{"
545 << " \"viewId\":" << child_view_info_.at(content_id).view_id << " }"
546 << "}";
547 auto call = out.str();
548
549 std::unique_ptr<flutter::PlatformMessage> message =
550 std::make_unique<flutter::PlatformMessage>(
551 "flutter/platform_views",
552 fml::MallocMapping::Copy(call.c_str(), call.size()), nullptr);
553 DispatchPlatformMessage(std::move(message));
554}
555
556bool PlatformView::OnHandlePointerEvent(
557 const fuchsia::ui::input::PointerEvent& pointer) {
558 TRACE_EVENT0("flutter", "PlatformView::OnHandlePointerEvent");
559
560 // TODO(SCN-1278): Use proper trace_id for tracing flow.
561 trace_flow_id_t trace_id =
562 PointerTraceHACK(pointer.radius_major, pointer.radius_minor);
563 TRACE_FLOW_END("input", "dispatch_event_to_client", trace_id);
564
565 const float pixel_ratio =
566 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
567
568 flutter::PointerData pointer_data;
569 pointer_data.Clear();
570 pointer_data.time_stamp = pointer.event_time / 1000;
571 pointer_data.change = GetChangeFromPointerEventPhase(pointer.phase);
572 pointer_data.kind = GetKindFromPointerType(pointer.type);
573 pointer_data.device = pointer.pointer_id;
574 // Pointer events are in logical pixels, so scale to physical.
575 pointer_data.physical_x = pointer.x * pixel_ratio;
576 pointer_data.physical_y = pointer.y * pixel_ratio;
577 // Buttons are single bit values starting with kMousePrimaryButton = 1.
578 pointer_data.buttons = static_cast<uint64_t>(pointer.buttons);
579
580 switch (pointer_data.change) {
582 // Make the pointer start in the view space, despite numerical drift.
583 auto clamped_pointer = ClampToViewSpace(pointer.x, pointer.y);
584 pointer_data.physical_x = clamped_pointer[0] * pixel_ratio;
585 pointer_data.physical_y = clamped_pointer[1] * pixel_ratio;
586
587 down_pointers_.insert(pointer_data.device);
588 break;
589 }
592 down_pointers_.erase(pointer_data.device);
593 break;
595 if (down_pointers_.count(pointer_data.device) == 0) {
597 }
598 break;
600 if (down_pointers_.count(pointer_data.device) != 0) {
601 FML_LOG(ERROR) << "Received add event for down pointer.";
602 }
603 break;
605 if (down_pointers_.count(pointer_data.device) != 0) {
606 FML_LOG(ERROR) << "Received remove event for down pointer.";
607 }
608 break;
610 if (down_pointers_.count(pointer_data.device) != 0) {
611 FML_LOG(ERROR) << "Received hover event for down pointer.";
612 }
613 break;
617 FML_DLOG(ERROR) << "Unexpectedly received pointer pan/zoom event";
618 break;
619 }
620
621 auto packet = std::make_unique<flutter::PointerDataPacket>(1);
622 packet->SetPointerData(0, pointer_data);
623 DispatchPointerDataPacket(std::move(packet));
624 return true;
625}
626
627// |flutter::PlatformView|
628std::unique_ptr<flutter::VsyncWaiter> PlatformView::CreateVSyncWaiter() {
629 return std::make_unique<flutter_runner::VsyncWaiter>(
630 await_vsync_callback_, await_vsync_for_secondary_callback_callback_,
632}
633
634// |flutter::PlatformView|
635std::unique_ptr<flutter::Surface> PlatformView::CreateRenderingSurface() {
636 return on_create_surface_callback_ ? on_create_surface_callback_() : nullptr;
637}
638
639// |flutter::PlatformView|
640std::shared_ptr<flutter::ExternalViewEmbedder>
641PlatformView::CreateExternalViewEmbedder() {
642 return external_view_embedder_;
643}
644
645// |flutter::PlatformView|
646void PlatformView::HandlePlatformMessage(
647 std::unique_ptr<flutter::PlatformMessage> message) {
648 if (!message) {
649 return;
650 }
651 const std::string channel = message->channel();
652 auto found = platform_message_handlers_.find(channel);
653 if (found == platform_message_handlers_.end()) {
654 const bool already_errored = unregistered_channels_.count(channel);
655 if (!already_errored) {
656 FML_LOG(INFO)
657 << "Platform view received message on channel '" << message->channel()
658 << "' with no registered handler. An empty response will be "
659 "generated. Please implement the native message handler. This "
660 "message will appear only once per channel.";
661 unregistered_channels_.insert(channel);
662 }
664 return;
665 }
666 auto response = message->response();
667 bool response_handled = found->second(std::move(message));
668
669 // Ensure all responses are completed.
670 if (response && !response_handled) {
671 // response_handled should be true if the response was completed.
672 FML_DCHECK(!response->is_complete());
673 response->CompleteEmpty();
674 }
675}
676
677// |flutter::PlatformView|
678void PlatformView::SetSemanticsEnabled(bool enabled) {
680 if (enabled) {
681 SetAccessibilityFeatures(static_cast<int32_t>(
683 } else {
684 SetAccessibilityFeatures(0);
685 }
686}
687
688// |flutter::PlatformView|
689void PlatformView::UpdateSemantics(
690 int64_t view_id,
693 const float pixel_ratio =
694 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
695
696 on_semantics_node_update_callback_(update, pixel_ratio);
697}
698
699// Channel handler for kAccessibilityChannel
700bool PlatformView::HandleAccessibilityChannelPlatformMessage(
701 std::unique_ptr<flutter::PlatformMessage> message) {
702 FML_DCHECK(message->channel() == kAccessibilityChannel);
703
704 const flutter::StandardMessageCodec& standard_message_codec =
706 std::unique_ptr<flutter::EncodableValue> decoded =
707 standard_message_codec.DecodeMessage(message->data().GetMapping(),
708 message->data().GetSize());
709
710 flutter::EncodableMap map = std::get<flutter::EncodableMap>(*decoded);
711 std::string type =
712 std::get<std::string>(map.at(flutter::EncodableValue("type")));
713 if (type == "announce") {
714 flutter::EncodableMap data_map = std::get<flutter::EncodableMap>(
715 map.at(flutter::EncodableValue("data")));
716 std::string text =
717 std::get<std::string>(data_map.at(flutter::EncodableValue("message")));
718
719 on_request_announce_callback_(text);
720 }
721
722 // Complete with an empty response.
723 return false;
724}
725
726// Channel handler for kFlutterPlatformChannel
727bool PlatformView::HandleFlutterPlatformChannelPlatformMessage(
728 std::unique_ptr<flutter::PlatformMessage> message) {
730
731 // Fuchsia does not handle any platform messages at this time.
732
733 // Complete with an empty response.
734 return false;
735}
736
737bool PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage(
738 std::unique_ptr<flutter::PlatformMessage> message) {
739 FML_DCHECK(message->channel() == kFlutterPlatformViewsChannel);
740 const auto& data = message->data();
741 rapidjson::Document document;
742 document.Parse(reinterpret_cast<const char*>(data.GetMapping()),
743 data.GetSize());
744 if (document.HasParseError() || !document.IsObject()) {
745 FML_LOG(ERROR) << "Could not parse document";
746 return false;
747 }
748 auto root = document.GetObject();
749 auto method_member = root.FindMember("method");
750 if (method_member == root.MemberEnd() || !method_member->value.IsString()) {
751 return false;
752 }
753 std::string method(method_member->value.GetString());
754
755 if (method == "View.enableWireframe") {
756 auto args_it = root.FindMember("args");
757 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
758 FML_LOG(ERROR) << "No arguments found.";
759 return false;
760 }
761 const auto& args = args_it->value;
762
763 auto enable = args.FindMember("enable");
764 if (!enable->value.IsBool()) {
765 FML_LOG(ERROR) << "Argument 'enable' is not a bool";
766 return false;
767 }
768
769 wireframe_enabled_callback_(enable->value.GetBool());
770 } else if (method == "View.create") {
771 auto args_it = root.FindMember("args");
772 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
773 FML_LOG(ERROR) << "No arguments found.";
774 return false;
775 }
776 const auto& args = args_it->value;
777
778 auto view_id = args.FindMember("viewId");
779 if (!view_id->value.IsUint64()) {
780 FML_LOG(ERROR) << "Argument 'viewId' is not a int64";
781 return false;
782 }
783
784 auto hit_testable = args.FindMember("hitTestable");
785 if (!hit_testable->value.IsBool()) {
786 FML_LOG(ERROR) << "Argument 'hitTestable' is not a bool";
787 return false;
788 }
789
790 auto focusable = args.FindMember("focusable");
791 if (!focusable->value.IsBool()) {
792 FML_LOG(ERROR) << "Argument 'focusable' is not a bool";
793 return false;
794 }
795
796 auto on_view_created = fml::MakeCopyable(
797 [platform_task_runner = task_runners_.GetPlatformTaskRunner(),
798 message = std::move(message)]() {
799 // The client is waiting for view creation. Send an empty response
800 // back to signal the view was created.
801 if (message->response()) {
802 message->response()->Complete(std::make_unique<fml::DataMapping>(
803 std::vector<uint8_t>({'[', '0', ']'})));
804 }
805 });
806 OnCreateView(std::move(on_view_created), view_id->value.GetUint64(),
807 hit_testable->value.GetBool(), focusable->value.GetBool());
808 return true;
809 } else if (method == "View.update") {
810 auto args_it = root.FindMember("args");
811 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
812 FML_LOG(ERROR) << "No arguments found.";
813 return false;
814 }
815 const auto& args = args_it->value;
816
817 auto view_id = args.FindMember("viewId");
818 if (!view_id->value.IsUint64()) {
819 FML_LOG(ERROR) << "Argument 'viewId' is not a int64";
820 return false;
821 }
822
823 auto hit_testable = args.FindMember("hitTestable");
824 if (!hit_testable->value.IsBool()) {
825 FML_LOG(ERROR) << "Argument 'hitTestable' is not a bool";
826 return false;
827 }
828
829 auto focusable = args.FindMember("focusable");
830 if (!focusable->value.IsBool()) {
831 FML_LOG(ERROR) << "Argument 'focusable' is not a bool";
832 return false;
833 }
834
835 SkRect view_occlusion_hint_raw = SkRect::MakeEmpty();
836 auto view_occlusion_hint = args.FindMember("viewOcclusionHintLTRB");
837 if (view_occlusion_hint != args.MemberEnd()) {
838 if (view_occlusion_hint->value.IsArray()) {
839 const auto& view_occlusion_hint_array =
840 view_occlusion_hint->value.GetArray();
841 if (view_occlusion_hint_array.Size() == 4) {
842 bool parse_error = false;
843 for (int i = 0; i < 4; i++) {
844 auto& array_val = view_occlusion_hint_array[i];
845 if (!array_val.IsDouble()) {
846 FML_LOG(ERROR) << "Argument 'viewOcclusionHintLTRB' element " << i
847 << " is not a double";
848 parse_error = true;
849 break;
850 }
851 }
852
853 if (!parse_error) {
854 view_occlusion_hint_raw =
855 SkRect::MakeLTRB(view_occlusion_hint_array[0].GetDouble(),
856 view_occlusion_hint_array[1].GetDouble(),
857 view_occlusion_hint_array[2].GetDouble(),
858 view_occlusion_hint_array[3].GetDouble());
859 }
860 } else {
861 FML_LOG(ERROR)
862 << "Argument 'viewOcclusionHintLTRB' expected size 4; got "
863 << view_occlusion_hint_array.Size();
864 }
865 } else {
866 FML_LOG(ERROR)
867 << "Argument 'viewOcclusionHintLTRB' is not a double array";
868 }
869 } else {
870 FML_LOG(WARNING) << "Argument 'viewOcclusionHintLTRB' is missing";
871 }
872
873 on_update_view_callback_(
874 view_id->value.GetUint64(), view_occlusion_hint_raw,
875 hit_testable->value.GetBool(), focusable->value.GetBool());
876 if (message->response()) {
877 message->response()->Complete(std::make_unique<fml::DataMapping>(
878 std::vector<uint8_t>({'[', '0', ']'})));
879 return true;
880 }
881 } else if (method == "View.dispose") {
882 auto args_it = root.FindMember("args");
883 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
884 FML_LOG(ERROR) << "No arguments found.";
885 return false;
886 }
887 const auto& args = args_it->value;
888
889 auto view_id = args.FindMember("viewId");
890 if (!view_id->value.IsUint64()) {
891 FML_LOG(ERROR) << "Argument 'viewId' is not a int64";
892 return false;
893 }
894
895 OnDisposeView(view_id->value.GetUint64());
896 if (message->response()) {
897 message->response()->Complete(std::make_unique<fml::DataMapping>(
898 std::vector<uint8_t>({'[', '0', ']'})));
899 return true;
900 }
901 } else if (method.rfind("View.focus", 0) == 0) {
902 return focus_delegate_->HandlePlatformMessage(document,
903 message->response());
904 } else if (method.rfind(PointerInjectorDelegate::kPointerInjectorMethodPrefix,
905 0) == 0) {
906 return pointer_injector_delegate_->HandlePlatformMessage(
907 document, 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
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
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switch_defs.h:36
std::map< EncodableValue, EncodableValue > EncodableMap
internal::CopyableLambda< T > MakeCopyable(T lambda)
Definition ref_ptr.h:261
impeller::ShaderType type
int32_t height
int32_t width
#define TRACE_EVENT0(category_group, name)
#define TRACE_FLOW_END(category, name, id)