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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// Copyright 2014 The Flutter 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/foundation.dart';
import 'package:flutter/rendering.dart';
import '../flutter_test_alternative.dart';
import 'rendering_tester.dart';
void main() {
test('nested repaint boundaries - smoke test', () {
RenderOpacity a, b, c;
a = RenderOpacity(
opacity: 1.0,
child: RenderRepaintBoundary(
child: b = RenderOpacity(
opacity: 1.0,
child: RenderRepaintBoundary(
child: c = RenderOpacity(
opacity: 1.0
)
),
),
),
);
layout(a, phase: EnginePhase.flushSemantics);
c.opacity = 0.9;
pumpFrame(phase: EnginePhase.flushSemantics);
a.opacity = 0.8;
c.opacity = 0.8;
pumpFrame(phase: EnginePhase.flushSemantics);
a.opacity = 0.7;
b.opacity = 0.7;
c.opacity = 0.7;
pumpFrame(phase: EnginePhase.flushSemantics);
});
test('Repaint boundary can get new parent after markNeedsCompositingBitsUpdate', () {
// Regression test for https://github.com/flutter/flutter/issues/24029.
final RenderRepaintBoundary repaintBoundary = RenderRepaintBoundary();
layout(repaintBoundary, phase: EnginePhase.flushSemantics);
repaintBoundary.markNeedsCompositingBitsUpdate();
renderer.renderView.child = null;
final RenderPadding padding = RenderPadding(
padding: const EdgeInsets.all(50),
);
renderer.renderView.child = padding;
padding.child = repaintBoundary;
pumpFrame(phase: EnginePhase.flushSemantics);
});
test('Framework creates an OffsetLayer for a repaint boundary', () {
final _TestRepaintBoundary repaintBoundary = _TestRepaintBoundary();
final RenderOpacity opacity = RenderOpacity(
opacity: 1.0,
child: repaintBoundary,
);
layout(opacity, phase: EnginePhase.flushSemantics);
expect(repaintBoundary.debugLayer, isA<OffsetLayer>());
});
test('Framework does not create an OffsetLayer for a non-repaint boundary', () {
final _TestNonCompositedBox nonCompositedBox = _TestNonCompositedBox();
final RenderOpacity opacity = RenderOpacity(
opacity: 1.0,
child: nonCompositedBox,
);
layout(opacity, phase: EnginePhase.flushSemantics);
expect(nonCompositedBox.debugLayer, null);
});
test('Framework allows a non-repaint boundary to create own layer', () {
final _TestCompositedBox compositedBox = _TestCompositedBox();
final RenderOpacity opacity = RenderOpacity(
opacity: 1.0,
child: compositedBox,
);
layout(opacity, phase: EnginePhase.flushSemantics);
expect(compositedBox.debugLayer, isA<OpacityLayer>());
});
test('Framework ensures repaint boundary layer is not overwritten', () {
final _TestRepaintBoundaryThatOverwritesItsLayer faultyRenderObject = _TestRepaintBoundaryThatOverwritesItsLayer();
final RenderOpacity opacity = RenderOpacity(
opacity: 1.0,
child: faultyRenderObject,
);
FlutterErrorDetails error;
layout(opacity, phase: EnginePhase.flushSemantics, onErrors: () {
error = renderer.takeFlutterErrorDetails();
});
expect('${error.exception}', contains('Attempted to set a layer to a repaint boundary render object.'));
});
}
// A plain render object that's a repaint boundary.
class _TestRepaintBoundary extends RenderBox {
@override
bool get isRepaintBoundary => true;
@override
void performLayout() {
size = constraints.smallest;
}
}
// A render object that's a repaint boundary and (incorrectly) creates its own layer.
class _TestRepaintBoundaryThatOverwritesItsLayer extends RenderBox {
@override
bool get isRepaintBoundary => true;
@override
void performLayout() {
size = constraints.smallest;
}
@override
void paint(PaintingContext context, Offset offset) {
layer = OpacityLayer(alpha: 50);
}
}
// A render object that's neither a repaint boundary nor creates its own layer.
class _TestNonCompositedBox extends RenderBox {
@override
bool get isRepaintBoundary => false;
@override
void performLayout() {
size = constraints.smallest;
}
}
// A render object that's not a repaint boundary but creates its own layer.
class _TestCompositedBox extends RenderBox {
@override
bool get isRepaintBoundary => false;
@override
void performLayout() {
size = constraints.smallest;
}
@override
void paint(PaintingContext context, Offset offset) {
layer = OpacityLayer(alpha: 50);
}
}