Skip to content

Commit 37ac2aa

Browse files
committed
Fix Android stream rotation mapping
1 parent 79fa227 commit 37ac2aa

2 files changed

Lines changed: 61 additions & 7 deletions

File tree

client/src/app/AppShell.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,12 @@ export function AppShell({
10251025
}, [isBooted]);
10261026

10271027
useEffect(() => {
1028+
if (isAndroidViewport) {
1029+
setRotationQuarterTurns((current) =>
1030+
normalizeQuarterTurns(current) === 0 ? current : 0,
1031+
);
1032+
return;
1033+
}
10281034
if (simulatorRotationQuarterTurns == null) {
10291035
return;
10301036
}
@@ -1036,7 +1042,7 @@ export function AppShell({
10361042
beginZoomAnimation();
10371043
return simulatorRotationQuarterTurns;
10381044
});
1039-
}, [simulatorRotationQuarterTurns]);
1045+
}, [isAndroidViewport, simulatorRotationQuarterTurns]);
10401046

10411047
useEffect(() => {
10421048
setChromeLoaded(!chromeRequired);

server/src/android.rs

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,11 +1083,15 @@ fn normalize_android_frame_orientation(
10831083
let (width, height) = if (width > height) == (target.width > target.height) {
10841084
(width, height)
10851085
} else {
1086-
rgba = rotate_rgba_clockwise(&rgba, width, height);
1086+
rgba = if target.rotation_quarter_turns == 3 {
1087+
rotate_rgba_counterclockwise(&rgba, width, height)
1088+
} else {
1089+
rotate_rgba_clockwise(&rgba, width, height)
1090+
};
10871091
(height, width)
10881092
};
10891093

1090-
if target.rotation_quarter_turns >= 2 {
1094+
if target.width > target.height {
10911095
rotate_rgba_180_in_place(&mut rgba, width, height);
10921096
}
10931097

@@ -1120,6 +1124,22 @@ fn rotate_rgba_180_in_place(rgba: &mut [u8], width: u32, height: u32) {
11201124
}
11211125
}
11221126

1127+
fn rotate_rgba_counterclockwise(rgba: &[u8], width: u32, height: u32) -> Vec<u8> {
1128+
let width = width as usize;
1129+
let height = height as usize;
1130+
let mut out = vec![0; rgba.len()];
1131+
for y in 0..height {
1132+
for x in 0..width {
1133+
let src = (y * width + x) * 4;
1134+
let dst_x = y;
1135+
let dst_y = width - 1 - x;
1136+
let dst = (dst_y * height + dst_x) * 4;
1137+
out[dst..dst + 4].copy_from_slice(&rgba[src..src + 4]);
1138+
}
1139+
}
1140+
out
1141+
}
1142+
11231143
fn flatten_android_frame_alpha(rgba: &mut [u8], width: u32, height: u32) {
11241144
if !rgba.chunks_exact(4).any(|pixel| pixel[3] != 255) {
11251145
return;
@@ -1942,6 +1962,34 @@ DisplayDeviceInfo{"Built-in Screen", 1080 x 2400, roundedCorners RoundedCorners{
19421962
assert_eq!(out, rgba);
19431963
}
19441964

1965+
#[test]
1966+
fn android_frame_orientation_flips_landscape_streams() {
1967+
let rgba = vec![
1968+
1, 0, 0, 255, 2, 0, 0, 255, 3, 0, 0, 255, //
1969+
4, 0, 0, 255, 5, 0, 0, 255, 6, 0, 0, 255,
1970+
];
1971+
1972+
let (width, height, rotated) = normalize_android_frame_orientation(
1973+
3,
1974+
2,
1975+
rgba,
1976+
Some(AndroidFrameTarget {
1977+
width: 3,
1978+
height: 2,
1979+
rotation_quarter_turns: 1,
1980+
}),
1981+
);
1982+
1983+
assert_eq!((width, height), (3, 2));
1984+
assert_eq!(
1985+
rotated,
1986+
vec![
1987+
6, 0, 0, 255, 5, 0, 0, 255, 4, 0, 0, 255, //
1988+
3, 0, 0, 255, 2, 0, 0, 255, 1, 0, 0, 255,
1989+
]
1990+
);
1991+
}
1992+
19451993
#[test]
19461994
fn android_frame_alpha_flattens_transparent_edges_to_nearest_row_pixel() {
19471995
let mut rgba = vec![0, 0, 0, 0, 10, 20, 30, 255, 40, 50, 60, 255, 0, 0, 0, 0];
@@ -1964,15 +2012,15 @@ DisplayDeviceInfo{"Built-in Screen", 1080 x 2400, roundedCorners RoundedCorners{
19642012
}
19652013

19662014
#[test]
1967-
fn android_frame_orientation_rotates_reverse_orientations_180() {
2015+
fn android_frame_orientation_rotates_counterclockwise_then_flips_reverse_landscape() {
19682016
let rgba = vec![
19692017
1, 0, 0, 255, 2, 0, 0, 255, 3, 0, 0, 255, //
19702018
4, 0, 0, 255, 5, 0, 0, 255, 6, 0, 0, 255,
19712019
];
19722020

19732021
let (width, height, rotated) = normalize_android_frame_orientation(
1974-
3,
19752022
2,
2023+
3,
19762024
rgba,
19772025
Some(AndroidFrameTarget {
19782026
width: 3,
@@ -1985,8 +2033,8 @@ DisplayDeviceInfo{"Built-in Screen", 1080 x 2400, roundedCorners RoundedCorners{
19852033
assert_eq!(
19862034
rotated,
19872035
vec![
1988-
6, 0, 0, 255, 5, 0, 0, 255, 4, 0, 0, 255, //
1989-
3, 0, 0, 255, 2, 0, 0, 255, 1, 0, 0, 255,
2036+
5, 0, 0, 255, 3, 0, 0, 255, 1, 0, 0, 255, //
2037+
6, 0, 0, 255, 4, 0, 0, 255, 2, 0, 0, 255,
19902038
]
19912039
);
19922040
}

0 commit comments

Comments
 (0)