layer.dart 8.05 KB
Newer Older
1 2 3 4 5 6 7 8 9
// 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';

10
abstract class Layer {
11
  Layer({ this.offset: Offset.zero });
12

13
  Offset offset; // From parent, in parent's coordinate system.
14 15 16 17 18 19 20 21 22 23 24 25 26 27

  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);
  }
Hixie's avatar
Hixie committed
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
  void replaceWith(Layer newLayer) {
    assert(_parent != null);
    assert(newLayer._parent == null);
    assert(newLayer._nextSibling == null);
    assert(newLayer._previousSibling == null);
    newLayer._nextSibling = _nextSibling;
    if (_nextSibling != null)
      newLayer._nextSibling._previousSibling = newLayer;
    newLayer._previousSibling = _previousSibling;
    if (_previousSibling != null)
      newLayer._previousSibling._nextSibling = newLayer;
    newLayer._parent = _parent;
    if (_parent._firstChild == this)
      _parent._firstChild = newLayer;
    if (_parent._lastChild == this)
      _parent._lastChild = newLayer;
    _nextSibling = null;
    _previousSibling = null;
    _parent = null;
  }
48

49
  void addToScene(sky.SceneBuilder builder, Offset layerOffset);
50 51 52
}

class PictureLayer extends Layer {
Hixie's avatar
Hixie committed
53
  PictureLayer({ Offset offset: Offset.zero, this.paintBounds })
54
    : super(offset: offset);
55

Hixie's avatar
Hixie committed
56
  Rect paintBounds;
57
  sky.Picture picture;
58

59 60
  void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
    builder.addPicture(offset + layerOffset, picture, paintBounds);
61 62
  }

63 64 65
}

class ContainerLayer extends Layer {
66
  ContainerLayer({ Offset offset: Offset.zero }) : super(offset: offset);
67

Hixie's avatar
Hixie committed
68
  // TODO(ianh): hide firstChild since nobody uses it
69 70 71
  Layer _firstChild;
  Layer get firstChild => _firstChild;

Hixie's avatar
Hixie committed
72
  // TODO(ianh): remove _lastChild since nobody uses it
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
  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;
  }

Hixie's avatar
Hixie committed
92
  // TODO(ianh): Remove 'before' and rename the function to 'append' since nobody uses 'before'
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
  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);
      }
    }
  }

Hixie's avatar
Hixie committed
130
  // TODO(ianh): Hide this function since only detach() uses it
131
  void remove(Layer child) {
Hixie's avatar
Hixie committed
132
    assert(child._parent == this);
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
    assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild));
    assert(_debugUltimateNextSiblingOf(child, equals: _lastChild));
    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;
  }
Hixie's avatar
Hixie committed
151

152 153 154 155 156 157 158 159 160 161 162 163 164
  void removeAllChildren() {
    Layer child = _firstChild;
    while (child != null) {
      Layer next = child.nextSibling;
      child._previousSibling = null;
      child._nextSibling = null;
      child._parent = null;
      child = next;
    }
    _firstChild = null;
    _lastChild = null;
  }

165 166
  void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
    addChildrenToScene(builder, offset + layerOffset);
Hixie's avatar
Hixie committed
167 168
  }

169
  void addChildrenToScene(sky.SceneBuilder builder, Offset layerOffset) {
Hixie's avatar
Hixie committed
170 171
    Layer child = firstChild;
    while (child != null) {
172
      child.addToScene(builder, layerOffset);
Hixie's avatar
Hixie committed
173 174 175
      child = child.nextSibling;
    }
  }
176

Hixie's avatar
Hixie committed
177 178 179 180 181 182 183 184
}

class ClipRectLayer extends ContainerLayer {
  ClipRectLayer({ Offset offset: Offset.zero, this.clipRect }) : super(offset: offset);

  // clipRect is _not_ affected by given offset
  Rect clipRect;

185 186 187 188
  void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
    builder.pushClipRect(clipRect.shift(layerOffset));
    addChildrenToScene(builder, offset + layerOffset);
    builder.pop();
Hixie's avatar
Hixie committed
189 190
  }

191
}
Hixie's avatar
Hixie committed
192 193 194 195 196 197 198 199

class ClipRRectLayer extends ContainerLayer {
  ClipRRectLayer({ Offset offset: Offset.zero, this.bounds, this.clipRRect }) : super(offset: offset);

  // bounds and clipRRect are _not_ affected by given offset
  Rect bounds;
  sky.RRect clipRRect;

200 201 202 203
  void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
    builder.pushClipRRect(clipRRect.shift(layerOffset), bounds.shift(layerOffset));
    addChildrenToScene(builder, offset + layerOffset);
    builder.pop();
Hixie's avatar
Hixie committed
204
  }
205

Hixie's avatar
Hixie committed
206 207 208 209 210 211 212 213 214
}

class ClipPathLayer extends ContainerLayer {
  ClipPathLayer({ Offset offset: Offset.zero, this.bounds, this.clipPath }) : super(offset: offset);

  // bounds and clipPath are _not_ affected by given offset
  Rect bounds;
  Path clipPath;

215 216 217 218
  void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
    builder.pushClipPath(clipPath.shift(layerOffset), bounds.shift(layerOffset));
    addChildrenToScene(builder, offset + layerOffset);
    builder.pop();
Hixie's avatar
Hixie committed
219
  }
220

221 222 223
}

class TransformLayer extends ContainerLayer {
224
  TransformLayer({ Offset offset: Offset.zero, this.transform }) : super(offset: offset);
225 226

  Matrix4 transform;
227

228 229 230 231 232 233
  void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
    Matrix4 offsetTransform = new Matrix4.identity();
    offsetTransform.translate(offset.dx + layerOffset.dx, offset.dy + layerOffset.dy);
    builder.pushTransform((offsetTransform * transform).storage);
    addChildrenToScene(builder, Offset.zero);
    builder.pop();
234
  }
235 236
}

237 238
class OpacityLayer extends ContainerLayer {
  OpacityLayer({ Offset offset: Offset.zero, this.bounds, this.alpha }) : super(offset: offset);
239

Hixie's avatar
Hixie committed
240 241
  // bounds is _not_ affected by given offset
  Rect bounds;
242 243
  int alpha;

244 245 246 247
  void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
    builder.pushOpacity(alpha, bounds == null ? null : bounds.shift(layerOffset));
    addChildrenToScene(builder, offset + layerOffset);
    builder.pop();
248
  }
249 250 251 252
}

class ColorFilterLayer extends ContainerLayer {
  ColorFilterLayer({
253
    Offset offset: Offset.zero,
254
    this.bounds,
255 256
    this.color,
    this.transferMode
257
  }) : super(offset: offset);
258

259 260
  // bounds is _not_ affected by given offset
  Rect bounds;
261 262
  Color color;
  sky.TransferMode transferMode;
263

264 265 266 267
  void addToScene(sky.SceneBuilder builder, Offset layerOffset) {
    builder.pushColorFilter(color, transferMode, bounds.shift(offset));
    addChildrenToScene(builder, offset + layerOffset);
    builder.pop();
268
  }
269
}