Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,8 @@ FILE: ../../../flutter/shell/platform/common/cpp/engine_switches_unittests.cc
FILE: ../../../flutter/shell/platform/common/cpp/flutter_platform_node_delegate.cc
FILE: ../../../flutter/shell/platform/common/cpp/flutter_platform_node_delegate.h
FILE: ../../../flutter/shell/platform/common/cpp/flutter_platform_node_delegate_unittests.cc
FILE: ../../../flutter/shell/platform/common/cpp/geometry.h
FILE: ../../../flutter/shell/platform/common/cpp/geometry_unittests.cc
FILE: ../../../flutter/shell/platform/common/cpp/incoming_message_dispatcher.cc
FILE: ../../../flutter/shell/platform/common/cpp/incoming_message_dispatcher.h
FILE: ../../../flutter/shell/platform/common/cpp/json_message_codec.cc
Expand Down Expand Up @@ -1496,6 +1498,7 @@ FILE: ../../../flutter/shell/platform/windows/task_runner_winuwp.cc
FILE: ../../../flutter/shell/platform/windows/task_runner_winuwp.h
FILE: ../../../flutter/shell/platform/windows/text_input_plugin.cc
FILE: ../../../flutter/shell/platform/windows/text_input_plugin.h
FILE: ../../../flutter/shell/platform/windows/text_input_plugin_delegate.h
FILE: ../../../flutter/shell/platform/windows/win32_dpi_utils.cc
FILE: ../../../flutter/shell/platform/windows/win32_dpi_utils.h
FILE: ../../../flutter/shell/platform/windows/win32_dpi_utils_unittests.cc
Expand Down
6 changes: 5 additions & 1 deletion shell/platform/common/cpp/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,10 @@ source_set("common_cpp") {
# embedding is futher along and it's clearer how much, if any, shared
# API surface there will be.
source_set("common_cpp_core") {
public = [ "path_utils.h" ]
public = [
"geometry.h",
"path_utils.h",
]

sources = [ "path_utils.cc" ]

Expand Down Expand Up @@ -160,6 +163,7 @@ if (enable_unittests) {

sources = [
"engine_switches_unittests.cc",
"geometry_unittests.cc",
"json_message_codec_unittests.cc",
"json_method_codec_unittests.cc",
"text_input_model_unittests.cc",
Expand Down
83 changes: 83 additions & 0 deletions shell/platform/common/cpp/geometry.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_SHELL_PLATFORM_COMMON_CPP_GEOMETRY_H_
#define FLUTTER_SHELL_PLATFORM_COMMON_CPP_GEOMETRY_H_

#include <cmath>

namespace flutter {

// A point in Cartesian space relative to a separately-maintained origin.
class Point {
public:
Point() = default;
Point(double x, double y) : x_(x), y_(y) {}
Point(const Point& point) = default;
Point& operator=(const Point& other) = default;

double x() const { return x_; }
double y() const { return y_; }

bool operator==(const Point& other) const {
return x_ == other.x_ && y_ == other.y_;
}

private:
double x_ = 0.0;
double y_ = 0.0;
};

// A 2D floating-point size with non-negative dimensions.
class Size {
public:
Size() = default;
Size(double width, double height)
: width_(std::fmax(0.0, width)), height_(std::fmax(0.0, height)) {}

Size(const Size& size) = default;
Size& operator=(const Size& other) = default;

double width() const { return width_; }
double height() const { return height_; }

bool operator==(const Size& other) const {
return width_ == other.width_ && height_ == other.height_;
}

private:
double width_ = 0.0;
double height_ = 0.0;
};

// A rectangle with position in Cartesian space specified relative to a
// separately-maintained origin.
class Rect {
public:
Rect() = default;
Rect(const Point& origin, const Size& size) : origin_(origin), size_(size) {}
Rect(const Rect& rect) = default;
Rect& operator=(const Rect& other) = default;

double left() const { return origin_.x(); }
double top() const { return origin_.y(); }
double right() const { return origin_.x() + size_.width(); }
double bottom() const { return origin_.y() + size_.height(); }
double width() const { return size_.width(); }
double height() const { return size_.height(); }
Point origin() const { return origin_; }
Size size() const { return size_; }

bool operator==(const Rect& other) const {
return origin_ == other.origin_ && size_ == other.size_;
}

private:
Point origin_;
Size size_;
};

} // namespace flutter

#endif // FLUTTER_SHELL_PLATFORM_COMMON_CPP_GEOMETRY_H_
55 changes: 55 additions & 0 deletions shell/platform/common/cpp/geometry_unittests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/shell/platform/common/cpp/geometry.h"

#include "gtest/gtest.h"

namespace flutter {

TEST(Point, SetsCoordinates) {
Point point(-30.0, 42.0);
EXPECT_DOUBLE_EQ(-30.0, point.x());
EXPECT_DOUBLE_EQ(42.0, point.y());
}

TEST(Size, SetsDimensions) {
Size size(20.0, 42.0);
EXPECT_DOUBLE_EQ(20.0, size.width());
EXPECT_DOUBLE_EQ(42.0, size.height());
}

TEST(Size, ClampsDimensionsPositive) {
Size size(-20.0, -42.0);
EXPECT_DOUBLE_EQ(0.0, size.width());
EXPECT_DOUBLE_EQ(0.0, size.height());
}

TEST(Rect, SetsOriginAndSize) {
Point origin(-30.0, 42.0);
Size size(20.0, 22.0);
Rect rect(origin, size);
EXPECT_EQ(origin, rect.origin());
EXPECT_EQ(size, rect.size());
}

TEST(Rect, ReturnsLTRB) {
Point origin(-30.0, 42.0);
Size size(20.0, 22.0);
Rect rect(origin, size);
EXPECT_DOUBLE_EQ(-30.0, rect.left());
EXPECT_DOUBLE_EQ(42.0, rect.top());
EXPECT_DOUBLE_EQ(-10.0, rect.right());
EXPECT_DOUBLE_EQ(64.0, rect.bottom());
}

TEST(Rect, ReturnsWidthHeight) {
Point origin(-30.0, 42.0);
Size size(20.0, 22.0);
Rect rect(origin, size);
EXPECT_DOUBLE_EQ(20.0, rect.width());
EXPECT_DOUBLE_EQ(22.0, rect.height());
}

} // namespace flutter
23 changes: 15 additions & 8 deletions shell/platform/windows/flutter_windows_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ void FlutterWindowsView::SetEngine(
auto internal_plugin_messenger = internal_plugin_registrar_->messenger();
keyboard_hook_handlers_.push_back(
std::make_unique<flutter::KeyEventHandler>(internal_plugin_messenger));
keyboard_hook_handlers_.push_back(
std::make_unique<flutter::TextInputPlugin>(internal_plugin_messenger));
keyboard_hook_handlers_.push_back(std::make_unique<flutter::TextInputPlugin>(
internal_plugin_messenger, this));
platform_handler_ = PlatformHandler::Create(internal_plugin_messenger, this);
cursor_handler_ = std::make_unique<flutter::CursorHandler>(
internal_plugin_messenger, binding_handler_.get());
Expand Down Expand Up @@ -135,6 +135,10 @@ void FlutterWindowsView::OnScroll(double x,
SendScroll(x, y, delta_x, delta_y, scroll_offset_multiplier);
}

void FlutterWindowsView::OnCursorRectUpdated(const Rect& rect) {
binding_handler_->UpdateCursorRect(rect);
}

// Sends new size information to FlutterEngine.
void FlutterWindowsView::SendWindowMetrics(size_t width,
size_t height,
Expand All @@ -160,12 +164,15 @@ void FlutterWindowsView::SetEventPhaseFromCursorButtonState(
FlutterPointerEvent* event_data) const {
// For details about this logic, see FlutterPointerPhase in the embedder.h
// file.
event_data->phase =
mouse_state_.buttons == 0
? mouse_state_.flutter_state_is_down ? FlutterPointerPhase::kUp
: FlutterPointerPhase::kHover
: mouse_state_.flutter_state_is_down ? FlutterPointerPhase::kMove
: FlutterPointerPhase::kDown;
if (mouse_state_.buttons == 0) {
event_data->phase = mouse_state_.flutter_state_is_down
? FlutterPointerPhase::kUp
: FlutterPointerPhase::kHover;
} else {
event_data->phase = mouse_state_.flutter_state_is_down
? FlutterPointerPhase::kMove
: FlutterPointerPhase::kDown;
}
}

void FlutterWindowsView::SendPointerMove(double x, double y) {
Expand Down
8 changes: 7 additions & 1 deletion shell/platform/windows/flutter_windows_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <vector>

#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h"
#include "flutter/shell/platform/common/cpp/geometry.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/windows/angle_surface_manager.h"
#include "flutter/shell/platform/windows/cursor_handler.h"
Expand All @@ -22,6 +23,7 @@
#include "flutter/shell/platform/windows/platform_handler.h"
#include "flutter/shell/platform/windows/public/flutter_windows.h"
#include "flutter/shell/platform/windows/text_input_plugin.h"
#include "flutter/shell/platform/windows/text_input_plugin_delegate.h"
#include "flutter/shell/platform/windows/window_binding_handler.h"
#include "flutter/shell/platform/windows/window_binding_handler_delegate.h"
#include "flutter/shell/platform/windows/window_state.h"
Expand All @@ -33,7 +35,8 @@ inline constexpr uint32_t kWindowFrameBufferID = 0;

// An OS-windowing neutral abstration for flutter
// view that works with win32 hwnds and Windows::UI::Composition visuals.
class FlutterWindowsView : public WindowBindingHandlerDelegate {
class FlutterWindowsView : public WindowBindingHandlerDelegate,
public TextInputPluginDelegate {
public:
// Creates a FlutterWindowsView with the given implementator of
// WindowBindingHandler.
Expand Down Expand Up @@ -106,6 +109,9 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate {
double delta_y,
int scroll_offset_multiplier) override;

// |TextInputPluginDelegate|
void OnCursorRectUpdated(const Rect& rect) override;

private:
// Struct holding the mouse state. The engine doesn't keep track of which
// mouse buttons have been pressed, so it's the embedding's responsibility.
Expand Down
72 changes: 71 additions & 1 deletion shell/platform/windows/text_input_plugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@
#include <iostream>

#include "flutter/shell/platform/common/cpp/json_method_codec.h"
#include "flutter/shell/platform/windows/flutter_windows_view.h"

static constexpr char kSetEditingStateMethod[] = "TextInput.setEditingState";
static constexpr char kClearClientMethod[] = "TextInput.clearClient";
static constexpr char kSetClientMethod[] = "TextInput.setClient";
static constexpr char kShowMethod[] = "TextInput.show";
static constexpr char kHideMethod[] = "TextInput.hide";
static constexpr char kSetMarkedTextRect[] = "TextInput.setMarkedTextRect";
static constexpr char kSetEditableSizeAndTransform[] =
"TextInput.setEditableSizeAndTransform";

static constexpr char kMultilineInputType[] = "TextInputType.multiline";

Expand All @@ -34,6 +38,11 @@ static constexpr char kSelectionBaseKey[] = "selectionBase";
static constexpr char kSelectionExtentKey[] = "selectionExtent";
static constexpr char kSelectionIsDirectionalKey[] = "selectionIsDirectional";
static constexpr char kTextKey[] = "text";
static constexpr char kXKey[] = "x";
static constexpr char kYKey[] = "y";
static constexpr char kWidthKey[] = "width";
static constexpr char kHeightKey[] = "height";
static constexpr char kTransformKey[] = "transform";

static constexpr char kChannelName[] = "flutter/textinput";

Expand Down Expand Up @@ -73,11 +82,13 @@ void TextInputPlugin::KeyboardHook(FlutterWindowsView* view,
}
}

TextInputPlugin::TextInputPlugin(flutter::BinaryMessenger* messenger)
TextInputPlugin::TextInputPlugin(flutter::BinaryMessenger* messenger,
TextInputPluginDelegate* delegate)
: channel_(std::make_unique<flutter::MethodChannel<rapidjson::Document>>(
messenger,
kChannelName,
&flutter::JsonMethodCodec::GetInstance())),
delegate_(delegate),
active_model_(nullptr) {
channel_->SetMethodCallHandler(
[this](
Expand Down Expand Up @@ -171,6 +182,54 @@ void TextInputPlugin::HandleMethodCall(
}
active_model_->SetText(text->value.GetString());
active_model_->SetSelection(TextRange(base, extent));
} else if (method.compare(kSetMarkedTextRect) == 0) {
if (!method_call.arguments() || method_call.arguments()->IsNull()) {
result->Error(kBadArgumentError, "Method invoked without args");
return;
}
const rapidjson::Document& args = *method_call.arguments();
auto x = args.FindMember(kXKey);
auto y = args.FindMember(kYKey);
auto width = args.FindMember(kWidthKey);
auto height = args.FindMember(kHeightKey);
if (x == args.MemberEnd() || x->value.IsNull() || //
y == args.MemberEnd() || y->value.IsNull() || //
width == args.MemberEnd() || width->value.IsNull() || //
height == args.MemberEnd() || height->value.IsNull()) {
result->Error(kInternalConsistencyError,
"Composing rect values invalid.");
return;
}
composing_rect_ = {{x->value.GetDouble(), y->value.GetDouble()},
{width->value.GetDouble(), height->value.GetDouble()}};

Rect transformed_rect = GetCursorRect();
delegate_->OnCursorRectUpdated(transformed_rect);
} else if (method.compare(kSetEditableSizeAndTransform) == 0) {
if (!method_call.arguments() || method_call.arguments()->IsNull()) {
result->Error(kBadArgumentError, "Method invoked without args");
return;
}
const rapidjson::Document& args = *method_call.arguments();
auto transform = args.FindMember(kTransformKey);
if (transform == args.MemberEnd() || transform->value.IsNull() ||
!transform->value.IsArray() || transform->value.Size() != 16) {
result->Error(kInternalConsistencyError,
"EditableText transform invalid.");
return;
}
size_t i = 0;
for (auto& entry : transform->value.GetArray()) {
if (entry.IsNull()) {
result->Error(kInternalConsistencyError,
"EditableText transform contains null value.");
return;
}
editabletext_transform_[i / 4][i % 4] = entry.GetDouble();
++i;
}
Rect transformed_rect = GetCursorRect();
delegate_->OnCursorRectUpdated(transformed_rect);
} else {
result->NotImplemented();
return;
Expand All @@ -180,6 +239,17 @@ void TextInputPlugin::HandleMethodCall(
result->Success();
}

Rect TextInputPlugin::GetCursorRect() const {
Point transformed_point = {
composing_rect_.left() * editabletext_transform_[0][0] +
composing_rect_.top() * editabletext_transform_[1][0] +
editabletext_transform_[3][0] + composing_rect_.width(),
composing_rect_.left() * editabletext_transform_[0][1] +
composing_rect_.top() * editabletext_transform_[1][1] +
editabletext_transform_[3][1] + composing_rect_.height()};
return {transformed_point, composing_rect_.size()};
}

void TextInputPlugin::SendStateUpdate(const TextInputModel& model) {
auto args = std::make_unique<rapidjson::Document>(rapidjson::kArrayType);
auto& allocator = args->GetAllocator();
Expand Down
Loading