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) {
|
ui.Shader _createShader(Rect bounds) {
|
||||||
return new LinearGradient(
|
return new LinearGradient(
|
||||||
begin: Point.origin,
|
begin: bounds.topLeft,
|
||||||
end: new Point(0.0, bounds.height),
|
end: bounds.bottomLeft,
|
||||||
colors: <Color>[const Color(0x00FFFFFF), const Color(0xFFFFFFFF)],
|
colors: <Color>[const Color(0x00FFFFFF), const Color(0xFFFFFFFF)],
|
||||||
stops: <double>[0.1, 0.35]
|
stops: <double>[0.1, 0.35]
|
||||||
)
|
)
|
||||||
|
@ -392,3 +392,31 @@ class OpacityLayer extends ContainerLayer {
|
|||||||
settings.add('alpha: $alpha');
|
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 'layer.dart';
|
||||||
export 'package:flutter/gestures.dart' show HitTestEntry, HitTestResult;
|
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.
|
/// Base class for data associated with a [RenderObject] by its parent.
|
||||||
///
|
///
|
||||||
/// Some render objects wish to store data on their children, such as their
|
/// Some render objects wish to store data on their children, such as their
|
||||||
@ -298,27 +296,21 @@ class PaintingContext {
|
|||||||
childContext._stopRecordingIfNeeded();
|
childContext._stopRecordingIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Paint _getPaintForShaderMask(Rect bounds,
|
|
||||||
ShaderCallback shaderCallback,
|
|
||||||
TransferMode transferMode) {
|
|
||||||
return new Paint()
|
|
||||||
..transferMode = transferMode
|
|
||||||
..shader = shaderCallback(bounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Push a shader mask.
|
/// Push a shader mask.
|
||||||
///
|
///
|
||||||
/// This function will call painter synchronously with a painting context that
|
/// This function will call painter synchronously with a painting context that
|
||||||
/// will be masked with the given shader.
|
/// will be masked with the given shader.
|
||||||
///
|
void pushShaderMask(Offset offset, ui.Shader shader, Rect maskRect, TransferMode transferMode, PaintingContextCallback painter) {
|
||||||
/// WARNING: This function does not yet support compositing.
|
_stopRecordingIfNeeded();
|
||||||
void pushShaderMask(bool needsCompositing, Offset offset, Rect bounds, ShaderCallback shaderCallback, TransferMode transferMode, PaintingContextCallback painter) {
|
ShaderMaskLayer shaderLayer = new ShaderMaskLayer(
|
||||||
assert(!needsCompositing); // TODO(abarth): Implement compositing for shader masks.
|
shader: shader,
|
||||||
canvas.saveLayer(bounds.shift(offset), _disableAntialias);
|
maskRect: maskRect,
|
||||||
painter(this, offset);
|
transferMode: transferMode
|
||||||
Paint shaderPaint = _getPaintForShaderMask(bounds, shaderCallback, transferMode);
|
);
|
||||||
canvas.drawRect(bounds, shaderPaint);
|
_appendLayer(shaderLayer, offset);
|
||||||
canvas.restore();
|
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);
|
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.
|
/// 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 {
|
class RenderShaderMask extends RenderProxyBox {
|
||||||
RenderShaderMask({ RenderBox child, ShaderCallback shaderCallback, TransferMode transferMode })
|
RenderShaderMask({ RenderBox child, ShaderCallback shaderCallback, TransferMode transferMode })
|
||||||
: _shaderCallback = shaderCallback, _transferMode = transferMode, super(child);
|
: _shaderCallback = shaderCallback, _transferMode = transferMode, super(child);
|
||||||
@ -604,9 +606,14 @@ class RenderShaderMask extends RenderProxyBox {
|
|||||||
markNeedsPaint();
|
markNeedsPaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get alwaysNeedsCompositing => child != null;
|
||||||
|
|
||||||
void paint(PaintingContext context, Offset offset) {
|
void paint(PaintingContext context, Offset offset) {
|
||||||
if (child != null)
|
if (child != null) {
|
||||||
context.pushShaderMask(needsCompositing, offset, Point.origin & size, _shaderCallback, _transferMode, super.paint);
|
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) {
|
ui.Shader createShader(Rect bounds) {
|
||||||
return new LinearGradient(
|
return new LinearGradient(
|
||||||
begin: Point.origin,
|
begin: bounds.topLeft,
|
||||||
end: new Point(0.0, bounds.height),
|
end: bounds.bottomLeft,
|
||||||
colors: <Color>[const Color(0x00FFFFFF), const Color(0xFFFFFFFF)],
|
colors: <Color>[const Color(0x00FFFFFF), const Color(0xFFFFFFFF)],
|
||||||
stops: <double>[0.1, 0.35]
|
stops: <double>[0.1, 0.35]
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user