| // 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:ui'; |
| |
| import 'package:flutter/rendering.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| import 'rendering_tester.dart'; |
| |
| void main() { |
| test('non-painted layers are detached', () { |
| RenderObject boundary, inner; |
| final RenderOpacity root = RenderOpacity( |
| child: boundary = RenderRepaintBoundary( |
| child: inner = RenderDecoratedBox( |
| decoration: const BoxDecoration(), |
| ), |
| ), |
| ); |
| layout(root, phase: EnginePhase.paint); |
| expect(inner.isRepaintBoundary, isFalse); |
| expect(() => inner.layer, throwsAssertionError); |
| expect(boundary.isRepaintBoundary, isTrue); |
| expect(boundary.layer, isNotNull); |
| expect(boundary.layer.attached, isTrue); // this time it painted... |
| |
| root.opacity = 0.0; |
| pumpFrame(phase: EnginePhase.paint); |
| expect(inner.isRepaintBoundary, isFalse); |
| expect(() => inner.layer, throwsAssertionError); |
| expect(boundary.isRepaintBoundary, isTrue); |
| expect(boundary.layer, isNotNull); |
| expect(boundary.layer.attached, isFalse); // this time it did not. |
| |
| root.opacity = 0.5; |
| pumpFrame(phase: EnginePhase.paint); |
| expect(inner.isRepaintBoundary, isFalse); |
| expect(() => inner.layer, throwsAssertionError); |
| expect(boundary.isRepaintBoundary, isTrue); |
| expect(boundary.layer, isNotNull); |
| expect(boundary.layer.attached, isTrue); // this time it did again! |
| }); |
| |
| test('layer subtree dirtiness is correctly computed', () { |
| final ContainerLayer a = ContainerLayer(); |
| final ContainerLayer b = ContainerLayer(); |
| final ContainerLayer c = ContainerLayer(); |
| final ContainerLayer d = ContainerLayer(); |
| final ContainerLayer e = ContainerLayer(); |
| final ContainerLayer f = ContainerLayer(); |
| final ContainerLayer g = ContainerLayer(); |
| |
| final PictureLayer h = PictureLayer(Rect.zero); |
| final PictureLayer i = PictureLayer(Rect.zero); |
| final PictureLayer j = PictureLayer(Rect.zero); |
| |
| // The tree is like the following where b and j are dirty: |
| // a____ |
| // / \ |
| // (x)b___ c |
| // / \ \ | |
| // d e f g |
| // / \ | |
| // h i j(x) |
| a.append(b); |
| a.append(c); |
| b.append(d); |
| b.append(e); |
| b.append(f); |
| d.append(h); |
| d.append(i); |
| c.append(g); |
| g.append(j); |
| |
| a.debugMarkClean(); |
| b.markNeedsAddToScene(); // ignore: invalid_use_of_protected_member |
| c.debugMarkClean(); |
| d.debugMarkClean(); |
| e.debugMarkClean(); |
| f.debugMarkClean(); |
| g.debugMarkClean(); |
| h.debugMarkClean(); |
| i.debugMarkClean(); |
| j.markNeedsAddToScene(); // ignore: invalid_use_of_protected_member |
| |
| a.updateSubtreeNeedsAddToScene(); |
| |
| expect(a.debugSubtreeNeedsAddToScene, true); |
| expect(b.debugSubtreeNeedsAddToScene, true); |
| expect(c.debugSubtreeNeedsAddToScene, true); |
| expect(g.debugSubtreeNeedsAddToScene, true); |
| expect(j.debugSubtreeNeedsAddToScene, true); |
| |
| expect(d.debugSubtreeNeedsAddToScene, false); |
| expect(e.debugSubtreeNeedsAddToScene, false); |
| expect(f.debugSubtreeNeedsAddToScene, false); |
| expect(h.debugSubtreeNeedsAddToScene, false); |
| expect(i.debugSubtreeNeedsAddToScene, false); |
| }); |
| |
| test('leader and follower layers are always dirty', () { |
| final LayerLink link = LayerLink(); |
| final LeaderLayer leaderLayer = LeaderLayer(link: link); |
| final FollowerLayer followerLayer = FollowerLayer(link: link); |
| leaderLayer.debugMarkClean(); |
| followerLayer.debugMarkClean(); |
| leaderLayer.updateSubtreeNeedsAddToScene(); |
| followerLayer.updateSubtreeNeedsAddToScene(); |
| expect(leaderLayer.debugSubtreeNeedsAddToScene, true); |
| expect(followerLayer.debugSubtreeNeedsAddToScene, true); |
| }); |
| |
| void checkNeedsAddToScene(Layer layer, void mutateCallback()) { |
| layer.debugMarkClean(); |
| layer.updateSubtreeNeedsAddToScene(); // ignore: invalid_use_of_protected_member |
| expect(layer.debugSubtreeNeedsAddToScene, false); |
| mutateCallback(); |
| layer.updateSubtreeNeedsAddToScene(); // ignore: invalid_use_of_protected_member |
| expect(layer.debugSubtreeNeedsAddToScene, true); |
| } |
| |
| test('mutating PictureLayer fields triggers needsAddToScene', () { |
| final PictureLayer pictureLayer = PictureLayer(Rect.zero); |
| checkNeedsAddToScene(pictureLayer, () { |
| final PictureRecorder recorder = PictureRecorder(); |
| pictureLayer.picture = recorder.endRecording(); |
| }); |
| |
| pictureLayer.isComplexHint = false; |
| checkNeedsAddToScene(pictureLayer, () { |
| pictureLayer.isComplexHint = true; |
| }); |
| |
| pictureLayer.willChangeHint = false; |
| checkNeedsAddToScene(pictureLayer, () { |
| pictureLayer.willChangeHint = true; |
| }); |
| }); |
| |
| final Rect unitRect = Rect.fromLTRB(0, 0, 1, 1); |
| |
| test('mutating PerformanceOverlayLayer fields triggers needsAddToScene', () { |
| final PerformanceOverlayLayer layer = PerformanceOverlayLayer( |
| overlayRect: Rect.zero, optionsMask: 0, rasterizerThreshold: 0, |
| checkerboardRasterCacheImages: false, checkerboardOffscreenLayers: false); |
| checkNeedsAddToScene(layer, () { |
| layer.overlayRect = unitRect; |
| }); |
| }); |
| |
| test('mutating OffsetLayer fields triggers needsAddToScene', () { |
| final OffsetLayer layer = OffsetLayer(); |
| checkNeedsAddToScene(layer, () { |
| layer.offset = const Offset(1, 1); |
| }); |
| }); |
| |
| test('mutating ClipRectLayer fields triggers needsAddToScene', () { |
| final ClipRectLayer layer = ClipRectLayer(clipRect: Rect.zero); |
| checkNeedsAddToScene(layer, () { |
| layer.clipRect = unitRect; |
| }); |
| checkNeedsAddToScene(layer, () { |
| layer.clipBehavior = Clip.antiAliasWithSaveLayer; |
| }); |
| }); |
| |
| test('mutating ClipRRectLayer fields triggers needsAddToScene', () { |
| final ClipRRectLayer layer = ClipRRectLayer(clipRRect: RRect.zero); |
| checkNeedsAddToScene(layer, () { |
| layer.clipRRect = RRect.fromRectAndRadius(unitRect, const Radius.circular(0)); |
| }); |
| checkNeedsAddToScene(layer, () { |
| layer.clipBehavior = Clip.antiAliasWithSaveLayer; |
| }); |
| }); |
| |
| test('mutating ClipPath fields triggers needsAddToScene', () { |
| final ClipPathLayer layer = ClipPathLayer(clipPath: Path()); |
| checkNeedsAddToScene(layer, () { |
| final Path newPath = Path(); |
| newPath.addRect(unitRect); |
| layer.clipPath = newPath; |
| }); |
| checkNeedsAddToScene(layer, () { |
| layer.clipBehavior = Clip.antiAliasWithSaveLayer; |
| }); |
| }); |
| |
| test('mutating OpacityLayer fields triggers needsAddToScene', () { |
| final OpacityLayer layer = OpacityLayer(alpha: 0); |
| checkNeedsAddToScene(layer, () { |
| layer.alpha = 1; |
| }); |
| checkNeedsAddToScene(layer, () { |
| layer.offset = const Offset(1, 1); |
| }); |
| }); |
| |
| test('mutating ShaderMaskLayer fields triggers needsAddToScene', () { |
| const Gradient gradient = RadialGradient(colors: <Color>[Color(0), Color(1)]); |
| final Shader shader = gradient.createShader(Rect.zero); |
| final ShaderMaskLayer layer = ShaderMaskLayer(shader: shader, maskRect: Rect.zero, blendMode: BlendMode.clear); |
| checkNeedsAddToScene(layer, () { |
| layer.maskRect = unitRect; |
| }); |
| checkNeedsAddToScene(layer, () { |
| layer.blendMode = BlendMode.color; |
| }); |
| checkNeedsAddToScene(layer, () { |
| layer.shader = gradient.createShader(unitRect); |
| }); |
| }); |
| |
| test('mutating BackdropFilterLayer fields triggers needsAddToScene', () { |
| final BackdropFilterLayer layer = BackdropFilterLayer(filter: ImageFilter.blur()); |
| checkNeedsAddToScene(layer, () { |
| layer.filter = ImageFilter.blur(sigmaX: 1.0); |
| }); |
| }); |
| |
| test('mutating PhysicalModelLayer fields triggers needsAddToScene', () { |
| final PhysicalModelLayer layer = PhysicalModelLayer( |
| clipPath: Path(), elevation: 0, color: const Color(0), shadowColor: const Color(0)); |
| checkNeedsAddToScene(layer, () { |
| final Path newPath = Path(); |
| newPath.addRect(unitRect); |
| layer.clipPath = newPath; |
| }); |
| checkNeedsAddToScene(layer, () { |
| layer.elevation = 1; |
| }); |
| checkNeedsAddToScene(layer, () { |
| layer.color = const Color(1); |
| }); |
| checkNeedsAddToScene(layer, () { |
| layer.shadowColor = const Color(1); |
| }); |
| }); |
| } |