6 #include "flutter/fml/string_conversion.h"
23 "TextInput.setEditableSizeAndTransform";
28 "TextInputClient.updateEditingState";
30 "TextInputClient.updateEditingStateWithDeltas";
50 static constexpr
char kXKey[] =
"x";
51 static constexpr
char kYKey[] =
"y";
60 "Internal Consistency Error";
67 if (active_model_ ==
nullptr) {
70 std::u16string text_before_change =
71 fml::Utf8ToUtf16(active_model_->GetText());
72 TextRange selection_before_change = active_model_->selection();
73 active_model_->AddText(
text);
75 if (enable_delta_model) {
78 SendStateUpdateWithDelta(*active_model_, &delta);
80 SendStateUpdate(*active_model_);
90 if (active_model_ ==
nullptr) {
98 EnterPressed(active_model_.get());
113 active_model_(nullptr) {
114 channel_->SetMethodCallHandler(
118 HandleMethodCall(call, std::move(result));
125 if (active_model_ ==
nullptr) {
128 active_model_->BeginComposing();
129 if (enable_delta_model) {
130 std::string
text = active_model_->GetText();
131 TextRange selection = active_model_->selection();
133 SendStateUpdateWithDelta(*active_model_, &delta);
135 SendStateUpdate(*active_model_);
140 if (active_model_ ==
nullptr) {
143 std::string text_before_change = active_model_->GetText();
144 TextRange selection_before_change = active_model_->selection();
145 TextRange composing_before_change = active_model_->composing_range();
146 std::string composing_text_before_change = text_before_change.substr(
147 composing_before_change.
start(), composing_before_change.
length());
148 active_model_->CommitComposing();
175 if (active_model_ ==
nullptr) {
178 std::string text_before_change = active_model_->GetText();
179 TextRange selection_before_change = active_model_->selection();
180 active_model_->CommitComposing();
181 active_model_->EndComposing();
182 if (enable_delta_model) {
183 std::string
text = active_model_->GetText();
185 SendStateUpdateWithDelta(*active_model_, &delta);
187 SendStateUpdate(*active_model_);
193 if (active_model_ ==
nullptr) {
196 std::string text_before_change = active_model_->GetText();
197 TextRange composing_before_change = active_model_->composing_range();
198 active_model_->AddText(
text);
199 cursor_pos += active_model_->composing_range().start();
200 active_model_->UpdateComposingText(
text);
201 active_model_->SetSelection(
TextRange(cursor_pos, cursor_pos));
202 std::string text_after_change = active_model_->GetText();
203 if (enable_delta_model) {
205 fml::Utf8ToUtf16(text_before_change), composing_before_change,
text);
206 SendStateUpdateWithDelta(*active_model_, &delta);
208 SendStateUpdate(*active_model_);
212 void TextInputPlugin::HandleMethodCall(
215 const std::string& method = method_call.
method_name();
220 if (active_model_ !=
nullptr && active_model_->composing()) {
221 active_model_->CommitComposing();
222 active_model_->EndComposing();
223 SendStateUpdate(*active_model_);
226 active_model_ =
nullptr;
232 const rapidjson::Document& args = *method_call.
arguments();
234 const rapidjson::Value& client_id_json = args[0];
235 const rapidjson::Value& client_config = args[1];
236 if (client_id_json.IsNull()) {
240 if (client_config.IsNull()) {
242 "Could not set client, missing arguments.");
245 client_id_ = client_id_json.GetInt();
247 if (enable_delta_model_json != client_config.MemberEnd() &&
248 enable_delta_model_json->value.IsBool()) {
249 enable_delta_model = enable_delta_model_json->value.GetBool();
253 if (input_action_json != client_config.MemberEnd() &&
254 input_action_json->value.IsString()) {
255 input_action_ = input_action_json->value.GetString();
258 auto input_type_info_json = client_config.FindMember(
kTextInputType);
259 if (input_type_info_json != client_config.MemberEnd() &&
260 input_type_info_json->value.IsObject()) {
261 auto input_type_json =
263 if (input_type_json != input_type_info_json->value.MemberEnd() &&
264 input_type_json->value.IsString()) {
265 input_type_ = input_type_json->value.GetString();
268 active_model_ = std::make_unique<TextInputModel>();
274 const rapidjson::Document& args = *method_call.
arguments();
276 if (active_model_ ==
nullptr) {
279 "Set editing state has been invoked, but no client is set.");
283 if (
text == args.MemberEnd() ||
text->value.IsNull()) {
285 "Set editing state has been invoked, but without text.");
290 if (base == args.MemberEnd() || base->value.IsNull() ||
291 extent == args.MemberEnd() || extent->value.IsNull()) {
293 "Selection base/extent values invalid.");
297 int selection_base = base->value.GetInt();
298 int selection_extent = extent->value.GetInt();
299 if (selection_base == -1 && selection_extent == -1) {
300 selection_base = selection_extent = 0;
302 active_model_->SetText(
text->value.GetString());
303 active_model_->SetSelection(TextRange(selection_base, selection_extent));
307 if (base == args.MemberEnd() || base->value.IsNull() ||
308 extent == args.MemberEnd() || extent->value.IsNull()) {
310 "Composing base/extent values invalid.");
313 int composing_base = base->value.GetInt();
314 int composing_extent = base->value.GetInt();
315 if (composing_base == -1 && composing_extent == -1) {
316 active_model_->EndComposing();
318 int composing_start = std::min(composing_base, composing_extent);
319 int cursor_offset = selection_base - composing_start;
320 active_model_->SetComposingRange(
321 TextRange(composing_base, composing_extent), cursor_offset);
328 const rapidjson::Document& args = *method_call.
arguments();
329 auto x = args.FindMember(
kXKey);
330 auto y = args.FindMember(
kYKey);
333 if (x == args.MemberEnd() || x->value.IsNull() ||
334 y == args.MemberEnd() || y->value.IsNull() ||
335 width == args.MemberEnd() || width->value.IsNull() ||
336 height == args.MemberEnd() || height->value.IsNull()) {
338 "Composing rect values invalid.");
341 composing_rect_ = {{x->value.GetDouble(), y->value.GetDouble()},
342 {width->value.GetDouble(), height->value.GetDouble()}};
344 Rect transformed_rect = GetCursorRect();
351 const rapidjson::Document& args = *method_call.
arguments();
353 if (transform == args.MemberEnd() || transform->value.IsNull() ||
354 !transform->value.IsArray() || transform->value.Size() != 16) {
356 "EditableText transform invalid.");
360 for (
auto& entry : transform->value.GetArray()) {
361 if (entry.IsNull()) {
363 "EditableText transform contains null value.");
366 editabletext_transform_[i / 4][i % 4] = entry.GetDouble();
369 Rect transformed_rect = GetCursorRect();
372 result->NotImplemented();
380 Rect TextInputPlugin::GetCursorRect()
const {
381 Point transformed_point = {
382 composing_rect_.
left() * editabletext_transform_[0][0] +
383 composing_rect_.
top() * editabletext_transform_[1][0] +
384 editabletext_transform_[3][0],
385 composing_rect_.
left() * editabletext_transform_[0][1] +
386 composing_rect_.
top() * editabletext_transform_[1][1] +
387 editabletext_transform_[3][1]};
388 return {transformed_point, composing_rect_.
size()};
391 void TextInputPlugin::SendStateUpdate(
const TextInputModel& model) {
392 auto args = std::make_unique<rapidjson::Document>(rapidjson::kArrayType);
393 auto& allocator = args->GetAllocator();
394 args->PushBack(client_id_, allocator);
396 TextRange selection = model.selection();
397 rapidjson::Value editing_state(rapidjson::kObjectType);
404 int composing_base = model.composing() ? model.composing_range().base() : -1;
405 int composing_extent =
406 model.composing() ? model.composing_range().extent() : -1;
409 editing_state.AddMember(
410 kTextKey, rapidjson::Value(model.GetText(), allocator).Move(), allocator);
411 args->PushBack(editing_state, allocator);
416 void TextInputPlugin::SendStateUpdateWithDelta(
const TextInputModel& model,
417 const TextEditingDelta* delta) {
418 auto args = std::make_unique<rapidjson::Document>(rapidjson::kArrayType);
419 auto& allocator = args->GetAllocator();
420 args->PushBack(client_id_, allocator);
422 rapidjson::Value object(rapidjson::kObjectType);
423 rapidjson::Value deltas(rapidjson::kArrayType);
424 rapidjson::Value deltaJson(rapidjson::kObjectType);
427 deltaJson.AddMember(
kDeltaTextKey, delta->delta_text(), allocator);
428 deltaJson.AddMember(
kDeltaStartKey, delta->delta_start(), allocator);
429 deltaJson.AddMember(
kDeltaEndKey, delta->delta_end(), allocator);
431 TextRange selection = model.selection();
437 int composing_base = model.composing() ? model.composing_range().base() : -1;
438 int composing_extent =
439 model.composing() ? model.composing_range().extent() : -1;
443 deltas.PushBack(deltaJson, allocator);
444 object.AddMember(
kDeltasKey, deltas, allocator);
445 args->PushBack(
object, allocator);
450 void TextInputPlugin::EnterPressed(TextInputModel* model) {
453 std::u16string text_before_change = fml::Utf8ToUtf16(model->GetText());
454 TextRange selection_before_change = model->selection();
455 model->AddText(u
"\n");
456 if (enable_delta_model) {
457 TextEditingDelta delta(text_before_change, selection_before_change,
459 SendStateUpdateWithDelta(*model, &delta);
461 SendStateUpdate(*model);
464 auto args = std::make_unique<rapidjson::Document>(rapidjson::kArrayType);
465 auto& allocator = args->GetAllocator();
466 args->PushBack(client_id_, allocator);
467 args->PushBack(rapidjson::Value(input_action_, allocator).Move(), allocator);