Repository: flutter
Issue: [Web] Position emoji picker when using multiple styles
Labels: a: text input,engine,platform-web,has reproducible steps,P2,team-web,triaged-web,found in release: 3.13,found in release: 3.14

To be able to interact with native input controls, like emoji pickers, accent panels, etc, we need to talk to the IME to set the editable size, transform and the caret rect.

However, on web, calling `setCaretRect` does nothing. Looking at the engine code, it looks like `setCaretRect` is a no-op:

```dart
class TextInputSetCaretRect extends TextInputCommand {
  const TextInputSetCaretRect();

  @override
  void run(HybridTextEditing textEditing) {
    // No-op: not supported on this platform.
  }
}
```

Flutter's `Editable` text seems to position the input controls by only setting the editable size and transform and the text style. I assume Flutter just sets the style in the native input element and lets the browser figure out where to position the input controls.

This is a problem for `SuperTextField`, because we support multiple styles in a single text field. If a single style is used, the panels are displayed at the correct position. However, if we use different font sizes, the panels are displayed at wrong positions:


https://github.com/flutter/flutter/assets/7597082/9713d1e0-4000-4f41-9fc6-0b45d331459d

Is there a way to correctly position these panels when using multiple styles?

### Steps to reproduce

1. Run the sample code on web (don't resize the window or move it around, because the editable size won't be updated)
2. Press and hold "a" until the accent panel is displayed

### Expected results

The accent panel should be displayed just before the word "open"

### Actual results

The accent panel is displayed at the word "Editor".  Tap "Switch" to see the accent panel being displayed at the expected position.

### 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: 'Super Editor is an open source text editor for Flutter projects',
    // The selection sits at "is an |open"
    selection: TextSelection.collapsed(offset: 20),
  );

  FocusNode _focusNode = FocusNode();

  GlobalKey _textKey = GlobalKey();

  bool _showRichText = true;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      _attach();
    });
  }

  @override
  void dispose() {
    _focusNode.dispose();
    super.dispose();
  }

  @override
  void updateEditingValueWithDeltas(List<TextEditingDelta> textEditingDeltas) {
    // Lock the current value.
    _inputConnection!.setEditingState(_currentEditingValue);
  }

  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,
      ),
    );

    final renderBox = _textKey.currentContext!.findRenderObject() as RenderBox;

    _inputConnection!
      ..show()
      ..setEditingState(_currentEditingValue)
      ..setEditableSizeAndTransform(renderBox.size, renderBox.getTransformTo(null))
      ..setStyle(
        fontFamily: 'Roboto',
        fontWeight: FontWeight.normal,
        fontSize: 24,
        textDirection: TextDirection.ltr,
        textAlign: TextAlign.left,
      );
  }

  @override
  Widget build(BuildContext context) {
    return Actions(
      actions: {
        // Prevent Flutter from using the arrow keys to perform focus traversal.
        DoNothingAndStopPropagationTextIntent: DoNothingAction(consumesKey: false),
      },
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Focus(
            focusNode: _focusNode,
            autofocus: true,
            child: _buildText(),
          ),
          ElevatedButton(
            onPressed: () {
              setState(() {
                _showRichText = !_showRichText;
              });
            },
            child: Text('Switch'),
          ),
        ],
      ),
    );
  }

  Widget _buildText() {
    return _showRichText ? _buildRichText() : _buildPlainText();
  }

  Widget _buildPlainText() {
    return Text(
      _currentEditingValue.text,
      key: _textKey,
      textAlign: TextAlign.center,
      style: TextStyle(
        fontFamily: 'Roboto',
        fontWeight: FontWeight.normal,
        fontSize: 24,
      ),
    );
  }

  Widget _buildRichText() {
    return RichText(
      key: _textKey,
      text: TextSpan(
        text: 'Super Editor',
        style: TextStyle(
          fontFamily: 'Roboto',
          fontWeight: FontWeight.normal,
          fontSize: 40,
          color: Colors.red,
        ),
        children: [
          TextSpan(
            text: ' is an open source text eidtor for Flutter projects',
            style: TextStyle(
              fontFamily: 'Roboto',
              fontWeight: FontWeight.normal,
              fontSize: 24,
              color: Colors.black,
            ),
          ),
        ],
      ),
    );
  }

  @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) {}
}

```