Switch painting over to using PictureLayer
Currently we have a single PictureLayer that everyone draws into. A future patch will teach the system to use multiple PictureLayers.
This commit is contained in:
parent
4b462bab5d
commit
7cba729110
@ -8,6 +8,7 @@ import 'dart:sky' as sky;
|
||||
import 'package:sky/base/debug.dart';
|
||||
import 'package:sky/painting/box_painter.dart';
|
||||
import 'package:sky/painting/text_style.dart';
|
||||
import 'package:sky/rendering/layer.dart';
|
||||
import 'package:sky/rendering/object.dart';
|
||||
import 'package:vector_math/vector_math.dart';
|
||||
|
||||
@ -1703,6 +1704,8 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
ContainerLayer _rootLayer;
|
||||
|
||||
// We never call layout() on this class, so this should never get
|
||||
// checked. (This class is laid out using scheduleInitialLayout().)
|
||||
bool debugDoesMeetConstraints() { assert(false); return false; }
|
||||
@ -1746,15 +1749,22 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
|
||||
void paintFrame() {
|
||||
sky.tracing.begin('RenderView.paintFrame');
|
||||
try {
|
||||
double devicePixelRatio = sky.view.devicePixelRatio;
|
||||
sky.PictureRecorder recorder = new sky.PictureRecorder();
|
||||
Rect cullRect = Point.origin & (size * devicePixelRatio);
|
||||
PaintingCanvas canvas = new PaintingCanvas(recorder, cullRect);
|
||||
PaintingContext context = new PaintingContext(canvas);
|
||||
canvas.drawColor(const Color(0xFF000000), sky.TransferMode.src);
|
||||
canvas.scale(devicePixelRatio, devicePixelRatio);
|
||||
final double devicePixelRatio = sky.view.devicePixelRatio;
|
||||
|
||||
// TODO(abarth): Really |_rootLayer| should be a TransformLayer that
|
||||
// applies the devicePixelRatio.
|
||||
Rect scaledBounds = Point.origin & (size * devicePixelRatio);
|
||||
PaintingContext context = new PaintingContext(scaledBounds);
|
||||
_rootLayer = new ContainerLayer(bounds: Point.origin & size);
|
||||
_rootLayer.add(context.layer);
|
||||
context.canvas.drawColor(const Color(0xFF000000), sky.TransferMode.src);
|
||||
context.canvas.scale(devicePixelRatio, devicePixelRatio);
|
||||
context.paintChild(child, Point.origin);
|
||||
sky.view.picture = recorder.endRecording();
|
||||
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');
|
||||
}
|
||||
|
140
packages/flutter/lib/rendering/layer.dart
Normal file
140
packages/flutter/lib/rendering/layer.dart
Normal file
@ -0,0 +1,140 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:sky' as sky;
|
||||
import 'dart:sky' show Point, Offset, Size, Rect, Color, Paint, Path;
|
||||
|
||||
import 'package:vector_math/vector_math.dart';
|
||||
|
||||
class Layer {
|
||||
Layer({ this.bounds });
|
||||
|
||||
Rect bounds;
|
||||
|
||||
ContainerLayer _parent;
|
||||
ContainerLayer get parent => _parent;
|
||||
|
||||
Layer _nextSibling;
|
||||
Layer get nextSibling => _nextSibling;
|
||||
|
||||
Layer _previousSibling;
|
||||
Layer get previousSibling => _previousSibling;
|
||||
|
||||
void detach() {
|
||||
if (_parent != null)
|
||||
_parent.remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
class PictureLayer extends Layer {
|
||||
PictureLayer({ Rect bounds })
|
||||
: super(bounds: bounds);
|
||||
|
||||
sky.Picture picture;
|
||||
}
|
||||
|
||||
class ContainerLayer extends Layer {
|
||||
ContainerLayer({ Rect bounds }) : super(bounds: bounds);
|
||||
|
||||
Layer _firstChild;
|
||||
Layer get firstChild => _firstChild;
|
||||
|
||||
Layer _lastChild;
|
||||
Layer get lastChild => _lastChild;
|
||||
|
||||
bool _debugUltimatePreviousSiblingOf(Layer child, { Layer equals }) {
|
||||
while (child._previousSibling != null) {
|
||||
assert(child._previousSibling != child);
|
||||
child = child._previousSibling;
|
||||
}
|
||||
return child == equals;
|
||||
}
|
||||
|
||||
bool _debugUltimateNextSiblingOf(Layer child, { Layer equals }) {
|
||||
while (child._nextSibling != null) {
|
||||
assert(child._nextSibling != child);
|
||||
child = child._nextSibling;
|
||||
}
|
||||
return child == equals;
|
||||
}
|
||||
|
||||
void add(Layer child, { Layer before }) {
|
||||
assert(child != this);
|
||||
assert(before != this);
|
||||
assert(child != before);
|
||||
assert(child != _firstChild);
|
||||
assert(child != _lastChild);
|
||||
assert(child._parent == null);
|
||||
assert(child._nextSibling == null);
|
||||
assert(child._previousSibling == null);
|
||||
child._parent = this;
|
||||
if (before == null) {
|
||||
child._previousSibling = _lastChild;
|
||||
if (_lastChild != null)
|
||||
_lastChild._nextSibling = child;
|
||||
_lastChild = child;
|
||||
if (_firstChild == null)
|
||||
_firstChild = child;
|
||||
} else {
|
||||
assert(_firstChild != null);
|
||||
assert(_lastChild != null);
|
||||
assert(_debugUltimatePreviousSiblingOf(before, equals: _firstChild));
|
||||
assert(_debugUltimateNextSiblingOf(before, equals: _lastChild));
|
||||
if (before._previousSibling == null) {
|
||||
assert(before == _firstChild);
|
||||
child._nextSibling = before;
|
||||
before._previousSibling = child;
|
||||
_firstChild = child;
|
||||
} else {
|
||||
child._previousSibling = before._previousSibling;
|
||||
child._nextSibling = before;
|
||||
child._previousSibling._nextSibling = child;
|
||||
child._nextSibling._previousSibling = child;
|
||||
assert(before._previousSibling == child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void remove(Layer child) {
|
||||
assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild));
|
||||
assert(_debugUltimateNextSiblingOf(child, equals: _lastChild));
|
||||
assert(child._parent == this);
|
||||
if (child._previousSibling == null) {
|
||||
assert(_firstChild == child);
|
||||
_firstChild = child._nextSibling;
|
||||
} else {
|
||||
child._previousSibling._nextSibling = child._nextSibling;
|
||||
}
|
||||
if (child._nextSibling == null) {
|
||||
assert(_lastChild == child);
|
||||
_lastChild = child._previousSibling;
|
||||
} else {
|
||||
child._nextSibling._previousSibling = child._previousSibling;
|
||||
}
|
||||
child._previousSibling = null;
|
||||
child._nextSibling = null;
|
||||
child._parent = null;
|
||||
}
|
||||
}
|
||||
|
||||
class TransformLayer extends ContainerLayer {
|
||||
TransformLayer({ this.transform, Rect bounds }) : super(bounds: bounds);
|
||||
|
||||
Matrix4 transform;
|
||||
}
|
||||
|
||||
class ClipLayer extends ContainerLayer {
|
||||
ClipLayer({ Rect bounds }) : super(bounds: bounds);
|
||||
}
|
||||
|
||||
class ColorFilterLayer extends ContainerLayer {
|
||||
ColorFilterLayer({
|
||||
Rect bounds,
|
||||
this.color,
|
||||
this.transferMode
|
||||
}) : super(bounds: bounds);
|
||||
|
||||
Color color;
|
||||
sky.TransferMode transferMode;
|
||||
}
|
@ -10,6 +10,7 @@ import 'package:sky/base/debug.dart';
|
||||
import 'package:sky/base/hit_test.dart';
|
||||
import 'package:sky/base/node.dart';
|
||||
import 'package:sky/base/scheduler.dart' as scheduler;
|
||||
import 'package:sky/rendering/layer.dart';
|
||||
import 'package:vector_math/vector_math.dart';
|
||||
|
||||
export 'dart:sky' show Point, Offset, Size, Rect, Color, Paint, Path;
|
||||
@ -32,9 +33,27 @@ class PaintingCanvas extends sky.Canvas {
|
||||
}
|
||||
|
||||
class PaintingContext {
|
||||
final PaintingCanvas canvas;
|
||||
PaintingCanvas canvas;
|
||||
|
||||
PaintingContext(this.canvas);
|
||||
PictureLayer get layer => _layer;
|
||||
PictureLayer _layer;
|
||||
|
||||
sky.PictureRecorder _recorder;
|
||||
|
||||
PaintingContext(Rect bounds) {
|
||||
_layer = new PictureLayer(bounds: bounds);
|
||||
_recorder = new sky.PictureRecorder();
|
||||
canvas = new PaintingCanvas(_recorder, bounds);
|
||||
}
|
||||
|
||||
PaintingContext.forTesting(this.canvas);
|
||||
|
||||
void endRecording() {
|
||||
canvas = null;
|
||||
_layer.picture = _recorder.endRecording();
|
||||
_recorder = null;
|
||||
_layer = null;
|
||||
}
|
||||
|
||||
void paintChild(RenderObject child, Point point) {
|
||||
// TODO(abarth): Support compositing.
|
||||
@ -318,6 +337,12 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
bool _needsPaint = true;
|
||||
bool get needsPaint => _needsPaint;
|
||||
|
||||
PictureLayer _layer;
|
||||
PictureLayer get layer {
|
||||
assert(requiresCompositing);
|
||||
return _layer;
|
||||
}
|
||||
|
||||
void markNeedsPaint() {
|
||||
assert(!debugDoingPaint);
|
||||
if (!attached) return; // Don't try painting things that aren't in the hierarchy
|
||||
@ -357,9 +382,11 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
void _repaint() {
|
||||
assert(!_needsLayout);
|
||||
assert(requiresCompositing);
|
||||
sky.PictureRecorder recorder = new sky.PictureRecorder();
|
||||
sky.Canvas canvas = new sky.Canvas(recorder, paintBounds);
|
||||
PaintingContext context = new PaintingContext(canvas);
|
||||
assert(_layer != null);
|
||||
PaintingContext context = new PaintingContext(paintBounds);
|
||||
_layer.parent.add(context.layer, before: _layer);
|
||||
_layer.detach();
|
||||
_layer = context._layer;
|
||||
_needsPaint = false;
|
||||
try {
|
||||
_paintWithContext(context, Offset.zero);
|
||||
|
Loading…
x
Reference in New Issue
Block a user