rendering_tester.dart 3.96 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1 2 3 4
// 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.

5
import 'package:flutter/foundation.dart';
Ian Hickson's avatar
Ian Hickson committed
6
import 'package:flutter/gestures.dart';
7
import 'package:flutter/rendering.dart';
Ian Hickson's avatar
Ian Hickson committed
8 9
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
10

11 12
import 'package:flutter_test/flutter_test.dart' show EnginePhase;
export 'package:flutter_test/flutter_test.dart' show EnginePhase;
13

14
class TestRenderingFlutterBinding extends BindingBase with ServicesBinding, GestureBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding {
Ian Hickson's avatar
Ian Hickson committed
15 16
  EnginePhase phase = EnginePhase.composite;

17
  @override
18
  void drawFrame() {
19
    assert(phase != EnginePhase.build, 'rendering_tester does not support testing the build phase; use flutter_test instead');
20
    pipelineOwner.flushLayout();
Ian Hickson's avatar
Ian Hickson committed
21 22
    if (phase == EnginePhase.layout)
      return;
23
    pipelineOwner.flushCompositingBits();
24 25
    if (phase == EnginePhase.compositingBits)
      return;
26
    pipelineOwner.flushPaint();
Ian Hickson's avatar
Ian Hickson committed
27 28
    if (phase == EnginePhase.paint)
      return;
29
    renderView.compositeFrame();
30 31
    if (phase == EnginePhase.composite)
      return;
32
    pipelineOwner.flushSemantics();
33 34
    if (phase == EnginePhase.flushSemantics)
      return;
35 36
    assert(phase == EnginePhase.flushSemantics ||
           phase == EnginePhase.sendSemanticsUpdate);
Ian Hickson's avatar
Ian Hickson committed
37 38 39 40
  }
}

TestRenderingFlutterBinding _renderer;
41
TestRenderingFlutterBinding get renderer {
42
  _renderer ??= TestRenderingFlutterBinding();
43 44
  return _renderer;
}
45

46 47
/// Place the box in the render tree, at the given size and with the given
/// alignment on the screen.
48 49 50 51 52 53 54
///
/// If you've updated `box` and want to lay it out again, use [pumpFrame].
///
/// Once a particular [RenderBox] has been passed to [layout], it cannot easily
/// be put in a different place in the tree or passed to [layout] again, because
/// [layout] places the given object into another [RenderBox] which you would
/// need to unparent it from (but that box isn't itself made available).
55 56 57
///
/// The EnginePhase must not be [EnginePhase.build], since the rendering layer
/// has no build phase.
58 59
void layout(
  RenderBox box, {
60
  BoxConstraints constraints,
61 62
  Alignment alignment = Alignment.center,
  EnginePhase phase = EnginePhase.layout,
63
}) {
64 65
  assert(box != null); // If you want to just repump the last box, call pumpFrame().
  assert(box.parent == null); // We stick the box in another, so you can't reuse it easily, sorry.
Hixie's avatar
Hixie committed
66

67
  renderer.renderView.child = null;
68
  if (constraints != null) {
69
    box = RenderPositionedBox(
70
      alignment: alignment,
71
      child: RenderConstrainedBox(
72
        additionalConstraints: constraints,
73 74
        child: box,
      ),
75 76
    );
  }
Ian Hickson's avatar
Ian Hickson committed
77
  renderer.renderView.child = box;
Hixie's avatar
Hixie committed
78 79 80 81

  pumpFrame(phase: phase);
}

82
void pumpFrame({ EnginePhase phase = EnginePhase.layout }) {
Ian Hickson's avatar
Ian Hickson committed
83
  assert(renderer != null);
84 85
  assert(renderer.renderView != null);
  assert(renderer.renderView.child != null); // call layout() first!
Ian Hickson's avatar
Ian Hickson committed
86
  renderer.phase = phase;
87
  renderer.drawFrame();
88
}
89 90 91 92 93 94

class TestCallbackPainter extends CustomPainter {
  const TestCallbackPainter({ this.onPaint });

  final VoidCallback onPaint;

95
  @override
96 97 98 99
  void paint(Canvas canvas, Size size) {
    onPaint();
  }

100
  @override
101 102
  bool shouldRepaint(TestCallbackPainter oldPainter) => true;
}
103 104 105 106 107 108 109 110


class RenderSizedBox extends RenderBox {
  RenderSizedBox(this._size);

  final Size _size;

  @override
111
  double computeMinIntrinsicWidth(double height) {
112 113 114 115
    return _size.width;
  }

  @override
116
  double computeMaxIntrinsicWidth(double height) {
117 118 119 120
    return _size.width;
  }

  @override
121
  double computeMinIntrinsicHeight(double width) {
122 123 124 125
    return _size.height;
  }

  @override
126
  double computeMaxIntrinsicHeight(double width) {
127 128 129 130 131 132 133 134
    return _size.height;
  }

  @override
  bool get sizedByParent => true;

  @override
  void performResize() {
135 136
    size = constraints.constrain(_size);
  }
137 138 139

  @override
  void performLayout() { }
140 141

  @override
142
  bool hitTestSelf(Offset position) => true;
143
}