Preserve Windows cursor alpha during native image decoding

This commit is contained in:
fufesou
2026-09-12 22:52:36 +08:00
parent afdd1d5c9d
commit 1fabdd6a9c
2 changed files with 10 additions and 5 deletions

View File

@@ -3461,9 +3461,10 @@ class CursorModel with ChangeNotifier {
List<dynamic> colors = json.decode(evt['colors']);
final rgba = Uint8List.fromList(colors.map((s) => s as int).toList());
final ui.Image? image;
final platform = parent.target?.ffiModel.pi.platform;
if (!isWeb &&
parent.target?.ffiModel.pi.platform == kPeerPlatformMacOS) {
image = await _decodeMacCursor(rgba, width, height);
(platform == kPeerPlatformMacOS || platform == kPeerPlatformWindows)) {
image = await _decodeStraightAlphaCursor(rgba, width, height);
} else {
image = await img.decodeImageFromPixels(
rgba, width, height, ui.PixelFormat.rgba8888);
@@ -3484,10 +3485,10 @@ class CursorModel with ChangeNotifier {
_updateCurData();
}
Future<ui.Image?> _decodeMacCursor(
Future<ui.Image?> _decodeStraightAlphaCursor(
Uint8List rgba, int width, int height) async {
// macOS packets keep straight alpha, regardless of density metadata.
// Premultiply only for native ui.Image; the PNG cache needs straight colors.
// macOS and Win32 capture send straight alpha; XFixes/DRM are premultiplied.
// Convert a copy for native ui.Image, preserving the wire and PNG cache colors.
final source = img2.Image.fromBytes(
width: width, height: height, bytes: rgba.buffer, order: img2.ChannelOrder.rgba);
for (final pixel in source) {

View File

@@ -69,6 +69,8 @@ void main() {
(kPeerPlatformMacOS, '0', [64, 32, 16, 128]),
(kPeerPlatformMacOS, '1', [64, 32, 16, 128]),
(kPeerPlatformMacOS, '2', [64, 32, 16, 128]),
(kPeerPlatformWindows, null, [64, 32, 16, 128]),
(kPeerPlatformWindows, '0', [64, 32, 16, 128]),
(kPeerPlatformLinux, '0', [32, 16, 8, 128]),
]) {
for (final dpr in [1.0, 2.0]) {
@@ -119,6 +121,8 @@ Future<void> _checkCursor((String, String?, List<int>) testCase, double dpr,
bytes: straight!.buffer,
bytesOffset: straight.offsetInBytes,
order: img.ChannelOrder.rgba));
// Real sessions own FFI strongly throughout asynchronous cursor decoding.
expect(cursor.parent.target, same(ffi));
}
void _checkRegistration(Map<dynamic, dynamic> args, double dpr) {