remove forced compositing from opacity (#105334)
This commit is contained in:
parent
d5c62438e3
commit
febc6a14f5
@ -13,6 +13,7 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:vector_math/vector_math_64.dart';
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
|
|
||||||
import 'box.dart';
|
import 'box.dart';
|
||||||
|
import 'debug.dart';
|
||||||
import 'layer.dart';
|
import 'layer.dart';
|
||||||
import 'layout_helper.dart';
|
import 'layout_helper.dart';
|
||||||
import 'object.dart';
|
import 'object.dart';
|
||||||
@ -884,16 +885,6 @@ class RenderOpacity extends RenderProxyBox {
|
|||||||
_alpha = ui.Color.getAlphaFromOpacity(opacity),
|
_alpha = ui.Color.getAlphaFromOpacity(opacity),
|
||||||
super(child);
|
super(child);
|
||||||
|
|
||||||
@override
|
|
||||||
bool get alwaysNeedsCompositing => child != null && (_alpha > 0);
|
|
||||||
|
|
||||||
@override
|
|
||||||
OffsetLayer updateCompositedLayer({required covariant OpacityLayer? oldLayer}) {
|
|
||||||
final OpacityLayer updatedLayer = oldLayer ?? OpacityLayer();
|
|
||||||
updatedLayer.alpha = _alpha;
|
|
||||||
return updatedLayer;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _alpha;
|
int _alpha;
|
||||||
|
|
||||||
/// The fraction to scale the child's alpha value.
|
/// The fraction to scale the child's alpha value.
|
||||||
@ -914,13 +905,9 @@ class RenderOpacity extends RenderProxyBox {
|
|||||||
if (_opacity == value) {
|
if (_opacity == value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final bool didNeedCompositing = alwaysNeedsCompositing;
|
|
||||||
final bool wasVisible = _alpha != 0;
|
final bool wasVisible = _alpha != 0;
|
||||||
_opacity = value;
|
_opacity = value;
|
||||||
_alpha = ui.Color.getAlphaFromOpacity(_opacity);
|
_alpha = ui.Color.getAlphaFromOpacity(_opacity);
|
||||||
if (didNeedCompositing != alwaysNeedsCompositing) {
|
|
||||||
markNeedsCompositingBitsUpdate();
|
|
||||||
}
|
|
||||||
markNeedsPaint();
|
markNeedsPaint();
|
||||||
if (wasVisible != (_alpha != 0) && !alwaysIncludeSemantics) {
|
if (wasVisible != (_alpha != 0) && !alwaysIncludeSemantics) {
|
||||||
markNeedsSemanticsUpdate();
|
markNeedsSemanticsUpdate();
|
||||||
@ -950,19 +937,40 @@ class RenderOpacity extends RenderProxyBox {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(PaintingContext context, Offset offset) {
|
void paint(PaintingContext context, Offset offset) {
|
||||||
if (child != null) {
|
if (child == null) {
|
||||||
if (_alpha == 0) {
|
return;
|
||||||
// No need to keep the layer. We'll create a new one if necessary.
|
}
|
||||||
layer = null;
|
if (_alpha == 0) {
|
||||||
return;
|
// No need to keep the layer. We'll create a new one if necessary.
|
||||||
}
|
layer = null;
|
||||||
assert(needsCompositing);
|
return;
|
||||||
|
}
|
||||||
|
if (_alpha == 255) {
|
||||||
|
layer = null;
|
||||||
|
return super.paint(context, offset);
|
||||||
|
}
|
||||||
|
// Due to https://github.com/flutter/flutter/issues/48417 this will always need to be
|
||||||
|
// composited on the web.
|
||||||
|
if (needsCompositing || kIsWeb) {
|
||||||
layer = context.pushOpacity(offset, _alpha, super.paint, oldLayer: layer as OpacityLayer?);
|
layer = context.pushOpacity(offset, _alpha, super.paint, oldLayer: layer as OpacityLayer?);
|
||||||
assert(() {
|
assert(() {
|
||||||
layer!.debugCreator = debugCreator;
|
layer?.debugCreator = debugCreator;
|
||||||
return true;
|
return true;
|
||||||
}());
|
}());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// debugDisableOpacityLayers is used by the SceneBuilder to remove opacity layers, but
|
||||||
|
// if the framework is not asked to composite will also need to remove the opacity here.
|
||||||
|
if (kDebugMode && debugDisableOpacityLayers) {
|
||||||
|
super.paint(context, offset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Color color = Color.fromRGBO(0, 0, 0, opacity);
|
||||||
|
final Canvas canvas = context.canvas;
|
||||||
|
canvas.saveLayer(size != null ? offset & size : null, Paint()..color = color);
|
||||||
|
super.paint(context, offset);
|
||||||
|
canvas.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -197,7 +197,7 @@ void main() {
|
|||||||
|
|
||||||
expect(data.lengthInBytes, equals(20 * 20 * 4));
|
expect(data.lengthInBytes, equals(20 * 20 * 4));
|
||||||
expect(data.elementSizeInBytes, equals(1));
|
expect(data.elementSizeInBytes, equals(1));
|
||||||
expect(getPixel(0, 0), equals(0x00000080));
|
expect(getPixel(0, 0), equals(0x0000007F));
|
||||||
expect(getPixel(image.width - 1, 0 ), equals(0xffffffff));
|
expect(getPixel(image.width - 1, 0 ), equals(0xffffffff));
|
||||||
|
|
||||||
final OffsetLayer layer = boundary.debugLayer! as OffsetLayer;
|
final OffsetLayer layer = boundary.debugLayer! as OffsetLayer;
|
||||||
@ -206,7 +206,7 @@ void main() {
|
|||||||
expect(image.width, equals(20));
|
expect(image.width, equals(20));
|
||||||
expect(image.height, equals(20));
|
expect(image.height, equals(20));
|
||||||
data = (await image.toByteData())!;
|
data = (await image.toByteData())!;
|
||||||
expect(getPixel(0, 0), equals(0x00000080));
|
expect(getPixel(0, 0), equals(0x0000007F));
|
||||||
expect(getPixel(image.width - 1, 0 ), equals(0xffffffff));
|
expect(getPixel(image.width - 1, 0 ), equals(0xffffffff));
|
||||||
|
|
||||||
// non-zero offsets.
|
// non-zero offsets.
|
||||||
@ -215,7 +215,7 @@ void main() {
|
|||||||
expect(image.height, equals(30));
|
expect(image.height, equals(30));
|
||||||
data = (await image.toByteData())!;
|
data = (await image.toByteData())!;
|
||||||
expect(getPixel(0, 0), equals(0x00000000));
|
expect(getPixel(0, 0), equals(0x00000000));
|
||||||
expect(getPixel(10, 10), equals(0x00000080));
|
expect(getPixel(10, 10), equals(0x0000007F));
|
||||||
expect(getPixel(image.width - 1, 0), equals(0x00000000));
|
expect(getPixel(image.width - 1, 0), equals(0x00000000));
|
||||||
expect(getPixel(image.width - 1, 10), equals(0xffffffff));
|
expect(getPixel(image.width - 1, 10), equals(0xffffffff));
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ void main() {
|
|||||||
expect(image.height, equals(60));
|
expect(image.height, equals(60));
|
||||||
data = (await image.toByteData())!;
|
data = (await image.toByteData())!;
|
||||||
expect(getPixel(0, 0), equals(0x00000000));
|
expect(getPixel(0, 0), equals(0x00000000));
|
||||||
expect(getPixel(20, 20), equals(0x00000080));
|
expect(getPixel(20, 20), equals(0x0000007F));
|
||||||
expect(getPixel(image.width - 1, 0), equals(0x00000000));
|
expect(getPixel(image.width - 1, 0), equals(0x00000000));
|
||||||
expect(getPixel(image.width - 1, 20), equals(0xffffffff));
|
expect(getPixel(image.width - 1, 20), equals(0xffffffff));
|
||||||
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/49857
|
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/49857
|
||||||
@ -240,13 +240,13 @@ void main() {
|
|||||||
expect(renderOpacity.needsCompositing, false);
|
expect(renderOpacity.needsCompositing, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('RenderOpacity does composite if it is opaque', () {
|
test('RenderOpacity does not composite if it is opaque', () {
|
||||||
final RenderOpacity renderOpacity = RenderOpacity(
|
final RenderOpacity renderOpacity = RenderOpacity(
|
||||||
child: RenderSizedBox(const Size(1.0, 1.0)), // size doesn't matter
|
child: RenderSizedBox(const Size(1.0, 1.0)), // size doesn't matter
|
||||||
);
|
);
|
||||||
|
|
||||||
layout(renderOpacity, phase: EnginePhase.composite);
|
layout(renderOpacity, phase: EnginePhase.composite);
|
||||||
expect(renderOpacity.needsCompositing, true);
|
expect(renderOpacity.needsCompositing, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('RenderOpacity reuses its layer', () {
|
test('RenderOpacity reuses its layer', () {
|
||||||
|
@ -285,8 +285,8 @@ void main() {
|
|||||||
child: Placeholder(),
|
child: Placeholder(),
|
||||||
),
|
),
|
||||||
const Opacity(
|
const Opacity(
|
||||||
opacity: 1.0,
|
opacity: 0.9, // ensure compositing is used.
|
||||||
child: Placeholder(),
|
child: RepaintBoundary(child: Placeholder()),
|
||||||
),
|
),
|
||||||
ImageFiltered(
|
ImageFiltered(
|
||||||
imageFilter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
|
imageFilter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user