Flutter Engine
 
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 };
371 SetViewportMetrics(kFlutterImplicitViewId, metrics);
372
373 parent_viewport_watcher_->GetLayout(
374 fit::bind_member(this, &PlatformView::OnGetLayout));
375}
376
377void PlatformView::OnParentViewportStatus(
378 fuchsia::ui::composition::ParentViewportStatus status) {
379 // TODO(fxbug.dev/116001): Investigate if it is useful to send hidden/shown
380 // signals.
381 parent_viewport_status_ = status;
382 parent_viewport_watcher_->GetStatus(
383 fit::bind_member(this, &PlatformView::OnParentViewportStatus));
384}
385
386void PlatformView::OnChildViewStatus(
387 uint64_t content_id,
388 fuchsia::ui::composition::ChildViewStatus status) {
389 FML_DCHECK(child_view_info_.count(content_id) == 1);
390
391 std::ostringstream out;
392 out << "{" << "\"method\":\"View.viewStateChanged\"," << "\"args\":{"
393 << " \"viewId\":" << child_view_info_.at(content_id).view_id
394 << "," // ViewId
395 << " \"is_rendering\":true," // IsViewRendering
396 << " \"state\":true" // IsViewRendering
397 << " }" << "}";
398 auto call = out.str();
399
400 std::unique_ptr<flutter::PlatformMessage> message =
401 std::make_unique<flutter::PlatformMessage>(
402 "flutter/platform_views",
403 fml::MallocMapping::Copy(call.c_str(), call.size()), nullptr);
404 DispatchPlatformMessage(std::move(message));
405
406 child_view_info_.at(content_id)
407 .child_view_watcher->GetStatus(
408 [this, content_id](fuchsia::ui::composition::ChildViewStatus status) {
409 OnChildViewStatus(content_id, status);
410 });
411}
412
413void PlatformView::OnChildViewViewRef(uint64_t content_id,
414 uint64_t view_id,
415 fuchsia::ui::views::ViewRef view_ref) {
416 FML_CHECK(child_view_info_.count(content_id) == 1);
417
418 fuchsia::ui::views::ViewRef view_ref_clone;
419 fidl::Clone(view_ref, &view_ref_clone);
420
421 focus_delegate_->OnChildViewViewRef(view_id, std::move(view_ref));
422
423 pointer_injector_delegate_->OnCreateView(view_id, std::move(view_ref_clone));
424 OnChildViewConnected(content_id);
425}
426
427void PlatformView::OnCreateView(ViewCallback on_view_created,
428 int64_t view_id_raw,
429 bool hit_testable,
430 bool focusable) {
431 auto on_view_bound = [weak = weak_factory_.GetWeakPtr(),
432 platform_task_runner =
433 task_runners_.GetPlatformTaskRunner(),
434 view_id = view_id_raw](
435 fuchsia::ui::composition::ContentId content_id,
436 fuchsia::ui::composition::ChildViewWatcherHandle
437 child_view_watcher_handle) {
438 FML_CHECK(weak);
439 FML_CHECK(weak->child_view_info_.count(content_id.value) == 0);
440
441 platform_task_runner->PostTask(fml::MakeCopyable(
442 [weak, view_id, content_id,
443 watcher_handle = std::move(child_view_watcher_handle)]() mutable {
444 if (!weak) {
445 FML_LOG(WARNING)
446 << "View bound to PlatformView after PlatformView was "
447 "destroyed; ignoring.";
448 return;
449 }
450
451 // Bind the child view watcher to the platform thread so that the FIDL
452 // calls are handled on the platform thread.
453 fuchsia::ui::composition::ChildViewWatcherPtr child_view_watcher =
454 watcher_handle.Bind();
455 FML_CHECK(child_view_watcher);
456
457 child_view_watcher.set_error_handler([weak, view_id, content_id](
458 zx_status_t status) {
459 FML_LOG(WARNING)
460 << "Child disconnected. ChildViewWatcher status: " << status;
461
462 if (!weak) {
463 FML_LOG(WARNING) << "View bound to PlatformView after "
464 "PlatformView was "
465 "destroyed; ignoring.";
466 return;
467 }
468
469 // Disconnected views cannot listen to pointer events.
470 weak->pointer_injector_delegate_->OnDestroyView(view_id);
471
472 weak->OnChildViewDisconnected(content_id.value);
473 });
474
475 weak->child_view_info_.emplace(
476 std::piecewise_construct, std::forward_as_tuple(content_id.value),
477 std::forward_as_tuple(view_id, std::move(child_view_watcher)));
478
479 weak->child_view_info_.at(content_id.value)
480 .child_view_watcher->GetStatus(
481 [weak, id = content_id.value](
482 fuchsia::ui::composition::ChildViewStatus status) {
483 weak->OnChildViewStatus(id, status);
484 });
485
486 weak->child_view_info_.at(content_id.value)
487 .child_view_watcher->GetViewRef(
488 [weak, content_id = content_id.value,
489 view_id](fuchsia::ui::views::ViewRef view_ref) {
490 weak->OnChildViewViewRef(content_id, view_id,
491 std::move(view_ref));
492 });
493 }));
494 };
495
496 on_create_view_callback_(view_id_raw, std::move(on_view_created),
497 std::move(on_view_bound), hit_testable, focusable);
498}
499
500void PlatformView::OnDisposeView(int64_t view_id_raw) {
501 auto on_view_unbound =
502 [weak = weak_factory_.GetWeakPtr(),
503 platform_task_runner = task_runners_.GetPlatformTaskRunner(),
504 view_id_raw](fuchsia::ui::composition::ContentId content_id) {
505 platform_task_runner->PostTask([weak, content_id, view_id_raw]() {
506 if (!weak) {
507 FML_LOG(WARNING)
508 << "View unbound from PlatformView after PlatformView"
509 "was destroyed; ignoring.";
510 return;
511 }
512
513 FML_DCHECK(weak->child_view_info_.count(content_id.value) == 1);
514 weak->OnChildViewDisconnected(content_id.value);
515 weak->child_view_info_.erase(content_id.value);
516 weak->focus_delegate_->OnDisposeChildView(view_id_raw);
517 weak->pointer_injector_delegate_->OnDestroyView(view_id_raw);
518 });
519 };
520 on_destroy_view_callback_(view_id_raw, std::move(on_view_unbound));
521}
522
523void PlatformView::OnChildViewConnected(uint64_t content_id) {
524 FML_CHECK(child_view_info_.count(content_id) == 1);
525 std::ostringstream out;
526 out << "{" << "\"method\":\"View.viewConnected\"," << "\"args\":{"
527 << " \"viewId\":" << child_view_info_.at(content_id).view_id << " }"
528 << "}";
529 auto call = out.str();
530
531 std::unique_ptr<flutter::PlatformMessage> message =
532 std::make_unique<flutter::PlatformMessage>(
533 "flutter/platform_views",
534 fml::MallocMapping::Copy(call.c_str(), call.size()), nullptr);
535 DispatchPlatformMessage(std::move(message));
536}
537
538void PlatformView::OnChildViewDisconnected(uint64_t content_id) {
539 FML_CHECK(child_view_info_.count(content_id) == 1);
540 std::ostringstream out;
541 out << "{" << "\"method\":\"View.viewDisconnected\"," << "\"args\":{"
542 << " \"viewId\":" << child_view_info_.at(content_id).view_id << " }"
543 << "}";
544 auto call = out.str();
545
546 std::unique_ptr<flutter::PlatformMessage> message =
547 std::make_unique<flutter::PlatformMessage>(
548 "flutter/platform_views",
549 fml::MallocMapping::Copy(call.c_str(), call.size()), nullptr);
550 DispatchPlatformMessage(std::move(message));
551}
552
553bool PlatformView::OnHandlePointerEvent(
554 const fuchsia::ui::input::PointerEvent& pointer) {
555 TRACE_EVENT0("flutter", "PlatformView::OnHandlePointerEvent");
556
557 // TODO(SCN-1278): Use proper trace_id for tracing flow.
558 trace_flow_id_t trace_id =
559 PointerTraceHACK(pointer.radius_major, pointer.radius_minor);
560 TRACE_FLOW_END("input", "dispatch_event_to_client", trace_id);
561
562 const float pixel_ratio =
563 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
564
565 flutter::PointerData pointer_data;
566 pointer_data.Clear();
567 pointer_data.time_stamp = pointer.event_time / 1000;
568 pointer_data.change = GetChangeFromPointerEventPhase(pointer.phase);
569 pointer_data.kind = GetKindFromPointerType(pointer.type);
570 pointer_data.device = pointer.pointer_id;
571 // Pointer events are in logical pixels, so scale to physical.
572 pointer_data.physical_x = pointer.x * pixel_ratio;
573 pointer_data.physical_y = pointer.y * pixel_ratio;
574 // Buttons are single bit values starting with kMousePrimaryButton = 1.
575 pointer_data.buttons = static_cast<uint64_t>(pointer.buttons);
576
577 switch (pointer_data.change) {
579 // Make the pointer start in the view space, despite numerical drift.
580 auto clamped_pointer = ClampToViewSpace(pointer.x, pointer.y);
581 pointer_data.physical_x = clamped_pointer[0] * pixel_ratio;
582 pointer_data.physical_y = clamped_pointer[1] * pixel_ratio;
583
584 down_pointers_.insert(pointer_data.device);
585 break;
586 }
589 down_pointers_.erase(pointer_data.device);
590 break;
592 if (down_pointers_.count(pointer_data.device) == 0) {
594 }
595 break;
597 if (down_pointers_.count(pointer_data.device) != 0) {
598 FML_LOG(ERROR) << "Received add event for down pointer.";
599 }
600 break;
602 if (down_pointers_.count(pointer_data.device) != 0) {
603 FML_LOG(ERROR) << "Received remove event for down pointer.";
604 }
605 break;
607 if (down_pointers_.count(pointer_data.device) != 0) {
608 FML_LOG(ERROR) << "Received hover event for down pointer.";
609 }
610 break;
614 FML_DLOG(ERROR) << "Unexpectedly received pointer pan/zoom event";
615 break;
616 }
617
618 auto packet = std::make_unique<flutter::PointerDataPacket>(1);
619 packet->SetPointerData(0, pointer_data);
620 DispatchPointerDataPacket(std::move(packet));
621 return true;
622}
623
624// |flutter::PlatformView|
625std::unique_ptr<flutter::VsyncWaiter> PlatformView::CreateVSyncWaiter() {
626 return std::make_unique<flutter_runner::VsyncWaiter>(
627 await_vsync_callback_, await_vsync_for_secondary_callback_callback_,
629}
630
631// |flutter::PlatformView|
632std::unique_ptr<flutter::Surface> PlatformView::CreateRenderingSurface() {
633 return on_create_surface_callback_ ? on_create_surface_callback_() : nullptr;
634}
635
636// |flutter::PlatformView|
637std::shared_ptr<flutter::ExternalViewEmbedder>
638PlatformView::CreateExternalViewEmbedder() {
639 return external_view_embedder_;
640}
641
642// |flutter::PlatformView|
643void PlatformView::HandlePlatformMessage(
644 std::unique_ptr<flutter::PlatformMessage> message) {
645 if (!message) {
646 return;
647 }
648 const std::string channel = message->channel();
649 auto found = platform_message_handlers_.find(channel);
650 if (found == platform_message_handlers_.end()) {
651 const bool already_errored = unregistered_channels_.count(channel);
652 if (!already_errored) {
653 FML_LOG(INFO)
654 << "Platform view received message on channel '" << message->channel()
655 << "' with no registered handler. An empty response will be "
656 "generated. Please implement the native message handler. This "
657 "message will appear only once per channel.";
658 unregistered_channels_.insert(channel);
659 }
661 return;
662 }
663 auto response = message->response();
664 bool response_handled = found->second(std::move(message));
665
666 // Ensure all responses are completed.
667 if (response && !response_handled) {
668 // response_handled should be true if the response was completed.
669 FML_DCHECK(!response->is_complete());
670 response->CompleteEmpty();
671 }
672}
673
674// |flutter::PlatformView|
675void PlatformView::SetSemanticsEnabled(bool enabled) {
677 if (enabled) {
678 SetAccessibilityFeatures(static_cast<int32_t>(
680 } else {
681 SetAccessibilityFeatures(0);
682 }
683}
684
685// |flutter::PlatformView|
686void PlatformView::UpdateSemantics(
687 int64_t view_id,
690 const float pixel_ratio =
691 view_pixel_ratio_.has_value() ? *view_pixel_ratio_ : 0.f;
692
693 on_semantics_node_update_callback_(update, pixel_ratio);
694}
695
696// Channel handler for kAccessibilityChannel
697bool PlatformView::HandleAccessibilityChannelPlatformMessage(
698 std::unique_ptr<flutter::PlatformMessage> message) {
699 FML_DCHECK(message->channel() == kAccessibilityChannel);
700
701 const flutter::StandardMessageCodec& standard_message_codec =
703 std::unique_ptr<flutter::EncodableValue> decoded =
704 standard_message_codec.DecodeMessage(message->data().GetMapping(),
705 message->data().GetSize());
706
707 flutter::EncodableMap map = std::get<flutter::EncodableMap>(*decoded);
708 std::string type =
709 std::get<std::string>(map.at(flutter::EncodableValue("type")));
710 if (type == "announce") {
711 flutter::EncodableMap data_map = std::get<flutter::EncodableMap>(
712 map.at(flutter::EncodableValue("data")));
713 std::string text =
714 std::get<std::string>(data_map.at(flutter::EncodableValue("message")));
715
716 on_request_announce_callback_(text);
717 }
718
719 // Complete with an empty response.
720 return false;
721}
722
723// Channel handler for kFlutterPlatformChannel
724bool PlatformView::HandleFlutterPlatformChannelPlatformMessage(
725 std::unique_ptr<flutter::PlatformMessage> message) {
727
728 // Fuchsia does not handle any platform messages at this time.
729
730 // Complete with an empty response.
731 return false;
732}
733
734bool PlatformView::HandleFlutterPlatformViewsChannelPlatformMessage(
735 std::unique_ptr<flutter::PlatformMessage> message) {
736 FML_DCHECK(message->channel() == kFlutterPlatformViewsChannel);
737 const auto& data = message->data();
738 rapidjson::Document document;
739 document.Parse(reinterpret_cast<const char*>(data.GetMapping()),
740 data.GetSize());
741 if (document.HasParseError() || !document.IsObject()) {
742 FML_LOG(ERROR) << "Could not parse document";
743 return false;
744 }
745 auto root = document.GetObject();
746 auto method_member = root.FindMember("method");
747 if (method_member == root.MemberEnd() || !method_member->value.IsString()) {
748 return false;
749 }
750 std::string method(method_member->value.GetString());
751
752 if (method == "View.enableWireframe") {
753 auto args_it = root.FindMember("args");
754 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
755 FML_LOG(ERROR) << "No arguments found.";
756 return false;
757 }
758 const auto& args = args_it->value;
759
760 auto enable = args.FindMember("enable");
761 if (!enable->value.IsBool()) {
762 FML_LOG(ERROR) << "Argument 'enable' is not a bool";
763 return false;
764 }
765
766 wireframe_enabled_callback_(enable->value.GetBool());
767 } else if (method == "View.create") {
768 auto args_it = root.FindMember("args");
769 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
770 FML_LOG(ERROR) << "No arguments found.";
771 return false;
772 }
773 const auto& args = args_it->value;
774
775 auto view_id = args.FindMember("viewId");
776 if (!view_id->value.IsUint64()) {
777 FML_LOG(ERROR) << "Argument 'viewId' is not a int64";
778 return false;
779 }
780
781 auto hit_testable = args.FindMember("hitTestable");
782 if (!hit_testable->value.IsBool()) {
783 FML_LOG(ERROR) << "Argument 'hitTestable' is not a bool";
784 return false;
785 }
786
787 auto focusable = args.FindMember("focusable");
788 if (!focusable->value.IsBool()) {
789 FML_LOG(ERROR) << "Argument 'focusable' is not a bool";
790 return false;
791 }
792
793 auto on_view_created = fml::MakeCopyable(
794 [platform_task_runner = task_runners_.GetPlatformTaskRunner(),
795 message = std::move(message)]() {
796 // The client is waiting for view creation. Send an empty response
797 // back to signal the view was created.
798 if (message->response()) {
799 message->response()->Complete(std::make_unique<fml::DataMapping>(
800 std::vector<uint8_t>({'[', '0', ']'})));
801 }
802 });
803 OnCreateView(std::move(on_view_created), view_id->value.GetUint64(),
804 hit_testable->value.GetBool(), focusable->value.GetBool());
805 return true;
806 } else if (method == "View.update") {
807 auto args_it = root.FindMember("args");
808 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
809 FML_LOG(ERROR) << "No arguments found.";
810 return false;
811 }
812 const auto& args = args_it->value;
813
814 auto view_id = args.FindMember("viewId");
815 if (!view_id->value.IsUint64()) {
816 FML_LOG(ERROR) << "Argument 'viewId' is not a int64";
817 return false;
818 }
819
820 auto hit_testable = args.FindMember("hitTestable");
821 if (!hit_testable->value.IsBool()) {
822 FML_LOG(ERROR) << "Argument 'hitTestable' is not a bool";
823 return false;
824 }
825
826 auto focusable = args.FindMember("focusable");
827 if (!focusable->value.IsBool()) {
828 FML_LOG(ERROR) << "Argument 'focusable' is not a bool";
829 return false;
830 }
831
832 SkRect view_occlusion_hint_raw = SkRect::MakeEmpty();
833 auto view_occlusion_hint = args.FindMember("viewOcclusionHintLTRB");
834 if (view_occlusion_hint != args.MemberEnd()) {
835 if (view_occlusion_hint->value.IsArray()) {
836 const auto& view_occlusion_hint_array =
837 view_occlusion_hint->value.GetArray();
838 if (view_occlusion_hint_array.Size() == 4) {
839 bool parse_error = false;
840 for (int i = 0; i < 4; i++) {
841 auto& array_val = view_occlusion_hint_array[i];
842 if (!array_val.IsDouble()) {
843 FML_LOG(ERROR) << "Argument 'viewOcclusionHintLTRB' element " << i
844 << " is not a double";
845 parse_error = true;
846 break;
847 }
848 }
849
850 if (!parse_error) {
851 view_occlusion_hint_raw =
852 SkRect::MakeLTRB(view_occlusion_hint_array[0].GetDouble(),
853 view_occlusion_hint_array[1].GetDouble(),
854 view_occlusion_hint_array[2].GetDouble(),
855 view_occlusion_hint_array[3].GetDouble());
856 }
857 } else {
858 FML_LOG(ERROR)
859 << "Argument 'viewOcclusionHintLTRB' expected size 4; got "
860 << view_occlusion_hint_array.Size();
861 }
862 } else {
863 FML_LOG(ERROR)
864 << "Argument 'viewOcclusionHintLTRB' is not a double array";
865 }
866 } else {
867 FML_LOG(WARNING) << "Argument 'viewOcclusionHintLTRB' is missing";
868 }
869
870 on_update_view_callback_(
871 view_id->value.GetUint64(), view_occlusion_hint_raw,
872 hit_testable->value.GetBool(), focusable->value.GetBool());
873 if (message->response()) {
874 message->response()->Complete(std::make_unique<fml::DataMapping>(
875 std::vector<uint8_t>({'[', '0', ']'})));
876 return true;
877 }
878 } else if (method == "View.dispose") {
879 auto args_it = root.FindMember("args");
880 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
881 FML_LOG(ERROR) << "No arguments found.";
882 return false;
883 }
884 const auto& args = args_it->value;
885
886 auto view_id = args.FindMember("viewId");
887 if (!view_id->value.IsUint64()) {
888 FML_LOG(ERROR) << "Argument 'viewId' is not a int64";
889 return false;
890 }
891
892 OnDisposeView(view_id->value.GetUint64());
893 if (message->response()) {
894 message->response()->Complete(std::make_unique<fml::DataMapping>(
895 std::vector<uint8_t>({'[', '0', ']'})));
896 return true;
897 }
898 } else if (method.rfind("View.focus", 0) == 0) {
899 return focus_delegate_->HandlePlatformMessage(root, message->response());
900 } else if (method.rfind(PointerInjectorDelegate::kPointerInjectorMethodPrefix,
901 0) == 0) {
902 return pointer_injector_delegate_->HandlePlatformMessage(
903 root, message->response());
904 } else {
905 FML_LOG(ERROR) << "Unknown " << message->channel() << " method " << method;
906 }
907 // Complete with an empty response by default.
908 return false;
909}
910
911bool PlatformView::HandleFuchsiaShaderWarmupChannelPlatformMessage(
912 OnShaderWarmupCallback on_shader_warmup_callback,
913 std::unique_ptr<flutter::PlatformMessage> message) {
914 FML_DCHECK(message->channel() == kFuchsiaShaderWarmupChannel);
915
916 if (!on_shader_warmup_callback) {
917 FML_LOG(ERROR) << "No shader warmup callback set!";
918 std::string result = "[0]";
919 message->response()->Complete(
920 std::make_unique<fml::DataMapping>(std::vector<uint8_t>(
921 (const uint8_t*)result.c_str(),
922 (const uint8_t*)result.c_str() + result.length())));
923 return true;
924 }
925
926 const auto& data = message->data();
927 rapidjson::Document document;
928 document.Parse(reinterpret_cast<const char*>(data.GetMapping()),
929 data.GetSize());
930 if (document.HasParseError() || !document.IsObject()) {
931 FML_LOG(ERROR) << "Could not parse document";
932 return false;
933 }
934 auto root = document.GetObject();
935 auto method = root.FindMember("method");
936 if (method == root.MemberEnd() || !method->value.IsString() ||
937 method->value != "WarmupSkps") {
938 FML_LOG(ERROR) << "Invalid method name";
939 return false;
940 }
941
942 auto args_it = root.FindMember("args");
943 if (args_it == root.MemberEnd() || !args_it->value.IsObject()) {
944 FML_LOG(ERROR) << "No arguments found.";
945 return false;
946 }
947
948 auto shaders_it = root["args"].FindMember("shaders");
949 if (shaders_it == root["args"].MemberEnd() || !shaders_it->value.IsArray()) {
950 FML_LOG(ERROR) << "No shaders found.";
951 return false;
952 }
953
954 auto width_it = root["args"].FindMember("width");
955 auto height_it = root["args"].FindMember("height");
956 if (width_it == root["args"].MemberEnd() || !width_it->value.IsNumber()) {
957 FML_LOG(ERROR) << "Invalid width";
958 return false;
959 }
960 if (height_it == root["args"].MemberEnd() || !height_it->value.IsNumber()) {
961 FML_LOG(ERROR) << "Invalid height";
962 return false;
963 }
964 auto width = width_it->value.GetUint64();
965 auto height = height_it->value.GetUint64();
966
967 std::vector<std::string> skp_paths;
968 const auto& shaders = shaders_it->value;
969 for (rapidjson::Value::ConstValueIterator itr = shaders.Begin();
970 itr != shaders.End(); ++itr) {
971 skp_paths.push_back((*itr).GetString());
972 }
973
974 auto completion_callback = [response =
975 message->response()](uint32_t num_successes) {
976 std::ostringstream result_stream;
977 result_stream << "[" << num_successes << "]";
978
979 std::string result(result_stream.str());
980
981 response->Complete(std::make_unique<fml::DataMapping>(std::vector<uint8_t>(
982 (const uint8_t*)result.c_str(),
983 (const uint8_t*)result.c_str() + result.length())));
984 };
985
986 on_shader_warmup_callback(skp_paths, completion_callback, width, height);
987 // The response has already been completed by us.
988 return true;
989}
990
991// Channel handler for kFuchsiaInputTestChannel
992bool PlatformView::HandleFuchsiaInputTestChannelPlatformMessage(
993 std::unique_ptr<flutter::PlatformMessage> message) {
994 FML_DCHECK(message->channel() == kFuchsiaInputTestChannel);
995
996 const auto& data = message->data();
997 rapidjson::Document document;
998 document.Parse(reinterpret_cast<const char*>(data.GetMapping()),
999 data.GetSize());
1000 if (document.HasParseError() || !document.IsObject()) {
1001 FML_LOG(ERROR) << "Could not parse document";
1002 return false;
1003 }
1004 auto root = document.GetObject();
1005 auto method = root.FindMember("method");
1006 if (method == root.MemberEnd() || !method->value.IsString()) {
1007 FML_LOG(ERROR) << "Missing method";
1008 return false;
1009 }
1010
1011 FML_LOG(INFO) << "fuchsia/input_test: method=" << method->value.GetString();
1012
1013 if (method->value == "TouchInputListener.ReportTouchInput") {
1014 if (!touch_input_listener_) {
1015 FML_LOG(ERROR) << "TouchInputListener not found.";
1016 return false;
1017 }
1018
1019 fuchsia::ui::test::input::TouchInputListenerReportTouchInputRequest request;
1020 CallWithMember<double>(
1021 root, "local_x", [&](double local_x) { request.set_local_x(local_x); });
1022 CallWithMember<double>(
1023 root, "local_y", [&](double local_y) { request.set_local_y(local_y); });
1024 CallWithMember<int64_t>(root, "time_received", [&](uint64_t time_received) {
1025 request.set_time_received(time_received);
1026 });
1027 CallWithMember<std::string>(root, "component_name",
1028 [&](std::string component_name) {
1029 request.set_component_name(component_name);
1030 });
1031
1032 touch_input_listener_->ReportTouchInput(std::move(request));
1033 return true;
1034 }
1035
1036 if (method->value == "KeyboardInputListener.ReportTextInput") {
1037 if (!keyboard_input_listener_) {
1038 FML_LOG(ERROR) << "KeyboardInputListener not found.";
1039 return false;
1040 }
1041
1042 fuchsia::ui::test::input::KeyboardInputListenerReportTextInputRequest
1043 request;
1044 CallWithMember<std::string>(
1045 root, "text", [&](std::string text) { request.set_text(text); });
1046
1047 keyboard_input_listener_->ReportTextInput(std::move(request));
1048 return true;
1049 }
1050
1051 if (method->value == "MouseInputListener.ReportMouseInput") {
1052 if (!mouse_input_listener_) {
1053 FML_LOG(ERROR) << "MouseInputListener not found.";
1054 return false;
1055 }
1056
1057 fuchsia::ui::test::input::MouseInputListenerReportMouseInputRequest request;
1058 CallWithMember<double>(
1059 root, "local_x", [&](double local_x) { request.set_local_x(local_x); });
1060 CallWithMember<double>(
1061 root, "local_y", [&](double local_y) { request.set_local_y(local_y); });
1062 CallWithMember<int64_t>(root, "time_received", [&](uint64_t time_received) {
1063 request.set_time_received(time_received);
1064 });
1065 CallWithMember<std::string>(root, "component_name",
1066 [&](std::string component_name) {
1067 request.set_component_name(component_name);
1068 });
1069 CallWithMember<int>(root, "buttons", [&](int button_mask) {
1070 std::vector<fuchsia::ui::test::input::MouseButton> buttons;
1071 if (button_mask & 1) {
1072 buttons.push_back(fuchsia::ui::test::input::MouseButton::FIRST);
1073 }
1074 if (button_mask & 2) {
1075 buttons.push_back(fuchsia::ui::test::input::MouseButton::SECOND);
1076 }
1077 if (button_mask & 4) {
1078 buttons.push_back(fuchsia::ui::test::input::MouseButton::THIRD);
1079 }
1080 request.set_buttons(buttons);
1081 });
1082 CallWithMember<std::string>(root, "phase", [&](std::string phase) {
1083 if (phase == "add") {
1084 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::ADD);
1085 } else if (phase == "hover") {
1086 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::HOVER);
1087 } else if (phase == "down") {
1088 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::DOWN);
1089 } else if (phase == "move") {
1090 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::MOVE);
1091 } else if (phase == "up") {
1092 request.set_phase(fuchsia::ui::test::input::MouseEventPhase::UP);
1093 } else {
1094 FML_LOG(ERROR) << "Unexpected mouse phase: " << phase;
1095 }
1096 });
1097 CallWithMember<double>(
1098 root, "wheel_x_physical_pixel", [&](double wheel_x_physical_pixel) {
1099 request.set_wheel_x_physical_pixel(wheel_x_physical_pixel);
1100 });
1101 CallWithMember<double>(
1102 root, "wheel_y_physical_pixel", [&](double wheel_y_physical_pixel) {
1103 request.set_wheel_y_physical_pixel(wheel_y_physical_pixel);
1104 });
1105
1106 mouse_input_listener_->ReportMouseInput(std::move(request));
1107 return true;
1108 }
1109
1110 FML_LOG(ERROR) << "fuchsia/input_test: unrecognized method "
1111 << method->value.GetString();
1112 return false;
1113}
1114
1115// Channel handler for kFuchsiaChildViewChannel
1116bool PlatformView::HandleFuchsiaChildViewChannelPlatformMessage(
1117 std::unique_ptr<flutter::PlatformMessage> message) {
1118 FML_DCHECK(message->channel() == kFuchsiaChildViewChannel);
1119
1120 if (message->data().GetSize() != 1 ||
1121 (message->data().GetMapping()[0] != '1')) {
1123 << " data must be singularly '1'.";
1124 return false;
1125 }
1126
1127 FML_DCHECK(message->data().GetMapping()[0] == '1');
1128
1129 if (!message->response()) {
1131 << " must have a response callback.";
1132 return false;
1133 }
1134
1135 if (!dart_application_svc_) {
1136 FML_LOG(ERROR) << "No service directory.";
1137 return false;
1138 }
1139
1140 fuchsia::ui::app::ViewProviderHandle view_provider_handle;
1141 zx_status_t status =
1142 dart_application_svc_->Connect(view_provider_handle.NewRequest());
1143 if (status != ZX_OK) {
1144 FML_LOG(ERROR) << "Failed to connect to view provider.";
1145 return false;
1146 }
1147 fuchsia::ui::app::ViewProviderPtr view_provider;
1148 view_provider.Bind(std::move(view_provider_handle));
1149
1150 zx::handle view_id;
1151
1152 zx::channel view_tokens[2];
1153 fuchsia::ui::views::ViewportCreationToken viewport_creation_token;
1154 fuchsia::ui::views::ViewCreationToken view_creation_token;
1155 status = zx::channel::create(0, &viewport_creation_token.value,
1156 &view_creation_token.value);
1157 if (status != ZX_OK) {
1158 FML_LOG(ERROR) << "Creating view tokens: " << zx_status_get_string(status);
1159 return false;
1160 }
1161
1162 fuchsia::ui::app::CreateView2Args create_view_args;
1163 create_view_args.set_view_creation_token(std::move(view_creation_token));
1164 view_provider->CreateView2(std::move(create_view_args));
1165
1166 view_id = std::move(viewport_creation_token.value);
1167
1168 if (view_id) {
1169 message->response()->Complete(
1170 std::make_unique<fml::DataMapping>(std::to_string(view_id.release())
1171
1172 ));
1173 return true;
1174 } else {
1175 return false;
1176 }
1177}
1178
1179} // 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_
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const gchar * channel
G_BEGIN_DECLS GBytes * message
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)