reattach_test.dart 5.43 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
// Copyright 2016 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/material.dart';
import 'package:flutter/rendering.dart';
import 'package:test/test.dart';

import 'rendering_tester.dart';

class TestTree {
  TestTree() {
    // viewport incoming constraints are tight 800x600
    // viewport is vertical by default
    root = new RenderViewport(
      // Place the child to be evaluated within both a repaint boundary and a
      // layout-root element (in this case a tightly constrained box). Otherwise
      // the act of transplanting the root into a new container will cause the
      // relayout/repaint of the new parent node to satisfy the test.
      child: new RenderRepaintBoundary(
        child: new RenderConstrainedBox(
          additionalConstraints: new BoxConstraints.tightFor(height: 20.0, width: 20.0),
          child: new RenderRepaintBoundary(
            child: new RenderCustomPaint(
              painter: new TestCallbackPainter(
                onPaint: () { painted = true; }
              ),
              child: new RenderPositionedBox(
                child: child = new RenderConstrainedBox(
                  additionalConstraints: new BoxConstraints.tightFor(height: 20.0, width: 20.0)
                )
              )
            )
          )
        )
      )
    );
  }
  RenderObject root;
  RenderConstrainedBox child;
  bool painted = false;
}

class MutableCompositor extends RenderProxyBox {
  MutableCompositor({ RenderBox child }) : super(child);
  bool _alwaysComposite = false;
  @override
  bool get alwaysNeedsCompositing => _alwaysComposite;
}

class TestCompositingBitsTree {
  TestCompositingBitsTree() {
    // viewport incoming constraints are tight 800x600
    // viewport is vertical by default
    root = new RenderViewport(
      // Place the child to be evaluated within a repaint boundary. Otherwise
      // the act of transplanting the root into a new container will cause the
      // repaint of the new parent node to satisfy the test.
      child: new RenderRepaintBoundary(
        child: compositor = new MutableCompositor(
          child: new RenderCustomPaint(
            painter: new TestCallbackPainter(
              onPaint: () { painted = true; }
            ),
            child: child = new RenderConstrainedBox(
              additionalConstraints: new BoxConstraints.tightFor(height: 20.0, width: 20.0)
            )
          )
        )
      )
    );
  }
  RenderObject root;
  MutableCompositor compositor;
  RenderConstrainedBox child;
  bool painted = false;
}

void main() {
  test('objects can be detached and re-attached: layout', () {
    TestTree testTree = new TestTree();
    // Lay out
    layout(testTree.root, phase: EnginePhase.layout);
    expect(testTree.child.size, equals(const Size(20.0, 20.0)));
    // Remove testTree from the custom render view
    renderer.renderView.child = null;
    expect(testTree.child.owner, isNull);
    // Dirty one of the elements
    testTree.child.additionalConstraints =
      new BoxConstraints.tightFor(height: 5.0, width: 5.0);
    // Lay out again
    layout(testTree.root, phase: EnginePhase.layout);
    expect(testTree.child.size, equals(const Size(5.0, 5.0)));
  });
  test('objects can be detached and re-attached: compositingBits', () {
    TestCompositingBitsTree testTree = new TestCompositingBitsTree();
    // Lay out, composite, and paint
    layout(testTree.root, phase: EnginePhase.paint);
    expect(testTree.painted, isTrue);
    // Remove testTree from the custom render view
    renderer.renderView.child = null;
    expect(testTree.child.owner, isNull);
    // Dirty one of the elements
    testTree.compositor._alwaysComposite = true;
    testTree.child.markNeedsCompositingBitsUpdate();
    testTree.painted = false;
    // Lay out, composite, and paint again
    layout(testTree.root, phase: EnginePhase.paint);
    expect(testTree.painted, isTrue);
  });
  test('objects can be detached and re-attached: paint', () {
    TestTree testTree = new TestTree();
    // Lay out, composite, and paint
    layout(testTree.root, phase: EnginePhase.paint);
    expect(testTree.painted, isTrue);
    // Remove testTree from the custom render view
    renderer.renderView.child = null;
    expect(testTree.child.owner, isNull);
    // Dirty one of the elements
    testTree.child.markNeedsPaint();
    testTree.painted = false;
    // Lay out, composite, and paint again
    layout(testTree.root, phase: EnginePhase.paint);
    expect(testTree.painted, isTrue);
  });
  test('objects can be detached and re-attached: semantics', () {
    TestTree testTree = new TestTree();
128 129 130 131 132 133
    int semanticsUpdateCount = 0;
    SemanticsHandle semanticsHandle = renderer.pipelineOwner.ensureSemantics(
      listener: () {
        ++semanticsUpdateCount;
      }
    );
134
    // Lay out, composite, paint, and update semantics
135
    layout(testTree.root, phase: EnginePhase.flushSemantics);
136
    expect(semanticsUpdateCount, 1);
137 138 139 140
    // Remove testTree from the custom render view
    renderer.renderView.child = null;
    expect(testTree.child.owner, isNull);
    // Dirty one of the elements
141
    semanticsUpdateCount = 0;
142
    testTree.child.markNeedsSemanticsUpdate();
143
    expect(semanticsUpdateCount, 0);
144
    // Lay out, composite, paint, and update semantics again
145
    layout(testTree.root, phase: EnginePhase.flushSemantics);
146 147
    expect(semanticsUpdateCount, 1);
    semanticsHandle.dispose();
148 149
  });
}