Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Web]: App crashes after selecting a text that contains emojis in it. Throws "Bad UTF-8 encoding found while decoding string:" #79105

Closed
delay opened this issue Mar 26, 2021 · 4 comments
Assignees
Labels
a: typography Text rendering, possibly libtxt assigned for triage issue is assigned to a domain expert for further triage c: fatal crash Crashes that terminate the process found in release: 2.1 Found to occur in 2.1 has reproducible steps The issue has been confirmed reproducible and is ready to work on P1 High-priority issues at the top of the work list platform-web Web applications specifically r: fixed Issue is closed as already fixed in a newer version team-web Owned by Web platform team

Comments

@delay
Copy link

delay commented Mar 26, 2021

My app is crashing when I print a string with an emoji in it. This problem is only able to be duplicated with flutter web. The error message on crash is: Bad UTF-8 encoding found while decoding string: Here is a project which reproduces the issue.

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(
          text:
              '😄 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
          style: TextStyle(color: Colors.black45, fontSize: 18)),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.text, this.style}) : super(key: key);

  final String text;
  final TextStyle style;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _textKey = GlobalKey();
  final List<Rect> _textRects = [];
  final List<Rect> _selectionRects = [];
  String selectedText = '';
  Rect _caretRect = Rect.zero;
  MouseCursor _cursor = SystemMouseCursors.basic;
  int _selectionBaseOffset;
  TextSelection _textSelection = TextSelection.collapsed(offset: -1);
  @override
  initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      _updateAllTextRects();
    });
  }

  void _onMouseMove(event) {
    if (event is PointerHoverEvent) {
      if (_renderParagraph == null) {
        return;
      }
      final allTextRects = _computeRectsForSelection(
        TextSelection(baseOffset: 0, extentOffset: widget.text.length),
      );
      bool isOverText = false;
      for (final rect in allTextRects) {
        if (rect.contains(event.localPosition)) {
          isOverText = true;
        }
      }
      final newCursor =
          isOverText ? SystemMouseCursors.text : SystemMouseCursors.basic;
      if (newCursor != _cursor) {
        setState(() {
          _cursor = newCursor;
        });
      }
    }
  }

  void _updateAllTextRects() {
    setState(() {
      _textRects
        ..clear()
        ..addAll(_computeRectsForSelection(
            TextSelection(baseOffset: 0, extentOffset: widget.text.length)));
    });
  }

  List<Rect> _computeRectsForSelection(TextSelection textSelection) {
    if (_renderParagraph == null) {
      return [];
    }
    final textBoxes = _renderParagraph.getBoxesForSelection(textSelection);
    return textBoxes.map((box) => box.toRect()).toList();
  }

  RenderParagraph get _renderParagraph =>
      _textKey.currentContext.findRenderObject() as RenderParagraph;

  void _onPanStart(DragStartDetails details) {
    if (_renderParagraph == null) {
      return;
    }
    _selectionBaseOffset =
        _renderParagraph.getPositionForOffset(details.localPosition).offset;
    _textSelection = TextSelection.collapsed(offset: _selectionBaseOffset);
    _updateSelectionDisplay();
  }

  void _updateSelectionDisplay() {
    //Compute selection rectangles
    final selectionRects = _computeRectsForSelection(_textSelection);
    //Update caret display
    final caretOffset =
        _renderParagraph.getOffsetForCaret(_textSelection.extent, Rect.zero);
    final caretHeight =
        _renderParagraph.getFullHeightForCaret(_textSelection.extent);
    setState(() {
      _selectionRects
        ..clear()
        ..addAll(selectionRects);
      _caretRect =
          Rect.fromLTWH(caretOffset.dx - 1, caretOffset.dy, 2, caretHeight);
      // widget.onSelectionChange?.call(_textSelection);
      selectedText = _textSelection.textInside(widget.text);
      print('selectedText: ' + selectedText.toString());
    });
  }

  void _onPanUpdate(DragUpdateDetails details) {
    final selectionExtentOffset =
        _renderParagraph.getPositionForOffset(details.localPosition).offset;
    _textSelection = TextSelection(
        baseOffset: _selectionBaseOffset, extentOffset: selectionExtentOffset);
    _updateSelectionDisplay();
  }

  void _onPanEnd(DragEndDetails details) {}
  void _onPanCancel() {}

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          Container(
            color: Colors.white,
            child: Center(
              child: Listener(
                onPointerHover: _onMouseMove,
                child: MouseRegion(
                  cursor: _cursor,
                  child: GestureDetector(
                    onPanStart: _onPanStart,
                    onPanUpdate: _onPanUpdate,
                    onPanEnd: _onPanEnd,
                    onPanCancel: _onPanCancel,
                    child: Stack(
                      children: [
                        CustomPaint(
                          painter: _SelectionPainter(
                              color: Colors.yellow,
                              rects: _selectionRects,
                              fill: true),
                        ),
                        CustomPaint(
                          painter: _SelectionPainter(
                              color: Colors.grey,
                              rects: _textRects,
                              fill: false),
                        ),
                        Text(widget.text, key: _textKey, style: widget.style),
                        CustomPaint(
                          painter: _SelectionPainter(
                              color: Colors.blue,
                              rects: [_caretRect],
                              fill: true),
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            ),
          ),
          Text(selectedText, style: widget.style),
        ],
      ),
    );
  }
}

class _SelectionPainter extends CustomPainter {
  _SelectionPainter({
    @required Color color,
    @required List<Rect> rects,
    bool fill = true,
  })  : _color = color,
        _rects = rects,
        _fill = fill,
        _paint = Paint()..color = color;

  final Color _color;
  final List<Rect> _rects;
  final bool _fill;
  Paint _paint;

  @override
  void paint(Canvas canvas, Size size) {
    //a rectangle
    if (_fill == false) {
      //make an outline of rectangle
      _paint = Paint()
        ..color = _color
        ..style = PaintingStyle.stroke;
    }
    for (Rect _rect in _rects) {
      canvas.drawRect(_rect, _paint);
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return true;
  }
}

Steps to Reproduce

  1. in the above project flutter run -d chrome for web. It works fine in iOS.
  2. Select some text in the app with your mouse cursor. Once you include the emoji in your selection it will crash.
  3. If you comment out the print('selectedText: ' + selectedText.toString()); and then re-run the app, it will then select the emoji without any problems in the app.
  4. This problem is only able to be duplicated with flutter web. The error message on crash is: Bad UTF-8 encoding found while decoding string:
  5. I am using VSCode, I don't think this would make a difference, but since it is console output that is crashing, I thought I would mention it.
@darshankawar darshankawar added the in triage Presently being triaged by the triage team label Mar 26, 2021
@darshankawar
Copy link
Member

Thanks @delay for reporting this with details and reproducible code. I see the same behavior after selecting text + emoji, using canvaskit and html renderers. The app crashes as soon as we select emoji.

crash log
selectedText: Lorem ipsum
selectedText: Lorem ipsum
selectedText: Lorem ipsum
selectedText:  Lorem ipsum
Bad UTF-8 encoding found while decoding string: selectedText: � Lorem ipsum
. The Flutter team would greatly appreciate if you could file a bug explaining exactly what you were doing when this happened:
https://github.com/flutter/flutter/issues/new/choose
The source bytes were:
[115, 101, 108, 101, 99, 116, 101, 100, 84, 101, 120, 116, 58, 32, 239, 191, 189, 32, 76, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109, 10]

flutter doctor -v
[✓] Flutter (Channel beta, 2.1.0-12.2.pre, on Mac OS X 10.15.4 19E2269
    darwin-x64, locale en-GB)
    • Flutter version 2.1.0-12.2.pre at /Users/dhs/documents/Fluttersdk/flutter
    • Framework revision 5bedb7b1d5 (8 days ago), 2021-03-17 17:06:30 -0700
    • Engine revision 711ab3fda0
    • Dart version 2.13.0 (build 2.13.0-116.0.dev)

[!] Xcode - develop for iOS and macOS
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 12.3, Build version 12C33
    ! CocoaPods 1.9.3 out of date (1.10.0 is recommended).
        CocoaPods is used to retrieve the iOS and macOS platform side's plugin
        code that responds to your plugin usage on the Dart side.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/platform-plugins
      To upgrade see
      https://guides.cocoapods.org/using/getting-started.html#installation for
      instructions.

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] VS Code (version 1.54.3)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.20.0

[✓] Connected device (3 available)
    • iPhone 12 Pro Max (mobile) • A5473606-0213-4FD8-BA16-553433949729 • ios
      • com.apple.CoreSimulator.SimRuntime.iOS-14-3 (simulator)
    • macOS (desktop)            • macos                                •
      darwin-x64     • Mac OS X 10.15.4 19E2269 darwin-x64
    • Chrome (web)               • chrome                               •
      web-javascript • Google Chrome 89.0.4389.90

! Doctor found issues in 1 category.

@darshankawar darshankawar changed the title Flutter web crashing "Bad UTF-8 encoding found while decoding string:" [Web]: App crashes after selecting a text that contains emojis in it. Throws "Bad UTF-8 encoding found while decoding string:" Mar 26, 2021
@darshankawar darshankawar added found in release: 2.1 Found to occur in 2.1 has reproducible steps The issue has been confirmed reproducible and is ready to work on platform-web Web applications specifically a: typography Text rendering, possibly libtxt c: fatal crash Crashes that terminate the process and removed in triage Presently being triaged by the triage team labels Mar 26, 2021
@yjbanov yjbanov added the assigned for triage issue is assigned to a domain expert for further triage label Apr 1, 2021
@mdebbar mdebbar removed their assignment Aug 5, 2021
@mdebbar mdebbar added the P1 High-priority issues at the top of the work list label Aug 5, 2021
@Hixie Hixie removed the assigned for triage issue is assigned to a domain expert for further triage label Feb 8, 2023
@flutter-triage-bot flutter-triage-bot bot added team-web Owned by Web platform team triaged-web Triaged by Web platform team labels Jul 8, 2023
@flutter-triage-bot
Copy link

This issue is marked P1 but has had no recent status updates.

The P1 label indicates high-priority issues that are at the top of the work list. This is the highest priority level a bug can have if it isn't affecting a top-tier customer or breaking the build. Bugs marked P1 are generally actively being worked on unless the assignee is dealing with a P0 bug (or another P1 bug). Issues at this level should be resolved in a matter of months and should have monthly updates on GitHub.

Please consider where this bug really falls in our current priorities, and label it or assign it accordingly. This allows people to have a clearer picture of what work is actually planned. Thanks!

@flutter-triage-bot flutter-triage-bot bot removed the triaged-web Triaged by Web platform team label Jul 21, 2023
@yjbanov yjbanov self-assigned this Jul 27, 2023
@yjbanov yjbanov added the assigned for triage issue is assigned to a domain expert for further triage label Jul 27, 2023
@yjbanov
Copy link
Contributor

yjbanov commented Jul 27, 2023

I just ran the sample above in debug and release modes and both work fine and can select any text with or without emoji. I'm going to consider this as fixed.

@yjbanov yjbanov closed this as completed Jul 27, 2023
@darshankawar darshankawar added the r: fixed Issue is closed as already fixed in a newer version label Jul 28, 2023
@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
a: typography Text rendering, possibly libtxt assigned for triage issue is assigned to a domain expert for further triage c: fatal crash Crashes that terminate the process found in release: 2.1 Found to occur in 2.1 has reproducible steps The issue has been confirmed reproducible and is ready to work on P1 High-priority issues at the top of the work list platform-web Web applications specifically r: fixed Issue is closed as already fixed in a newer version team-web Owned by Web platform team
Projects
None yet
Development

No branches or pull requests

5 participants