Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:math' as math; | 5 import 'dart:math' as math; |
| 6 import 'dart:sky' as sky; | 6 import 'dart:sky' as sky; |
| 7 import 'dart:sky' show Point, Offset, Size, Rect, Color, Paint, Path; | 7 import 'dart:sky' show Point, Offset, Size, Rect, Color, Paint, Path; |
| 8 | 8 |
| 9 import '../base/hit_test.dart'; | 9 import '../base/hit_test.dart'; |
| 10 import '../base/node.dart'; | 10 import '../base/node.dart'; |
| 11 import '../base/scheduler.dart' as scheduler; | 11 import '../base/scheduler.dart' as scheduler; |
| 12 | 12 |
| 13 export 'dart:sky' show Point, Offset, Size, Rect, Color, Paint, Path; | 13 export 'dart:sky' show Point, Offset, Size, Rect, Color, Paint, Path; |
| 14 export '../base/hit_test.dart' show HitTestTarget, HitTestEntry, HitTestResult; | 14 export '../base/hit_test.dart' show HitTestTarget, HitTestEntry, HitTestResult; |
| 15 | 15 |
| 16 | 16 |
| 17 class ParentData { | 17 class ParentData { |
| 18 void detach() { | 18 void detach() { |
| 19 detachSiblings(); | 19 detachSiblings(); |
| 20 } | 20 } |
| 21 void detachSiblings() { } // workaround for lack of inter-class mixins in Dart | 21 void detachSiblings() { } // workaround for lack of inter-class mixins in Dart |
| 22 void merge(ParentData other) { | 22 void merge(ParentData other) { |
| 23 // override this in subclasses to merge in data from other into this | 23 // override this in subclasses to merge in data from other into this |
| 24 assert(other.runtimeType == this.runtimeType); | 24 assert(other.runtimeType == this.runtimeType); |
| 25 } | 25 } |
| 26 String toString() => '<none>'; | 26 String toString() => '<none>'; |
| 27 } | 27 } |
| 28 | 28 |
| 29 class PaintingCanvas extends sky.Canvas { | 29 class PaintingCanvas extends sky.Canvas { |
| 30 PaintingCanvas(sky.PictureRecorder recorder, Size bounds) : super(recorder, bo unds); | 30 PaintingCanvas(sky.PictureRecorder recorder, Rect bounds) : super(recorder, bo unds); |
| 31 | 31 |
| 32 List<RenderObject> _descendentsWithPaintingCanvases; // used by RenderObject._ updatePaintingCanvas() to find out which RenderObjects to ask to paint | |
| 32 void paintChild(RenderObject child, Point point) { | 33 void paintChild(RenderObject child, Point point) { |
| 33 child.paint(this, point.toOffset()); | 34 if (child.createNewDisplayList) { |
| 35 if (_descendentsWithPaintingCanvases == null) | |
| 36 _descendentsWithPaintingCanvases = new List<RenderObject>(); | |
|
abarth-chromium
2015/07/06 20:50:58
You can simplify this pattern by writing:
final L
iansf
2015/07/07 20:36:47
Done.
| |
| 37 assert(!_descendentsWithPaintingCanvases.contains(child)); | |
| 38 _descendentsWithPaintingCanvases.add(child); | |
| 39 translate(point.x, point.y); | |
| 40 drawPaintingNode(child._paintingNode); | |
| 41 translate(-point.x, -point.y); | |
|
abarth-chromium
2015/07/06 20:50:58
It looks like drawPaintingNode should take a Point
iansf
2015/07/07 20:36:47
Done.
| |
| 42 } else { | |
| 43 child._paintOnCanvas(this, point.toOffset()); | |
| 44 } | |
| 34 } | 45 } |
| 35 } | 46 } |
| 36 | 47 |
| 37 abstract class Constraints { | 48 abstract class Constraints { |
| 38 const Constraints(); | 49 const Constraints(); |
| 39 bool get isTight; | 50 bool get isTight; |
| 40 } | 51 } |
| 41 | 52 |
| 42 abstract class RenderObject extends AbstractNode implements HitTestTarget { | 53 abstract class RenderObject extends AbstractNode implements HitTestTarget { |
| 43 | 54 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 131 _cleanRelayoutSubtreeRootChildren(); | 142 _cleanRelayoutSubtreeRootChildren(); |
| 132 } | 143 } |
| 133 } | 144 } |
| 134 void _cleanRelayoutSubtreeRootChildren() { } // workaround for lack of inter-c lass mixins in Dart | 145 void _cleanRelayoutSubtreeRootChildren() { } // workaround for lack of inter-c lass mixins in Dart |
| 135 void scheduleInitialLayout() { | 146 void scheduleInitialLayout() { |
| 136 assert(attached); | 147 assert(attached); |
| 137 assert(parent == null); | 148 assert(parent == null); |
| 138 assert(_relayoutSubtreeRoot == null); | 149 assert(_relayoutSubtreeRoot == null); |
| 139 _relayoutSubtreeRoot = this; | 150 _relayoutSubtreeRoot = this; |
| 140 _nodesNeedingLayout.add(this); | 151 _nodesNeedingLayout.add(this); |
| 152 _nodesNeedingPaint.add(this); | |
| 141 scheduler.ensureVisualUpdate(); | 153 scheduler.ensureVisualUpdate(); |
| 142 } | 154 } |
| 143 static void flushLayout() { | 155 static void flushLayout() { |
| 144 sky.tracing.begin('RenderObject.flushLayout'); | 156 sky.tracing.begin('RenderObject.flushLayout'); |
| 145 _debugDoingLayout = true; | 157 _debugDoingLayout = true; |
| 146 try { | 158 try { |
| 147 List<RenderObject> dirtyNodes = _nodesNeedingLayout; | 159 List<RenderObject> dirtyNodes = _nodesNeedingLayout; |
| 148 _nodesNeedingLayout = new List<RenderObject>(); | 160 _nodesNeedingLayout = new List<RenderObject>(); |
| 149 dirtyNodes..sort((a, b) => a.depth - b.depth)..forEach((node) { | 161 dirtyNodes..sort((a, b) => a.depth - b.depth)..forEach((node) { |
| 150 if (node._needsLayout && node.attached) | 162 if (node._needsLayout && node.attached) |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 231 | 243 |
| 232 void rotate({ | 244 void rotate({ |
| 233 int oldAngle, // 0..3 | 245 int oldAngle, // 0..3 |
| 234 int newAngle, // 0..3 | 246 int newAngle, // 0..3 |
| 235 Duration time | 247 Duration time |
| 236 }) { } | 248 }) { } |
| 237 | 249 |
| 238 | 250 |
| 239 // PAINTING | 251 // PAINTING |
| 240 | 252 |
| 241 static bool debugDoingPaint = false; | 253 static List<RenderObject> _nodesNeedingPaint = new List<RenderObject>(); |
| 254 static bool _debugDoingPaint = false; | |
| 255 static bool get debugDoingPaint => _debugDoingPaint; | |
| 256 | |
| 257 sky.PaintingNode _paintingNode = new sky.PaintingNode(); // only set if create NewDisplayList is true | |
|
abarth-chromium
2015/07/06 20:50:58
Without |final|, this call to new will happen all
iansf
2015/07/07 21:11:22
I made this final -- it's never reassigned.
| |
| 258 sky.PaintingNode get paintingNode => _paintingNode; | |
| 259 bool _needsPaint = true; | |
| 260 bool get needsPaint => _needsPaint; | |
| 261 bool get createNewDisplayList => true; | |
|
abarth-chromium
2015/07/06 20:50:58
I'm not sure we want the default behavior to be to
iansf
2015/07/07 21:11:23
Done.
| |
| 262 | |
| 242 void markNeedsPaint() { | 263 void markNeedsPaint() { |
| 243 assert(!debugDoingPaint); | 264 assert(!debugDoingPaint); |
| 244 scheduler.ensureVisualUpdate(); | 265 if (_needsPaint) return; |
| 266 if (createNewDisplayList) { | |
| 267 _needsPaint = true; | |
| 268 _nodesNeedingPaint.add(this); | |
| 269 scheduler.ensureVisualUpdate(); | |
| 270 } else if (parent != null) { | |
| 271 if (parent is RenderObject) { | |
| 272 (parent as RenderObject).markNeedsPaint(); // TODO(ianh): remove the cas t once the analyzer is cleverer | |
| 273 } | |
| 274 } | |
| 245 } | 275 } |
| 276 | |
| 277 static void flushPaint() { | |
| 278 _debugDoingPaint = true; | |
| 279 List<RenderObject> dirtyNodes = _nodesNeedingPaint; | |
| 280 _nodesNeedingPaint = new List<RenderObject>(); | |
| 281 dirtyNodes..sort((a, b) => a.depth - b.depth)..forEach((node) { | |
| 282 if (node._needsPaint && node.attached) | |
| 283 node._updatePaintingCanvas(); | |
| 284 }); | |
| 285 assert(_nodesNeedingPaint.length == 0); | |
| 286 _debugDoingPaint = false; | |
|
abarth-chromium
2015/07/06 20:50:58
We should wrap the body of this function in a try
iansf
2015/07/07 20:36:47
Done.
| |
| 287 } | |
| 288 | |
| 289 void _updatePaintingCanvas() { | |
| 290 assert(!_needsLayout); | |
| 291 assert(createNewDisplayList); | |
| 292 sky.PictureRecorder recorder = new sky.PictureRecorder(); | |
| 293 PaintingCanvas canvas = new PaintingCanvas(recorder, paintBounds); | |
| 294 _needsPaint = false; | |
| 295 try { | |
| 296 _paintOnCanvas(canvas, Offset.zero); | |
| 297 } catch (e, stack) { | |
|
abarth-chromium
2015/07/06 20:50:58
Capturing the stack here is going to be too expens
Hixie
2015/07/06 21:13:42
If you change this make sure the equivalent code i
iansf
2015/07/07 20:36:47
Done.
iansf
2015/07/07 20:36:47
Done.
| |
| 298 print('Exception raised during _updatePaintingCanvas:\n${e}\nContext:\n${t his}'); | |
| 299 print(stack); | |
| 300 return; | |
| 301 } | |
| 302 assert(!_needsLayout); // check that the paint() method didn't mark us dirty again | |
| 303 assert(!_needsPaint); // check that the paint() method didn't mark us dirty again | |
| 304 _paintingNode.setBackingDrawable(recorder.endRecordingAsDrawable()); | |
| 305 | |
| 306 if (canvas._descendentsWithPaintingCanvases != null) { | |
| 307 canvas._descendentsWithPaintingCanvases.forEach((node) { | |
|
abarth-chromium
2015/07/06 20:50:57
We should use a for-each loop rather than calling
iansf
2015/07/07 20:36:47
Done.
| |
| 308 assert(node.attached == attached); | |
| 309 if (node._needsPaint) | |
| 310 node._updatePaintingCanvas(); | |
| 311 }); | |
| 312 } | |
| 313 | |
| 314 } | |
| 315 | |
| 316 void _paintOnCanvas(PaintingCanvas canvas, Offset offset) { | |
| 317 _needsPaint = false; | |
|
abarth-chromium
2015/07/06 20:50:58
Why do we set _needsPaint = false both here and on
iansf
2015/07/07 20:36:47
Done.
| |
| 318 paint(canvas, offset); | |
| 319 assert(!_needsPaint); | |
| 320 } | |
| 321 | |
| 322 Rect get paintBounds; | |
| 323 | |
| 246 void paint(PaintingCanvas canvas, Offset offset) { } | 324 void paint(PaintingCanvas canvas, Offset offset) { } |
| 247 | 325 |
| 248 | 326 |
| 249 // EVENTS | 327 // EVENTS |
| 250 | 328 |
| 251 void handleEvent(sky.Event event, HitTestEntry entry) { | 329 void handleEvent(sky.Event event, HitTestEntry entry) { |
| 252 // override this if you have a client, to hand it to the client | 330 // override this if you have a client, to hand it to the client |
| 253 // override this if you want to do anything with the event | 331 // override this if you want to do anything with the event |
| 254 } | 332 } |
| 255 | 333 |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 529 int count = 1; | 607 int count = 1; |
| 530 ChildType child = _firstChild; | 608 ChildType child = _firstChild; |
| 531 while (child != null) { | 609 while (child != null) { |
| 532 result += '${prefix}child ${count}: ${child.toString(prefix)}'; | 610 result += '${prefix}child ${count}: ${child.toString(prefix)}'; |
| 533 count += 1; | 611 count += 1; |
| 534 child = child.parentData.nextSibling; | 612 child = child.parentData.nextSibling; |
| 535 } | 613 } |
| 536 return result; | 614 return result; |
| 537 } | 615 } |
| 538 } | 616 } |
| OLD | NEW |