Commit 24c0645d authored by Adam Barth's avatar Adam Barth

Merge pull request #1182 from abarth/composite_blends

Always using OpacityLayer for blending
parents 91551c79 635168d9
......@@ -372,11 +372,7 @@ class TransformLayer extends ContainerLayer {
/// A composited layer that makes its children partially transparent
class OpacityLayer extends ContainerLayer {
OpacityLayer({ Offset offset: Offset.zero, this.bounds, this.alpha }) : super(offset: offset);
/// Unused
Rect bounds;
// TODO(abarth): Remove.
OpacityLayer({ Offset offset: Offset.zero, this.alpha }) : super(offset: offset);
/// The amount to multiply into the alpha channel
///
......@@ -386,14 +382,13 @@ class OpacityLayer extends ContainerLayer {
void addToScene(ui.SceneBuilder builder, Offset layerOffset) {
Offset childOffset = offset + layerOffset;
builder.pushOpacity(alpha, bounds?.shift(childOffset));
builder.pushOpacity(alpha, null);
addChildrenToScene(builder, childOffset);
builder.pop();
}
void debugDescribeSettings(List<String> settings) {
super.debugDescribeSettings(settings);
settings.add('bounds: $bounds');
settings.add('alpha: $alpha');
}
}
......@@ -285,31 +285,17 @@ class PaintingContext {
}
}
static Paint _getPaintForAlpha(int alpha) {
return new Paint()
..color = new Color.fromARGB(alpha, 0, 0, 0)
..transferMode = TransferMode.srcOver
..isAntiAlias = false;
}
/// Push an opacity layer.
///
/// This function will call painter synchronously with a painting context that
/// will be blended with the given alpha value.
void pushOpacity(bool needsCompositing, Offset offset, Rect bounds, int alpha, PaintingContextCallback painter) {
if (needsCompositing) {
void pushOpacity(Offset offset, int alpha, PaintingContextCallback painter) {
_stopRecordingIfNeeded();
OpacityLayer opacityLayer = new OpacityLayer(bounds: bounds, alpha: alpha);
OpacityLayer opacityLayer = new OpacityLayer(alpha: alpha);
_appendLayer(opacityLayer, offset);
PaintingContext childContext = new PaintingContext._(opacityLayer, _paintBounds);
painter(childContext, Offset.zero);
childContext._stopRecordingIfNeeded();
} else {
// TODO(abarth): pushOpacity should require bounds.
canvas.saveLayer(bounds?.shift(offset), _getPaintForAlpha(alpha));
painter(this, offset);
canvas.restore();
}
}
static Paint _getPaintForShaderMask(Rect bounds,
......@@ -435,7 +421,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
setupParentData(child);
super.adoptChild(child);
markNeedsLayout();
_markNeedsCompositingBitsUpdate();
markNeedsCompositingBitsUpdate();
}
/// Called by subclasses when they decide a render object is no longer a child.
......@@ -451,7 +437,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
child.parentData = null;
super.dropChild(child);
markNeedsLayout();
_markNeedsCompositingBitsUpdate();
markNeedsCompositingBitsUpdate();
}
/// Calls visitor for each immediate child of this render object.
......@@ -854,7 +840,8 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
/// creates at least one composited layer. For example, videos should return
/// true if they use hardware decoders.
///
/// Warning: This getter must not change value over the lifetime of this object.
/// You must call markNeedsCompositingBitsUpdate() if the value of this
/// getter changes.
bool get alwaysNeedsCompositing => false;
ContainerLayer _layer;
......@@ -880,7 +867,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
/// This method does not schedule a rendering frame, because since
/// it cannot be the case that _only_ the compositing bits changed,
/// something else will have scheduled a frame for us.
void _markNeedsCompositingBitsUpdate() {
void markNeedsCompositingBitsUpdate() {
if (_needsCompositingBitsUpdate)
return;
_needsCompositingBitsUpdate = true;
......@@ -889,7 +876,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
if (parent._needsCompositingBitsUpdate)
return;
if (!isRepaintBoundary && !parent.isRepaintBoundary) {
parent._markNeedsCompositingBitsUpdate();
parent.markNeedsCompositingBitsUpdate();
return;
}
}
......
......@@ -525,6 +525,8 @@ class RenderIntrinsicHeight extends RenderProxyBox {
}
int _getAlphaFromOpacity(double opacity) => (opacity * 255).round();
/// Makes its child partially transparent.
///
/// This class paints its child into an intermediate buffer and then blends the
......@@ -534,10 +536,12 @@ class RenderIntrinsicHeight extends RenderProxyBox {
/// into an intermediate buffer.
class RenderOpacity extends RenderProxyBox {
RenderOpacity({ RenderBox child, double opacity })
: this._opacity = opacity, super(child) {
: _opacity = opacity, _alpha = _getAlphaFromOpacity(opacity), super(child) {
assert(opacity >= 0.0 && opacity <= 1.0);
}
bool get alwaysNeedsCompositing => _alpha != 0 && _alpha != 255;
/// The fraction to scale the child's alpha value.
///
/// An opacity of 1.0 is fully opaque. An opacity of 0.0 is fully transparent
......@@ -550,22 +554,23 @@ class RenderOpacity extends RenderProxyBox {
if (_opacity == newOpacity)
return;
_opacity = newOpacity;
_alpha = _getAlphaFromOpacity(_opacity);
markNeedsCompositingBitsUpdate();
markNeedsPaint();
}
int get _alpha => (_opacity * 255).round();
int _alpha;
void paint(PaintingContext context, Offset offset) {
if (child != null) {
int a = _alpha;
if (a == 0)
if (_alpha == 0)
return;
if (a == 255) {
if (_alpha == 255) {
context.paintChild(child, offset);
return;
}
// TODO(abarth): We should pass bounds here.
context.pushOpacity(needsCompositing, offset, null, a, super.paint);
assert(needsCompositing);
context.pushOpacity(offset, _alpha, super.paint);
}
}
......
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