clip_test.dart 24.8 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1 2 3 4 5 6
// Copyright 2015 The Chromium Authors. All rights reserved.
// 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
  testWidgets('ClipRect updates clipBehavior in updateRenderObject', (WidgetTester tester) async {
65
    await tester.pumpWidget(const _UpdateCountedClipRect());
66 67 68 69 70

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

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

71
    await tester.pumpWidget(const _UpdateCountedClipRect(clipBehavior: Clip.hardEdge));
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

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

  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 {
89
    await tester.pumpWidget(const _UpdateCountedClipOval());
90 91 92 93 94

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

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

95
    await tester.pumpWidget(const _UpdateCountedClipOval(clipBehavior: Clip.hardEdge));
96 97 98 99 100

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

  testWidgets('ClipPath updates clipBehavior in updateRenderObject', (WidgetTester tester) async {
101
    await tester.pumpWidget(const _UpdateCountedClipPath());
102 103 104 105 106

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

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

107
    await tester.pumpWidget(const _UpdateCountedClipPath(clipBehavior: Clip.hardEdge));
108 109 110 111

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

112 113
  testWidgets('ClipPath', (WidgetTester tester) async {
    await tester.pumpWidget(
114 115 116
      ClipPath(
        clipper: PathClipper(),
        child: GestureDetector(
Ian Hickson's avatar
Ian Hickson committed
117 118
          behavior: HitTestBehavior.opaque,
          onTap: () { log.add('tap'); },
119
        ),
Ian Hickson's avatar
Ian Hickson committed
120 121
      )
    );
122
    expect(log, equals(<String>['getClip']));
Ian Hickson's avatar
Ian Hickson committed
123

124
    await tester.tapAt(const Offset(10.0, 10.0));
125
    expect(log, equals(<String>['getClip']));
Ian Hickson's avatar
Ian Hickson committed
126 127
    log.clear();

128
    await tester.tapAt(const Offset(100.0, 100.0));
129
    expect(log, equals(<String>['tap']));
Ian Hickson's avatar
Ian Hickson committed
130 131 132
    log.clear();
  });

133 134
  testWidgets('ClipOval', (WidgetTester tester) async {
    await tester.pumpWidget(
135 136
      ClipOval(
        child: GestureDetector(
Ian Hickson's avatar
Ian Hickson committed
137 138
          behavior: HitTestBehavior.opaque,
          onTap: () { log.add('tap'); },
139
        ),
Ian Hickson's avatar
Ian Hickson committed
140 141
      )
    );
142
    expect(log, equals(<String>[]));
Ian Hickson's avatar
Ian Hickson committed
143

144
    await tester.tapAt(const Offset(10.0, 10.0));
145
    expect(log, equals(<String>[]));
Ian Hickson's avatar
Ian Hickson committed
146 147
    log.clear();

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

153 154
  testWidgets('Transparent ClipOval hit test', (WidgetTester tester) async {
    await tester.pumpWidget(
155
      Opacity(
156
        opacity: 0.0,
157 158
        child: ClipOval(
          child: GestureDetector(
159 160
            behavior: HitTestBehavior.opaque,
            onTap: () { log.add('tap'); },
161 162
          ),
        ),
163 164 165 166
      )
    );
    expect(log, equals(<String>[]));

167
    await tester.tapAt(const Offset(10.0, 10.0));
168 169 170
    expect(log, equals(<String>[]));
    log.clear();

171
    await tester.tapAt(const Offset(400.0, 300.0));
172 173 174 175
    expect(log, equals(<String>['tap']));
    log.clear();
  });

176 177
  testWidgets('ClipRect', (WidgetTester tester) async {
    await tester.pumpWidget(
178
      Align(
179
        alignment: Alignment.topLeft,
180
        child: SizedBox(
181 182
          width: 100.0,
          height: 100.0,
183
          child: ClipRect(
Dan Field's avatar
Dan Field committed
184
            clipper: ValueClipper<Rect>('a', const Rect.fromLTWH(5.0, 5.0, 10.0, 10.0)),
185
            child: GestureDetector(
186 187
              behavior: HitTestBehavior.opaque,
              onTap: () { log.add('tap'); },
188 189 190
            ),
          ),
        ),
191 192 193 194
      )
    );
    expect(log, equals(<String>['a']));

195
    await tester.tapAt(const Offset(10.0, 10.0));
196 197
    expect(log, equals(<String>['a', 'tap']));

198
    await tester.tapAt(const Offset(100.0, 100.0));
199 200 201
    expect(log, equals(<String>['a', 'tap']));

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

    await tester.pumpWidget(
220
      Align(
221
        alignment: Alignment.topLeft,
222
        child: SizedBox(
223 224
          width: 200.0,
          height: 200.0,
225
          child: ClipRect(
Dan Field's avatar
Dan Field committed
226
            clipper: ValueClipper<Rect>('a', const Rect.fromLTWH(5.0, 5.0, 10.0, 10.0)),
227
            child: GestureDetector(
228 229
              behavior: HitTestBehavior.opaque,
              onTap: () { log.add('tap'); },
230 231 232
            ),
          ),
        ),
233 234 235 236 237
      )
    );
    expect(log, equals(<String>['a', 'tap', 'a']));

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

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

    await tester.pumpWidget(
274
      Align(
275
        alignment: Alignment.topLeft,
276
        child: SizedBox(
277 278
          width: 200.0,
          height: 200.0,
279
          child: ClipRect(
Dan Field's avatar
Dan Field committed
280
            clipper: ValueClipper<Rect>('c', const Rect.fromLTWH(25.0, 25.0, 10.0, 10.0)),
281
            child: GestureDetector(
282 283
              behavior: HitTestBehavior.opaque,
              onTap: () { log.add('tap'); },
284 285 286
            ),
          ),
        ),
287 288 289 290
      )
    );
    expect(log, equals(<String>['a', 'tap', 'a', 'b', 'c']));

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

294
    await tester.tapAt(const Offset(100.0, 100.0));
295 296 297
    expect(log, equals(<String>['a', 'tap', 'a', 'b', 'c', 'tap']));
  });

298 299 300
  testWidgets('debugPaintSizeEnabled', (WidgetTester tester) async {
    await tester.pumpWidget(
      const ClipRect(
301
        child: Placeholder(),
302 303 304 305
      ),
    );
    expect(tester.renderObject(find.byType(ClipRect)).paint, paints
      ..save()
Dan Field's avatar
Dan Field committed
306
      ..clipRect(rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0))
307 308 309
      ..save()
      ..path() // Placeholder
      ..restore()
310
      ..restore(),
311 312
    );
    debugPaintSizeEnabled = true;
313
    expect(tester.renderObject(find.byType(ClipRect)).debugPaint, paints
Dan Field's avatar
Dan Field committed
314
      ..rect(rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0))
315
      ..paragraph(),
316 317 318
    );
    debugPaintSizeEnabled = false;
  });
319 320 321

  testWidgets('ClipRect painting', (WidgetTester tester) async {
    await tester.pumpWidget(
322 323 324
      Center(
        child: RepaintBoundary(
          child: Container(
325
            color: Colors.white,
326
            child: Padding(
327
              padding: const EdgeInsets.all(100.0),
328
              child: SizedBox(
329 330
                height: 100.0,
                width: 100.0,
331
                child: Transform.rotate(
332
                  angle: 1.0, // radians
333 334
                  child: ClipRect(
                    child: Container(
335
                      color: Colors.red,
336
                      child: Container(
337
                        color: Colors.white,
338 339 340
                        child: RepaintBoundary(
                          child: Center(
                            child: Container(
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
                              color: Colors.black,
                              height: 10.0,
                              width: 10.0,
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
    await expectLater(
      find.byType(RepaintBoundary).first,
359
      matchesGoldenFile('clip.ClipRect.1.png'),
360 361 362
    );
  });

363 364
  testWidgets('ClipRect save, overlay, and antialiasing', (WidgetTester tester) async {
    await tester.pumpWidget(
365 366
      RepaintBoundary(
        child: Stack(
367 368
          textDirection: TextDirection.ltr,
          children: <Widget>[
369
            Positioned(
370 371 372 373
              top: 0.0,
              left: 0.0,
              width: 100.0,
              height: 100.0,
374 375
              child: ClipRect(
                child: Container(
376 377 378 379 380
                  color: Colors.blue,
                ),
                clipBehavior: Clip.hardEdge,
              ),
            ),
381
            Positioned(
382 383 384 385
              top: 50.0,
              left: 50.0,
              width: 100.0,
              height: 100.0,
386
              child: Transform.rotate(
387
                angle: 1.0,
388
                child: Container(
389 390 391 392 393 394 395 396 397 398
                  color: Colors.red,
                ),
              ),
            ),
          ],
        ),
      ),
    );
    await expectLater(
      find.byType(RepaintBoundary).first,
399
      matchesGoldenFile('clip.ClipRectOverlay.1.png'),
400 401 402
    );
  });

403 404
  testWidgets('ClipRRect painting', (WidgetTester tester) async {
    await tester.pumpWidget(
405 406 407
      Center(
        child: RepaintBoundary(
          child: Container(
408
            color: Colors.white,
409
            child: Padding(
410
              padding: const EdgeInsets.all(100.0),
411
              child: SizedBox(
412 413
                height: 100.0,
                width: 100.0,
414
                child: Transform.rotate(
415
                  angle: 1.0, // radians
416
                  child: ClipRRect(
417
                    borderRadius: const BorderRadius.only(
418 419 420 421
                      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),
422
                    ),
423
                    child: Container(
424
                      color: Colors.red,
425
                      child: Container(
426
                        color: Colors.white,
427 428 429
                        child: RepaintBoundary(
                          child: Center(
                            child: Container(
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
                              color: Colors.black,
                              height: 10.0,
                              width: 10.0,
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
    await expectLater(
      find.byType(RepaintBoundary).first,
448
      matchesGoldenFile('clip.ClipRRect.1.png'),
449 450 451 452 453
    );
  });

  testWidgets('ClipOval painting', (WidgetTester tester) async {
    await tester.pumpWidget(
454 455 456
      Center(
        child: RepaintBoundary(
          child: Container(
457
            color: Colors.white,
458
            child: Padding(
459
              padding: const EdgeInsets.all(100.0),
460
              child: SizedBox(
461 462
                height: 100.0,
                width: 100.0,
463
                child: Transform.rotate(
464
                  angle: 1.0, // radians
465 466
                  child: ClipOval(
                    child: Container(
467
                      color: Colors.red,
468
                      child: Container(
469
                        color: Colors.white,
470 471 472
                        child: RepaintBoundary(
                          child: Center(
                            child: Container(
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
                              color: Colors.black,
                              height: 10.0,
                              width: 10.0,
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
    await expectLater(
      find.byType(RepaintBoundary).first,
491
      matchesGoldenFile('clip.ClipOval.1.png'),
492 493 494 495 496
    );
  });

  testWidgets('ClipPath painting', (WidgetTester tester) async {
    await tester.pumpWidget(
497 498 499
      Center(
        child: RepaintBoundary(
          child: Container(
500
            color: Colors.white,
501
            child: Padding(
502
              padding: const EdgeInsets.all(100.0),
503
              child: SizedBox(
504 505
                height: 100.0,
                width: 100.0,
506
                child: Transform.rotate(
507
                  angle: 1.0, // radians
508 509 510 511
                  child: ClipPath(
                    clipper: ShapeBorderClipper(
                      shape: BeveledRectangleBorder(
                        borderRadius: BorderRadius.circular(20.0),
512 513
                      ),
                    ),
514
                    child: Container(
515
                      color: Colors.red,
516
                      child: Container(
517
                        color: Colors.white,
518 519 520
                        child: RepaintBoundary(
                          child: Center(
                            child: Container(
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
                              color: Colors.black,
                              height: 10.0,
                              width: 10.0,
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
    await expectLater(
      find.byType(RepaintBoundary).first,
539
      matchesGoldenFile('clip.ClipPath.1.png'),
540 541 542
    );
  });

543
  Center genPhysicalModel(Clip clipBehavior) {
544 545 546
    return Center(
      child: RepaintBoundary(
        child: Container(
547
          color: Colors.white,
548
          child: Padding(
549
            padding: const EdgeInsets.all(100.0),
550
            child: SizedBox(
551 552
              height: 100.0,
              width: 100.0,
553
              child: Transform.rotate(
554
                angle: 1.0, // radians
555 556
                child: PhysicalModel(
                  borderRadius: BorderRadius.circular(20.0),
557 558
                  color: Colors.red,
                  clipBehavior: clipBehavior,
559
                  child: Container(
560
                    color: Colors.white,
561 562 563
                    child: RepaintBoundary(
                      child: Center(
                        child: Container(
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
                          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,
584
      matchesGoldenFile('clip.PhysicalModel.antiAlias.1.png'),
585 586 587 588 589 590 591
    );
  });

  testWidgets('PhysicalModel painting with Clip.hardEdge', (WidgetTester tester) async {
    await tester.pumpWidget(genPhysicalModel(Clip.hardEdge));
    await expectLater(
      find.byType(RepaintBoundary).first,
592
      matchesGoldenFile('clip.PhysicalModel.hardEdge.1.png'),
593 594 595 596 597 598 599 600 601
    );
  });

  // 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,
602
      matchesGoldenFile('clip.PhysicalModel.antiAliasWithSaveLayer.png'),
603 604 605 606
    );
  });

  testWidgets('Default PhysicalModel painting', (WidgetTester tester) async {
607
    await tester.pumpWidget(
608 609 610
      Center(
        child: RepaintBoundary(
          child: Container(
611
            color: Colors.white,
612
            child: Padding(
613
              padding: const EdgeInsets.all(100.0),
614
              child: SizedBox(
615 616
                height: 100.0,
                width: 100.0,
617
                child: Transform.rotate(
618
                  angle: 1.0, // radians
619 620
                  child: PhysicalModel(
                    borderRadius: BorderRadius.circular(20.0),
621
                    color: Colors.red,
622
                    child: Container(
623
                      color: Colors.white,
624 625 626
                      child: RepaintBoundary(
                        child: Center(
                          child: Container(
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
                            color: Colors.black,
                            height: 10.0,
                            width: 10.0,
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
    await expectLater(
      find.byType(RepaintBoundary).first,
644
      matchesGoldenFile('clip.PhysicalModel.default.1.png'),
645
    );
646
  });
647 648

  Center genPhysicalShape(Clip clipBehavior) {
649 650 651
    return Center(
      child: RepaintBoundary(
        child: Container(
652
          color: Colors.white,
653
          child: Padding(
654
            padding: const EdgeInsets.all(100.0),
655
            child: SizedBox(
656 657
              height: 100.0,
              width: 100.0,
658
              child: Transform.rotate(
659
                angle: 1.0, // radians
660 661 662 663
                child: PhysicalShape(
                  clipper: ShapeBorderClipper(
                    shape: BeveledRectangleBorder(
                      borderRadius: BorderRadius.circular(20.0),
664 665 666 667
                    ),
                  ),
                  clipBehavior: clipBehavior,
                  color: Colors.red,
668
                  child: Container(
669
                    color: Colors.white,
670 671 672
                    child: RepaintBoundary(
                      child: Center(
                        child: Container(
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
                          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,
693
      matchesGoldenFile('clip.PhysicalShape.antiAlias.1.png'),
694 695 696 697 698 699 700
    );
  });

  testWidgets('PhysicalShape painting with Clip.hardEdge', (WidgetTester tester) async {
    await tester.pumpWidget(genPhysicalShape(Clip.hardEdge));
    await expectLater(
      find.byType(RepaintBoundary).first,
701
      matchesGoldenFile('clip.PhysicalShape.hardEdge.1.png'),
702 703 704 705 706 707 708
    );
  });

  testWidgets('PhysicalShape painting with Clip.antiAliasWithSaveLayer', (WidgetTester tester) async {
    await tester.pumpWidget(genPhysicalShape(Clip.antiAliasWithSaveLayer));
    await expectLater(
      find.byType(RepaintBoundary).first,
709
      matchesGoldenFile('clip.PhysicalShape.antiAliasWithSaveLayer.png'),
710 711 712 713 714
    );
  });

  testWidgets('PhysicalShape painting', (WidgetTester tester) async {
    await tester.pumpWidget(
715 716 717
      Center(
        child: RepaintBoundary(
          child: Container(
718
            color: Colors.white,
719
            child: Padding(
720
              padding: const EdgeInsets.all(100.0),
721
              child: SizedBox(
722 723
                height: 100.0,
                width: 100.0,
724
                child: Transform.rotate(
725
                  angle: 1.0, // radians
726 727 728 729
                  child: PhysicalShape(
                    clipper: ShapeBorderClipper(
                      shape: BeveledRectangleBorder(
                        borderRadius: BorderRadius.circular(20.0),
730 731 732
                      ),
                    ),
                    color: Colors.red,
733
                    child: Container(
734
                      color: Colors.white,
735 736 737
                      child: RepaintBoundary(
                        child: Center(
                          child: Container(
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
                            color: Colors.black,
                            height: 10.0,
                            width: 10.0,
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
    await expectLater(
      find.byType(RepaintBoundary).first,
755
      matchesGoldenFile('clip.PhysicalShape.default.1.png'),
756
    );
757
  });
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 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

  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
815
}