Flutter Linux Embedder
fl_accessible_text_field.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 
8 
9 G_DEFINE_AUTOPTR_CLEANUP_FUNC(PangoContext, g_object_unref)
10 // PangoLayout g_autoptr macro weren't added until 1.49.4. Add them manually.
11 // https://gitlab.gnome.org/GNOME/pango/-/commit/0b84e14
12 #if !PANGO_VERSION_CHECK(1, 49, 4)
13 G_DEFINE_AUTOPTR_CLEANUP_FUNC(PangoLayout, g_object_unref)
14 #endif
15 
16 typedef bool (*FlTextBoundaryCallback)(const PangoLogAttr* attr);
17 
19  FlAccessibleNode parent_instance;
20 
23  GtkEntryBuffer* buffer;
24  FlutterTextDirection text_direction;
25 };
26 
27 static void fl_accessible_text_iface_init(AtkTextIface* iface);
28 static void fl_accessible_editable_text_iface_init(AtkEditableTextIface* iface);
29 
31  FlAccessibleTextField,
32  fl_accessible_text_field,
33  fl_accessible_node_get_type(),
34  G_IMPLEMENT_INTERFACE(ATK_TYPE_TEXT, fl_accessible_text_iface_init)
35  G_IMPLEMENT_INTERFACE(ATK_TYPE_EDITABLE_TEXT,
37 
38 static gchar* get_substring(FlAccessibleTextField* self,
39  glong start,
40  glong end) {
41  const gchar* value = gtk_entry_buffer_get_text(self->buffer);
42  glong length = g_utf8_strlen(value, -1);
43  if (end == -1) {
44  // g_utf8_substring() accepts -1 since 2.72
45  end = length;
46  }
47  start = CLAMP(start, 0, length);
48  end = CLAMP(end, start, length);
50 }
51 
52 static PangoContext* get_pango_context(FlAccessibleTextField* self) {
53  PangoFontMap* font_map = pango_cairo_font_map_get_default();
54  PangoContext* context = pango_font_map_create_context(font_map);
55  pango_context_set_base_dir(context,
56  self->text_direction == kFlutterTextDirectionRTL
57  ? PANGO_DIRECTION_RTL
58  : PANGO_DIRECTION_LTR);
59  return context;
60 }
61 
62 static PangoLayout* create_pango_layout(FlAccessibleTextField* self) {
63  g_autoptr(PangoContext) context = get_pango_context(self);
64  PangoLayout* layout = pango_layout_new(context);
65  pango_layout_set_text(layout, gtk_entry_buffer_get_text(self->buffer), -1);
66  return layout;
67 }
68 
69 static gchar* get_string_at_offset(FlAccessibleTextField* self,
70  gint start,
71  gint end,
72  FlTextBoundaryCallback is_start,
74  gint* start_offset,
75  gint* end_offset) {
76  g_autoptr(PangoLayout) layout = create_pango_layout(self);
77 
78  gint n_attrs = 0;
79  const PangoLogAttr* attrs =
80  pango_layout_get_log_attrs_readonly(layout, &n_attrs);
81 
82  start = CLAMP(start, 0, MAX(n_attrs - 1, 0));
83  end = CLAMP(end, 0, MAX(n_attrs - 1, 0));
84 
85  while (start > 0 && !is_start(&attrs[start])) {
86  --start;
87  }
88 
89  while (end < n_attrs && !is_end(&attrs[end])) {
90  ++end;
91  }
92 
93  if (start_offset != nullptr) {
94  *start_offset = start;
95  }
96  if (end_offset != nullptr) {
97  *end_offset = end;
98  }
99 
100  return get_substring(self, start, end);
101 }
102 
103 static gchar* get_char_at_offset(FlAccessibleTextField* self,
104  gint offset,
105  gint* start_offset,
106  gint* end_offset) {
107  return get_string_at_offset(
108  self, offset, offset + 1,
109  [](const PangoLogAttr* attr) -> bool { return attr->is_char_break; },
110  [](const PangoLogAttr* attr) -> bool { return attr->is_char_break; },
111  start_offset, end_offset);
112 }
113 
114 static gchar* get_word_at_offset(FlAccessibleTextField* self,
115  gint offset,
116  gint* start_offset,
117  gint* end_offset) {
118  return get_string_at_offset(
119  self, offset, offset,
120  [](const PangoLogAttr* attr) -> bool { return attr->is_word_start; },
121  [](const PangoLogAttr* attr) -> bool { return attr->is_word_end; },
122  start_offset, end_offset);
123 }
124 
125 static gchar* get_sentence_at_offset(FlAccessibleTextField* self,
126  gint offset,
127  gint* start_offset,
128  gint* end_offset) {
129  return get_string_at_offset(
130  self, offset, offset,
131  [](const PangoLogAttr* attr) -> bool { return attr->is_sentence_start; },
132  [](const PangoLogAttr* attr) -> bool { return attr->is_sentence_end; },
133  start_offset, end_offset);
134 }
135 
136 static gchar* get_line_at_offset(FlAccessibleTextField* self,
137  gint offset,
138  gint* start_offset,
139  gint* end_offset) {
140  g_autoptr(PangoLayout) layout = create_pango_layout(self);
141 
142  GSList* lines = pango_layout_get_lines_readonly(layout);
143  while (lines != nullptr) {
144  PangoLayoutLine* line = static_cast<PangoLayoutLine*>(lines->data);
145  if (offset >= line->start_index &&
146  offset <= line->start_index + line->length) {
147  if (start_offset != nullptr) {
148  *start_offset = line->start_index;
149  }
150  if (end_offset != nullptr) {
151  *end_offset = line->start_index + line->length;
152  }
153  return get_substring(self, line->start_index,
154  line->start_index + line->length);
155  }
156  lines = lines->next;
157  }
158 
159  return nullptr;
160 }
161 
162 static gchar* get_paragraph_at_offset(FlAccessibleTextField* self,
163  gint offset,
164  gint* start_offset,
165  gint* end_offset) {
166  g_autoptr(PangoLayout) layout = create_pango_layout(self);
167 
168  PangoLayoutLine* start = nullptr;
169  PangoLayoutLine* end = nullptr;
170  gint n_lines = pango_layout_get_line_count(layout);
171  for (gint i = 0; i < n_lines; ++i) {
172  PangoLayoutLine* line = pango_layout_get_line(layout, i);
173  if (line->is_paragraph_start) {
174  end = line;
175  }
176  if (start != nullptr && end != nullptr && offset >= start->start_index &&
177  offset <= end->start_index + end->length) {
178  if (start_offset != nullptr) {
179  *start_offset = start->start_index;
180  }
181  if (end_offset != nullptr) {
182  *end_offset = end->start_index + end->length;
183  }
184  return get_substring(self, start->start_index,
185  end->start_index + end->length);
186  }
187  if (line->is_paragraph_start) {
188  start = line;
189  }
190  }
191 
192  return nullptr;
193 }
194 
195 static void perform_set_text_action(FlAccessibleTextField* self,
196  const char* text) {
198  g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new();
199  g_autoptr(GBytes) message =
200  fl_message_codec_encode_message(FL_MESSAGE_CODEC(codec), value, nullptr);
201 
202  fl_accessible_node_perform_action(FL_ACCESSIBLE_NODE(self),
203  kFlutterSemanticsActionSetText, message);
204 }
205 
206 static void perform_set_selection_action(FlAccessibleTextField* self,
207  gint base,
208  gint extent) {
211  fl_value_set_string_take(value, "extent", fl_value_new_int(extent));
212 
213  g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new();
214  g_autoptr(GBytes) message =
215  fl_message_codec_encode_message(FL_MESSAGE_CODEC(codec), value, nullptr);
216 
218  FL_ACCESSIBLE_NODE(self), kFlutterSemanticsActionSetSelection, message);
219 }
220 
221 // Implements GObject::dispose.
222 static void fl_accessible_text_field_dispose(GObject* object) {
223  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(object);
224 
225  g_clear_object(&self->buffer);
226 
227  G_OBJECT_CLASS(fl_accessible_text_field_parent_class)->dispose(object);
228 }
229 
230 // Implements FlAccessibleNode::set_value.
231 static void fl_accessible_text_field_set_value(FlAccessibleNode* node,
232  const gchar* value) {
233  g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(node));
234  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(node);
235 
236  if (g_strcmp0(gtk_entry_buffer_get_text(self->buffer), value) == 0) {
237  return;
238  }
239 
240  gtk_entry_buffer_set_text(self->buffer, value, -1);
241 }
242 
243 // Implements FlAccessibleNode::set_text_selection.
244 static void fl_accessible_text_field_set_text_selection(FlAccessibleNode* node,
245  gint base,
246  gint extent) {
247  g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(node));
248  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(node);
249 
250  gboolean caret_moved = extent != self->selection_extent;
251  gboolean has_selection = base != extent;
252  gboolean had_selection = self->selection_base != self->selection_extent;
253  gboolean selection_changed = (has_selection || had_selection) &&
254  (caret_moved || base != self->selection_base);
255 
256  self->selection_base = base;
257  self->selection_extent = extent;
258 
259  if (selection_changed) {
260  g_signal_emit_by_name(self, "text-selection-changed", nullptr);
261  }
262 
263  if (caret_moved) {
264  g_signal_emit_by_name(self, "text-caret-moved", extent, nullptr);
265  }
266 }
267 
268 // Implements FlAccessibleNode::set_text_direction.
270  FlAccessibleNode* node,
271  FlutterTextDirection direction) {
272  g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(node));
273  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(node);
274 
275  self->text_direction = direction;
276 }
277 
278 // Overrides FlAccessibleNode::perform_action.
279 void fl_accessible_text_field_perform_action(FlAccessibleNode* self,
280  FlutterSemanticsAction action,
281  GBytes* data) {
282  FlAccessibleNodeClass* parent_class =
283  FL_ACCESSIBLE_NODE_CLASS(fl_accessible_text_field_parent_class);
284 
285  switch (action) {
286  case kFlutterSemanticsActionMoveCursorForwardByCharacter:
287  case kFlutterSemanticsActionMoveCursorBackwardByCharacter:
288  case kFlutterSemanticsActionMoveCursorForwardByWord:
289  case kFlutterSemanticsActionMoveCursorBackwardByWord: {
290  // These actions require a boolean argument that indicates whether the
291  // selection should be extended or collapsed when moving the cursor.
292  g_autoptr(FlValue) extend_selection = fl_value_new_bool(false);
293  g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new();
295  FL_MESSAGE_CODEC(codec), extend_selection, nullptr);
296  parent_class->perform_action(self, action, message);
297  break;
298  }
299  default:
300  parent_class->perform_action(self, action, data);
301  break;
302  }
303 }
304 
305 // Implements AtkText::get_character_count.
307  g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(text), 0);
308  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(text);
309 
310  return gtk_entry_buffer_get_length(self->buffer);
311 }
312 
313 // Implements AtkText::get_text.
314 static gchar* fl_accessible_text_field_get_text(AtkText* text,
315  gint start_offset,
316  gint end_offset) {
317  g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(text), nullptr);
318  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(text);
319 
320  return get_substring(self, start_offset, end_offset);
321 }
322 
323 // Implements AtkText::get_string_at_offset.
325  AtkText* text,
326  gint offset,
327  AtkTextGranularity granularity,
328  gint* start_offset,
329  gint* end_offset) {
330  g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(text), nullptr);
331  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(text);
332 
333  switch (granularity) {
334  case ATK_TEXT_GRANULARITY_CHAR:
335  return get_char_at_offset(self, offset, start_offset, end_offset);
336  case ATK_TEXT_GRANULARITY_WORD:
337  return get_word_at_offset(self, offset, start_offset, end_offset);
338  case ATK_TEXT_GRANULARITY_SENTENCE:
339  return get_sentence_at_offset(self, offset, start_offset, end_offset);
340  case ATK_TEXT_GRANULARITY_LINE:
341  return get_line_at_offset(self, offset, start_offset, end_offset);
342  case ATK_TEXT_GRANULARITY_PARAGRAPH:
343  return get_paragraph_at_offset(self, offset, start_offset, end_offset);
344  default:
345  return nullptr;
346  }
347 }
348 
349 // Implements AtkText::get_text_at_offset (deprecated but still commonly used).
351  AtkText* text,
352  gint offset,
353  AtkTextBoundary boundary_type,
354  gint* start_offset,
355  gint* end_offset) {
356  switch (boundary_type) {
357  case ATK_TEXT_BOUNDARY_CHAR:
359  text, offset, ATK_TEXT_GRANULARITY_CHAR, start_offset, end_offset);
360  break;
361  case ATK_TEXT_BOUNDARY_WORD_START:
362  case ATK_TEXT_BOUNDARY_WORD_END:
364  text, offset, ATK_TEXT_GRANULARITY_WORD, start_offset, end_offset);
365  break;
366  case ATK_TEXT_BOUNDARY_SENTENCE_START:
367  case ATK_TEXT_BOUNDARY_SENTENCE_END:
369  text, offset, ATK_TEXT_GRANULARITY_SENTENCE, start_offset,
370  end_offset);
371  break;
372  case ATK_TEXT_BOUNDARY_LINE_START:
373  case ATK_TEXT_BOUNDARY_LINE_END:
375  text, offset, ATK_TEXT_GRANULARITY_LINE, start_offset, end_offset);
376  break;
377  default:
378  return nullptr;
379  }
380 }
381 
382 // Implements AtkText::get_caret_offset.
383 static gint fl_accessible_text_field_get_caret_offset(AtkText* text) {
384  g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(text), -1);
385  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(text);
386 
387  return self->selection_extent;
388 }
389 
390 // Implements AtkText::set_caret_offset.
391 static gboolean fl_accessible_text_field_set_caret_offset(AtkText* text,
392  gint offset) {
393  g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(text), false);
394  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(text);
395 
396  perform_set_selection_action(self, offset, offset);
397  return TRUE;
398 }
399 
400 // Implements AtkText::get_n_selections.
401 static gint fl_accessible_text_field_get_n_selections(AtkText* text) {
402  g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(text), 0);
403  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(text);
404 
405  if (self->selection_base == self->selection_extent) {
406  return 0;
407  }
408 
409  return 1;
410 }
411 
412 // Implements AtkText::get_selection.
413 static gchar* fl_accessible_text_field_get_selection(AtkText* text,
414  gint selection_num,
415  gint* start_offset,
416  gint* end_offset) {
417  g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(text), nullptr);
418  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(text);
419 
420  if (selection_num != 0 || self->selection_base == self->selection_extent) {
421  return nullptr;
422  }
423 
424  gint start = MIN(self->selection_base, self->selection_extent);
425  gint end = MAX(self->selection_base, self->selection_extent);
426 
427  if (start_offset != nullptr) {
428  *start_offset = start;
429  }
430  if (end_offset != nullptr) {
431  *end_offset = end;
432  }
433 
434  return get_substring(self, start, end);
435 }
436 
437 // Implements AtkText::add_selection.
438 static gboolean fl_accessible_text_field_add_selection(AtkText* text,
439  gint start_offset,
440  gint end_offset) {
441  g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(text), false);
442  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(text);
443 
444  if (self->selection_base != self->selection_extent) {
445  return FALSE;
446  }
447 
448  perform_set_selection_action(self, start_offset, end_offset);
449  return TRUE;
450 }
451 
452 // Implements AtkText::remove_selection.
453 static gboolean fl_accessible_text_field_remove_selection(AtkText* text,
454  gint selection_num) {
455  g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(text), false);
456  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(text);
457 
458  if (selection_num != 0 || self->selection_base == self->selection_extent) {
459  return FALSE;
460  }
461 
462  perform_set_selection_action(self, self->selection_extent,
463  self->selection_extent);
464  return TRUE;
465 }
466 
467 // Implements AtkText::set_selection.
468 static gboolean fl_accessible_text_field_set_selection(AtkText* text,
469  gint selection_num,
470  gint start_offset,
471  gint end_offset) {
472  g_return_val_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(text), false);
473  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(text);
474 
475  if (selection_num != 0) {
476  return FALSE;
477  }
478 
479  perform_set_selection_action(self, start_offset, end_offset);
480  return TRUE;
481 }
482 
483 // Implements AtkEditableText::set_text_contents.
485  AtkEditableText* editable_text,
486  const gchar* string) {
487  g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(editable_text));
488  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(editable_text);
489 
490  perform_set_text_action(self, string);
491 }
492 
493 // Implements AtkEditableText::insert_text.
494 static void fl_accessible_text_field_insert_text(AtkEditableText* editable_text,
495  const gchar* string,
496  gint length,
497  gint* position) {
498  g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(editable_text));
499  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(editable_text);
500 
501  *position +=
502  gtk_entry_buffer_insert_text(self->buffer, *position, string, length);
503 
504  perform_set_text_action(self, gtk_entry_buffer_get_text(self->buffer));
505  perform_set_selection_action(self, *position, *position);
506 }
507 
508 // Implements AtkEditableText::delete_text.
509 static void fl_accessible_node_delete_text(AtkEditableText* editable_text,
510  gint start_pos,
511  gint end_pos) {
512  g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(editable_text));
513  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(editable_text);
514 
515  gtk_entry_buffer_delete_text(self->buffer, start_pos, end_pos - start_pos);
516 
517  perform_set_text_action(self, gtk_entry_buffer_get_text(self->buffer));
518  perform_set_selection_action(self, start_pos, start_pos);
519 }
520 
521 // Implement AtkEditableText::copy_text.
522 static void fl_accessible_text_field_copy_text(AtkEditableText* editable_text,
523  gint start_pos,
524  gint end_pos) {
525  g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(editable_text));
526  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(editable_text);
527 
528  perform_set_selection_action(self, start_pos, end_pos);
529 
530  fl_accessible_node_perform_action(FL_ACCESSIBLE_NODE(editable_text),
531  kFlutterSemanticsActionCopy, nullptr);
532 }
533 
534 // Implements AtkEditableText::cut_text.
535 static void fl_accessible_text_field_cut_text(AtkEditableText* editable_text,
536  gint start_pos,
537  gint end_pos) {
538  g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(editable_text));
539  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(editable_text);
540 
541  perform_set_selection_action(self, start_pos, end_pos);
542 
543  fl_accessible_node_perform_action(FL_ACCESSIBLE_NODE(editable_text),
544  kFlutterSemanticsActionCut, nullptr);
545 }
546 
547 // Implements AtkEditableText::paste_text.
548 static void fl_accessible_text_field_paste_text(AtkEditableText* editable_text,
549  gint position) {
550  g_return_if_fail(FL_IS_ACCESSIBLE_TEXT_FIELD(editable_text));
551  FlAccessibleTextField* self = FL_ACCESSIBLE_TEXT_FIELD(editable_text);
552 
553  perform_set_selection_action(self, position, position);
554 
555  fl_accessible_node_perform_action(FL_ACCESSIBLE_NODE(editable_text),
556  kFlutterSemanticsActionPaste, nullptr);
557 }
558 
560  FlAccessibleTextFieldClass* klass) {
561  G_OBJECT_CLASS(klass)->dispose = fl_accessible_text_field_dispose;
562  FL_ACCESSIBLE_NODE_CLASS(klass)->set_value =
564  FL_ACCESSIBLE_NODE_CLASS(klass)->set_text_selection =
566  FL_ACCESSIBLE_NODE_CLASS(klass)->set_text_direction =
568  FL_ACCESSIBLE_NODE_CLASS(klass)->perform_action =
570 }
571 
572 static void fl_accessible_text_iface_init(AtkTextIface* iface) {
573  iface->get_character_count = fl_accessible_text_field_get_character_count;
574  iface->get_text = fl_accessible_text_field_get_text;
575  iface->get_text_at_offset = fl_accessible_text_field_get_text_at_offset;
576  iface->get_string_at_offset = fl_accessible_text_field_get_string_at_offset;
577 
578  iface->get_caret_offset = fl_accessible_text_field_get_caret_offset;
579  iface->set_caret_offset = fl_accessible_text_field_set_caret_offset;
580 
581  iface->get_n_selections = fl_accessible_text_field_get_n_selections;
582  iface->get_selection = fl_accessible_text_field_get_selection;
583  iface->add_selection = fl_accessible_text_field_add_selection;
584  iface->remove_selection = fl_accessible_text_field_remove_selection;
585  iface->set_selection = fl_accessible_text_field_set_selection;
586 }
587 
589  AtkEditableTextIface* iface) {
590  iface->set_text_contents = fl_accessible_text_field_set_text_contents;
591  iface->insert_text = fl_accessible_text_field_insert_text;
592  iface->delete_text = fl_accessible_node_delete_text;
593 
594  iface->copy_text = fl_accessible_text_field_copy_text;
595  iface->cut_text = fl_accessible_text_field_cut_text;
596  iface->paste_text = fl_accessible_text_field_paste_text;
597 }
598 
599 static void fl_accessible_text_field_init(FlAccessibleTextField* self) {
600  self->selection_base = -1;
601  self->selection_extent = -1;
602 
603  self->buffer = gtk_entry_buffer_new("", 0);
604 
605  g_signal_connect_object(
606  self->buffer, "inserted-text",
607  G_CALLBACK(+[](FlAccessibleTextField* self, guint position, gchar* chars,
608  guint n_chars) {
609  g_signal_emit_by_name(self, "text-insert", position, n_chars, chars,
610  nullptr);
611  }),
612  self, G_CONNECT_SWAPPED);
613 
614  g_signal_connect_object(self->buffer, "deleted-text",
615  G_CALLBACK(+[](FlAccessibleTextField* self,
616  guint position, guint n_chars) {
617  g_autofree gchar* chars = atk_text_get_text(
618  ATK_TEXT(self), position, position + n_chars);
619  g_signal_emit_by_name(self, "text-remove", position,
620  n_chars, chars, nullptr);
621  }),
622  self, G_CONNECT_SWAPPED);
623 }
624 
625 FlAccessibleNode* fl_accessible_text_field_new(FlEngine* engine,
626  FlutterViewId view_id,
627  int32_t id) {
628  return FL_ACCESSIBLE_NODE(g_object_new(fl_accessible_text_field_get_type(),
629  "engine", engine, "view-id", view_id,
630  "node-id", id, nullptr));
631 }
const char * message
g_autoptr(FlEngine) engine
void fl_accessible_node_perform_action(FlAccessibleNode *self, FlutterSemanticsAction action, GBytes *data)
static void perform_set_selection_action(FlAccessibleTextField *self, gint base, gint extent)
static gint fl_accessible_text_field_get_n_selections(AtkText *text)
static void fl_accessible_text_field_insert_text(AtkEditableText *editable_text, const gchar *string, gint length, gint *position)
static void fl_accessible_text_field_dispose(GObject *object)
static void fl_accessible_text_field_paste_text(AtkEditableText *editable_text, gint position)
static gboolean fl_accessible_text_field_set_selection(AtkText *text, gint selection_num, gint start_offset, gint end_offset)
static void fl_accessible_text_field_set_text_contents(AtkEditableText *editable_text, const gchar *string)
static void fl_accessible_text_field_copy_text(AtkEditableText *editable_text, gint start_pos, gint end_pos)
glong length
static gchar * fl_accessible_text_field_get_text_at_offset(AtkText *text, gint offset, AtkTextBoundary boundary_type, gint *start_offset, gint *end_offset)
static void fl_accessible_text_field_init(FlAccessibleTextField *self)
static gboolean fl_accessible_text_field_remove_selection(AtkText *text, gint selection_num)
static gchar * get_sentence_at_offset(FlAccessibleTextField *self, gint offset, gint *start_offset, gint *end_offset)
static gchar * get_char_at_offset(FlAccessibleTextField *self, gint offset, gint *start_offset, gint *end_offset)
static gchar * get_string_at_offset(FlAccessibleTextField *self, gint start, gint end, FlTextBoundaryCallback is_start, FlTextBoundaryCallback is_end, gint *start_offset, gint *end_offset)
static gchar * get_word_at_offset(FlAccessibleTextField *self, gint offset, gint *start_offset, gint *end_offset)
G_DEFINE_TYPE_WITH_CODE(FlAccessibleTextField, fl_accessible_text_field, fl_accessible_node_get_type(), G_IMPLEMENT_INTERFACE(ATK_TYPE_EDITABLE_TEXT, fl_accessible_editable_text_iface_init)) static gchar *get_substring(FlAccessibleTextField *self
static PangoLayout * create_pango_layout(FlAccessibleTextField *self)
static void fl_accessible_text_field_set_text_direction(FlAccessibleNode *node, FlutterTextDirection direction)
static void fl_accessible_text_field_set_text_selection(FlAccessibleNode *node, gint base, gint extent)
bool(* FlTextBoundaryCallback)(const PangoLogAttr *attr)
static void fl_accessible_text_iface_init(AtkTextIface *iface)
static void fl_accessible_text_field_set_value(FlAccessibleNode *node, const gchar *value)
static PangoContext * get_pango_context(FlAccessibleTextField *self)
static gchar * get_paragraph_at_offset(FlAccessibleTextField *self, gint offset, gint *start_offset, gint *end_offset)
static void fl_accessible_editable_text_iface_init(AtkEditableTextIface *iface)
FlAccessibleNode * fl_accessible_text_field_new(FlEngine *engine, FlutterViewId view_id, int32_t id)
static gchar * fl_accessible_text_field_get_selection(AtkText *text, gint selection_num, gint *start_offset, gint *end_offset)
static gboolean fl_accessible_text_field_set_caret_offset(AtkText *text, gint offset)
static gchar * fl_accessible_text_field_get_string_at_offset(AtkText *text, gint offset, AtkTextGranularity granularity, gint *start_offset, gint *end_offset)
static void fl_accessible_node_delete_text(AtkEditableText *editable_text, gint start_pos, gint end_pos)
static void fl_accessible_text_field_cut_text(AtkEditableText *editable_text, gint start_pos, gint end_pos)
static gboolean fl_accessible_text_field_add_selection(AtkText *text, gint start_offset, gint end_offset)
static void perform_set_text_action(FlAccessibleTextField *self, const char *text)
static void fl_accessible_text_field_class_init(FlAccessibleTextFieldClass *klass)
return g_utf8_substring(value, start, end)
static gchar * get_line_at_offset(FlAccessibleTextField *self, gint offset, gint *start_offset, gint *end_offset)
static gint fl_accessible_text_field_get_character_count(AtkText *text)
static gchar * fl_accessible_text_field_get_text(AtkText *text, gint start_offset, gint end_offset)
static gint fl_accessible_text_field_get_caret_offset(AtkText *text)
glong glong end
void fl_accessible_text_field_perform_action(FlAccessibleNode *self, FlutterSemanticsAction action, GBytes *data)
return TRUE
G_MODULE_EXPORT GBytes * fl_message_codec_encode_message(FlMessageCodec *self, FlValue *message, GError **error)
uint8_t value
G_MODULE_EXPORT FlStandardMessageCodec * fl_standard_message_codec_new()
G_MODULE_EXPORT void fl_value_set_string_take(FlValue *self, const gchar *key, FlValue *value)
Definition: fl_value.cc:650
G_MODULE_EXPORT FlValue * fl_value_new_string(const gchar *value)
Definition: fl_value.cc:276
G_MODULE_EXPORT FlValue * fl_value_new_bool(bool value)
Definition: fl_value.cc:255
G_MODULE_EXPORT FlValue * fl_value_new_int(int64_t value)
Definition: fl_value.cc:262
G_MODULE_EXPORT FlValue * fl_value_new_map()
Definition: fl_value.cc:366
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:42
G_BEGIN_DECLS FlutterViewId view_id
FlutterTextDirection text_direction