Repository: flutter
Issue: WidgetSpan wrong caret position
Labels: a: text input,framework,f: material design,a: typography,has reproducible steps,P3,found in release: 3.0,found in release: 3.1,team-design,triaged-design

# Steps to Reproduce

Type the word "widget" inside the text field.

Expected results:
The caret reflects the correct position.

Actual results:
The caret is moved in a wrong position (probably the x - size of the widget span)

<details>

<summary>Code sample:</summary>

```
import 'package:flutter/material.dart';

void main() {
  runApp(const InputExample());
}

class InputExample extends StatefulWidget {
  const InputExample({Key? key}) : super(key: key);

  @override
  State<InputExample> createState() => _InputExampleState();
}

class _InputExampleState extends State<InputExample> {

  late final WidgetSpanTextFieldController titleController;

  @override
  void initState() {
    titleController = WidgetSpanTextFieldController();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Input Example'),
        ),
        body: Container(
          padding: const EdgeInsets.all(16),
          child: _title(context),
        ),
      ),
    );
  }

  Widget _title(BuildContext context) {
    return TextField(
      controller: titleController,
      textCapitalization: TextCapitalization.none,
      maxLines: null,
      keyboardType: TextInputType.multiline,
      decoration: const InputDecoration(hintText: "Type here"),
      cursorWidth: 5,
      cursorColor: Colors.orange,
      style: const TextStyle(
        color: Colors.black,
        fontSize: 20,
        fontWeight: FontWeight.w500,
      ),
    );
  }
}

class WidgetSpanTextFieldController extends TextEditingController {
  WidgetSpanTextFieldController();

  @override
  TextSpan buildTextSpan({
    required BuildContext context,
    TextStyle? style,
    required bool withComposing,
  }) {
    TextRange? matchedRange;

    if (text.contains("widget")) {
      matchedRange = _findMatchedRange(text);
    }

    if (matchedRange != null) {
      return TextSpan(
        children: [
          _textSpan(matchedRange.textBefore(text)),
          _widgetSpan(matchedRange.textInside(text)),
          _textSpan(matchedRange.textAfter(text)),
        ],
        style: style,
      );
    }

    return TextSpan(text: text, style: style);
  }

  TextRange _findMatchedRange(String text) {
    final RegExp matchPattern = RegExp('widget', caseSensitive: false);
    late TextRange matchedRange;

    for (final Match match in matchPattern.allMatches(text)) {
      matchedRange = TextRange(start: match.start, end: match.end);
    }

    return matchedRange;
  }

  WidgetSpan _widgetSpan(String text) {
    return WidgetSpan(
      alignment: PlaceholderAlignment.middle,
      child: Container(
          height: 20,
          padding: const EdgeInsets.symmetric(horizontal: 5),
          decoration: BoxDecoration(
            color: Colors.redAccent,
            borderRadius: BorderRadius.circular(3),
          ),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                text,
                style: const TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.w500,
                  fontSize: 17,
                ),
              ),
            ],
          )),
    );
  }

  TextSpan _textSpan(String text) {
    return TextSpan(text: text);
  }
}

```

</details>

Tested on master and stable channels.

Video:

https://user-images.githubusercontent.com/12783325/178372128-f8070105-f88f-4843-909b-15cd5b7aa7a2.mov