Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit eaee2af

Browse files
committed
[Windows] Simplify accessibility initialization
1 parent e3e59ba commit eaee2af

18 files changed

+119
-111
lines changed

shell/platform/windows/flutter_window.cc

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ static uint64_t ConvertWinButtonToFlutterButton(UINT button) {
119119
FlutterWindow::FlutterWindow(
120120
int width,
121121
int height,
122-
std::unique_ptr<WindowsProcTable> windows_proc_table,
122+
std::shared_ptr<WindowsProcTable> windows_proc_table,
123123
std::unique_ptr<TextInputManager> text_input_manager)
124124
: binding_handler_delegate_(nullptr),
125125
touch_id_generator_(kMinTouchDeviceId, kMaxTouchDeviceId),
@@ -356,12 +356,7 @@ PointerLocation FlutterWindow::GetPrimaryPointerLocation() {
356356
}
357357

358358
void FlutterWindow::OnThemeChange() {
359-
binding_handler_delegate_->UpdateHighContrastEnabled(
360-
GetHighContrastEnabled());
361-
}
362-
363-
void FlutterWindow::SendInitialAccessibilityFeatures() {
364-
OnThemeChange();
359+
binding_handler_delegate_->OnHighContrastChanged();
365360
}
366361

367362
ui::AXFragmentRootDelegateWin* FlutterWindow::GetAxFragmentRootDelegate() {
@@ -950,19 +945,6 @@ float FlutterWindow::GetScrollOffsetMultiplier() {
950945
return scroll_offset_multiplier_;
951946
}
952947

953-
bool FlutterWindow::GetHighContrastEnabled() {
954-
HIGHCONTRAST high_contrast = {.cbSize = sizeof(HIGHCONTRAST)};
955-
// API call is only supported on Windows 8+
956-
if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(HIGHCONTRAST),
957-
&high_contrast, 0)) {
958-
return high_contrast.dwFlags & HCF_HIGHCONTRASTON;
959-
} else {
960-
FML_LOG(INFO) << "Failed to get status of high contrast feature,"
961-
<< "support only for Windows 8 + ";
962-
return false;
963-
}
964-
}
965-
966948
LRESULT FlutterWindow::Win32DefWindowProc(HWND hWnd,
967949
UINT Msg,
968950
WPARAM wParam,

shell/platform/windows/flutter_window.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class FlutterWindow : public KeyboardManager::WindowDelegate,
3838
// Create flutter Window for use as child window
3939
FlutterWindow(int width,
4040
int height,
41-
std::unique_ptr<WindowsProcTable> windows_proc_table = nullptr,
41+
std::shared_ptr<WindowsProcTable> windows_proc_table = nullptr,
4242
std::unique_ptr<TextInputManager> text_input_manager = nullptr);
4343

4444
virtual ~FlutterWindow();
@@ -189,9 +189,6 @@ class FlutterWindow : public KeyboardManager::WindowDelegate,
189189
// Called when a theme change message is issued.
190190
virtual void OnThemeChange();
191191

192-
// |WindowBindingHandler|
193-
virtual void SendInitialAccessibilityFeatures() override;
194-
195192
// |WindowBindingHandler|
196193
virtual AlertPlatformNodeDelegate* GetAlertDelegate() override;
197194

@@ -281,9 +278,6 @@ class FlutterWindow : public KeyboardManager::WindowDelegate,
281278
// Returns the current pixel per scroll tick value.
282279
virtual float GetScrollOffsetMultiplier();
283280

284-
// Check if the high contrast feature is enabled on the OS
285-
virtual bool GetHighContrastEnabled();
286-
287281
// Delegate to a alert_node_ used to set the announcement text.
288282
std::unique_ptr<AlertPlatformNodeDelegate> alert_delegate_;
289283

@@ -381,7 +375,7 @@ class FlutterWindow : public KeyboardManager::WindowDelegate,
381375

382376
// Abstracts Windows APIs that may not be available on all supported versions
383377
// of Windows.
384-
std::unique_ptr<WindowsProcTable> windows_proc_table_;
378+
std::shared_ptr<WindowsProcTable> windows_proc_table_;
385379

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

shell/platform/windows/flutter_window_unittests.cc

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ class MockFlutterWindow : public FlutterWindow {
6464
(override));
6565
MOCK_METHOD(void, OnSetCursor, (), (override));
6666
MOCK_METHOD(float, GetScrollOffsetMultiplier, (), (override));
67-
MOCK_METHOD(bool, GetHighContrastEnabled, (), (override));
6867
MOCK_METHOD(float, GetDpiScale, (), (override));
6968
MOCK_METHOD(bool, IsVisible, (), (override));
7069
MOCK_METHOD(void, UpdateCursorRect, (const Rect&), (override));
@@ -290,8 +289,7 @@ TEST(FlutterWindowTest, OnThemeChange) {
290289
MockWindowBindingHandlerDelegate delegate;
291290
win32window.SetView(&delegate);
292291

293-
ON_CALL(win32window, GetHighContrastEnabled()).WillByDefault(Return(true));
294-
EXPECT_CALL(delegate, UpdateHighContrastEnabled(true)).Times(1);
292+
EXPECT_CALL(delegate, OnHighContrastChanged).Times(1);
295293

296294
win32window.InjectWindowMessage(WM_THEMECHANGED, 0, 0);
297295
}
@@ -305,17 +303,6 @@ TEST(FlutterWindowTest, AccessibilityNodeWithoutView) {
305303
EXPECT_EQ(win32window.GetNativeViewAccessible(), nullptr);
306304
}
307305

308-
TEST(FlutterWindowTest, InitialAccessibilityFeatures) {
309-
MockFlutterWindow win32window;
310-
MockWindowBindingHandlerDelegate delegate;
311-
win32window.SetView(&delegate);
312-
313-
ON_CALL(win32window, GetHighContrastEnabled()).WillByDefault(Return(true));
314-
EXPECT_CALL(delegate, UpdateHighContrastEnabled(true)).Times(1);
315-
316-
win32window.SendInitialAccessibilityFeatures();
317-
}
318-
319306
// Ensure that announcing the alert propagates the message to the alert node.
320307
// Different screen readers use different properties for alerts.
321308
TEST(FlutterWindowTest, AlertNode) {

shell/platform/windows/flutter_windows.cc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,18 @@ static FlutterDesktopTextureRegistrarRef HandleForTextureRegistrar(
6464
FlutterDesktopViewControllerRef FlutterDesktopViewControllerCreate(
6565
int width,
6666
int height,
67-
FlutterDesktopEngineRef engine) {
67+
FlutterDesktopEngineRef ref) {
68+
auto engine = EngineFromHandle(ref);
6869
std::unique_ptr<flutter::WindowBindingHandler> window_wrapper =
69-
std::make_unique<flutter::FlutterWindow>(width, height);
70+
std::make_unique<flutter::FlutterWindow>(width, height,
71+
engine->windows_proc_table());
7072

7173
auto state = std::make_unique<FlutterDesktopViewControllerState>();
7274
state->view =
7375
std::make_unique<flutter::FlutterWindowsView>(std::move(window_wrapper));
7476
// Take ownership of the engine, starting it if necessary.
7577
state->view->SetEngine(
76-
std::unique_ptr<flutter::FlutterWindowsEngine>(EngineFromHandle(engine)));
78+
std::unique_ptr<flutter::FlutterWindowsEngine>(engine));
7779
state->view->CreateRenderSurface();
7880
if (!state->view->GetEngine()->running()) {
7981
if (!state->view->GetEngine()->Run()) {
@@ -83,7 +85,11 @@ FlutterDesktopViewControllerRef FlutterDesktopViewControllerCreate(
8385

8486
// Must happen after engine is running.
8587
state->view->SendInitialBounds();
86-
state->view->SendInitialAccessibilityFeatures();
88+
89+
// The Windows embedder listens to accessibility updates using the
90+
// view's HWND. The embedder's accessibility features may be stale if
91+
// the app was in headless mode.
92+
state->view->GetEngine()->UpdateAccessibilityFeatures();
8793
return state.release();
8894
}
8995

shell/platform/windows/flutter_windows_engine.cc

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,17 @@ FlutterLocale CovertToFlutterLocale(const LanguageInfo& info) {
157157

158158
} // namespace
159159

160-
FlutterWindowsEngine::FlutterWindowsEngine(const FlutterProjectBundle& project)
160+
FlutterWindowsEngine::FlutterWindowsEngine(
161+
const FlutterProjectBundle& project,
162+
std::shared_ptr<WindowsProcTable> windows_proc_table)
161163
: project_(std::make_unique<FlutterProjectBundle>(project)),
164+
windows_proc_table_(std::move(windows_proc_table)),
162165
aot_data_(nullptr, nullptr),
163166
lifecycle_manager_(std::make_unique<WindowsLifecycleManager>(this)) {
167+
if (windows_proc_table_ == nullptr) {
168+
windows_proc_table_ = std::make_shared<WindowsProcTable>();
169+
}
170+
164171
embedder_api_.struct_size = sizeof(FlutterEngineProcTable);
165172
FlutterEngineGetProcAddresses(&embedder_api_);
166173

@@ -569,8 +576,7 @@ void FlutterWindowsEngine::HandlePlatformMessage(
569576

570577
auto message = ConvertToDesktopMessage(*engine_message);
571578

572-
message_dispatcher_->HandleMessage(
573-
message, [this] {}, [this] {});
579+
message_dispatcher_->HandleMessage(message, [this] {}, [this] {});
574580
}
575581

576582
void FlutterWindowsEngine::ReloadSystemFonts() {
@@ -605,7 +611,7 @@ void FlutterWindowsEngine::SetLifecycleState(flutter::AppLifecycleState state) {
605611

606612
void FlutterWindowsEngine::SendSystemLocales() {
607613
std::vector<LanguageInfo> languages =
608-
GetPreferredLanguageInfo(windows_proc_table_);
614+
GetPreferredLanguageInfo(*windows_proc_table_);
609615
std::vector<FlutterLocale> flutter_locales;
610616
flutter_locales.reserve(languages.size());
611617
for (const auto& info : languages) {
@@ -737,34 +743,27 @@ std::string FlutterWindowsEngine::GetExecutableName() const {
737743
return "Flutter";
738744
}
739745

740-
void FlutterWindowsEngine::UpdateAccessibilityFeatures(
741-
FlutterAccessibilityFeature flags) {
742-
embedder_api_.UpdateAccessibilityFeatures(engine_, flags);
746+
void FlutterWindowsEngine::UpdateAccessibilityFeatures() {
747+
UpdateHighContrastMode();
743748
}
744749

745-
void FlutterWindowsEngine::UpdateHighContrastEnabled(bool enabled) {
746-
high_contrast_enabled_ = enabled;
747-
int flags = EnabledAccessibilityFeatures();
748-
if (enabled) {
749-
flags |=
750-
FlutterAccessibilityFeature::kFlutterAccessibilityFeatureHighContrast;
751-
} else {
752-
flags &=
753-
~FlutterAccessibilityFeature::kFlutterAccessibilityFeatureHighContrast;
754-
}
755-
UpdateAccessibilityFeatures(static_cast<FlutterAccessibilityFeature>(flags));
756-
settings_plugin_->UpdateHighContrastMode(enabled);
750+
void FlutterWindowsEngine::UpdateHighContrastMode() {
751+
high_contrast_enabled_ = windows_proc_table_->GetHighContrastEnabled();
752+
753+
SendAccessibilityFeatures();
754+
settings_plugin_->UpdateHighContrastMode(high_contrast_enabled_);
757755
}
758756

759-
int FlutterWindowsEngine::EnabledAccessibilityFeatures() const {
757+
void FlutterWindowsEngine::SendAccessibilityFeatures() {
760758
int flags = 0;
761-
if (high_contrast_enabled()) {
759+
760+
if (high_contrast_enabled_) {
762761
flags |=
763762
FlutterAccessibilityFeature::kFlutterAccessibilityFeatureHighContrast;
764763
}
765-
// As more accessibility features are enabled for Windows,
766-
// the corresponding checks and flags should be added here.
767-
return flags;
764+
765+
embedder_api_.UpdateAccessibilityFeatures(
766+
engine_, static_cast<FlutterAccessibilityFeature>(flags));
768767
}
769768

770769
void FlutterWindowsEngine::HandleAccessibilityMessage(

shell/platform/windows/flutter_windows_engine.h

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ static void WindowsPlatformThreadPrioritySetter(
7878
class FlutterWindowsEngine {
7979
public:
8080
// Creates a new Flutter engine object configured to run |project|.
81-
explicit FlutterWindowsEngine(const FlutterProjectBundle& project);
81+
FlutterWindowsEngine(
82+
const FlutterProjectBundle& project,
83+
std::shared_ptr<WindowsProcTable> windows_proc_table = nullptr);
8284

8385
virtual ~FlutterWindowsEngine();
8486

@@ -215,11 +217,11 @@ class FlutterWindowsEngine {
215217
// Returns true if the semantics tree is enabled.
216218
bool semantics_enabled() const { return semantics_enabled_; }
217219

218-
// Update the high contrast feature state.
219-
void UpdateHighContrastEnabled(bool enabled);
220+
// Refresh accessibility features and send them to the engine.
221+
void UpdateAccessibilityFeatures();
220222

221-
// Returns the flags for all currently enabled accessibility features
222-
int EnabledAccessibilityFeatures() const;
223+
// Refresh high contrast accessibility mode and notify the engine.
224+
void UpdateHighContrastMode();
223225

224226
// Returns true if the high contrast feature is enabled.
225227
bool high_contrast_enabled() const { return high_contrast_enabled_; }
@@ -240,9 +242,6 @@ class FlutterWindowsEngine {
240242
// Returns the executable name for this process or "Flutter" if unknown.
241243
std::string GetExecutableName() const;
242244

243-
// Updates accessibility, e.g. switch to high contrast mode
244-
void UpdateAccessibilityFeatures(FlutterAccessibilityFeature flags);
245-
246245
// Called when the application quits in response to a quit request.
247246
void OnQuit(std::optional<HWND> hwnd,
248247
std::optional<WPARAM> wparam,
@@ -274,6 +273,10 @@ class FlutterWindowsEngine {
274273
return lifecycle_manager_.get();
275274
}
276275

276+
std::shared_ptr<WindowsProcTable> windows_proc_table() {
277+
return windows_proc_table_;
278+
}
279+
277280
protected:
278281
// Creates the keyboard key handler.
279282
//
@@ -320,6 +323,9 @@ class FlutterWindowsEngine {
320323
// Calling this method again resets the keyboard state.
321324
void InitializeKeyboard();
322325

326+
// Send the currently enabled accessibility features to the engine.
327+
void SendAccessibilityFeatures();
328+
323329
void HandleAccessibilityMessage(FlutterDesktopMessengerRef messenger,
324330
const FlutterDesktopMessage* message);
325331

@@ -414,7 +420,7 @@ class FlutterWindowsEngine {
414420
// Handler for top level window messages.
415421
std::unique_ptr<WindowsLifecycleManager> lifecycle_manager_;
416422

417-
WindowsProcTable windows_proc_table_;
423+
std::shared_ptr<WindowsProcTable> windows_proc_table_;
418424

419425
FML_DISALLOW_COPY_AND_ASSIGN(FlutterWindowsEngine);
420426
};

shell/platform/windows/flutter_windows_engine_unittests.cc

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "flutter/shell/platform/windows/testing/engine_modifier.h"
1313
#include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h"
1414
#include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
15+
#include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h"
1516
#include "flutter/shell/platform/windows/testing/test_keyboard.h"
1617
#include "flutter/shell/platform/windows/testing/windows_test.h"
1718
#include "flutter/third_party/accessibility/ax/platform/ax_platform_node_win.h"
@@ -25,6 +26,8 @@
2526
namespace flutter {
2627
namespace testing {
2728

29+
using ::testing::Return;
30+
2831
class FlutterWindowsEngineTest : public WindowsTest {};
2932

3033
TEST_F(FlutterWindowsEngineTest, RunDoesExpectedInitialization) {
@@ -558,29 +561,41 @@ TEST_F(FlutterWindowsEngineTest, GetExecutableName) {
558561
// Ensure that after setting or resetting the high contrast feature,
559562
// the corresponding status flag can be retrieved from the engine.
560563
TEST_F(FlutterWindowsEngineTest, UpdateHighContrastFeature) {
564+
auto windows_proc_table = std::make_shared<MockWindowsProcTable>();
565+
EXPECT_CALL(*windows_proc_table, GetHighContrastEnabled)
566+
.WillOnce(Return(true))
567+
.WillOnce(Return(false));
568+
561569
FlutterWindowsEngineBuilder builder{GetContext()};
570+
builder.SetWindowsProcTable(windows_proc_table);
562571
std::unique_ptr<FlutterWindowsEngine> engine = builder.Build();
563572
EngineModifier modifier(engine.get());
564573

565-
bool called = false;
574+
std::optional<FlutterAccessibilityFeature> engine_flags;
566575
modifier.embedder_api().UpdateAccessibilityFeatures = MOCK_ENGINE_PROC(
567-
UpdateAccessibilityFeatures, ([&called](auto engine, auto flags) {
568-
called = true;
576+
UpdateAccessibilityFeatures, ([&engine_flags](auto engine, auto flags) {
577+
engine_flags = flags;
569578
return kSuccess;
570579
}));
571580

572-
engine->UpdateHighContrastEnabled(true);
581+
// 1: High contrast is enabled.
582+
engine->UpdateHighContrastMode();
583+
584+
EXPECT_TRUE(engine->high_contrast_enabled());
585+
EXPECT_TRUE(engine_flags.has_value());
573586
EXPECT_TRUE(
574-
engine->EnabledAccessibilityFeatures() &
587+
engine_flags.value() &
575588
FlutterAccessibilityFeature::kFlutterAccessibilityFeatureHighContrast);
576-
EXPECT_TRUE(engine->high_contrast_enabled());
577-
EXPECT_TRUE(called);
578589

579-
engine->UpdateHighContrastEnabled(false);
590+
// 2: High contrast is disabled.
591+
engine_flags.reset();
592+
engine->UpdateHighContrastMode();
593+
594+
EXPECT_FALSE(engine->high_contrast_enabled());
595+
EXPECT_TRUE(engine_flags.has_value());
580596
EXPECT_FALSE(
581-
engine->EnabledAccessibilityFeatures() &
597+
engine_flags.value() &
582598
FlutterAccessibilityFeature::kFlutterAccessibilityFeatureHighContrast);
583-
EXPECT_FALSE(engine->high_contrast_enabled());
584599
}
585600

586601
TEST_F(FlutterWindowsEngineTest, PostRasterThreadTask) {

shell/platform/windows/flutter_windows_view.cc

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -611,12 +611,8 @@ void FlutterWindowsView::DestroyRenderSurface() {
611611
}
612612
}
613613

614-
void FlutterWindowsView::SendInitialAccessibilityFeatures() {
615-
binding_handler_->SendInitialAccessibilityFeatures();
616-
}
617-
618-
void FlutterWindowsView::UpdateHighContrastEnabled(bool enabled) {
619-
engine_->UpdateHighContrastEnabled(enabled);
614+
void FlutterWindowsView::OnHighContrastChanged() {
615+
engine_->UpdateHighContrastMode();
620616
}
621617

622618
WindowsRenderTarget* FlutterWindowsView::GetRenderTarget() const {

0 commit comments

Comments
 (0)