proxy_box_test.dart 7.18 KB
Newer Older
1 2 3 4
// Copyright 2017 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.

5 6 7
import 'dart:typed_data';

import 'dart:ui' as ui show Image;
8
import 'package:flutter/foundation.dart';
9
import 'package:flutter/gestures.dart';
10 11 12 13 14 15 16 17 18 19 20
import 'package:flutter/rendering.dart';
import 'package:test/test.dart';

import 'rendering_tester.dart';

void main() {
  test('RenderFittedBox paint', () {
    bool painted;
    RenderFittedBox makeFittedBox() {
      return new RenderFittedBox(
        child: new RenderCustomPaint(
21 22 23
          painter: new TestCallbackPainter(onPaint: () {
            painted = true;
          }),
24 25 26 27 28 29 30 31 32 33 34 35 36
        ),
      );
    }

    painted = false;
    layout(makeFittedBox(), phase: EnginePhase.paint);
    expect(painted, equals(true));

    // The RenderFittedBox should not paint if it is empty.
    painted = false;
    layout(makeFittedBox(), constraints: new BoxConstraints.tight(Size.zero), phase: EnginePhase.paint);
    expect(painted, equals(false));
  });
37 38 39 40

  test('RenderPhysicalModel compositing on Fuchsia', () {
    debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;

41
    final RenderPhysicalModel root = new RenderPhysicalModel(color: const Color(0xffff00ff));
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
    layout(root, phase: EnginePhase.composite);
    expect(root.needsCompositing, isFalse);

    // On Fuchsia, the system compositor is responsible for drawing shadows
    // for physical model layers with non-zero elevation.
    root.elevation = 1.0;
    pumpFrame(phase: EnginePhase.composite);
    expect(root.needsCompositing, isTrue);

    root.elevation = 0.0;
    pumpFrame(phase: EnginePhase.composite);
    expect(root.needsCompositing, isFalse);

    debugDefaultTargetPlatformOverride = null;
  });

  test('RenderPhysicalModel compositing on non-Fuchsia', () {
    debugDefaultTargetPlatformOverride = TargetPlatform.iOS;

61
    final RenderPhysicalModel root = new RenderPhysicalModel(color: const Color(0xffff00ff));
62 63 64 65 66 67 68 69 70 71 72 73 74 75
    layout(root, phase: EnginePhase.composite);
    expect(root.needsCompositing, isFalse);

    // On non-Fuchsia platforms, Flutter draws its own shadows.
    root.elevation = 1.0;
    pumpFrame(phase: EnginePhase.composite);
    expect(root.needsCompositing, isFalse);

    root.elevation = 0.0;
    pumpFrame(phase: EnginePhase.composite);
    expect(root.needsCompositing, isFalse);

    debugDefaultTargetPlatformOverride = null;
  });
76 77 78 79 80 81 82

  test('RenderSemanticsGestureHandler adds/removes correct semantic actions', () {
    final RenderSemanticsGestureHandler renderObj = new RenderSemanticsGestureHandler(
      onTap: () {},
      onHorizontalDragUpdate: (DragUpdateDetails details) {},
    );

83 84 85 86 87
    SemanticsConfiguration config = new SemanticsConfiguration();
    renderObj.describeSemanticsConfiguration(config);
    expect(config.getActionHandler(SemanticsAction.tap), isNotNull);
    expect(config.getActionHandler(SemanticsAction.scrollLeft), isNotNull);
    expect(config.getActionHandler(SemanticsAction.scrollRight), isNotNull);
88

89
    config = new SemanticsConfiguration();
90 91
    renderObj.validActions = <SemanticsAction>[SemanticsAction.tap, SemanticsAction.scrollLeft].toSet();

92 93 94 95
    renderObj.describeSemanticsConfiguration(config);
    expect(config.getActionHandler(SemanticsAction.tap), isNotNull);
    expect(config.getActionHandler(SemanticsAction.scrollLeft), isNotNull);
    expect(config.getActionHandler(SemanticsAction.scrollRight), isNull);
96
  });
97 98 99 100 101 102 103 104 105

  group('RenderPhysicalShape', () {
    setUp(() {
      debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
    });

    test('shape change triggers repaint', () {
      final RenderPhysicalShape root = new RenderPhysicalShape(
        color: const Color(0xffff00ff),
106
        clipper: const ShapeBorderClipper(shape: const CircleBorder()),
107 108 109 110 111
      );
      layout(root, phase: EnginePhase.composite);
      expect(root.debugNeedsPaint, isFalse);

      // Same shape, no repaint.
112
      root.clipper = const ShapeBorderClipper(shape: const CircleBorder());
113 114 115
      expect(root.debugNeedsPaint, isFalse);

      // Different shape triggers repaint.
116
      root.clipper = const ShapeBorderClipper(shape: const StadiumBorder());
117 118 119 120 121 122
      expect(root.debugNeedsPaint, isTrue);
    });

    test('compositing on non-Fuchsia', () {
      final RenderPhysicalShape root = new RenderPhysicalShape(
        color: const Color(0xffff00ff),
123
        clipper: const ShapeBorderClipper(shape: const CircleBorder()),
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
      );
      layout(root, phase: EnginePhase.composite);
      expect(root.needsCompositing, isFalse);

      // On non-Fuchsia platforms, Flutter draws its own shadows.
      root.elevation = 1.0;
      pumpFrame(phase: EnginePhase.composite);
      expect(root.needsCompositing, isFalse);

      root.elevation = 0.0;
      pumpFrame(phase: EnginePhase.composite);
      expect(root.needsCompositing, isFalse);

      debugDefaultTargetPlatformOverride = null;
    });
  });
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192

  test('RenderRepaintBoundary can capture images of itself', () async {
    RenderRepaintBoundary boundary = new RenderRepaintBoundary();
    layout(boundary, constraints: new BoxConstraints.tight(const Size(100.0, 200.0)));
    pumpFrame(phase: EnginePhase.composite);
    ui.Image image = await boundary.toImage();
    expect(image.width, equals(100));
    expect(image.height, equals(200));

    // Now with pixel ratio set to something other than 1.0.
    boundary = new RenderRepaintBoundary();
    layout(boundary, constraints: new BoxConstraints.tight(const Size(100.0, 200.0)));
    pumpFrame(phase: EnginePhase.composite);
    image = await boundary.toImage(pixelRatio: 2.0);
    expect(image.width, equals(200));
    expect(image.height, equals(400));

    // Try building one with two child layers and make sure it renders them both.
    boundary = new RenderRepaintBoundary();
    final RenderStack stack = new RenderStack()..alignment = Alignment.topLeft;
    final RenderDecoratedBox blackBox = new RenderDecoratedBox(
        decoration: const BoxDecoration(color: const Color(0xff000000)),
        child: new RenderConstrainedBox(
          additionalConstraints: new BoxConstraints.tight(const Size.square(20.0)),
        ));
    stack.add(new RenderOpacity()
      ..opacity = 0.5
      ..child = blackBox);
    final RenderDecoratedBox whiteBox = new RenderDecoratedBox(
        decoration: const BoxDecoration(color: const Color(0xffffffff)),
        child: new RenderConstrainedBox(
          additionalConstraints: new BoxConstraints.tight(const Size.square(10.0)),
        ));
    final RenderPositionedBox positioned = new RenderPositionedBox(
      widthFactor: 2.0,
      heightFactor: 2.0,
      alignment: Alignment.topRight,
      child: whiteBox,
    );
    stack.add(positioned);
    boundary.child = stack;
    layout(boundary, constraints: new BoxConstraints.tight(const Size(20.0, 20.0)));
    pumpFrame(phase: EnginePhase.composite);
    image = await boundary.toImage();
    expect(image.width, equals(20));
    expect(image.height, equals(20));
    final ByteData data = await image.toByteData();
    expect(data.lengthInBytes, equals(20 * 20 * 4));
    expect(data.elementSizeInBytes, equals(1));
    const int stride = 20 * 4;
    expect(data.getUint32(0), equals(0x00000080));
    expect(data.getUint32(stride - 4), equals(0xffffffff));
  });
193
}