clip_test.dart 25.8 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
Ian Hickson's avatar
Ian Hickson committed
2 3 4 5 6
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
7 8 9
import 'package:flutter/rendering.dart';

import '../rendering/mock_canvas.dart';
10
import 'test_border.dart' show TestBorder;
Ian Hickson's avatar
Ian Hickson committed
11 12 13 14 15 16 17

final List<String> log = <String>[];

class PathClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    log.add('getClip');
18
    return Path()
Dan Field's avatar
Dan Field committed
19
      ..addRect(const Rect.fromLTWH(50.0, 50.0, 100.0, 100.0));
Ian Hickson's avatar
Ian Hickson committed
20 21
  }
  @override
22
  bool shouldReclip(PathClipper oldClipper) => false;
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
}

class ValueClipper<T> extends CustomClipper<T> {
  ValueClipper(this.message, this.value);

  final String message;
  final T value;

  @override
  T getClip(Size size) {
    log.add(message);
    return value;
  }

  @override
38
  bool shouldReclip(ValueClipper<T> oldClipper) {
39 40
    return oldClipper.message != message || oldClipper.value != value;
  }
Ian Hickson's avatar
Ian Hickson committed
41 42
}

43
class _UpdateCountedClipRect extends ClipRect {
44
  const _UpdateCountedClipRect({Clip clipBehavior = Clip.antiAlias})
45 46 47 48 49 50 51 52 53
    : super(clipBehavior: clipBehavior);
}

class _UpdateCountedClipRRect extends ClipRRect {
  _UpdateCountedClipRRect({Clip clipBehavior = Clip.antiAlias})
      : super(clipBehavior: clipBehavior, borderRadius: BorderRadius.circular(1.0));
}

class _UpdateCountedClipOval extends ClipOval {
54
  const _UpdateCountedClipOval({Clip clipBehavior = Clip.antiAlias})
55 56 57 58
      : super(clipBehavior: clipBehavior);
}

class _UpdateCountedClipPath extends ClipPath {
59
  const _UpdateCountedClipPath({Clip clipBehavior = Clip.antiAlias})
60 61 62
      : super(clipBehavior: clipBehavior);
}

Ian Hickson's avatar
Ian Hickson committed
63
void main() {
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
  testWidgets('ClipRect with a FittedBox child sized to zero works with semantics', (WidgetTester tester) async {
    await tester.pumpWidget(Directionality(
        textDirection: TextDirection.ltr,
        child: ClipRect(
          child: FittedBox(
            child: SizedBox.fromSize(
              size: Size.zero,
              child: Semantics(
                image: true,
                label: 'Image',
              ),
            ),
          ),
        ),
      ),
    );
    expect(find.byType(FittedBox), findsOneWidget);
  });

83
  testWidgets('ClipRect updates clipBehavior in updateRenderObject', (WidgetTester tester) async {
84
    await tester.pumpWidget(const _UpdateCountedClipRect());
85 86 87 88 89

    final RenderClipRect renderClip = tester.allRenderObjects.whereType<RenderClipRect>().first;

    expect(renderClip.clipBehavior, equals(Clip.antiAlias));

90
    await tester.pumpWidget(const _UpdateCountedClipRect(clipBehavior: Clip.hardEdge));
91 92 93 94

    expect(renderClip.clipBehavior, equals(Clip.hardEdge));
  });

95 96 97 98 99 100
  test('ClipRRect constructs with the right default values', () {
    const ClipRRect clipRRect = ClipRRect();
    expect(clipRRect.clipBehavior, equals(Clip.antiAlias));
    expect(clipRRect.borderRadius, equals(BorderRadius.zero));
  });

101 102 103 104 105 106 107 108 109 110 111 112 113
  testWidgets('ClipRRect updates clipBehavior in updateRenderObject', (WidgetTester tester) async {
    await tester.pumpWidget(_UpdateCountedClipRRect());

    final RenderClipRRect renderClip = tester.allRenderObjects.whereType<RenderClipRRect>().first;

    expect(renderClip.clipBehavior, equals(Clip.antiAlias));

    await tester.pumpWidget(_UpdateCountedClipRRect(clipBehavior: Clip.hardEdge));

    expect(renderClip.clipBehavior, equals(Clip.hardEdge));
  });

  testWidgets('ClipOval updates clipBehavior in updateRenderObject', (WidgetTester tester) async {
114
    await tester.pumpWidget(const _UpdateCountedClipOval());
115 116 117 118 119

    final RenderClipOval renderClip = tester.allRenderObjects.whereType<RenderClipOval>().first;

    expect(renderClip.clipBehavior, equals(Clip.antiAlias));

120
    await tester.pumpWidget(const _UpdateCountedClipOval(clipBehavior: Clip.hardEdge));
121 122 123 124 125

    expect(renderClip.clipBehavior, equals(Clip.hardEdge));
  });

  testWidgets('ClipPath updates clipBehavior in updateRenderObject', (WidgetTester tester) async {
126
    await tester.pumpWidget(const _UpdateCountedClipPath());
127 128 129 130 131

    final RenderClipPath renderClip = tester.allRenderObjects.whereType<RenderClipPath>().first;

    expect(renderClip.clipBehavior, equals(Clip.antiAlias));

132
    await tester.pumpWidget(const _UpdateCountedClipPath(clipBehavior: Clip.hardEdge));
133 134 135 136

    expect(renderClip.clipBehavior, equals(Clip.hardEdge));
  });

137 138
  testWidgets('ClipPath', (WidgetTester tester) async {
    await tester.pumpWidget(
139 140 141
      ClipPath(
        clipper: PathClipper(),
        child: GestureDetector(
Ian Hickson's avatar
Ian Hickson committed
142 143
          behavior: HitTestBehavior.opaque,
          onTap: () { log.add('tap'); },
144
        ),
145
      ),
Ian Hickson's avatar
Ian Hickson committed
146
    );
147
    expect(log, equals(<String>['getClip']));
Ian Hickson's avatar
Ian Hickson committed
148

149
    await tester.tapAt(const Offset(10.0, 10.0));
150
    expect(log, equals(<String>['getClip']));
Ian Hickson's avatar
Ian Hickson committed
151 152
    log.clear();

153
    await tester.tapAt(const Offset(100.0, 100.0));
154
    expect(log, equals(<String>['tap']));
Ian Hickson's avatar
Ian Hickson committed
155 156 157
    log.clear();
  });

158 159
  testWidgets('ClipOval', (WidgetTester tester) async {
    await tester.pumpWidget(
160 161
      ClipOval(
        child: GestureDetector(
Ian Hickson's avatar
Ian Hickson committed
162 163
          behavior: HitTestBehavior.opaque,
          onTap: () { log.add('tap'); },
164
        ),
165
      ),
Ian Hickson's avatar
Ian Hickson committed
166
    );
167
    expect(log, equals(<String>[]));
Ian Hickson's avatar
Ian Hickson committed
168

169
    await tester.tapAt(const Offset(10.0, 10.0));
170
    expect(log, equals(<String>[]));
Ian Hickson's avatar
Ian Hickson committed
171 172
    log.clear();

173
    await tester.tapAt(const Offset(400.0, 300.0));
174
    expect(log, equals(<String>['tap']));
Ian Hickson's avatar
Ian Hickson committed
175 176
    log.clear();
  });
177

178 179
  testWidgets('Transparent ClipOval hit test', (WidgetTester tester) async {
    await tester.pumpWidget(
180
      Opacity(
181
        opacity: 0.0,
182 183
        child: ClipOval(
          child: GestureDetector(
184 185
            behavior: HitTestBehavior.opaque,
            onTap: () { log.add('tap'); },
186 187
          ),
        ),
188
      ),
189 190 191
    );
    expect(log, equals(<String>[]));

192
    await tester.tapAt(const Offset(10.0, 10.0));
193 194 195
    expect(log, equals(<String>[]));
    log.clear();

196
    await tester.tapAt(const Offset(400.0, 300.0));
197 198 199 200
    expect(log, equals(<String>['tap']));
    log.clear();
  });

201 202
  testWidgets('ClipRect', (WidgetTester tester) async {
    await tester.pumpWidget(
203
      Align(
204
        alignment: Alignment.topLeft,
205
        child: SizedBox(
206 207
          width: 100.0,
          height: 100.0,
208
          child: ClipRect(
Dan Field's avatar
Dan Field committed
209
            clipper: ValueClipper<Rect>('a', const Rect.fromLTWH(5.0, 5.0, 10.0, 10.0)),
210
            child: GestureDetector(
211 212
              behavior: HitTestBehavior.opaque,
              onTap: () { log.add('tap'); },
213 214 215
            ),
          ),
        ),
216
      ),
217 218 219
    );
    expect(log, equals(<String>['a']));

220
    await tester.tapAt(const Offset(10.0, 10.0));
221 222
    expect(log, equals(<String>['a', 'tap']));

223
    await tester.tapAt(const Offset(100.0, 100.0));
224 225 226
    expect(log, equals(<String>['a', 'tap']));

    await tester.pumpWidget(
227
      Align(
228
        alignment: Alignment.topLeft,
229
        child: SizedBox(
230 231
          width: 100.0,
          height: 100.0,
232
          child: ClipRect(
Dan Field's avatar
Dan Field committed
233
            clipper: ValueClipper<Rect>('a', const Rect.fromLTWH(5.0, 5.0, 10.0, 10.0)),
234
            child: GestureDetector(
235 236
              behavior: HitTestBehavior.opaque,
              onTap: () { log.add('tap'); },
237 238 239
            ),
          ),
        ),
240
      ),
241 242 243 244
    );
    expect(log, equals(<String>['a', 'tap']));

    await tester.pumpWidget(
245
      Align(
246
        alignment: Alignment.topLeft,
247
        child: SizedBox(
248 249
          width: 200.0,
          height: 200.0,
250
          child: ClipRect(
Dan Field's avatar
Dan Field committed
251
            clipper: ValueClipper<Rect>('a', const Rect.fromLTWH(5.0, 5.0, 10.0, 10.0)),
252
            child: GestureDetector(
253 254
              behavior: HitTestBehavior.opaque,
              onTap: () { log.add('tap'); },
255 256 257
            ),
          ),
        ),
258
      ),
259 260 261 262
    );
    expect(log, equals(<String>['a', 'tap', 'a']));

    await tester.pumpWidget(
263
      Align(
264
        alignment: Alignment.topLeft,
265
        child: SizedBox(
266 267
          width: 200.0,
          height: 200.0,
268
          child: ClipRect(
Dan Field's avatar
Dan Field committed
269
            clipper: ValueClipper<Rect>('a', const Rect.fromLTWH(5.0, 5.0, 10.0, 10.0)),
270
            child: GestureDetector(
271 272
              behavior: HitTestBehavior.opaque,
              onTap: () { log.add('tap'); },
273 274 275
            ),
          ),
        ),
276
      ),
277 278 279 280
    );
    expect(log, equals(<String>['a', 'tap', 'a']));

    await tester.pumpWidget(
281
      Align(
282
        alignment: Alignment.topLeft,
283
        child: SizedBox(
284 285
          width: 200.0,
          height: 200.0,
286
          child: ClipRect(
Dan Field's avatar
Dan Field committed
287
            clipper: ValueClipper<Rect>('b', const Rect.fromLTWH(5.0, 5.0, 10.0, 10.0)),
288
            child: GestureDetector(
289 290
              behavior: HitTestBehavior.opaque,
              onTap: () { log.add('tap'); },
291 292 293
            ),
          ),
        ),
294
      ),
295 296 297 298
    );
    expect(log, equals(<String>['a', 'tap', 'a', 'b']));

    await tester.pumpWidget(
299
      Align(
300
        alignment: Alignment.topLeft,
301
        child: SizedBox(
302 303
          width: 200.0,
          height: 200.0,
304
          child: ClipRect(
Dan Field's avatar
Dan Field committed
305
            clipper: ValueClipper<Rect>('c', const Rect.fromLTWH(25.0, 25.0, 10.0, 10.0)),
306
            child: GestureDetector(
307 308
              behavior: HitTestBehavior.opaque,
              onTap: () { log.add('tap'); },
309 310 311
            ),
          ),
        ),
312
      ),
313 314 315
    );
    expect(log, equals(<String>['a', 'tap', 'a', 'b', 'c']));

316
    await tester.tapAt(const Offset(30.0, 30.0));
317 318
    expect(log, equals(<String>['a', 'tap', 'a', 'b', 'c', 'tap']));

319
    await tester.tapAt(const Offset(100.0, 100.0));
320 321 322
    expect(log, equals(<String>['a', 'tap', 'a', 'b', 'c', 'tap']));
  });

323 324 325
  testWidgets('debugPaintSizeEnabled', (WidgetTester tester) async {
    await tester.pumpWidget(
      const ClipRect(
326
        child: Placeholder(),
327 328 329 330
      ),
    );
    expect(tester.renderObject(find.byType(ClipRect)).paint, paints
      ..save()
Dan Field's avatar
Dan Field committed
331
      ..clipRect(rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0))
332 333 334
      ..save()
      ..path() // Placeholder
      ..restore()
335
      ..restore(),
336 337
    );
    debugPaintSizeEnabled = true;
338
    expect(tester.renderObject(find.byType(ClipRect)).debugPaint, paints
Dan Field's avatar
Dan Field committed
339
      ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0))
340
      ..paragraph(),
341 342 343
    );
    debugPaintSizeEnabled = false;
  });
344 345 346

  testWidgets('ClipRect painting', (WidgetTester tester) async {
    await tester.pumpWidget(
347 348 349
      Center(
        child: RepaintBoundary(
          child: Container(
350
            color: Colors.white,
351
            child: Padding(
352
              padding: const EdgeInsets.all(100.0),
353
              child: SizedBox(
354 355
                height: 100.0,
                width: 100.0,
356
                child: Transform.rotate(
357
                  angle: 1.0, // radians
358 359
                  child: ClipRect(
                    child: Container(
360
                      color: Colors.red,
361
                      child: Container(
362
                        color: Colors.white,
363 364 365
                        child: RepaintBoundary(
                          child: Center(
                            child: Container(
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
                              color: Colors.black,
                              height: 10.0,
                              width: 10.0,
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
    await expectLater(
      find.byType(RepaintBoundary).first,
384
      matchesGoldenFile('clip.ClipRect.png'),
385
    );
386
  }, skip: isBrowser);
387

388 389
  testWidgets('ClipRect save, overlay, and antialiasing', (WidgetTester tester) async {
    await tester.pumpWidget(
390 391
      RepaintBoundary(
        child: Stack(
392 393
          textDirection: TextDirection.ltr,
          children: <Widget>[
394
            Positioned(
395 396 397 398
              top: 0.0,
              left: 0.0,
              width: 100.0,
              height: 100.0,
399 400
              child: ClipRect(
                child: Container(
401 402 403 404 405
                  color: Colors.blue,
                ),
                clipBehavior: Clip.hardEdge,
              ),
            ),
406
            Positioned(
407 408 409 410
              top: 50.0,
              left: 50.0,
              width: 100.0,
              height: 100.0,
411
              child: Transform.rotate(
412
                angle: 1.0,
413
                child: Container(
414 415 416 417 418 419 420 421 422 423
                  color: Colors.red,
                ),
              ),
            ),
          ],
        ),
      ),
    );
    await expectLater(
      find.byType(RepaintBoundary).first,
424
      matchesGoldenFile('clip.ClipRectOverlay.png'),
425
    );
426
  }, skip: isBrowser);
427

428 429
  testWidgets('ClipRRect painting', (WidgetTester tester) async {
    await tester.pumpWidget(
430 431 432
      Center(
        child: RepaintBoundary(
          child: Container(
433
            color: Colors.white,
434
            child: Padding(
435
              padding: const EdgeInsets.all(100.0),
436
              child: SizedBox(
437 438
                height: 100.0,
                width: 100.0,
439
                child: Transform.rotate(
440
                  angle: 1.0, // radians
441
                  child: ClipRRect(
442
                    borderRadius: const BorderRadius.only(
443 444 445 446
                      topLeft: Radius.elliptical(10.0, 20.0),
                      topRight: Radius.elliptical(5.0, 30.0),
                      bottomLeft: Radius.elliptical(2.5, 12.0),
                      bottomRight: Radius.elliptical(15.0, 6.0),
447
                    ),
448
                    child: Container(
449
                      color: Colors.red,
450
                      child: Container(
451
                        color: Colors.white,
452 453 454
                        child: RepaintBoundary(
                          child: Center(
                            child: Container(
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
                              color: Colors.black,
                              height: 10.0,
                              width: 10.0,
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
    await expectLater(
      find.byType(RepaintBoundary).first,
473
      matchesGoldenFile('clip.ClipRRect.png'),
474
    );
475
  }, skip: isBrowser);
476 477 478

  testWidgets('ClipOval painting', (WidgetTester tester) async {
    await tester.pumpWidget(
479 480 481
      Center(
        child: RepaintBoundary(
          child: Container(
482
            color: Colors.white,
483
            child: Padding(
484
              padding: const EdgeInsets.all(100.0),
485
              child: SizedBox(
486 487
                height: 100.0,
                width: 100.0,
488
                child: Transform.rotate(
489
                  angle: 1.0, // radians
490 491
                  child: ClipOval(
                    child: Container(
492
                      color: Colors.red,
493
                      child: Container(
494
                        color: Colors.white,
495 496 497
                        child: RepaintBoundary(
                          child: Center(
                            child: Container(
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
                              color: Colors.black,
                              height: 10.0,
                              width: 10.0,
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
    await expectLater(
      find.byType(RepaintBoundary).first,
516
      matchesGoldenFile('clip.ClipOval.png'),
517
    );
518
  }, skip: isBrowser);
519 520 521

  testWidgets('ClipPath painting', (WidgetTester tester) async {
    await tester.pumpWidget(
522 523 524
      Center(
        child: RepaintBoundary(
          child: Container(
525
            color: Colors.white,
526
            child: Padding(
527
              padding: const EdgeInsets.all(100.0),
528
              child: SizedBox(
529 530
                height: 100.0,
                width: 100.0,
531
                child: Transform.rotate(
532
                  angle: 1.0, // radians
533 534 535 536
                  child: ClipPath(
                    clipper: ShapeBorderClipper(
                      shape: BeveledRectangleBorder(
                        borderRadius: BorderRadius.circular(20.0),
537 538
                      ),
                    ),
539
                    child: Container(
540
                      color: Colors.red,
541
                      child: Container(
542
                        color: Colors.white,
543 544 545
                        child: RepaintBoundary(
                          child: Center(
                            child: Container(
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
                              color: Colors.black,
                              height: 10.0,
                              width: 10.0,
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
    await expectLater(
      find.byType(RepaintBoundary).first,
564
      matchesGoldenFile('clip.ClipPath.png'),
565
    );
566
  }, skip: isBrowser);
567

568
  Center genPhysicalModel(Clip clipBehavior) {
569 570 571
    return Center(
      child: RepaintBoundary(
        child: Container(
572
          color: Colors.white,
573
          child: Padding(
574
            padding: const EdgeInsets.all(100.0),
575
            child: SizedBox(
576 577
              height: 100.0,
              width: 100.0,
578
              child: Transform.rotate(
579
                angle: 1.0, // radians
580 581
                child: PhysicalModel(
                  borderRadius: BorderRadius.circular(20.0),
582 583
                  color: Colors.red,
                  clipBehavior: clipBehavior,
584
                  child: Container(
585
                    color: Colors.white,
586 587 588
                    child: RepaintBoundary(
                      child: Center(
                        child: Container(
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
                          color: Colors.black,
                          height: 10.0,
                          width: 10.0,
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }

  testWidgets('PhysicalModel painting with Clip.antiAlias', (WidgetTester tester) async {
    await tester.pumpWidget(genPhysicalModel(Clip.antiAlias));
    await expectLater(
      find.byType(RepaintBoundary).first,
609
      matchesGoldenFile('clip.PhysicalModel.antiAlias.png'),
610
    );
611
  }, skip: isBrowser);
612 613 614 615 616

  testWidgets('PhysicalModel painting with Clip.hardEdge', (WidgetTester tester) async {
    await tester.pumpWidget(genPhysicalModel(Clip.hardEdge));
    await expectLater(
      find.byType(RepaintBoundary).first,
617
      matchesGoldenFile('clip.PhysicalModel.hardEdge.png'),
618
    );
619
  }, skip: isBrowser);
620 621 622 623 624 625 626

  // There will be bleeding edges on the rect edges, but there shouldn't be any bleeding edges on the
  // round corners.
  testWidgets('PhysicalModel painting with Clip.antiAliasWithSaveLayer', (WidgetTester tester) async {
    await tester.pumpWidget(genPhysicalModel(Clip.antiAliasWithSaveLayer));
    await expectLater(
      find.byType(RepaintBoundary).first,
627
      matchesGoldenFile('clip.PhysicalModel.antiAliasWithSaveLayer.png'),
628
    );
629
  }, skip: isBrowser);
630 631

  testWidgets('Default PhysicalModel painting', (WidgetTester tester) async {
632
    await tester.pumpWidget(
633 634 635
      Center(
        child: RepaintBoundary(
          child: Container(
636
            color: Colors.white,
637
            child: Padding(
638
              padding: const EdgeInsets.all(100.0),
639
              child: SizedBox(
640 641
                height: 100.0,
                width: 100.0,
642
                child: Transform.rotate(
643
                  angle: 1.0, // radians
644 645
                  child: PhysicalModel(
                    borderRadius: BorderRadius.circular(20.0),
646
                    color: Colors.red,
647
                    child: Container(
648
                      color: Colors.white,
649 650 651
                      child: RepaintBoundary(
                        child: Center(
                          child: Container(
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
                            color: Colors.black,
                            height: 10.0,
                            width: 10.0,
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
    await expectLater(
      find.byType(RepaintBoundary).first,
669
      matchesGoldenFile('clip.PhysicalModel.default.png'),
670
    );
671
  }, skip: isBrowser);
672 673

  Center genPhysicalShape(Clip clipBehavior) {
674 675 676
    return Center(
      child: RepaintBoundary(
        child: Container(
677
          color: Colors.white,
678
          child: Padding(
679
            padding: const EdgeInsets.all(100.0),
680
            child: SizedBox(
681 682
              height: 100.0,
              width: 100.0,
683
              child: Transform.rotate(
684
                angle: 1.0, // radians
685 686 687 688
                child: PhysicalShape(
                  clipper: ShapeBorderClipper(
                    shape: BeveledRectangleBorder(
                      borderRadius: BorderRadius.circular(20.0),
689 690 691 692
                    ),
                  ),
                  clipBehavior: clipBehavior,
                  color: Colors.red,
693
                  child: Container(
694
                    color: Colors.white,
695 696 697
                    child: RepaintBoundary(
                      child: Center(
                        child: Container(
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
                          color: Colors.black,
                          height: 10.0,
                          width: 10.0,
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }

  testWidgets('PhysicalShape painting with Clip.antiAlias', (WidgetTester tester) async {
    await tester.pumpWidget(genPhysicalShape(Clip.antiAlias));
    await expectLater(
      find.byType(RepaintBoundary).first,
718
      matchesGoldenFile('clip.PhysicalShape.antiAlias.png'),
719
    );
720
  }, skip: isBrowser);
721 722 723 724 725

  testWidgets('PhysicalShape painting with Clip.hardEdge', (WidgetTester tester) async {
    await tester.pumpWidget(genPhysicalShape(Clip.hardEdge));
    await expectLater(
      find.byType(RepaintBoundary).first,
726
      matchesGoldenFile('clip.PhysicalShape.hardEdge.png'),
727
    );
728
  }, skip: isBrowser);
729 730 731 732 733

  testWidgets('PhysicalShape painting with Clip.antiAliasWithSaveLayer', (WidgetTester tester) async {
    await tester.pumpWidget(genPhysicalShape(Clip.antiAliasWithSaveLayer));
    await expectLater(
      find.byType(RepaintBoundary).first,
734
      matchesGoldenFile('clip.PhysicalShape.antiAliasWithSaveLayer.png'),
735
    );
736
  }, skip: isBrowser);
737 738 739

  testWidgets('PhysicalShape painting', (WidgetTester tester) async {
    await tester.pumpWidget(
740 741 742
      Center(
        child: RepaintBoundary(
          child: Container(
743
            color: Colors.white,
744
            child: Padding(
745
              padding: const EdgeInsets.all(100.0),
746
              child: SizedBox(
747 748
                height: 100.0,
                width: 100.0,
749
                child: Transform.rotate(
750
                  angle: 1.0, // radians
751 752 753 754
                  child: PhysicalShape(
                    clipper: ShapeBorderClipper(
                      shape: BeveledRectangleBorder(
                        borderRadius: BorderRadius.circular(20.0),
755 756 757
                      ),
                    ),
                    color: Colors.red,
758
                    child: Container(
759
                      color: Colors.white,
760 761 762
                      child: RepaintBoundary(
                        child: Center(
                          child: Container(
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
                            color: Colors.black,
                            height: 10.0,
                            width: 10.0,
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
    await expectLater(
      find.byType(RepaintBoundary).first,
780
      matchesGoldenFile('clip.PhysicalShape.default.png'),
781
    );
782
  }, skip: isBrowser);
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839

  testWidgets('ClipPath.shape', (WidgetTester tester) async {
    final List<String> logs = <String>[];
    final ShapeBorder shape = TestBorder((String message) { logs.add(message); });
    Widget buildClipPath() {
      return ClipPath.shape(
        shape: shape,
        child: const SizedBox(width: 100.0, height: 100.0),
      );
    }
    final Widget clipPath = buildClipPath();
    // verify that a regular clip works as one would expect
    logs.add('--0');
    await tester.pumpWidget(clipPath);
    // verify that pumping again doesn't recompute the clip
    // even though the widget itself is new (the shape doesn't change identity)
    logs.add('--1');
    await tester.pumpWidget(buildClipPath());
    // verify that ClipPath passes the TextDirection on to its shape
    logs.add('--2');
    await tester.pumpWidget(Directionality(
      textDirection: TextDirection.ltr,
      child: clipPath,
    ));
    // verify that changing the text direction from LTR to RTL has an effect
    // even though the widget itself is identical
    logs.add('--3');
    await tester.pumpWidget(Directionality(
      textDirection: TextDirection.rtl,
      child: clipPath,
    ));
    // verify that pumping again with a text direction has no effect
    logs.add('--4');
    await tester.pumpWidget(Directionality(
      textDirection: TextDirection.rtl,
      child: buildClipPath(),
    ));
    logs.add('--5');
    // verify that changing the text direction and the widget at the same time
    // works as expected
    await tester.pumpWidget(Directionality(
      textDirection: TextDirection.ltr,
      child: clipPath,
    ));
    expect(logs, <String>[
      '--0',
      'getOuterPath Rect.fromLTRB(0.0, 0.0, 800.0, 600.0) null',
      '--1',
      '--2',
      'getOuterPath Rect.fromLTRB(0.0, 0.0, 800.0, 600.0) TextDirection.ltr',
      '--3',
      'getOuterPath Rect.fromLTRB(0.0, 0.0, 800.0, 600.0) TextDirection.rtl',
      '--4',
      '--5',
      'getOuterPath Rect.fromLTRB(0.0, 0.0, 800.0, 600.0) TextDirection.ltr',
    ]);
  });
Ian Hickson's avatar
Ian Hickson committed
840
}