Skip to content

Commit

Permalink
[Windows] handle repaint message in FlutterView window (flutter#34306)
Browse files Browse the repository at this point in the history
This PR will fix the blank FlutterView issue by handling the repaint message in FlutterView window.

Currently, WM_PAINT msg is not handled in flutter window and the default WindowProc will do nothing but paint the background. In some user cases, e.g., hide/show/min/max the app window, this can result in blank FlutterView if the content is static and there are no running animation.

Addresses flutter/flutter#101339
Addresses flutter/flutter#102030
  • Loading branch information
sevenstars authored Jul 13, 2022
1 parent 46d71f0 commit 563d3b0
Show file tree
Hide file tree
Showing 13 changed files with 92 additions and 9 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ Callum Moffat <[email protected]>
Koutaro Mori <[email protected]>
TheOneWithTheBraid <[email protected]>
Twin Sun, LLC <[email protected]>
Qixing Cao <[email protected]>
6 changes: 6 additions & 0 deletions shell/platform/windows/flutter_window_win32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ void FlutterWindowWin32::OnResize(unsigned int width, unsigned int height) {
}
}

void FlutterWindowWin32::OnPaint() {
if (binding_handler_delegate_ != nullptr) {
binding_handler_delegate_->OnWindowRepaint();
}
}

void FlutterWindowWin32::OnPointerMove(double x,
double y,
FlutterPointerDeviceKind device_kind,
Expand Down
3 changes: 3 additions & 0 deletions shell/platform/windows/flutter_window_win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ class FlutterWindowWin32 : public WindowWin32, public WindowBindingHandler {
// |WindowWin32|
void OnResize(unsigned int width, unsigned int height) override;

// |WindowWin32|
void OnPaint() override;

// |WindowWin32|
void OnPointerMove(double x,
double y,
Expand Down
17 changes: 17 additions & 0 deletions shell/platform/windows/flutter_window_win32_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ class MockFlutterWindowWin32 : public FlutterWindowWin32 {
// Wrapper for GetCurrentDPI() which is a protected method.
UINT GetDpi() { return GetCurrentDPI(); }

// Simulates a WindowProc message from the OS.
LRESULT InjectWindowMessage(UINT const message,
WPARAM const wparam,
LPARAM const lparam) {
return HandleMessage(message, wparam, lparam);
}

MOCK_METHOD1(OnDpiScale, void(unsigned int));
MOCK_METHOD2(OnResize, void(unsigned int, unsigned int));
MOCK_METHOD4(OnPointerMove,
Expand Down Expand Up @@ -346,5 +353,15 @@ TEST(FlutterWindowWin32Test, OnScrollCallsGetScrollOffsetMultiplier) {
kDefaultPointerDeviceId);
}

TEST(FlutterWindowWin32Test, OnWindowRepaint) {
MockFlutterWindowWin32 win32window;
MockWindowBindingHandlerDelegate delegate;
win32window.SetView(&delegate);

EXPECT_CALL(delegate, OnWindowRepaint()).Times(1);

win32window.InjectWindowMessage(WM_PAINT, 0, 0);
}

} // namespace testing
} // namespace flutter
6 changes: 6 additions & 0 deletions shell/platform/windows/flutter_windows_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ void FlutterWindowsView::OnWindowSizeChanged(size_t width, size_t height) {
}
}

void FlutterWindowsView::OnWindowRepaint() {
ForceRedraw();
}

void FlutterWindowsView::OnPointerMove(double x,
double y,
FlutterPointerDeviceKind device_kind,
Expand Down Expand Up @@ -603,6 +607,8 @@ void FlutterWindowsView::CreateRenderSurface() {
PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds();
engine_->surface_manager()->CreateSurface(GetRenderTarget(), bounds.width,
bounds.height);
resize_target_width_ = bounds.width;
resize_target_height_ = bounds.height;
}
}

Expand Down
3 changes: 3 additions & 0 deletions shell/platform/windows/flutter_windows_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate,
// |WindowBindingHandlerDelegate|
void OnWindowSizeChanged(size_t width, size_t height) override;

// |WindowBindingHandlerDelegate|
void OnWindowRepaint() override;

// |WindowBindingHandlerDelegate|
void OnPointerMove(double x,
double y,
Expand Down
29 changes: 29 additions & 0 deletions shell/platform/windows/flutter_windows_view_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "flutter/shell/platform/common/json_message_codec.h"
#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
#include "flutter/shell/platform/windows/flutter_window_win32.h"
#include "flutter/shell/platform/windows/flutter_windows_engine.h"
#include "flutter/shell/platform/windows/flutter_windows_texture_registrar.h"
#include "flutter/shell/platform/windows/testing/engine_modifier.h"
Expand Down Expand Up @@ -577,5 +578,33 @@ TEST(FlutterWindowsViewTest, WindowResizeTests) {
EXPECT_TRUE(send_window_metrics_event_called);
}

TEST(FlutterWindowsViewTest, WindowRepaintTests) {
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
EngineModifier modifier(engine.get());

FlutterWindowsView view(
std::make_unique<flutter::FlutterWindowWin32>(100, 100));
view.SetEngine(std::move(engine));
view.CreateRenderSurface();

bool send_window_metrics_event_called = false;
size_t width = 0;
size_t height = 0;
modifier.embedder_api().SendWindowMetricsEvent = MOCK_ENGINE_PROC(
SendWindowMetricsEvent,
([&send_window_metrics_event_called, &width, &height](
auto engine, const FlutterWindowMetricsEvent* event) {
send_window_metrics_event_called = true;
width = event->width;
height = event->height;
return kSuccess;
}));

view.OnWindowRepaint();
EXPECT_TRUE(send_window_metrics_event_called);
EXPECT_EQ(width, 100);
EXPECT_EQ(height, 100);
}

} // namespace testing
} // namespace flutter
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class MockWindowBindingHandlerDelegate : public WindowBindingHandlerDelegate {
MockWindowBindingHandlerDelegate const&) = delete;

MOCK_METHOD2(OnWindowSizeChanged, void(size_t, size_t));
MOCK_METHOD0(OnWindowRepaint, void());
MOCK_METHOD4(OnPointerMove,
void(double, double, FlutterPointerDeviceKind, int32_t));
MOCK_METHOD5(OnPointerDown,
Expand Down
1 change: 1 addition & 0 deletions shell/platform/windows/testing/mock_window_win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class MockWin32Window : public WindowWin32 {

MOCK_METHOD1(OnDpiScale, void(unsigned int));
MOCK_METHOD2(OnResize, void(unsigned int, unsigned int));
MOCK_METHOD0(OnPaint, void());
MOCK_METHOD4(OnPointerMove,
void(double, double, FlutterPointerDeviceKind, int32_t));
MOCK_METHOD5(OnPointerDown,
Expand Down
22 changes: 13 additions & 9 deletions shell/platform/windows/window_binding_handler_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,54 +22,58 @@ class WindowBindingHandlerDelegate {
// called on the platform thread.
virtual void OnWindowSizeChanged(size_t width, size_t height) = 0;

// Notifies delegate that backing window needs to be repainted.
// Typically called by currently configured WindowBindingHandler.
virtual void OnWindowRepaint() = 0;

// Notifies delegate that backing window mouse has moved.
// Typically called by currently configured WindowBindingHandler
// Typically called by currently configured WindowBindingHandler.
virtual void OnPointerMove(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id) = 0;

// Notifies delegate that backing window mouse pointer button has been
// pressed. Typically called by currently configured WindowBindingHandler
// pressed. Typically called by currently configured WindowBindingHandler.
virtual void OnPointerDown(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id,
FlutterPointerMouseButtons button) = 0;

// Notifies delegate that backing window mouse pointer button has been
// released. Typically called by currently configured WindowBindingHandler
// released. Typically called by currently configured WindowBindingHandler.
virtual void OnPointerUp(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id,
FlutterPointerMouseButtons button) = 0;

// Notifies delegate that backing window mouse pointer has left the window.
// Typically called by currently configured WindowBindingHandler
// Typically called by currently configured WindowBindingHandler.
virtual void OnPointerLeave(double x,
double y,
FlutterPointerDeviceKind device_kind,
int32_t device_id) = 0;

// Notifies delegate that a pan/zoom gesture has started.
// Typically called by DirectManipulationEventHandler
// Typically called by DirectManipulationEventHandler.
virtual void OnPointerPanZoomStart(int32_t device_id) = 0;

// Notifies delegate that a pan/zoom gesture has updated.
// Typically called by DirectManipulationEventHandler
// Typically called by DirectManipulationEventHandler.
virtual void OnPointerPanZoomUpdate(int32_t device_id,
double pan_x,
double pan_y,
double scale,
double rotation) = 0;

// Notifies delegate that a pan/zoom gesture has ended.
// Typically called by DirectManipulationEventHandler
// Typically called by DirectManipulationEventHandler.
virtual void OnPointerPanZoomEnd(int32_t device_id) = 0;

// Notifies delegate that backing window has received text.
// Typically called by currently configured WindowBindingHandler
// Typically called by currently configured WindowBindingHandler.
virtual void OnText(const std::u16string&) = 0;

// Notifies delegate that backing window size has received key press. Should
Expand Down Expand Up @@ -109,7 +113,7 @@ class WindowBindingHandlerDelegate {
virtual void OnComposeChange(const std::u16string& text, int cursor_pos) = 0;

// Notifies delegate that backing window size has recevied scroll.
// Typically called by currently configured WindowBindingHandler
// Typically called by currently configured WindowBindingHandler.
virtual void OnScroll(double x,
double y,
double delta_x,
Expand Down
3 changes: 3 additions & 0 deletions shell/platform/windows/window_win32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,9 @@ WindowWin32::HandleMessage(UINT const message,
current_height_ = height;
HandleResize(width, height);
break;
case WM_PAINT:
OnPaint();
break;
case WM_TOUCH: {
UINT num_points = LOWORD(wparam);
touch_points_.resize(num_points);
Expand Down
3 changes: 3 additions & 0 deletions shell/platform/windows/window_win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ class WindowWin32 : public KeyboardManagerWin32::WindowDelegate {
// Called when a resize occurs.
virtual void OnResize(UINT width, UINT height) = 0;

// Called when a paint is requested.
virtual void OnPaint() = 0;

// Called when the pointer moves within the
// window bounds.
virtual void OnPointerMove(double x,
Expand Down
6 changes: 6 additions & 0 deletions shell/platform/windows/window_win32_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -273,5 +273,11 @@ TEST(MockWin32Window, KeyDownWithCtrlToggled) {
SetKeyboardState(keyboard_state);
}

TEST(MockWin32Window, Paint) {
MockWin32Window window;
EXPECT_CALL(window, OnPaint()).Times(1);
window.InjectWindowMessage(WM_PAINT, 0, 0);
}

} // namespace testing
} // namespace flutter

0 comments on commit 563d3b0

Please sign in to comment.