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

Commit 2dce470

Browse files
[flutter_releases] Flutter Stable 2.0.4 Engine Cherrypicks (#25341)
* [web] Fix right click issue when dragging (#24447) * [web] Fix placeholder-only paragraphs (#24572) * [web] Reland: Fix painting of last placeholder in paragraph (#24905) Co-authored-by: Mouad Debbar <[email protected]>
1 parent 3459eb2 commit 2dce470

File tree

7 files changed

+428
-211
lines changed

7 files changed

+428
-211
lines changed

lib/web_ui/dev/goldens_lock.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
repository: https://github.com/flutter/goldens.git
2-
revision: ec80c8042759905a5215ab1cd87ad280e8ef3cd7
2+
revision: 4b4c256d6124a135b70c1a9a7ff10cf2827df31c

lib/web_ui/lib/src/engine/pointer_binding.dart

Lines changed: 57 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -415,41 +415,43 @@ class _ButtonSanitizer {
415415
);
416416
}
417417

418-
_SanitizedDetails? sanitizeUpEvent() {
418+
_SanitizedDetails? sanitizeMissingRightClickUp({required int buttons}) {
419+
final int newPressedButtons = _htmlButtonsToFlutterButtons(buttons);
420+
// This could happen when RMB is clicked and released but no pointerup
421+
// event was received because context menu was shown.
422+
if (_pressedButtons != 0 && newPressedButtons == 0) {
423+
_pressedButtons = 0;
424+
return _SanitizedDetails(
425+
change: ui.PointerChange.up,
426+
buttons: _pressedButtons,
427+
);
428+
}
429+
return null;
430+
}
431+
432+
_SanitizedDetails? sanitizeUpEvent({required int? buttons}) {
419433
// The pointer could have been released by a `pointerout` event, in which
420434
// case `pointerup` should have no effect.
421435
if (_pressedButtons == 0) {
422436
return null;
423437
}
424-
_pressedButtons = 0;
425-
return _SanitizedDetails(
426-
change: ui.PointerChange.up,
427-
buttons: _pressedButtons,
428-
);
429-
}
430438

431-
_SanitizedDetails? sanitizeUpEventWithButtons({required int buttons}) {
432-
final int newPressedButtons = _htmlButtonsToFlutterButtons(buttons);
433-
// This could happen when the context menu is active and the user clicks
434-
// RMB somewhere else. The browser sends a down event with `buttons:0`.
435-
//
436-
// In this case, we keep the old `buttons` value so we don't confuse the
437-
// framework.
438-
if (_pressedButtons != 0 && newPressedButtons == 0) {
439+
_pressedButtons = _htmlButtonsToFlutterButtons(buttons ?? 0);
440+
441+
if (_pressedButtons == 0) {
442+
// All buttons have been released.
443+
return _SanitizedDetails(
444+
change: ui.PointerChange.up,
445+
buttons: _pressedButtons,
446+
);
447+
} else {
448+
// There are still some unreleased buttons, we shouldn't send an up event
449+
// yet. Instead we send a move event to update the position of the pointer.
439450
return _SanitizedDetails(
440451
change: ui.PointerChange.move,
441452
buttons: _pressedButtons,
442453
);
443454
}
444-
445-
_pressedButtons = newPressedButtons;
446-
447-
return _SanitizedDetails(
448-
change: _pressedButtons == 0
449-
? ui.PointerChange.hover
450-
: ui.PointerChange.move,
451-
buttons: _pressedButtons,
452-
);
453455
}
454456

455457
_SanitizedDetails sanitizeCancelEvent() {
@@ -462,7 +464,6 @@ class _ButtonSanitizer {
462464
}
463465

464466
typedef _PointerEventListener = dynamic Function(html.PointerEvent event);
465-
const int kContextMenuButton = 2;
466467

467468
/// Adapter class to be used with browsers that support native pointer events.
468469
///
@@ -512,54 +513,45 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
512513
final int device = event.pointerId!;
513514
final List<ui.PointerData> pointerData = <ui.PointerData>[];
514515
final _ButtonSanitizer sanitizer = _ensureSanitizer(device);
515-
if (event.button == kContextMenuButton) {
516-
_handleMissingRightMouseUpEvent(sanitizer,
517-
sanitizer._pressedButtons,
518-
sanitizer._pressedButtons & ~kContextMenuButton,
519-
event,
520-
pointerData);
516+
final _SanitizedDetails? up =
517+
sanitizer.sanitizeMissingRightClickUp(buttons: event.buttons!);
518+
if (up != null) {
519+
_convertEventsToPointerData(data: pointerData, event: event, details: up);
521520
}
522-
final _SanitizedDetails details =
521+
final _SanitizedDetails down =
523522
sanitizer.sanitizeDownEvent(
524523
button: event.button,
525524
buttons: event.buttons!,
526525
);
527-
_convertEventsToPointerData(data: pointerData, event: event, details: details);
526+
_convertEventsToPointerData(data: pointerData, event: event, details: down);
528527
_callback(pointerData);
529528
});
530529

531530
_addPointerEventListener('pointermove', (html.PointerEvent event) {
532531
final int device = event.pointerId!;
533532
final _ButtonSanitizer sanitizer = _ensureSanitizer(device);
534533
final List<ui.PointerData> pointerData = <ui.PointerData>[];
535-
final int buttonsBeforeEvent = sanitizer._pressedButtons;
536-
final Iterable<_SanitizedDetails> detailsList = _expandEvents(event).map(
537-
(html.PointerEvent expandedEvent) {
538-
return sanitizer.sanitizeMoveEvent(buttons: expandedEvent.buttons!);
539-
},
540-
);
541-
_handleMissingRightMouseUpEvent(
542-
sanitizer,
543-
buttonsBeforeEvent,
544-
(sanitizer._inferDownFlutterButtons(event.button, event.buttons!)
545-
& kContextMenuButton),
546-
event,
547-
pointerData);
548-
for (_SanitizedDetails details in detailsList) {
549-
_convertEventsToPointerData(data: pointerData, event: event, details: details);
534+
final List<html.PointerEvent> expandedEvents = _expandEvents(event);
535+
for (final html.PointerEvent event in expandedEvents) {
536+
final _SanitizedDetails? up = sanitizer.sanitizeMissingRightClickUp(buttons: event.buttons!);
537+
if (up != null) {
538+
_convertEventsToPointerData(data: pointerData, event: event, details: up);
539+
}
540+
final _SanitizedDetails move = sanitizer.sanitizeMoveEvent(buttons: event.buttons!);
541+
_convertEventsToPointerData(data: pointerData, event: event, details: move);
550542
}
551543
_callback(pointerData);
552544
}, acceptOutsideGlasspane: true);
553545

554546
_addPointerEventListener('pointerup', (html.PointerEvent event) {
555547
final int device = event.pointerId!;
556548
final List<ui.PointerData> pointerData = <ui.PointerData>[];
557-
final _SanitizedDetails? details = _getSanitizer(device).sanitizeUpEvent();
549+
final _SanitizedDetails? details = _getSanitizer(device).sanitizeUpEvent(buttons: event.buttons);
558550
_removePointerIfUnhoverable(event);
559551
if (details != null) {
560552
_convertEventsToPointerData(data: pointerData, event: event, details: details);
553+
_callback(pointerData);
561554
}
562-
_callback(pointerData);
563555
}, acceptOutsideGlasspane: true);
564556

565557
// A browser fires cancel event if it concludes the pointer will no longer
@@ -578,39 +570,6 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {
578570
});
579571
}
580572

581-
// Handle special case where right mouse button no longer is pressed.
582-
// We need to synthesize right mouse up, otherwise drag gesture will fail
583-
// to complete or multiple RMB down events will lead to wrong state.
584-
void _handleMissingRightMouseUpEvent(_ButtonSanitizer sanitizer,
585-
int buttonsBeforeEvent, int buttonsAfterEvent, html.PointerEvent event,
586-
List<ui.PointerData> pointerData) {
587-
if ((buttonsBeforeEvent & kContextMenuButton) != 0 &&
588-
buttonsAfterEvent == 0) {
589-
final ui.PointerDeviceKind kind =
590-
_pointerTypeToDeviceKind(event.pointerType!);
591-
final int device = kind == ui.PointerDeviceKind.mouse
592-
? _mouseDeviceId : event.pointerId!;
593-
final double tilt = _computeHighestTilt(event);
594-
final Duration timeStamp = _BaseAdapter._eventTimeStampToDuration(event.timeStamp!);
595-
sanitizer._pressedButtons &= ~kContextMenuButton;
596-
_pointerDataConverter.convert(
597-
pointerData,
598-
change: ui.PointerChange.up,
599-
timeStamp: timeStamp,
600-
kind: kind,
601-
signalKind: ui.PointerSignalKind.none,
602-
device: device,
603-
physicalX: event.client.x.toDouble() * ui.window.devicePixelRatio,
604-
physicalY: event.client.y.toDouble() * ui.window.devicePixelRatio,
605-
buttons: sanitizer._pressedButtons,
606-
pressure: event.pressure as double,
607-
pressureMin: 0.0,
608-
pressureMax: 1.0,
609-
tilt: tilt,
610-
);
611-
}
612-
}
613-
614573
// For each event that is de-coalesced from `event` and described in
615574
// `details`, convert it to pointer data and store in `data`.
616575
void _convertEventsToPointerData({
@@ -852,12 +811,10 @@ class _MouseAdapter extends _BaseAdapter with _WheelEventListenerMixin {
852811
void setup() {
853812
_addMouseEventListener('mousedown', (html.MouseEvent event) {
854813
final List<ui.PointerData> pointerData = <ui.PointerData>[];
855-
if (event.button == kContextMenuButton) {
856-
_handleMissingRightMouseUpEvent(_sanitizer,
857-
_sanitizer._pressedButtons,
858-
_sanitizer._pressedButtons & ~kContextMenuButton,
859-
event,
860-
pointerData);
814+
final _SanitizedDetails? up =
815+
_sanitizer.sanitizeMissingRightClickUp(buttons: event.buttons!);
816+
if (up != null) {
817+
_convertEventsToPointerData(data: pointerData, event: event, details: up);
861818
}
862819
final _SanitizedDetails sanitizedDetails =
863820
_sanitizer.sanitizeDownEvent(
@@ -870,60 +827,29 @@ class _MouseAdapter extends _BaseAdapter with _WheelEventListenerMixin {
870827

871828
_addMouseEventListener('mousemove', (html.MouseEvent event) {
872829
final List<ui.PointerData> pointerData = <ui.PointerData>[];
873-
final int buttonsBeforeEvent = _sanitizer._pressedButtons;
874-
_handleMissingRightMouseUpEvent(
875-
_sanitizer,
876-
buttonsBeforeEvent,
877-
(_sanitizer._inferDownFlutterButtons(event.button, event.buttons!)
878-
& kContextMenuButton),
879-
event,
880-
pointerData);
881-
final _SanitizedDetails sanitizedDetails = _sanitizer.sanitizeMoveEvent(buttons: event.buttons!);
882-
_convertEventsToPointerData(data: pointerData, event: event, details: sanitizedDetails);
830+
final _SanitizedDetails? up = _sanitizer.sanitizeMissingRightClickUp(buttons: event.buttons!);
831+
if (up != null) {
832+
_convertEventsToPointerData(data: pointerData, event: event, details: up);
833+
}
834+
final _SanitizedDetails move = _sanitizer.sanitizeMoveEvent(buttons: event.buttons!);
835+
_convertEventsToPointerData(data: pointerData, event: event, details: move);
883836
_callback(pointerData);
884837
}, acceptOutsideGlasspane: true);
885838

886839
_addMouseEventListener('mouseup', (html.MouseEvent event) {
887840
final List<ui.PointerData> pointerData = <ui.PointerData>[];
888-
final bool isEndOfDrag = event.buttons == 0;
889-
final _SanitizedDetails sanitizedDetails = isEndOfDrag ?
890-
_sanitizer.sanitizeUpEvent()! :
891-
_sanitizer.sanitizeUpEventWithButtons(buttons: event.buttons!)!;
892-
_convertEventsToPointerData(data: pointerData, event: event, details: sanitizedDetails);
893-
_callback(pointerData);
841+
final _SanitizedDetails? sanitizedDetails = _sanitizer.sanitizeUpEvent(buttons: event.buttons);
842+
if (sanitizedDetails != null) {
843+
_convertEventsToPointerData(data: pointerData, event: event, details: sanitizedDetails);
844+
_callback(pointerData);
845+
}
894846
}, acceptOutsideGlasspane: true);
895847

896848
_addWheelEventListener((html.Event event) {
897849
_handleWheelEvent(event);
898850
});
899851
}
900852

901-
// Handle special case where right mouse button no longer is pressed.
902-
// We need to synthesize right mouse up, otherwise drag gesture will fail
903-
// to complete or multiple RMB down events will lead to wrong state.
904-
void _handleMissingRightMouseUpEvent(_ButtonSanitizer sanitizer,
905-
int buttonsBeforeEvent, int buttonsAfterEvent, html.MouseEvent event,
906-
List<ui.PointerData> pointerData) {
907-
if ((buttonsBeforeEvent & kContextMenuButton) != 0 &&
908-
buttonsAfterEvent == 0) {
909-
sanitizer._pressedButtons &= ~2;
910-
_pointerDataConverter.convert(
911-
pointerData,
912-
change: ui.PointerChange.up,
913-
timeStamp: _BaseAdapter._eventTimeStampToDuration(event.timeStamp!),
914-
kind: ui.PointerDeviceKind.mouse,
915-
signalKind: ui.PointerSignalKind.none,
916-
device: _mouseDeviceId,
917-
physicalX: event.client.x.toDouble() * ui.window.devicePixelRatio,
918-
physicalY: event.client.y.toDouble() * ui.window.devicePixelRatio,
919-
buttons: _sanitizer._pressedButtons,
920-
pressure: 1.0,
921-
pressureMin: 0.0,
922-
pressureMax: 1.0,
923-
);
924-
}
925-
}
926-
927853
// For each event that is de-coalesced from `event` and described in
928854
// `detailsList`, convert it to pointer data and store in `data`.
929855
void _convertEventsToPointerData({

lib/web_ui/lib/src/engine/pointer_converter.dart

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ class _PointerState {
1919
_pointer = _pointerCount;
2020
}
2121

22-
bool down = false;
23-
2422
double x;
2523
double y;
2624
}
@@ -240,8 +238,9 @@ class PointerDataConverter {
240238
double scrollDeltaY = 0.0,
241239
}) {
242240
if (_debugLogPointerConverter) {
243-
print('>> device=$device change = $change buttons = $buttons');
241+
print('>> device=$device change=$change buttons=$buttons');
244242
}
243+
final bool isDown = buttons != 0;
245244
assert(change != null); // ignore: unnecessary_null_comparison
246245
if (signalKind == null ||
247246
signalKind == ui.PointerSignalKind.none) {
@@ -281,9 +280,8 @@ class PointerDataConverter {
281280
break;
282281
case ui.PointerChange.hover:
283282
final bool alreadyAdded = _pointers.containsKey(device);
284-
final _PointerState state = _ensureStateForPointer(
285-
device, physicalX, physicalY);
286-
assert(!state.down);
283+
_ensureStateForPointer(device, physicalX, physicalY);
284+
assert(!isDown);
287285
if (!alreadyAdded) {
288286
// Synthesizes an add pointer data.
289287
result.add(
@@ -348,7 +346,7 @@ class PointerDataConverter {
348346
final bool alreadyAdded = _pointers.containsKey(device);
349347
final _PointerState state = _ensureStateForPointer(
350348
device, physicalX, physicalY);
351-
assert(!state.down);
349+
assert(isDown);
352350
state.startNewPointer();
353351
if (!alreadyAdded) {
354352
// Synthesizes an add pointer data.
@@ -412,7 +410,6 @@ class PointerDataConverter {
412410
)
413411
);
414412
}
415-
state.down = true;
416413
result.add(
417414
_generateCompletePointerData(
418415
timeStamp: timeStamp,
@@ -445,8 +442,7 @@ class PointerDataConverter {
445442
break;
446443
case ui.PointerChange.move:
447444
assert(_pointers.containsKey(device));
448-
final _PointerState state = _pointers[device]!;
449-
assert(state.down);
445+
assert(isDown);
450446
result.add(
451447
_generateCompletePointerData(
452448
timeStamp: timeStamp,
@@ -481,7 +477,7 @@ class PointerDataConverter {
481477
case ui.PointerChange.cancel:
482478
assert(_pointers.containsKey(device));
483479
final _PointerState state = _pointers[device]!;
484-
assert(state.down);
480+
assert(!isDown);
485481
// Cancel events can have different coordinates due to various
486482
// reasons (window lost focus which is accompanied by window
487483
// movement, or PointerEvent simply always gives 0). Instead of
@@ -522,7 +518,6 @@ class PointerDataConverter {
522518
)
523519
);
524520
}
525-
state.down = false;
526521
result.add(
527522
_generateCompletePointerData(
528523
timeStamp: timeStamp,
@@ -588,7 +583,7 @@ class PointerDataConverter {
588583
case ui.PointerChange.remove:
589584
assert(_pointers.containsKey(device));
590585
final _PointerState state = _pointers[device]!;
591-
assert(!state.down);
586+
assert(!isDown);
592587
result.add(
593588
_generateCompletePointerData(
594589
timeStamp: timeStamp,
@@ -624,8 +619,7 @@ class PointerDataConverter {
624619
switch (signalKind) {
625620
case ui.PointerSignalKind.scroll:
626621
final bool alreadyAdded = _pointers.containsKey(device);
627-
final _PointerState state = _ensureStateForPointer(
628-
device, physicalX, physicalY);
622+
_ensureStateForPointer(device, physicalX, physicalY);
629623
if (!alreadyAdded) {
630624
// Synthesizes an add pointer data.
631625
result.add(
@@ -661,7 +655,7 @@ class PointerDataConverter {
661655
// before sending the scroll event, if necessary, so that clients
662656
// don't have to worry about native ordering of hover and scroll
663657
// events.
664-
if (state.down) {
658+
if (isDown) {
665659
result.add(
666660
_synthesizePointerData(
667661
timeStamp: timeStamp,

0 commit comments

Comments
 (0)