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
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -2486,6 +2486,8 @@ FILE: ../../../flutter/shell/platform/windows/window_proc_delegate_manager.h
FILE: ../../../flutter/shell/platform/windows/window_proc_delegate_manager_unittests.cc
FILE: ../../../flutter/shell/platform/windows/window_state.h
FILE: ../../../flutter/shell/platform/windows/window_unittests.cc
FILE: ../../../flutter/shell/platform/windows/windows_proc_table.cc
FILE: ../../../flutter/shell/platform/windows/windows_proc_table.h
FILE: ../../../flutter/shell/profiling/sampling_profiler.cc
FILE: ../../../flutter/shell/profiling/sampling_profiler.h
FILE: ../../../flutter/shell/profiling/sampling_profiler_unittest.cc
Expand Down
4 changes: 4 additions & 0 deletions shell/platform/windows/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ source_set("flutter_windows_source") {
"window_proc_delegate_manager.cc",
"window_proc_delegate_manager.h",
"window_state.h",
"windows_proc_table.cc",
"windows_proc_table.h",
]

libs = [
Expand Down Expand Up @@ -189,13 +191,15 @@ executable("flutter_windows_unittests") {
"testing/engine_modifier.h",
"testing/flutter_window_test.cc",
"testing/flutter_window_test.h",
"testing/mock_direct_manipulation.h",
"testing/mock_gl_functions.h",
"testing/mock_text_input_manager.cc",
"testing/mock_text_input_manager.h",
"testing/mock_window.cc",
"testing/mock_window.h",
"testing/mock_window_binding_handler.cc",
"testing/mock_window_binding_handler.h",
"testing/mock_windows_proc_table.h",
"testing/test_keyboard.cc",
"testing/test_keyboard.h",
"testing/test_keyboard_unittests.cc",
Expand Down
5 changes: 4 additions & 1 deletion shell/platform/windows/direct_manipulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class DirectManipulationEventHandler;
class DirectManipulationOwner {
public:
explicit DirectManipulationOwner(Window* window);
virtual ~DirectManipulationOwner() = default;
// Initialize a DirectManipulation viewport with specified width and height.
// These should match the width and height of the application window.
int Init(unsigned int width, unsigned int height);
Expand All @@ -34,7 +35,7 @@ class DirectManipulationOwner {
WindowBindingHandlerDelegate* binding_handler_delegate);
// Called when DM_POINTERHITTEST occurs with an acceptable pointer type. Will
// start DirectManipulation for that interaction.
void SetContact(UINT contactId);
virtual void SetContact(UINT contactId);
// Called to get updates from DirectManipulation. Should be called frequently
// to provide smooth updates.
void Update();
Expand All @@ -57,6 +58,8 @@ class DirectManipulationOwner {
Microsoft::WRL::ComPtr<IDirectManipulationViewport> viewport_;
// Child needed for operation of the DirectManipulation API.
fml::RefPtr<DirectManipulationEventHandler> handler_;

FML_DISALLOW_COPY_AND_ASSIGN(DirectManipulationOwner);
};

// Implements DirectManipulation event handling interfaces, receives calls from
Expand Down
30 changes: 30 additions & 0 deletions shell/platform/windows/testing/mock_direct_manipulation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// 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_WINDOWS_TESTING_MOCK_DIRECT_MANIPULATION_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_DIRECT_MANIPULATION_H_

#include "flutter/shell/platform/windows/direct_manipulation.h"
#include "gmock/gmock.h"

namespace flutter {
namespace testing {

/// Mock for the |DirectManipulationOwner| base class.
class MockDirectManipulationOwner : public DirectManipulationOwner {
public:
explicit MockDirectManipulationOwner(Window* window)
: DirectManipulationOwner(window){};
virtual ~MockDirectManipulationOwner() = default;

MOCK_METHOD1(SetContact, void(UINT contact_id));

private:
FML_DISALLOW_COPY_AND_ASSIGN(MockDirectManipulationOwner);
};

} // namespace testing
} // namespace flutter

#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_DIRECT_MANIPULATION_H_
10 changes: 8 additions & 2 deletions shell/platform/windows/testing/mock_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
namespace flutter {
namespace testing {
MockWindow::MockWindow() : Window(){};
MockWindow::MockWindow(std::unique_ptr<TextInputManager> text_input_manager)
: Window(std::move(text_input_manager)){};
MockWindow::MockWindow(std::unique_ptr<WindowsProcTable> window_proc_table,
std::unique_ptr<TextInputManager> text_input_manager)
: Window(std::move(window_proc_table), std::move(text_input_manager)){};

MockWindow::~MockWindow() = default;

Expand All @@ -23,6 +24,11 @@ LRESULT MockWindow::Win32DefWindowProc(HWND hWnd,
return kWmResultDefault;
}

void MockWindow::SetDirectManipulationOwner(
std::unique_ptr<DirectManipulationOwner> owner) {
direct_manipulation_owner_ = std::move(owner);
}

LRESULT MockWindow::InjectWindowMessage(UINT const message,
WPARAM const wparam,
LPARAM const lparam) {
Expand Down
7 changes: 6 additions & 1 deletion shell/platform/windows/testing/mock_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ namespace testing {
class MockWindow : public Window {
public:
MockWindow();
MockWindow(std::unique_ptr<TextInputManager> text_input_manager);
MockWindow(std::unique_ptr<WindowsProcTable> windows_proc_table,
std::unique_ptr<TextInputManager> text_input_manager);
virtual ~MockWindow();

// Prevent copying.
Expand All @@ -28,6 +29,10 @@ class MockWindow : public Window {
// Wrapper for GetCurrentDPI() which is a protected method.
UINT GetDpi();

// Set the Direct Manipulation owner for testing purposes.
void SetDirectManipulationOwner(
std::unique_ptr<DirectManipulationOwner> owner);

// Simulates a WindowProc message from the OS.
LRESULT InjectWindowMessage(UINT const message,
WPARAM const wparam,
Expand Down
30 changes: 30 additions & 0 deletions shell/platform/windows/testing/mock_windows_proc_table.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// 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_WINDOWS_TESTING_MOCK_WINDOWS_PROC_TABLE_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_WINDOWS_PROC_TABLE_H_

#include "flutter/shell/platform/windows/windows_proc_table.h"
#include "gmock/gmock.h"

namespace flutter {
namespace testing {

/// Mock for the |WindowsProcTable| base class.
class MockWindowsProcTable : public WindowsProcTable {
public:
MockWindowsProcTable() = default;
virtual ~MockWindowsProcTable() = default;

MOCK_METHOD2(GetPointerType,
BOOL(UINT32 pointer_id, POINTER_INPUT_TYPE* pointer_type));

private:
FML_DISALLOW_COPY_AND_ASSIGN(MockWindowsProcTable);
};

} // namespace testing
} // namespace flutter

#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_WINDOWS_PROC_TABLE_H_
19 changes: 12 additions & 7 deletions shell/platform/windows/window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,12 @@ static const int kLinesPerScrollWindowsDefault = 3;

} // namespace

Window::Window() : Window(nullptr) {}
Window::Window() : Window(nullptr, nullptr) {}

Window::Window(std::unique_ptr<TextInputManager> text_input_manager)
Window::Window(std::unique_ptr<WindowsProcTable> windows_proc_table,
std::unique_ptr<TextInputManager> text_input_manager)
: touch_id_generator_(kMinTouchDeviceId, kMaxTouchDeviceId),
windows_proc_table_(std::move(windows_proc_table)),
text_input_manager_(std::move(text_input_manager)) {
// Get the DPI of the primary monitor as the initial DPI. If Per-Monitor V2 is
// supported, |current_dpi_| should be updated in the
Expand All @@ -67,6 +69,9 @@ Window::Window(std::unique_ptr<TextInputManager> text_input_manager)
// https://github.com/flutter/flutter/issues/107248
UpdateScrollOffsetMultiplier();

if (windows_proc_table_ == nullptr) {
windows_proc_table_ = std::make_unique<WindowsProcTable>();
}
if (text_input_manager_ == nullptr) {
text_input_manager_ = std::make_unique<TextInputManager>();
}
Expand Down Expand Up @@ -482,11 +487,11 @@ Window::HandleMessage(UINT const message,
break;
case DM_POINTERHITTEST: {
if (direct_manipulation_owner_) {
UINT contactId = GET_POINTERID_WPARAM(wparam);
POINTER_INPUT_TYPE pointerType;
if (GetPointerType(contactId, &pointerType) &&
pointerType == PT_TOUCHPAD) {
direct_manipulation_owner_->SetContact(contactId);
UINT contact_id = GET_POINTERID_WPARAM(wparam);
POINTER_INPUT_TYPE pointer_type;
if (windows_proc_table_->GetPointerType(contact_id, &pointer_type) &&
pointer_type == PT_TOUCHPAD) {
direct_manipulation_owner_->SetContact(contact_id);
}
}
break;
Expand Down
8 changes: 7 additions & 1 deletion shell/platform/windows/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "flutter/shell/platform/windows/keyboard_manager.h"
#include "flutter/shell/platform/windows/sequential_id_generator.h"
#include "flutter/shell/platform/windows/text_input_manager.h"
#include "flutter/shell/platform/windows/windows_proc_table.h"
#include "flutter/third_party/accessibility/gfx/native_widget_types.h"

namespace flutter {
Expand All @@ -28,7 +29,8 @@ namespace flutter {
class Window : public KeyboardManager::WindowDelegate {
public:
Window();
Window(std::unique_ptr<TextInputManager> text_input_manager);
Window(std::unique_ptr<WindowsProcTable> windows_proc_table,
std::unique_ptr<TextInputManager> text_input_manager);
virtual ~Window();

// Initializes as a child window with size using |width| and |height| and
Expand Down Expand Up @@ -266,6 +268,10 @@ class Window : public KeyboardManager::WindowDelegate {
double mouse_x_ = 0;
double mouse_y_ = 0;

// Abstracts Windows APIs that may not be available on all supported versions
// of Windows.
std::unique_ptr<WindowsProcTable> windows_proc_table_;

// Manages IME state.
std::unique_ptr<TextInputManager> text_input_manager_;

Expand Down
104 changes: 96 additions & 8 deletions shell/platform/windows/window_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@

#include <array>

#include "flutter/shell/platform/windows/testing/mock_direct_manipulation.h"
#include "flutter/shell/platform/windows/testing/mock_text_input_manager.h"
#include "flutter/shell/platform/windows/testing/mock_window.h"
#include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

using testing::_;
using testing::Eq;
using testing::InSequence;
using testing::Invoke;
using testing::Return;
Expand Down Expand Up @@ -39,9 +43,11 @@ TEST(MockWindow, VerticalScroll) {
}

TEST(MockWindow, OnImeCompositionCompose) {
MockTextInputManager* text_input_manager = new MockTextInputManager();
auto windows_proc_table = std::make_unique<MockWindowsProcTable>();
auto* text_input_manager = new MockTextInputManager();
std::unique_ptr<TextInputManager> text_input_manager_ptr(text_input_manager);
MockWindow window(std::move(text_input_manager_ptr));
MockWindow window(std::move(windows_proc_table),
std::move(text_input_manager_ptr));
EXPECT_CALL(*text_input_manager, GetComposingString())
.WillRepeatedly(
Return(std::optional<std::u16string>(std::u16string(u"nihao"))));
Expand All @@ -63,9 +69,11 @@ TEST(MockWindow, OnImeCompositionCompose) {
}

TEST(MockWindow, OnImeCompositionResult) {
MockTextInputManager* text_input_manager = new MockTextInputManager();
auto windows_proc_table = std::make_unique<MockWindowsProcTable>();
auto* text_input_manager = new MockTextInputManager();
std::unique_ptr<TextInputManager> text_input_manager_ptr(text_input_manager);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't remember why this is using new and not make_unique() but definitely feel free to clean it up.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. I'll do it in a follow-up pull request. I need to merge this one back into the beta release branch, which is already has hairy merge conflicts 😅

MockWindow window(std::move(text_input_manager_ptr));
MockWindow window(std::move(windows_proc_table),
std::move(text_input_manager_ptr));
EXPECT_CALL(*text_input_manager, GetComposingString())
.WillRepeatedly(
Return(std::optional<std::u16string>(std::u16string(u"nihao"))));
Expand All @@ -87,9 +95,11 @@ TEST(MockWindow, OnImeCompositionResult) {
}

TEST(MockWindow, OnImeCompositionResultAndCompose) {
MockTextInputManager* text_input_manager = new MockTextInputManager();
auto windows_proc_table = std::make_unique<MockWindowsProcTable>();
auto* text_input_manager = new MockTextInputManager();
std::unique_ptr<TextInputManager> text_input_manager_ptr(text_input_manager);
MockWindow window(std::move(text_input_manager_ptr));
MockWindow window(std::move(windows_proc_table),
std::move(text_input_manager_ptr));

// This situation is that Google Japanese Input finished composing "今日" in
// "今日は" but is still composing "は".
Expand Down Expand Up @@ -123,9 +133,11 @@ TEST(MockWindow, OnImeCompositionResultAndCompose) {
}

TEST(MockWindow, OnImeCompositionClearChange) {
MockTextInputManager* text_input_manager = new MockTextInputManager();
auto windows_proc_table = std::make_unique<MockWindowsProcTable>();
auto* text_input_manager = new MockTextInputManager();
std::unique_ptr<TextInputManager> text_input_manager_ptr(text_input_manager);
MockWindow window(std::move(text_input_manager_ptr));
MockWindow window(std::move(windows_proc_table),
std::move(text_input_manager_ptr));
EXPECT_CALL(window, OnComposeChange(std::u16string(u""), 0)).Times(1);
EXPECT_CALL(window, OnComposeCommit()).Times(1);
ON_CALL(window, OnImeComposition)
Expand Down Expand Up @@ -272,5 +284,81 @@ TEST(MockWindow, Paint) {
window.InjectWindowMessage(WM_PAINT, 0, 0);
}

// Verify direct manipulation isn't notified of pointer hit tests.
TEST(MockWindow, PointerHitTest) {
UINT32 pointer_id = 123;
auto windows_proc_table = std::make_unique<MockWindowsProcTable>();
auto text_input_manager = std::make_unique<MockTextInputManager>();

EXPECT_CALL(*windows_proc_table, GetPointerType(Eq(pointer_id), _))
.Times(1)
.WillOnce([](UINT32 pointer_id, POINTER_INPUT_TYPE* type) {
*type = PT_POINTER;
return TRUE;
});

MockWindow window(std::move(windows_proc_table),
std::move(text_input_manager));

auto direct_manipulation =
std::make_unique<MockDirectManipulationOwner>(&window);

EXPECT_CALL(*direct_manipulation, SetContact).Times(0);

window.SetDirectManipulationOwner(std::move(direct_manipulation));
window.InjectWindowMessage(DM_POINTERHITTEST, MAKEWPARAM(pointer_id, 0), 0);
}

// Verify direct manipulation is notified of touchpad hit tests.
TEST(MockWindow, TouchPadHitTest) {
UINT32 pointer_id = 123;
auto windows_proc_table = std::make_unique<MockWindowsProcTable>();
auto text_input_manager = std::make_unique<MockTextInputManager>();

EXPECT_CALL(*windows_proc_table, GetPointerType(Eq(pointer_id), _))
.Times(1)
.WillOnce([](UINT32 pointer_id, POINTER_INPUT_TYPE* type) {
*type = PT_TOUCHPAD;
return TRUE;
});

MockWindow window(std::move(windows_proc_table),
std::move(text_input_manager));

auto direct_manipulation =
std::make_unique<MockDirectManipulationOwner>(&window);

EXPECT_CALL(*direct_manipulation, SetContact(Eq(pointer_id))).Times(1);

window.SetDirectManipulationOwner(std::move(direct_manipulation));
window.InjectWindowMessage(DM_POINTERHITTEST, MAKEWPARAM(pointer_id, 0), 0);
}

// Verify direct manipulation isn't notified of unknown hit tests.
// This can happen if determining the pointer type fails, for example,
// if GetPointerType is unsupported by the current Windows version.
// See: https://github.com/flutter/flutter/issues/109412
TEST(MockWindow, UnknownPointerTypeSkipsDirectManipulation) {
UINT32 pointer_id = 123;
auto windows_proc_table = std::make_unique<MockWindowsProcTable>();
auto text_input_manager = std::make_unique<MockTextInputManager>();

EXPECT_CALL(*windows_proc_table, GetPointerType(Eq(pointer_id), _))
.Times(1)
.WillOnce(
[](UINT32 pointer_id, POINTER_INPUT_TYPE* type) { return FALSE; });

MockWindow window(std::move(windows_proc_table),
std::move(text_input_manager));

auto direct_manipulation =
std::make_unique<MockDirectManipulationOwner>(&window);

EXPECT_CALL(*direct_manipulation, SetContact).Times(0);

window.SetDirectManipulationOwner(std::move(direct_manipulation));
window.InjectWindowMessage(DM_POINTERHITTEST, MAKEWPARAM(pointer_id, 0), 0);
}

} // namespace testing
} // namespace flutter
Loading