Skip to content

Path.combine not implemented in the HTML backend #44572

@eugene-kalaganov

Description

@eugene-kalaganov

this code below works fine on flutter mobile
but on web it throws an error

import 'package:flutter/material.dart';

void main() => runApp(App());

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: SafeArea(
          child: Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                UnicornOutlineButton(
                  strokeWidth: 2,
                  radius: 24,
                  gradient: LinearGradient(colors: [Colors.black, Colors.redAccent]),
                  child: Text('OMG', style: TextStyle(fontSize: 16)),
                  onPressed: () {},
                ),
                SizedBox(width: 0, height: 24),
                UnicornOutlineButton(
                  strokeWidth: 4,
                  radius: 16,
                  gradient: LinearGradient(
                    colors: [Colors.blue, Colors.yellow],
                    begin: Alignment.topCenter,
                    end: Alignment.bottomCenter,
                  ),
                  child: Text('Wow', style: TextStyle(fontSize: 16)),
                  onPressed: () {},
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class UnicornOutlineButton extends StatelessWidget {
  final _GradientPainter _painter;
  final Widget _child;
  final VoidCallback _callback;
  final double _radius;

  UnicornOutlineButton({
    @required double strokeWidth,
    @required double radius,
    @required Gradient gradient,
    @required Widget child,
    @required VoidCallback onPressed,
  })  : this._painter = _GradientPainter(strokeWidth: strokeWidth, radius: radius, gradient: gradient),
        this._child = child,
        this._callback = onPressed,
        this._radius = radius;

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: _painter,
      child: GestureDetector(
        behavior: HitTestBehavior.translucent,
        onTap: _callback,
        child: InkWell(
          borderRadius: BorderRadius.circular(_radius),
          onTap: _callback,
          child: Container(
            constraints: BoxConstraints(minWidth: 88, minHeight: 48),
            child: Row(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                _child,
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class _GradientPainter extends CustomPainter {
  final Paint _paint = Paint();
  final double radius;
  final double strokeWidth;
  final Gradient gradient;

  _GradientPainter({@required double strokeWidth, @required double radius, @required Gradient gradient})
      : this.strokeWidth = strokeWidth,
        this.radius = radius,
        this.gradient = gradient;

  @override
  void paint(Canvas canvas, Size size) {
    // create outer rectangle equals size
    Rect outerRect = Offset.zero & size;
    var outerRRect = RRect.fromRectAndRadius(outerRect, Radius.circular(radius));

    // create inner rectangle smaller by strokeWidth
    Rect innerRect = Rect.fromLTWH(strokeWidth, strokeWidth, size.width - strokeWidth * 2, size.height - strokeWidth * 2);
    var innerRRect = RRect.fromRectAndRadius(innerRect, Radius.circular(radius - strokeWidth));

    // apply gradient shader
    _paint.shader = gradient.createShader(outerRect);

    // create difference between outer and inner paths and draw it
    Path path1 = Path()..addRRect(outerRRect);
    Path path2 = Path()..addRRect(innerRRect);
    var path = Path.combine(PathOperation.difference, path1, path2);
    canvas.drawPath(path, _paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => oldDelegate != this;
}

here is full log

Performing hot restart...
Reloaded application in 423ms.
══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
The following UnimplementedError was thrown during paint():
UnimplementedError

The relevant error-causing widget was:
CustomPaint org-dartlang-app:///packages/mywebapp/main.dart:64:12

When the exception was thrown, this was the stack:
package:dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 194:49  throw_
package:build_web_compilers/lib/ui/src/ui/canvas.dart 2200:5                          combine
package:mywebapp/main.dart 115:21                                                     paint
package:flutter/src/rendering/custom_paint.dart 531:12                                [_paintWithPainter]
package:flutter/src/rendering/custom_paint.dart 572:7                                 paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/box.dart 2508:14                                        defaultPaint
package:flutter/src/rendering/flex.dart 948:7                                         paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/shifted_box.dart 70:14                                  paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/shifted_box.dart 70:14                                  paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/box.dart 2508:14                                        defaultPaint
package:flutter/src/rendering/custom_layout.dart 396:5                                paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/proxy_box.dart 123:14                                   paint
package:flutter/src/material/material.dart 530:11                                     paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/proxy_box.dart 123:14                                   paint
package:flutter/src/rendering/object.dart 384:12                                      pushLayer
package:flutter/src/rendering/proxy_box.dart 1757:14                                  paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/proxy_box.dart 123:14                                   paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/proxy_box.dart 123:14                                   paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 135:10                                      _repaintCompositedChild
package:flutter/src/rendering/object.dart 95:5                                        repaintCompositedChild
package:flutter/src/rendering/object.dart 201:7                                       [_compositeChild]
package:flutter/src/rendering/object.dart 182:7                                       paintChild
package:flutter/src/rendering/proxy_box.dart 123:14                                   paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/proxy_box.dart 921:16                                   paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/proxy_box.dart 123:14                                   paint
package:flutter/src/rendering/proxy_box.dart 2464:13                                  paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/proxy_box.dart 123:14                                   paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 135:10                                      _repaintCompositedChild
package:flutter/src/rendering/object.dart 95:5                                        repaintCompositedChild
package:flutter/src/rendering/object.dart 201:7                                       [_compositeChild]
package:flutter/src/rendering/object.dart 182:7                                       paintChild
package:flutter/src/rendering/proxy_box.dart 123:14                                   paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/proxy_box.dart 123:14                                   paint
package:flutter/src/rendering/proxy_box.dart 3174:11                                  paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/box.dart 2508:14                                        defaultPaint
package:flutter/src/rendering/stack.dart 589:5                                        paintStack
package:flutter/src/rendering/stack.dart 597:7                                        paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/proxy_box.dart 123:14                                   paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/proxy_box.dart 123:14                                   paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/proxy_box.dart 123:14                                   paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/proxy_box.dart 123:14                                   paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/proxy_box.dart 123:14                                   paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/proxy_box.dart 123:14                                   paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 184:12                                      paintChild
package:flutter/src/rendering/view.dart 210:14                                        paint
package:flutter/src/rendering/object.dart 2211:7                                      [_paintWithContext]
package:flutter/src/rendering/object.dart 135:10                                      _repaintCompositedChild
package:flutter/src/rendering/object.dart 95:5                                        repaintCompositedChild
package:flutter/src/rendering/object.dart 937:29                                      flushPaint
package:flutter/src/rendering/binding.dart 346:19                                     drawFrame
package:flutter/src/widgets/binding.dart 774:13                                       drawFrame
package:flutter/src/rendering/binding.dart 283:5                                      [_handlePersistentFrameCallback]
package:flutter/src/scheduler/binding.dart 1101:15                                    [_invokeFrameCallback]
package:flutter/src/scheduler/binding.dart 1040:9                                     handleDrawFrame
package:flutter/src/scheduler/binding.dart 849:7                                      <fn>
package: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: RenderCustomPaint#dc268 relayoutBoundary=up4:
creator: CustomPaint ← UnicornOutlineButton ← Column ← Center ← MediaQuery ← Padding ← SafeArea ←
_BodyBuilder ← MediaQuery ← LayoutId-[<_ScaffoldSlot.body>] ← CustomMultiChildLayout ←
AnimatedBuilder ← ⋯
parentData: offset=Offset(0.0, 0.0); flex=null; fit=null (can use size)
constraints: BoxConstraints(0.0<=w<=1920.0, 0.0<=h<=Infinity)
size: Size(88.0, 48.0)
This RenderObject had the following descendants (showing up to depth 5):
child: RenderSemanticsGestureHandler#078b7 relayoutBoundary=up5 NEEDS-PAINT
child: RenderPointerListener#fd406 relayoutBoundary=up6 NEEDS-PAINT
child: RenderSemanticsAnnotations#9008b relayoutBoundary=up7 NEEDS-PAINT
child: RenderMouseRegion#dec56 relayoutBoundary=up8 NEEDS-PAINT
child: RenderSemanticsGestureHandler#cea3a relayoutBoundary=up9 NEEDS-PAINT
════════════════════════════════════════════════════════════════════════════════════════════════════
Another exception was thrown: UnimplementedError

if I commented this line, everything if ok and working fine, but I need subtract one path from another. Actually all path operations are throwing errors on flutter web.
var path = Path.combine(PathOperation.difference, path1, path2);

Tried on MAC Catalina and Windows 10.

flutter doctor -v

    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 3.5)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 40.2.2
    • Dart plugin version 191.8593
    • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)

[✓] Connected device (2 available)
    • Chrome     • chrome     • web-javascript • Google Chrome 78.0.3904.97
    • Web Server • web-server • web-javascript • Flutter Tools

• No issues found!

my original post on SO https://stackoverflow.com/questions/55395641/outlined-transparent-button-with-gradient-border-in-flutter/55638138

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Issues that are less important to the Flutter projecta: imagesLoading, displaying, rendering imagesc: crashStack traces logged to the consolecustomer: crowdAffects or could affect many people, though not necessarily a specific customer.customer: thrivecustomer: web10e: web_htmlHTML rendering backend for Webfound in release: 3.13Found to occur in 3.13found in release: 3.17Found to occur in 3.17frameworkflutter/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 teamteam: skip-testAn issue used to track tests that are skipped.triaged-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