blob: fc4f34d0f645f02b0759e908e3f3d54519e9e244 [file] [log] [blame]
// 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.
import 'dart:typed_data';
import 'dart:ui' as ui show Image;
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
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(
painter: new TestCallbackPainter(onPaint: () {
painted = true;
}),
),
);
}
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));
});
test('RenderPhysicalModel compositing on Fuchsia', () {
debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
final RenderPhysicalModel root = new RenderPhysicalModel(color: const Color(0xffff00ff));
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;
final RenderPhysicalModel root = new RenderPhysicalModel(color: const Color(0xffff00ff));
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;
});
test('RenderSemanticsGestureHandler adds/removes correct semantic actions', () {
final RenderSemanticsGestureHandler renderObj = new RenderSemanticsGestureHandler(
onTap: () {},
onHorizontalDragUpdate: (DragUpdateDetails details) {},
);
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);
config = new SemanticsConfiguration();
renderObj.validActions = <SemanticsAction>[SemanticsAction.tap, SemanticsAction.scrollLeft].toSet();
renderObj.describeSemanticsConfiguration(config);
expect(config.getActionHandler(SemanticsAction.tap), isNotNull);
expect(config.getActionHandler(SemanticsAction.scrollLeft), isNotNull);
expect(config.getActionHandler(SemanticsAction.scrollRight), isNull);
});
group('RenderPhysicalShape', () {
setUp(() {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
});
test('shape change triggers repaint', () {
final RenderPhysicalShape root = new RenderPhysicalShape(
color: const Color(0xffff00ff),
clipper: const ShapeBorderClipper(shape: const CircleBorder()),
);
layout(root, phase: EnginePhase.composite);
expect(root.debugNeedsPaint, isFalse);
// Same shape, no repaint.
root.clipper = const ShapeBorderClipper(shape: const CircleBorder());
expect(root.debugNeedsPaint, isFalse);
// Different shape triggers repaint.
root.clipper = const ShapeBorderClipper(shape: const StadiumBorder());
expect(root.debugNeedsPaint, isTrue);
});
test('compositing on non-Fuchsia', () {
final RenderPhysicalShape root = new RenderPhysicalShape(
color: const Color(0xffff00ff),
clipper: const ShapeBorderClipper(shape: const CircleBorder()),
);
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;
});
});
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));
});
}