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

Commit 45137ea

Browse files
authored
Report display sizes in physical pixels on MacOS (#50221)
Fixes flutter/flutter#142629 `Display.size`'s [documentation](https://main-api.flutter.dev/flutter/dart-ui/Display/size.html) says (emphasize mine): > The **physical** size of this display. But we have actually been reporting the size in logical pixels - up until now!
1 parent a632531 commit 45137ea

File tree

3 files changed

+58
-4
lines changed

3 files changed

+58
-4
lines changed

shell/platform/darwin/macos/framework/Source/FlutterEngine.mm

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -824,23 +824,28 @@ - (void)updateDisplayConfig:(NSNotification*)notification {
824824
[self updateDisplayConfig];
825825
}
826826

827+
- (NSArray<NSScreen*>*)screens {
828+
return [NSScreen screens];
829+
}
830+
827831
- (void)updateDisplayConfig {
828832
if (!_engine) {
829833
return;
830834
}
831835

832836
std::vector<FlutterEngineDisplay> displays;
833-
for (NSScreen* screen : [NSScreen screens]) {
837+
for (NSScreen* screen : [self screens]) {
834838
CGDirectDisplayID displayID =
835839
static_cast<CGDirectDisplayID>([screen.deviceDescription[@"NSScreenNumber"] integerValue]);
836840

841+
double devicePixelRatio = screen.backingScaleFactor;
837842
FlutterEngineDisplay display;
838843
display.struct_size = sizeof(display);
839844
display.display_id = displayID;
840845
display.single_display = false;
841-
display.width = static_cast<size_t>(screen.frame.size.width);
842-
display.height = static_cast<size_t>(screen.frame.size.height);
843-
display.device_pixel_ratio = screen.backingScaleFactor;
846+
display.width = static_cast<size_t>(screen.frame.size.width) * devicePixelRatio;
847+
display.height = static_cast<size_t>(screen.frame.size.height) * devicePixelRatio;
848+
display.device_pixel_ratio = devicePixelRatio;
844849

845850
CVDisplayLinkRef displayLinkRef = nil;
846851
CVReturn error = CVDisplayLinkCreateWithCGDisplay(displayID, &displayLinkRef);

shell/platform/darwin/macos/framework/Source/FlutterEngineTest.mm

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,23 @@ + (void)registerWithRegistrar:(id<FlutterPluginRegistrar>)registrar {
118118

119119
#pragma mark -
120120

121+
@interface MockableFlutterEngine : FlutterEngine
122+
@end
123+
124+
@implementation MockableFlutterEngine
125+
- (NSArray<NSScreen*>*)screens {
126+
id mockScreen = OCMClassMock([NSScreen class]);
127+
OCMStub([mockScreen backingScaleFactor]).andReturn(2.0);
128+
OCMStub([mockScreen deviceDescription]).andReturn(@{
129+
@"NSScreenNumber" : [NSNumber numberWithInt:10]
130+
});
131+
OCMStub([mockScreen frame]).andReturn(NSMakeRect(10, 20, 30, 40));
132+
return [NSArray arrayWithObject:mockScreen];
133+
}
134+
@end
135+
136+
#pragma mark -
137+
121138
namespace flutter::testing {
122139

123140
TEST_F(FlutterEngineTest, CanLaunch) {
@@ -1148,6 +1165,34 @@ + (void)registerWithRegistrar:(id<FlutterPluginRegistrar>)registrar {
11481165
EXPECT_TRUE(updated);
11491166
}
11501167

1168+
TEST_F(FlutterEngineTest, DisplaySizeIsInPhysicalPixel) {
1169+
NSString* fixtures = @(testing::GetFixturesPath());
1170+
FlutterDartProject* project = [[FlutterDartProject alloc]
1171+
initWithAssetsPath:fixtures
1172+
ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
1173+
project.rootIsolateCreateCallback = FlutterEngineTest::IsolateCreateCallback;
1174+
MockableFlutterEngine* engine = [[MockableFlutterEngine alloc] initWithName:@"foobar"
1175+
project:project
1176+
allowHeadlessExecution:true];
1177+
BOOL updated = NO;
1178+
auto original_update_displays = engine.embedderAPI.NotifyDisplayUpdate;
1179+
engine.embedderAPI.NotifyDisplayUpdate = MOCK_ENGINE_PROC(
1180+
NotifyDisplayUpdate, ([&updated, &original_update_displays](
1181+
auto engine, auto update_type, auto* displays, auto display_count) {
1182+
EXPECT_EQ(display_count, 1UL);
1183+
EXPECT_EQ(displays->display_id, 10UL);
1184+
EXPECT_EQ(displays->width, 60UL);
1185+
EXPECT_EQ(displays->height, 80UL);
1186+
EXPECT_EQ(displays->device_pixel_ratio, 2UL);
1187+
updated = YES;
1188+
return original_update_displays(engine, update_type, displays, display_count);
1189+
}));
1190+
EXPECT_TRUE([engine runWithEntrypoint:@"main"]);
1191+
EXPECT_TRUE(updated);
1192+
[engine shutDownEngine];
1193+
engine = nil;
1194+
}
1195+
11511196
} // namespace flutter::testing
11521197

11531198
// NOLINTEND(clang-analyzer-core.StackAddressEscape)

shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ typedef NS_ENUM(NSInteger, FlutterAppExitResponse) {
215215
- (void)announceAccessibilityMessage:(NSString*)message
216216
withPriority:(NSAccessibilityPriorityLevel)priority;
217217

218+
/**
219+
* Returns an array of screen objects representing all of the screens available on the system.
220+
*/
221+
- (NSArray<NSScreen*>*)screens;
218222
@end
219223

220224
@interface FlutterEngine (Tests)

0 commit comments

Comments
 (0)