Commit 82bb3bd4 authored by Adam Barth's avatar Adam Barth

ShaderMask needs to play nicely with compositing

This patch adds ShaderLayer and makes ShaderMask use it.

Fixes #1155
parent 875da1f5
......@@ -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]
)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment