1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'package:flutter/rendering.dart'; |
6 | import 'package:flutter_test/flutter_test.dart'; |
7 | |
8 | import 'rendering_tester.dart'; |
9 | |
10 | void main() { |
11 | TestRenderingFlutterBinding.ensureInitialized(); |
12 | |
13 | // Create non-const instances, otherwise tests pass even if the |
14 | // operator override is incorrect. |
15 | ViewConfiguration createViewConfiguration({ |
16 | Size size = const Size(20, 20), |
17 | double devicePixelRatio = 2.0, |
18 | }) { |
19 | final BoxConstraints constraints = BoxConstraints.tight(size); |
20 | return ViewConfiguration( |
21 | logicalConstraints: constraints, |
22 | physicalConstraints: constraints * devicePixelRatio, |
23 | devicePixelRatio: devicePixelRatio, |
24 | ); |
25 | } |
26 | |
27 | group('RenderView' , () { |
28 | test('accounts for device pixel ratio in paintBounds' , () { |
29 | layout(RenderAspectRatio(aspectRatio: 1.0)); |
30 | pumpFrame(); |
31 | final Size logicalSize = TestRenderingFlutterBinding.instance.renderView.size; |
32 | final double devicePixelRatio = TestRenderingFlutterBinding.instance.renderView.configuration.devicePixelRatio; |
33 | final Size physicalSize = logicalSize * devicePixelRatio; |
34 | expect(TestRenderingFlutterBinding.instance.renderView.paintBounds, Offset.zero & physicalSize); |
35 | }); |
36 | |
37 | test('does not replace the root layer unnecessarily' , () { |
38 | final RenderView view = RenderView( |
39 | configuration: createViewConfiguration(), |
40 | view: RendererBinding.instance.platformDispatcher.views.single, |
41 | ); |
42 | final PipelineOwner owner = PipelineOwner(); |
43 | view.attach(owner); |
44 | view.prepareInitialFrame(); |
45 | final ContainerLayer firstLayer = view.debugLayer!; |
46 | view.configuration = createViewConfiguration(); |
47 | expect(identical(view.debugLayer, firstLayer), true); |
48 | |
49 | view.configuration = createViewConfiguration(devicePixelRatio: 5.0); |
50 | expect(identical(view.debugLayer, firstLayer), false); |
51 | }); |
52 | |
53 | test('does not replace the root layer unnecessarily when view resizes' , () { |
54 | final RenderView view = RenderView( |
55 | configuration: createViewConfiguration(size: const Size(100.0, 100.0)), |
56 | view: RendererBinding.instance.platformDispatcher.views.single, |
57 | ); |
58 | final PipelineOwner owner = PipelineOwner(); |
59 | view.attach(owner); |
60 | view.prepareInitialFrame(); |
61 | final ContainerLayer firstLayer = view.debugLayer!; |
62 | view.configuration = createViewConfiguration(size: const Size(100.0, 1117.0)); |
63 | expect(identical(view.debugLayer, firstLayer), true); |
64 | }); |
65 | }); |
66 | |
67 | test('ViewConfiguration == and hashCode' , () { |
68 | final ViewConfiguration viewConfigurationA = createViewConfiguration(); |
69 | final ViewConfiguration viewConfigurationB = createViewConfiguration(); |
70 | final ViewConfiguration viewConfigurationC = createViewConfiguration(devicePixelRatio: 3.0); |
71 | |
72 | expect(viewConfigurationA == viewConfigurationB, true); |
73 | expect(viewConfigurationA != viewConfigurationC, true); |
74 | expect(viewConfigurationA.hashCode, viewConfigurationB.hashCode); |
75 | expect(viewConfigurationA.hashCode != viewConfigurationC.hashCode, true); |
76 | }); |
77 | |
78 | test('invokes DebugPaintCallback' , () { |
79 | final PaintPattern paintsOrangeRect = paints..rect( |
80 | color: orange, |
81 | rect: orangeRect, |
82 | ); |
83 | final PaintPattern paintsGreenRect = paints..rect( |
84 | color: green, |
85 | rect: greenRect, |
86 | ); |
87 | final PaintPattern paintOrangeAndGreenRect = paints |
88 | ..rect( |
89 | color: orange, |
90 | rect: orangeRect, |
91 | ) |
92 | ..rect( |
93 | color: green, |
94 | rect: greenRect, |
95 | ); |
96 | void paintCallback(PaintingContext context, Offset offset, RenderView renderView) { |
97 | context.canvas.drawRect( |
98 | greenRect, |
99 | Paint()..color = green, |
100 | ); |
101 | } |
102 | |
103 | layout(TestRenderObject()); |
104 | expect( |
105 | TestRenderingFlutterBinding.instance.renderView, |
106 | paintsOrangeRect, |
107 | ); |
108 | expect( |
109 | TestRenderingFlutterBinding.instance.renderView, |
110 | isNot(paintsGreenRect), |
111 | ); |
112 | |
113 | RenderView.debugAddPaintCallback(paintCallback); |
114 | expect( |
115 | TestRenderingFlutterBinding.instance.renderView, |
116 | paintOrangeAndGreenRect, |
117 | ); |
118 | |
119 | RenderView.debugRemovePaintCallback(paintCallback); |
120 | expect( |
121 | TestRenderingFlutterBinding.instance.renderView, |
122 | paintsOrangeRect, |
123 | ); |
124 | expect( |
125 | TestRenderingFlutterBinding.instance.renderView, |
126 | isNot(paintsGreenRect), |
127 | ); |
128 | }); |
129 | |
130 | test('Config can be set and changed after instantiation without calling prepareInitialFrame first' , () { |
131 | final RenderView view = RenderView( |
132 | view: RendererBinding.instance.platformDispatcher.views.single, |
133 | ); |
134 | view.configuration = ViewConfiguration(logicalConstraints: BoxConstraints.tight(const Size(100, 200)), devicePixelRatio: 3.0); |
135 | view.configuration = ViewConfiguration(logicalConstraints: BoxConstraints.tight(const Size(200, 300)), devicePixelRatio: 2.0); |
136 | PipelineOwner().rootNode = view; |
137 | view.prepareInitialFrame(); |
138 | }); |
139 | |
140 | test('Constraints are derived from configuration' , () { |
141 | const BoxConstraints constraints = BoxConstraints(minWidth: 1, maxWidth: 2, minHeight: 3, maxHeight: 4); |
142 | const double devicePixelRatio = 3.0; |
143 | final ViewConfiguration config = ViewConfiguration( |
144 | logicalConstraints: constraints, |
145 | physicalConstraints: constraints * devicePixelRatio, |
146 | devicePixelRatio: devicePixelRatio, |
147 | ); |
148 | |
149 | // Configuration set via setter. |
150 | final RenderView view = RenderView( |
151 | view: RendererBinding.instance.platformDispatcher.views.single, |
152 | ); |
153 | expect(() => view.constraints, throwsA(isA<StateError>().having( |
154 | (StateError e) => e.message, |
155 | 'message' , |
156 | contains('RenderView has not been given a configuration yet' ), |
157 | ))); |
158 | view.configuration = config; |
159 | expect(view.constraints, constraints); |
160 | |
161 | // Configuration set in constructor. |
162 | final RenderView view2 = RenderView( |
163 | view: RendererBinding.instance.platformDispatcher.views.single, |
164 | configuration: config, |
165 | ); |
166 | expect(view2.constraints, constraints); |
167 | }); |
168 | } |
169 | |
170 | const Color orange = Color(0xFFFF9000); |
171 | const Color green = Color(0xFF0FF900); |
172 | const Rect orangeRect = Rect.fromLTWH(10, 10, 50, 75); |
173 | const Rect greenRect = Rect.fromLTWH(20, 20, 100, 150); |
174 | |
175 | class TestRenderObject extends RenderBox { |
176 | @override |
177 | void performLayout() { |
178 | size = constraints.biggest; |
179 | } |
180 | |
181 | @override |
182 | void paint(PaintingContext context, Offset offset) { |
183 | context.canvas.drawRect( |
184 | orangeRect, |
185 | Paint()..color = orange, |
186 | ); |
187 | } |
188 | } |
189 | |