Repository: flutter
Issue: [web] Typing compound characters generates unexpected deltas on Safari
Labels: a: text input,engine,platform-web,has reproducible steps,browser: safari-macos,assigned for triage,P2,team-web,triaged-web,found in release: 3.13,found in release: 3.14

### Is there an existing issue for this?

- [X] I have searched the [existing issues](https://github.com/flutter/flutter/issues)
- [X] I have read the [guide to filing a bug](https://flutter.dev/docs/resources/bug-reports)

### Steps to reproduce

1. Run the sample code with `flutter run -d web-server --web-port 8080 --web-hostname 0.0.0.0` 
2. Access the page on safari with `http://localhost:8080` using a brazilian keyboard (ABNT2)
3. Press "Attach to IME"
4. Type `~` (or press OPTION + U on an english keyboard)

### Expected results

Flutter generates a single delta or a single call to `updateEditingValueWithDeltas` with two deltas.

### Actual results

Flutter calls `updateEditingValueWithDeltas` with an insertion delta and then calls `updateEditingValueWithDeltas` again with a non-text delta.

### Code sample

<details><summary>Code sample</summary>

```dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(
    const MaterialApp(
      home: Scaffold(
        body: TextInputExample(),
      ),
    ),
  );
}

class TextInputExample extends StatefulWidget {
  const TextInputExample({Key? key}) : super(key: key);

  @override
  State<TextInputExample> createState() => _TextInputExampleState();
}

class _TextInputExampleState extends State<TextInputExample> implements DeltaTextInputClient {
  TextInputConnection? _inputConnection;
  TextEditingValue _currentEditingValue = TextEditingValue(
    text: 'Type ~: ',
    selection: TextSelection.collapsed(offset: 8),
  );
  FocusNode _focusNode = FocusNode();

  @override
  void dispose() {
    _focusNode.dispose();
    super.dispose();
  }

  @override
  void updateEditingValueWithDeltas(List<TextEditingDelta> textEditingDeltas) {
    print('Received ${textEditingDeltas.length} deltas');
    TextEditingValue newEditingValue = _currentEditingValue;

    for (final delta in textEditingDeltas) {
      print(delta);
      newEditingValue = delta.apply(newEditingValue);
    }

    setState(() {
      _currentEditingValue = newEditingValue;
    });
  }

  void _run() {
    _detach();
    _attach();
  }

  void _attach() {
    if (_inputConnection != null) {
      return;
    }
    _inputConnection = TextInput.attach(
      this,
      const TextInputConfiguration(
        enableDeltaModel: true,
        inputType: TextInputType.multiline,
        textCapitalization: TextCapitalization.sentences,
        inputAction: TextInputAction.newline,
        keyboardAppearance: Brightness.light,
      ),
    );
    _inputConnection!.show();
    _inputConnection!.setEditingState(_currentEditingValue);
  }

  void _detach() {
    _inputConnection?.close();
    _inputConnection = null;
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Focus(
            focusNode: _focusNode,
            autofocus: true,
            child: Text(
              _currentEditingValue.toString(),
              textAlign: TextAlign.center,
            ),
          ),
          ElevatedButton(
            onPressed: _run,
            child: const Text('Attach to IME'),
          ),
        ],
      ),
    );
  }

  @override
  void connectionClosed() {}

  @override
  AutofillScope? get currentAutofillScope => null;

  @override
  TextEditingValue? get currentTextEditingValue => null;

  @override
  void insertTextPlaceholder(Size size) {}

  @override
  void performAction(TextInputAction action) {}

  @override
  void performPrivateCommand(String action, Map<String, dynamic> data) {}

  @override
  void removeTextPlaceholder() {}

  @override
  void showAutocorrectionPromptRect(int start, int end) {}

  @override
  void showToolbar() {}

  @override
  void updateEditingValue(TextEditingValue value) {}

  @override
  void updateFloatingCursor(RawFloatingCursorPoint point) {}

  @override
  void didChangeInputControl(TextInputControl? oldControl, TextInputControl? newControl) {}

  @override
  void insertContent(KeyboardInsertedContent content) {}

  @override
  void performSelector(String selectorName) {}
}
```

</details>


### Screenshots or Video

_No response_

### Logs

<details><summary>Logs</summary>

```console
[Log] Received 1 deltas (dart_sdk.js, line 29632)
[Log] TextEditingDeltaInsertion#978a0(oldText: Type ~:, textInserted: ~, insertionOffset: 8, selection: TextSelection(baseOffset: 8, extentOffset: 9, isDirectional: false), composing: TextRange(start: 8, end: 9)) (dart_sdk.js, line 29632)
[Log] Received 1 deltas (dart_sdk.js, line 29632)
[Log] TextEditingDeltaNonTextUpdate#f1345(oldText: Type ~: ~, selection: TextSelection.collapsed(offset: 9, affinity: TextAffinity.downstream, isDirectional: false), composing: TextRange(start: 8, end: 9)) (dart_sdk.js, line 29632)
```

</details>


### Flutter Doctor output

<details><summary>Doctor output</summary>

```console
[✓] Flutter (Channel master, 3.14.0-14.0.pre.93, on macOS 13.5.1 22G90 darwin-arm64, locale pt-BR)
    • Flutter version 3.14.0-14.0.pre.93 on channel master at /Users/angelosilvestre/dev/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision ef9befc9da (2 days ago), 2023-09-03 11:23:20 -0700
    • Engine revision fbc6f4a540
    • Dart version 3.2.0 (build 3.2.0-131.0.dev)
    • DevTools version 2.27.0

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/angelosilvestre/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.3.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14E300c
    • CocoaPods version 1.12.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)

[✓] VS Code (version 1.81.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.70.0

[✓] Connected device (3 available)
    • iPhone 14 Pro (mobile) • AD5DBB2E-DE25-40C9-9346-CE61E9971B76 • ios            •
      com.apple.CoreSimulator.SimRuntime.iOS-16-4 (simulator)
    • macOS (desktop)        • macos                                • darwin-arm64   • macOS
      13.5.1 22G90 darwin-arm64
    • Chrome (web)           • chrome                               • web-javascript • Google
      Chrome 116.0.5845.140

[✓] Network resources
    • All expected network resources are available.

• No issues found!
```

</details>