Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
fl_view_test.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
6
7#include <memory>
8
16
18#include "gtest/gtest.h"
19
20// FIXME(robert-ancell): Disabled, see below.
21#if 0
22static void first_frame_cb(FlView* view, gboolean* first_frame_emitted) {
23 *first_frame_emitted = TRUE;
24}
25#endif
26
28
29TEST_F(FlViewTest, GetEngine) {
30 FlView* view = fl_view_new(project);
31
32 // Check the engine is immediately available (i.e. before the widget is
33 // realized).
34 FlEngine* engine = fl_view_get_engine(view);
35 EXPECT_NE(engine, nullptr);
36}
37
38TEST_F(FlViewTest, StateUpdateDoesNotHappenInInit) {
39 FlView* view = fl_view_new(project);
40 // Check that creating a view doesn't try to query the window state in
41 // initialization, causing a critical log to be issued.
42 EXPECT_EQ(
44 (GLogLevelFlags)0x0);
45
46 (void)view;
47}
48
49// Disposing a view that holds the text input focus clears the handler's
50// widget pointer so it does not dangle.
51// https://github.com/flutter/flutter/issues/188657
52TEST_F(FlViewTest, DisposeClearsTextInputWidget) {
53 FlView* view = fl_view_new(project);
54 g_object_ref_sink(view);
55 g_autoptr(FlEngine) engine =
56 FL_ENGINE(g_object_ref(fl_view_get_engine(view)));
57 StartEngine(engine);
58 FlTextInputHandler* handler = fl_engine_get_text_input_handler(engine);
59
60 // Give the view text input focus.
62 EXPECT_EQ(fl_text_input_handler_get_widget(handler), GTK_WIDGET(view));
63
64 // Destroy the view while the engine and handler persist.
65 g_object_unref(view);
66
67 EXPECT_EQ(fl_text_input_handler_get_widget(handler), nullptr);
68}
69
70// FIXME(robert-ancell): Disabling this test as it requires the FlView
71// to be realized to work after some refactoring. This is proving to be
72// very difficult to mock. Following PRs will change this code so enable the
73// test again after that.
74#if 0
75TEST_F(FlViewTest, FirstFrameSignal) {
76 FlView* view = fl_view_new(project);
77 gboolean first_frame_emitted = FALSE;
78 g_signal_connect(view, "first-frame", G_CALLBACK(first_frame_cb),
79 &first_frame_emitted);
80
81 EXPECT_FALSE(first_frame_emitted);
82
83 fl_renderable_present_layers(FL_RENDERABLE(view), nullptr, 0);
84
85 // Signal is emitted in idle, clear the main loop.
86 while (g_main_context_iteration(g_main_context_default(), FALSE)) {
87 // Repeat until nothing to iterate on.
88 }
89
90 // Check view has detected frame.
91 EXPECT_TRUE(first_frame_emitted);
92}
93#endif
94
95// Check semantics update applied
96TEST_F(FlViewTest, SemanticsUpdate) {
97 FlView* view = fl_view_new(project);
98
99 FlEngine* engine = fl_view_get_engine(view);
100 StartEngine(engine);
101
102 FlutterSemanticsFlags flags = {};
103 FlutterSemanticsNode2 root_node = {
104 .id = 0, .label = "root", .flags2 = &flags};
105 FlutterSemanticsNode2* nodes[1] = {&root_node};
106 FlutterSemanticsUpdate2 update = {
107 .node_count = 1, .nodes = nodes, .view_id = 0};
108 g_signal_emit_by_name(engine, "update-semantics", &update);
109
110 FlViewAccessible* accessible = fl_view_get_accessible(view);
111 EXPECT_EQ(atk_object_get_n_accessible_children(ATK_OBJECT(accessible)), 1);
112 AtkObject* root_object =
113 atk_object_ref_accessible_child(ATK_OBJECT(accessible), 0);
114 EXPECT_STREQ(atk_object_get_name(root_object), "root");
115}
116
117// Check semantics update ignored for other view
118TEST_F(FlViewTest, SemanticsUpdateOtherView) {
119 FlView* view = fl_view_new(project);
120
121 FlEngine* engine = fl_view_get_engine(view);
122 StartEngine(engine);
123
124 FlutterSemanticsFlags flags = {};
125 FlutterSemanticsNode2 root_node = {
126 .id = 0, .label = "root", .flags2 = &flags};
127 FlutterSemanticsNode2* nodes[1] = {&root_node};
128 FlutterSemanticsUpdate2 update = {
129 .node_count = 1, .nodes = nodes, .view_id = 99};
130 g_signal_emit_by_name(engine, "update-semantics", &update);
131
132 FlViewAccessible* accessible = fl_view_get_accessible(view);
133 EXPECT_EQ(atk_object_get_n_accessible_children(ATK_OBJECT(accessible)), 0);
134}
135
136// Check secondary view is registered with engine.
137TEST_F(FlViewTest, SecondaryView) {
138 FlView* implicit_view = fl_view_new(project);
139
140 FlEngine* engine = fl_view_get_engine(implicit_view);
141
142 auto view_id = std::make_shared<FlutterViewId>(-1);
144 AddView, ([view_id](auto engine, const FlutterAddViewInfo* info) {
145 *view_id = info->view_id;
146 FlutterAddViewResult result = {
148 .added = true,
149 .user_data = info->user_data};
150 info->add_view_callback(&result);
151 return kSuccess;
152 }));
153
154 StartEngine(engine);
155
156 FlView* secondary_view = fl_view_new_for_engine(engine);
157 EXPECT_EQ(*view_id, fl_view_get_id(secondary_view));
158}
159
160// Check secondary view that fails registration.
161TEST_F(FlViewTest, SecondaryViewError) {
162 FlView* implicit_view = fl_view_new(project);
163
164 FlEngine* engine = fl_view_get_engine(implicit_view);
165
166 auto view_id = std::make_shared<FlutterViewId>(-1);
168 AddView, ([view_id](auto engine, const FlutterAddViewInfo* info) {
169 *view_id = info->view_id;
170 return kInvalidArguments;
171 }));
172
173 StartEngine(engine);
174
175 FlView* secondary_view = fl_view_new_for_engine(engine);
176 EXPECT_EQ(*view_id, fl_view_get_id(secondary_view));
177}
178
179// Check views are deregistered on destruction.
180TEST_F(FlViewTest, ViewDestroy) {
181 FlView* implicit_view = fl_view_new(project);
182
183 FlEngine* engine = fl_view_get_engine(implicit_view);
184
185 g_autoptr(GPtrArray) removed_views = g_ptr_array_new();
187 RemoveView,
188 ([removed_views](auto engine, const FlutterRemoveViewInfo* info) {
189 g_ptr_array_add(removed_views, GINT_TO_POINTER(info->view_id));
190 return kSuccess;
191 }));
192
193 StartEngine(engine);
194
195 FlView* secondary_view = fl_view_new_for_engine(engine);
196
197 int64_t implicit_view_id = fl_view_get_id(implicit_view);
198 int64_t secondary_view_id = fl_view_get_id(secondary_view);
199
200 fl_gtk_widget_destroy(GTK_WIDGET(secondary_view));
201 fl_gtk_widget_destroy(GTK_WIDGET(implicit_view));
202
203 EXPECT_EQ(removed_views->len, 2u);
204 EXPECT_EQ(GPOINTER_TO_INT(g_ptr_array_index(removed_views, 0)),
205 secondary_view_id);
206 EXPECT_EQ(GPOINTER_TO_INT(g_ptr_array_index(removed_views, 1)),
207 implicit_view_id);
208}
209
210// Check views deregistered with errors works.
211TEST_F(FlViewTest, ViewDestroyError) {
212 FlView* implicit_view = fl_view_new(project);
213
214 FlEngine* engine = fl_view_get_engine(implicit_view);
215
217 RemoveView, ([](auto engine, const FlutterRemoveViewInfo* info) {
218 return kInvalidArguments;
219 }));
220
221 StartEngine(engine);
222
223 FlView* secondary_view = fl_view_new_for_engine(engine);
224
225 fl_gtk_widget_destroy(GTK_WIDGET(secondary_view));
226 fl_gtk_widget_destroy(GTK_WIDGET(implicit_view));
227}
228
229// Check can create a view that is sized to the content.
230TEST_F(FlViewTest, SizedToContent) {
231 FlView* implicit_view = fl_view_new(project);
232
233 FlEngine* engine = fl_view_get_engine(implicit_view);
234
236 RemoveView, ([](auto engine, const FlutterRemoveViewInfo* info) {
237 return kInvalidArguments;
238 }));
239
240 StartEngine(engine);
241
242 FlView* secondary_view = fl_view_new_sized_to_content(engine);
243
244 fl_gtk_widget_destroy(GTK_WIDGET(secondary_view));
245 fl_gtk_widget_destroy(GTK_WIDGET(implicit_view));
246}
@ kInvalidArguments
Definition embedder.h:75
@ kSuccess
Definition embedder.h:73
FlutterEngine engine
Definition main.cc:84
FlViewAccessible * accessible
FlView * view
g_autoptr(FlEngine) engine
return TRUE
FlutterEngineProcTable * fl_engine_get_embedder_api(FlEngine *self)
Definition fl_engine.cc:920
FlTextInputHandler * fl_engine_get_text_input_handler(FlEngine *self)
const gchar FlBinaryMessengerMessageHandler handler
void fl_renderable_present_layers(FlRenderable *self, const FlutterLayer **layers, size_t layers_count)
void fl_text_input_handler_set_widget(FlTextInputHandler *self, GtkWidget *widget)
GtkWidget * fl_text_input_handler_get_widget(FlTextInputHandler *self)
G_MODULE_EXPORT FlView * fl_view_new_for_engine(FlEngine *engine)
Definition fl_view.cc:719
FlViewAccessible * fl_view_get_accessible(FlView *self)
Definition fl_view.cc:770
G_MODULE_EXPORT FlView * fl_view_new(FlDartProject *project)
Definition fl_view.cc:705
G_MODULE_EXPORT FlEngine * fl_view_get_engine(FlView *self)
Definition fl_view.cc:753
G_MODULE_EXPORT int64_t fl_view_get_id(FlView *self)
Definition fl_view.cc:759
G_MODULE_EXPORT FlView * fl_view_new_sized_to_content(FlEngine *engine)
Definition fl_view.cc:735
G_BEGIN_DECLS FlutterViewId view_id
static void first_frame_cb(FlViewMonitor *self)
TEST_F(FlViewTest, GetEngine)
void fl_gtk_widget_destroy(GtkWidget *widget)
Definition mock_gtk.cc:280
GLogLevelFlags fl_get_received_gtk_log_levels()
Returns the recorded log levels.
#define MOCK_ENGINE_PROC(proc, mock_impl)
FlutterAddViewCallback add_view_callback
Definition embedder.h:1147
FlutterViewId view_id
The identifier for the view to add. This must be unique.
Definition embedder.h:1127
FlutterEngineAddViewFnPtr AddView
Definition embedder.h:3807
FlutterEngineRemoveViewFnPtr RemoveView
Definition embedder.h:3808
FlutterViewId view_id
Definition embedder.h:1178
int32_t id
The unique identifier for this node.
Definition embedder.h:1668
A batch of updates to semantics nodes and custom actions.
Definition embedder.h:1851
size_t node_count
The number of semantics node updates.
Definition embedder.h:1855