diff --git a/sky/engine/core/painting/Picture.cpp b/sky/engine/core/painting/Picture.cpp index c40cb08b4a8980d714b210e22058b78c708fe064..e59ca8815b90285d8ee7f1a389c3c00e78364d44 100644 --- a/sky/engine/core/painting/Picture.cpp +++ b/sky/engine/core/painting/Picture.cpp @@ -4,6 +4,8 @@ #include "sky/engine/core/painting/Picture.h" +#include "sky/engine/core/painting/Canvas.h" + namespace blink { PassRefPtr Picture::create(PassRefPtr skPicture) @@ -21,4 +23,9 @@ Picture::~Picture() { } +void Picture::playback(Canvas* canvas) +{ + m_picture->playback(canvas->skCanvas()); +} + } // namespace blink diff --git a/sky/engine/core/painting/Picture.h b/sky/engine/core/painting/Picture.h index fc12c942cac73ec3e99840735961602a8462ec42..6d61bc52b0c5cbcd9a6f85c7074b40b26f371e44 100644 --- a/sky/engine/core/painting/Picture.h +++ b/sky/engine/core/painting/Picture.h @@ -12,6 +12,8 @@ namespace blink { +class Canvas; + class Picture : public RefCounted, public DartWrappable { DEFINE_WRAPPERTYPEINFO(); public: @@ -20,6 +22,8 @@ public: SkPicture* toSkia() const { return m_picture.get(); } + void playback(Canvas* canvas); + private: explicit Picture(PassRefPtr skPicture); diff --git a/sky/engine/core/painting/Picture.idl b/sky/engine/core/painting/Picture.idl index 0f618fdef72cafeff11960cb00f1fb24a959a6b0..277bdbd0617e3b437f9ba943bbe735f85103be19 100644 --- a/sky/engine/core/painting/Picture.idl +++ b/sky/engine/core/painting/Picture.idl @@ -2,4 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. interface Picture { + // Replays the drawing commands on the specified canvas. Note that + // this has the effect of unfurling this picture into the destination + // canvas. Using the Canvas drawPicture entry point gives the destination + // canvas the option of just taking a ref. + void playback(Canvas canvas); }; diff --git a/sky/engine/core/painting/Rect.dart b/sky/engine/core/painting/Rect.dart index 270e22fb4e0d9adcb62e5dbcd8d0287a38321ace..4a1dc1cf417faaf60439c83773489c261c782bd5 100644 --- a/sky/engine/core/painting/Rect.dart +++ b/sky/engine/core/painting/Rect.dart @@ -39,6 +39,13 @@ class Rect { Rect deflate(double delta) { return inflate(-delta); } + Rect intersect(Rect other) { + return new Rect.fromLTRB( + math.max(left, other.left), + math.max(top, other.top), + math.max(right, other.right), + math.max(bottom, other.bottom)); + } double get width => right - left; double get height => bottom - top; diff --git a/sky/packages/sky/lib/rendering/box.dart b/sky/packages/sky/lib/rendering/box.dart index ee2aa5982dc7bfeb5ed9325b94ce5e782625135d..f9dbd2c767ef3c472e384caf2101c1f1be5c4425 100644 --- a/sky/packages/sky/lib/rendering/box.dart +++ b/sky/packages/sky/lib/rendering/box.dart @@ -1750,26 +1750,31 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin sky.tracing.begin('RenderView.paintFrame'); try { final double devicePixelRatio = sky.view.devicePixelRatio; - - // TODO(abarth): Really |_rootLayer| should be a TransformLayer that - // applies the devicePixelRatio. + Matrix4 transform = new Matrix4.diagonal3Values(devicePixelRatio, devicePixelRatio, 1.0); + Rect bounds = Point.origin & size; Rect scaledBounds = Point.origin & (size * devicePixelRatio); - PaintingContext context = new PaintingContext(scaledBounds); - _rootLayer = new ContainerLayer(bounds: Point.origin & size); + _rootLayer = new TransformLayer(bounds: scaledBounds, transform: transform); + PaintingContext context = new PaintingContext(bounds); _rootLayer.add(context.layer); - context.canvas.drawColor(const Color(0xFF000000), sky.TransferMode.src); - context.canvas.scale(devicePixelRatio, devicePixelRatio); context.paintChild(child, Point.origin); context.endRecording(); - - // TODO(abarth): Once we have more than one PictureLayer, we should walk - // the layer tree to generate the final picture. - sky.view.picture = (_rootLayer.firstChild as PictureLayer).picture; } finally { sky.tracing.end('RenderView.paintFrame'); } } + void compositeFrame() { + sky.tracing.begin('RenderView.compositeFrame'); + try { + sky.PictureRecorder recorder = new sky.PictureRecorder(); + sky.Canvas canvas = new sky.Canvas(recorder, _rootLayer.bounds); + _rootLayer.paint(canvas); + sky.view.picture = recorder.endRecording(); + } finally { + sky.tracing.end('RenderView.compositeFrame'); + } + } + Rect get paintBounds => Point.origin & size; } diff --git a/sky/packages/sky/lib/rendering/layer.dart b/sky/packages/sky/lib/rendering/layer.dart index 6afe9257a7aec036d97621ebf73345d9870097b6..616de5f3bee8c24194dc8ede2fc5b64af893718a 100644 --- a/sky/packages/sky/lib/rendering/layer.dart +++ b/sky/packages/sky/lib/rendering/layer.dart @@ -7,7 +7,7 @@ import 'dart:sky' show Point, Offset, Size, Rect, Color, Paint, Path; import 'package:vector_math/vector_math.dart'; -class Layer { +abstract class Layer { Layer({ this.bounds }); Rect bounds; @@ -25,6 +25,8 @@ class Layer { if (_parent != null) _parent.remove(this); } + + void paint(sky.Canvas canvas); } class PictureLayer extends Layer { @@ -32,11 +34,23 @@ class PictureLayer extends Layer { : super(bounds: bounds); sky.Picture picture; + + void paint(sky.Canvas canvas) { + canvas.drawPicture(picture); + } } class ContainerLayer extends Layer { ContainerLayer({ Rect bounds }) : super(bounds: bounds); + void paint(sky.Canvas canvas) { + Layer child = firstChild; + while (child != null) { + child.paint(canvas); + child = child.nextSibling; + } + } + Layer _firstChild; Layer get firstChild => _firstChild; @@ -122,10 +136,24 @@ class TransformLayer extends ContainerLayer { TransformLayer({ this.transform, Rect bounds }) : super(bounds: bounds); Matrix4 transform; + + void paint(sky.Canvas canvas) { + canvas.save(); + canvas.concat(transform.storage); + super.paint(canvas); + canvas.restore(); + } } class ClipLayer extends ContainerLayer { ClipLayer({ Rect bounds }) : super(bounds: bounds); + + void paint(sky.Canvas canvas) { + canvas.save(); + canvas.clipRect(bounds); + super.paint(canvas); + canvas.restore(); + } } class ColorFilterLayer extends ContainerLayer { @@ -137,4 +165,14 @@ class ColorFilterLayer extends ContainerLayer { Color color; sky.TransferMode transferMode; + + void paint(sky.Canvas canvas) { + Paint paint = new Paint() + ..color = color + ..setTransferMode(transferMode); + + canvas.saveLayer(bounds, paint); + super.paint(canvas); + canvas.restore(); + } } diff --git a/sky/packages/sky/lib/rendering/object.dart b/sky/packages/sky/lib/rendering/object.dart index 3ba0d6372bdb27b182142a1ec933972ef841a4f9..44593fe407d0c575f9d9485924f74df1f7782da7 100644 --- a/sky/packages/sky/lib/rendering/object.dart +++ b/sky/packages/sky/lib/rendering/object.dart @@ -41,14 +41,24 @@ class PaintingContext { sky.PictureRecorder _recorder; PaintingContext(Rect bounds) { + _startRecording(bounds); + } + + PaintingContext.forTesting(this.canvas); + + void _startRecording(Rect bounds) { + assert(_layer == null); + assert(_recorder == null); + assert(canvas == null); _layer = new PictureLayer(bounds: bounds); _recorder = new sky.PictureRecorder(); canvas = new PaintingCanvas(_recorder, bounds); } - PaintingContext.forTesting(this.canvas); - void endRecording() { + assert(_layer != null); + assert(_recorder != null); + assert(canvas != null); canvas = null; _layer.picture = _recorder.endRecording(); _recorder = null; @@ -56,9 +66,22 @@ class PaintingContext { } void paintChild(RenderObject child, Point point) { - // TODO(abarth): Support compositing. - assert(!child.requiresCompositing); - child._paintWithContext(this, point.toOffset()); + final Offset offset = point.toOffset(); + + if (!child.requiresCompositing) + return child._paintWithContext(this, offset); + + final Layer originalLayer = layer; + endRecording(); + + Rect bounds = child.paintBounds.shift(offset); + PaintingContext context = new PaintingContext(bounds); + originalLayer.parent.add(context.layer, before: originalLayer.nextSibling); + child._paintWithContext(context, Offset.zero); + context.endRecording(); + + _startRecording(originalLayer.bounds); + originalLayer.parent.add(layer, before: context.layer.nextSibling); } } diff --git a/sky/packages/sky/lib/rendering/sky_binding.dart b/sky/packages/sky/lib/rendering/sky_binding.dart index 7d4e4f98f591d56916653dcd5147cdee75b3721f..55902d6840e463fcc53aceb1e03987177218bac8 100644 --- a/sky/packages/sky/lib/rendering/sky_binding.dart +++ b/sky/packages/sky/lib/rendering/sky_binding.dart @@ -73,6 +73,7 @@ class SkyBinding { RenderObject.flushLayout(); RenderObject.flushPaint(); _renderView.paintFrame(); + _renderView.compositeFrame(); } final List _eventListeners = new List(); diff --git a/sky/tests/resources/display_list.dart b/sky/tests/resources/display_list.dart index 962368a890a402c0ab0d8819d237b30ca93b6a0c..0b64100b4799f0b7d8868e01aba728c49e8d9af9 100644 --- a/sky/tests/resources/display_list.dart +++ b/sky/tests/resources/display_list.dart @@ -159,6 +159,9 @@ class TestRenderView extends RenderView { RenderObject.debugDoingPaint = false; } + void compositeFrame() { + } + // TEST API: void syncCheckFrame() {