ShaderMask needs to play nicely with compositing
This patch adds ShaderLayer and makes ShaderMask use it. Fixes #1155
This commit is contained in:
parent
875da1f53f
commit
82bb3bd40d
@ -393,8 +393,8 @@ class CardCollectionState extends State<CardCollection> {
|
||||
|
||||
ui.Shader _createShader(Rect bounds) {
|
||||
return new LinearGradient(
|
||||
begin: Point.origin,
|
||||
end: new Point(0.0, bounds.height),
|
||||
begin: bounds.topLeft,
|
||||
end: bounds.bottomLeft,
|
||||
colors: <Color>[const Color(0x00FFFFFF), const Color(0xFFFFFFFF)],
|
||||
stops: <double>[0.1, 0.35]
|
||||
)
|
||||
|
@ -392,3 +392,31 @@ class OpacityLayer extends ContainerLayer {
|
||||
settings.add('alpha: $alpha');
|
||||
}
|
||||
}
|
||||
|
||||
/// A composited layer that applies a shader to hits children.
|
||||
class ShaderMaskLayer extends ContainerLayer {
|
||||
ShaderMaskLayer({ Offset offset: Offset.zero, this.shader, this.maskRect, this.transferMode }) : super(offset: offset);
|
||||
|
||||
/// The shader to apply to the children.
|
||||
ui.Shader shader;
|
||||
|
||||
/// The size of the shader.
|
||||
Rect maskRect;
|
||||
|
||||
/// The tranfer mode to apply when blending the shader with the children.
|
||||
TransferMode transferMode;
|
||||
|
||||
void addToScene(ui.SceneBuilder builder, Offset layerOffset) {
|
||||
Offset childOffset = offset + layerOffset;
|
||||
builder.pushShaderMask(shader, maskRect.shift(childOffset), transferMode);
|
||||
addChildrenToScene(builder, childOffset);
|
||||
builder.pop();
|
||||
}
|
||||
|
||||
void debugDescribeSettings(List<String> settings) {
|
||||
super.debugDescribeSettings(settings);
|
||||
settings.add('shader: $shader');
|
||||
settings.add('maskRect: $maskRect');
|
||||
settings.add('transferMode: $transferMode');
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,6 @@ import 'node.dart';
|
||||
export 'layer.dart';
|
||||
export 'package:flutter/gestures.dart' show HitTestEntry, HitTestResult;
|
||||
|
||||
typedef ui.Shader ShaderCallback(Rect bounds);
|
||||
|
||||
/// Base class for data associated with a [RenderObject] by its parent.
|
||||
///
|
||||
/// Some render objects wish to store data on their children, such as their
|
||||
@ -298,27 +296,21 @@ class PaintingContext {
|
||||
childContext._stopRecordingIfNeeded();
|
||||
}
|
||||
|
||||
static Paint _getPaintForShaderMask(Rect bounds,
|
||||
ShaderCallback shaderCallback,
|
||||
TransferMode transferMode) {
|
||||
return new Paint()
|
||||
..transferMode = transferMode
|
||||
..shader = shaderCallback(bounds);
|
||||
}
|
||||
|
||||
/// Push a shader mask.
|
||||
///
|
||||
/// This function will call painter synchronously with a painting context that
|
||||
/// will be masked with the given shader.
|
||||
///
|
||||
/// WARNING: This function does not yet support compositing.
|
||||
void pushShaderMask(bool needsCompositing, Offset offset, Rect bounds, ShaderCallback shaderCallback, TransferMode transferMode, PaintingContextCallback painter) {
|
||||
assert(!needsCompositing); // TODO(abarth): Implement compositing for shader masks.
|
||||
canvas.saveLayer(bounds.shift(offset), _disableAntialias);
|
||||
painter(this, offset);
|
||||
Paint shaderPaint = _getPaintForShaderMask(bounds, shaderCallback, transferMode);
|
||||
canvas.drawRect(bounds, shaderPaint);
|
||||
canvas.restore();
|
||||
void pushShaderMask(Offset offset, ui.Shader shader, Rect maskRect, TransferMode transferMode, PaintingContextCallback painter) {
|
||||
_stopRecordingIfNeeded();
|
||||
ShaderMaskLayer shaderLayer = new ShaderMaskLayer(
|
||||
shader: shader,
|
||||
maskRect: maskRect,
|
||||
transferMode: transferMode
|
||||
);
|
||||
_appendLayer(shaderLayer, offset);
|
||||
PaintingContext childContext = new PaintingContext._(shaderLayer, _paintBounds);
|
||||
painter(childContext, Offset.zero);
|
||||
childContext._stopRecordingIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -540,7 +540,7 @@ class RenderOpacity extends RenderProxyBox {
|
||||
assert(opacity >= 0.0 && opacity <= 1.0);
|
||||
}
|
||||
|
||||
bool get alwaysNeedsCompositing => _alpha != 0 && _alpha != 255;
|
||||
bool get alwaysNeedsCompositing => child != null && (_alpha != 0 && _alpha != 255);
|
||||
|
||||
/// The fraction to scale the child's alpha value.
|
||||
///
|
||||
@ -580,6 +580,8 @@ class RenderOpacity extends RenderProxyBox {
|
||||
}
|
||||
}
|
||||
|
||||
typedef ui.Shader ShaderCallback(Rect bounds);
|
||||
|
||||
class RenderShaderMask extends RenderProxyBox {
|
||||
RenderShaderMask({ RenderBox child, ShaderCallback shaderCallback, TransferMode transferMode })
|
||||
: _shaderCallback = shaderCallback, _transferMode = transferMode, super(child);
|
||||
@ -604,9 +606,14 @@ class RenderShaderMask extends RenderProxyBox {
|
||||
markNeedsPaint();
|
||||
}
|
||||
|
||||
bool get alwaysNeedsCompositing => child != null;
|
||||
|
||||
void paint(PaintingContext context, Offset offset) {
|
||||
if (child != null)
|
||||
context.pushShaderMask(needsCompositing, offset, Point.origin & size, _shaderCallback, _transferMode, super.paint);
|
||||
if (child != null) {
|
||||
assert(needsCompositing);
|
||||
Rect rect = Point.origin & size;
|
||||
context.pushShaderMask(offset, _shaderCallback(rect), rect, _transferMode, super.paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,8 @@ import 'package:test/test.dart';
|
||||
|
||||
ui.Shader createShader(Rect bounds) {
|
||||
return new LinearGradient(
|
||||
begin: Point.origin,
|
||||
end: new Point(0.0, bounds.height),
|
||||
begin: bounds.topLeft,
|
||||
end: bounds.bottomLeft,
|
||||
colors: <Color>[const Color(0x00FFFFFF), const Color(0xFFFFFFFF)],
|
||||
stops: <double>[0.1, 0.35]
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user