Preserve thin cursor proportions at the visibility minimum

This commit is contained in:
fufesou
2026-09-14 13:54:04 +08:00
parent 70e345a76d
commit f487aaed99
6 changed files with 51 additions and 38 deletions

View File

@@ -1125,9 +1125,8 @@ class _ImagePaintState extends State<ImagePaint> {
// the existing unzoomed sizing policy for other hosts.
return (isWindows ? dpr : 1.0) / peerDpr;
}
// Without density, keep the legacy unzoomed scale of 1. Dividing by
// controller DPR would also trigger the legacy short-edge minimum,
// enlarging thin artwork that previously needed no resizing.
// Without density, preserve the legacy unzoomed size. Controller
// DPR alone cannot determine the remote bitmap's logical size.
final imageScale = isViewScaled() && zoomCursor.isTrue
? _cursorImageScale(widget.ffi, cursor, useLocalPointer: true)
: s;
@@ -1456,10 +1455,8 @@ class CursorPaint extends StatelessWidget {
if (image != null && (logicalMinimum || scale * nativePixels != 1.0)) {
final sx = kMinCursorSize / (image.width * nativePixels);
final sy = kMinCursorSize / (image.height * nativePixels);
// Preserve Original's short-edge minimum; scaled views use the long edge.
final minimumScale = c.viewStyle.style == kRemoteViewStyleOriginal
? (sx > sy ? sx : sy)
: (sx < sy ? sx : sy);
// Match native resizing: a thin axis must not enlarge the whole cursor.
final minimumScale = sx < sy ? sx : sy;
if (scale < minimumScale) scale = minimumScale;
}
// Anchor the hotspot to the video position even when the minimum size

View File

@@ -2915,19 +2915,11 @@ class CursorData {
debugPrint('Rejected cursor $id: invalid scale $scale');
return null;
}
if (!useLegacyMinimum) {
// Preserve unscaled legacy artwork, but never enlarge a thin cursor just
// to make its short edge reach the visibility minimum.
if (!useLegacyMinimum || scale != 1.0) {
scale = max(scale, kMinCursorSize / max(width, height));
}
if (useLegacyMinimum && scale != 1.0) {
// Update data if scale changed.
final tgtWidth = width * scale;
final tgtHeight = height * scale;
if (tgtWidth < kMinCursorSize || tgtHeight < kMinCursorSize) {
double sw = kMinCursorSize.toDouble() / width;
double sh = kMinCursorSize.toDouble() / height;
scale = sw < sh ? sh : sw;
}
}
if (!_validCursorRasterSize(width * scale, height * scale,
rasterScale: rasterScale)) {

View File

@@ -26,8 +26,8 @@ MouseCursor buildCursorOfCache(
// bitmap even when the remote view scale has not changed.
final dpr = WidgetsBinding
.instance.platformDispatcher.views.single.devicePixelRatio;
// Keep Original and older peers unchanged. A long-edge minimum preserves
// the proportions of thin remote cursors when normalizing their DPI.
// Keep Original and older peers' pixel units and scale-1 behavior.
// Resizing uses a long-edge minimum regardless of source density.
final legacyMinimum = cache.pixelRatio == 0 ||
cursor.parent.target?.canvasModel.viewStyle.style == kRemoteViewStyleOriginal;
// The minimum is logical, while Windows callers pass a physical scale.