-
Notifications
You must be signed in to change notification settings - Fork 6k
Fix web editable text composing range #33590
Fix web editable text composing range #33590
Conversation
mdebbar
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than my concern about delta state, this PR looks good!
Thanks for taking the time to fix this!
| void handleCompositionUpdate(html.Event event) { | ||
| final EditingState newEditingState = EditingState.fromDomElement(activeDomElement); | ||
| editingDeltaState.composingOffset = newEditingState.baseOffset!; | ||
| editingDeltaState.composingExtent = newEditingState.extentOffset!; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I honestly don't know how delta state works with composing range. Your change here seems to break delta state because it won't be able to take composing range into account anymore:
engine/lib/web_ui/lib/src/engine/text_editing/text_editing.dart
Lines 506 to 512 in 593140b
| // If we are composing then set the delta range to the composing region we | |
| // captured in compositionupdate. | |
| final bool isCurrentlyComposing = newTextEditingDeltaState.composingOffset != null && newTextEditingDeltaState.composingOffset != newTextEditingDeltaState.composingExtent; | |
| if (newTextEditingDeltaState.deltaText.isNotEmpty && previousSelectionWasCollapsed && isCurrentlyComposing) { | |
| newTextEditingDeltaState.deltaStart = newTextEditingDeltaState.composingOffset!; | |
| newTextEditingDeltaState.deltaEnd = newTextEditingDeltaState.composingExtent!; | |
| } |
I'd love to get @Renzo-Olivares's opinion on this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems to be causing some issues, but i'm still looking into it. Ideally we could just pull the composingOffset and composingExtent from the EditingState after determineCompositionState() is called, but I'm getting some weird behavior doing that. I'll keep investigating, and post an update asap. I'll also update the documentation since this should be more clearly explained.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We were previously setting the deltaStart and deltaEnd to the composing region captured in compositionupdate. I previously derived the composing region by grabbing the editing state from the DOM at the time when the compositionupdate event was fired and using the selection as the composing region. At the time of firing the compositionupdate event, the editing states selection contains the range that was replaced during composition. Previously this worked fine because we were replacing the replaced range with the composed text. However, this was a bit inaccurate since it is not the composing region after the edit was made. When making the composing region accurate through this change, a failure occurs in the _replace method because the range being replaced did not exist yet. For example when composing:
Type: ’n’
oldText = ‘’
deltaText = ’n’
deltaStart = ‘0’ (from composingOffset)
deltaEnd = ‘1’ (from composingExtent)
_replace tries to replace (0,1) with ’n’ in oldText which is an empty string. This fails and a delta is not produced. The reason for this being, by deriving the composing region from compositionupdate using CompositionAwareMixin we are actually deriving the composing region after that composing step has finished, i.e. after ’n’ has already been added to the EditingState the composing region is (0,1).
To fix this the deltaStart and deltaEnd should be the range replaced by the composing region, and not the composing region after the compositionupdate event has updated the editing state. We can do this by setting the deltaStart to the composingOffset captured by the CompositionAwareMixin and leaving the deltaEnd as the one captured by beforeInput. This will be the position of the caret before the compositionupdate event is fired. In the case of our example above it would be (0). So coming back to our previous example we would have:
Type: ’n’
oldText = ‘’
deltaText = ’n’
deltaStart = ‘0’ (from composingOffset)
deltaEnd = ‘0’ (from beforeInput extentOffset)
Which would not cause a failure on _replace and generate the correct delta.
The fix would look something like Renzo-Olivares@f459888 .
I'm unsure if we want to rely on beforeInput or if we want to rely on 'CompositionAwareMixin’ to save the selection range from the active DOM editing state in compositionupdate and set the composing region and deltaStart and deltaEnd through something like determineCompositionStateForDelta().
justinmc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just small comments below, overall this looks good. +1 to having @Renzo-Olivares take a look as it pertains to deltas.
lib/web_ui/lib/src/engine/text_editing/composition_aware_mixin.dart
Outdated
Show resolved
Hide resolved
lib/web_ui/lib/src/engine/text_editing/composition_aware_mixin.dart
Outdated
Show resolved
Hide resolved
lib/web_ui/lib/src/engine/text_editing/composition_aware_mixin.dart
Outdated
Show resolved
Hide resolved
lib/web_ui/lib/src/engine/text_editing/composition_aware_mixin.dart
Outdated
Show resolved
Hide resolved
| editingStrategy.disable(); | ||
| }); | ||
|
|
||
| test('should have newly entered composing characters', () async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Renzo-Olivares This test group are the tests for the delta fix you had me implement - lmk your input
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM thanks for making these
|
Unfortunately, the failing test is not a flake - I'm able to reproduce the behavior on Firefox. Here's a video of what is happening on Firefox: delta_bug.movessentially, it looks like on composing using delta mode on Firefox, a second action is required to "flush" the composed region. Not sure why this is, but it's consistent with the tests: the test failing on Firefox passes if I send a dummy event after composition. This is looking like a much more involved fix than originally planned because of deltas - I can continue trying to monkey patch this, but not sure if it will be beneficial, since Renzo said that deltas are getting refactored soon. Thoughts? EDIT: Spoke offline w/ Renzo and Mouad. This is probably safe to merge because the bug reproduces on master, meaning it doesn't introduce a regression. The test is failing because it was previously a blind spot in the testing suite. |
|
@antholeole thanks again for being patient here. When I spoke to Renzo last week, we agreed that the refactoring was a good idea. I suggest waiting for that refactor. It should make this PR a lot simpler. What do you think @Renzo-Olivares ? |
We talked offline, but I think this can be merged since it is reproducible on master. The source of the issue is a difference in events given by Chrome and Firefox flutter/flutter#105244 (comment) |
mdebbar
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
justinmc
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
Just a bunch of small comments below.
lib/web_ui/lib/src/engine/text_editing/composition_aware_mixin.dart
Outdated
Show resolved
Hide resolved
lib/web_ui/lib/src/engine/text_editing/composition_aware_mixin.dart
Outdated
Show resolved
Hide resolved
|
🤞 |
Flutter web framework now gets valid composing region updates from engine Co-authored-by: Anthony Oleinik <oleina@google.com>

Flutter framework on web was not getting
composingRangeupdates from the engine. This is the fix. Loosely based on this PR.I attempted to pull most of the composing logic out into it's own
mixin, so it would be easier to test + read.before:
after:
List which issues are fixed by this PR. You must list at least one issue.
Demo Code
Pre-launch Checklist
writing and running engine tests.
///).