Skip to content

CupertinoTextSelectionToolbar doesn't work on web with HTML renderer #123560

@justinmc

Description

@justinmc

Path.combine isn't supported by the HTML renderer according to #44572, but CupertinoTextSelectionToolbar uses it:

return Path.combine(PathOperation.union, rrect, arrow);

We should either fix Path.combine on the HTML renderer, or migrate to something else for CupertinoTextSelectionToolbar.

Impact

By default, web uses the browser's context menus, so this bug will only ever appear to users that have disabled the browser context menu (recently possible with #118194). For that reason, this issue is unlikely to affect most users.

Steps to reproduce

  1. On web with the HTML renderer (`flutter run -d chrome --web-renderer=html), either run the app below, or run an app with a text field and show the context menu (iOS).

Expected: The iOS context menu is shown.
Actual: An error occurs.

Demo app
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        appBar: AppBar(
          title: const Text("Demo"),
        ),
        body: Center(
          child: CupertinoTextSelectionToolbar(
            anchorAbove: Offset.zero,
            anchorBelow: Offset.zero,
            children: const <Widget>[
              Text('Hello World'),
            ],
          ),
        ),
      ),
    );
  }
}
Error
══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
The following UnimplementedError was thrown during paint():
combinePaths not implemented in HTML renderer.

The relevant error-causing widget was:
  CupertinoTextSelectionToolbar
  CupertinoTextSelectionToolbar:file:///usr/local/google/home/jmccandless/Projects/issues/sandbox/lib/main.dart:20:18

When the exception was thrown, this was the stack:
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 288:49  throw_
lib/_engine/engine/html/renderer.dart 222:5                                   combinePaths
lib/ui/path.dart 54:21                                                        combine
packages/flutter/src/cupertino/text_selection_toolbar.dart 353:17             [_clipPath]
packages/flutter/src/cupertino/text_selection_toolbar.dart 367:7              paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 169:10                             _repaintCompositedChild
packages/flutter/src/rendering/object.dart 112:5                              repaintCompositedChild
packages/flutter/src/rendering/object.dart 264:7                              [_compositeChild]
packages/flutter/src/rendering/object.dart 245:7                              paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/proxy_box.dart 2338:11                         paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/shifted_box.dart 74:14                         paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/shifted_box.dart 74:14                         paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/shifted_box.dart 74:14                         paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/box.dart 2879:14                               defaultPaint
packages/flutter/src/rendering/custom_layout.dart 408:5                       paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/material/material.dart 664:11                            paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/proxy_box.dart 2076:15                         <fn>
packages/flutter/src/rendering/object.dart 562:14                             pushClipRRect
packages/flutter/src/rendering/proxy_box.dart 2063:20                         paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 169:10                             _repaintCompositedChild
packages/flutter/src/rendering/object.dart 112:5                              repaintCompositedChild
packages/flutter/src/rendering/object.dart 264:7                              [_compositeChild]
packages/flutter/src/rendering/object.dart 245:7                              paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/material/page_transitions_theme.dart 995:23              paint
packages/flutter/src/widgets/snapshot_widget.dart 335:15                      paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/material/page_transitions_theme.dart 923:23              paint
packages/flutter/src/widgets/snapshot_widget.dart 335:15                      paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/material/page_transitions_theme.dart 995:23              paint
packages/flutter/src/widgets/snapshot_widget.dart 335:15                      paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/material/page_transitions_theme.dart 923:23              paint
packages/flutter/src/widgets/snapshot_widget.dart 335:15                      paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 169:10                             _repaintCompositedChild
packages/flutter/src/rendering/object.dart 112:5                              repaintCompositedChild
packages/flutter/src/rendering/object.dart 264:7                              [_compositeChild]
packages/flutter/src/rendering/object.dart 245:7                              paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/proxy_box.dart 3771:11                         paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/widgets/overlay.dart 860:14                              paint
packages/flutter/src/widgets/overlay.dart 1120:13                             paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/custom_paint.dart 618:11                       paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/proxy_box.dart 146:14                          paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 253:12                             paintChild
packages/flutter/src/rendering/view.dart 213:14                               paint
packages/flutter/src/rendering/object.dart 3059:7                             [_paintWithContext]
packages/flutter/src/rendering/object.dart 169:10                             _repaintCompositedChild
packages/flutter/src/rendering/object.dart 112:5                              repaintCompositedChild
packages/flutter/src/rendering/object.dart 1147:31                            flushPaint
packages/flutter/src/rendering/binding.dart 494:19                            drawFrame
packages/flutter/src/widgets/binding.dart 895:13                              drawFrame
packages/flutter/src/rendering/binding.dart 358:5                             [_handlePersistentFrameCallback]
packages/flutter/src/scheduler/binding.dart 1284:15                           [_invokeFrameCallback]
packages/flutter/src/scheduler/binding.dart 1214:9                            handleDrawFrame
The Flutter DevTools debugger and profiler on Chrome is available at: http://127.0.0.1:9100?uri=http://127.0.0.1:45743/60Ub34m_MzY=
packages/flutter/src/scheduler/binding.dart 939:7                             <fn>
dart-sdk/lib/_internal/js_dev_runtime/private/isolate_helper.dart 48:19       internalCallback

The following RenderObject was being processed when the exception was fired: _RenderCupertinoTextSelectionToolbarShape#a6eca relayoutBoundary=up5:
  needs compositing
  creator: _CupertinoTextSelectionToolbarShape ← DecoratedBox ← _CupertinoTextSelectionToolbarContent
    ← CustomSingleChildLayout ← Padding ← CupertinoTextSelectionToolbar ← Center ←
    KeyedSubtree-[GlobalKey#7ecfb] ← _BodyBuilder ← MediaQuery ← LayoutId-[<_ScaffoldSlot.body>] ←
    CustomMultiChildLayout ← ⋯
  parentData: <none> (can use size)
  constraints: BoxConstraints(0.0<=w<=1845.0, 0.0<=h<=1894.0)
  layer: OffsetLayer#2a5ab DETACHED
  size: Size(72.0, 43.0)
This RenderObject had the following descendants (showing up to depth 5):
    child: RenderDecoratedBox#b02f3 relayoutBoundary=up6 NEEDS-PAINT
      child: RenderAnimatedOpacity#d415c relayoutBoundary=up7 NEEDS-PAINT
        child: _RenderCupertinoTextSelectionToolbarItems#b39da relayoutBoundary=up8 NEEDS-PAINT
          back button: RenderMouseRegion#715dc relayoutBoundary=up9 NEEDS-PAINT
            child: RenderSemanticsGestureHandler#e3eda relayoutBoundary=up10 NEEDS-PAINT
          next button: RenderMouseRegion#0aab7 relayoutBoundary=up9 NEEDS-PAINT
            child: RenderSemanticsGestureHandler#c312e relayoutBoundary=up10 NEEDS-PAINT
          next button disabled: RenderMouseRegion#ebb00 relayoutBoundary=up9 NEEDS-PAINT
            child: RenderSemanticsGestureHandler#009b1 relayoutBoundary=up10 NEEDS-PAINT
          menu item: RenderParagraph#54494 relayoutBoundary=up9 NEEDS-PAINT
            text: TextSpan
════════════════════════════════════════════════════════════════════════════════════════════════════

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work lista: text inputEntering text in a text field or keyboard related problemse: web_htmlHTML rendering backend for Webf: cupertinoflutter/packages/flutter/cupertino repositoryfound in release: 3.7Found to occur in 3.7found in release: 3.9Found to occur in 3.9frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-webWeb applications specificallyr: solvedIssue is closed as solvedteam-webOwned by Web platform teamtriaged-webTriaged by Web platform team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions