Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(248)

Side by Side Diff: runtime/observatory/lib/src/elements/containers/virtual_tree.dart

Issue 2968813002: Avoid Stack Overflows during VirtualTree expansion (Closed)
Patch Set: Addressed comments Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | runtime/observatory/tests/observatory_ui/virtual_tree/element_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 import 'dart:async'; 5 import 'dart:async';
6 import 'dart:html'; 6 import 'dart:html';
7 import 'dart:collection';
7 import 'dart:math' as Math; 8 import 'dart:math' as Math;
8 import 'package:observatory/src/elements/containers/virtual_collection.dart'; 9 import 'package:observatory/src/elements/containers/virtual_collection.dart';
9 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart'; 10 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
10 import 'package:observatory/src/elements/helpers/tag.dart'; 11 import 'package:observatory/src/elements/helpers/tag.dart';
11 12
12 typedef HtmlElement VirtualTreeCreateCallback( 13 typedef HtmlElement VirtualTreeCreateCallback(
13 toggle({bool autoToggleSingleChildNodes, bool autoToggleWholeTree})); 14 toggle({bool autoToggleSingleChildNodes, bool autoToggleWholeTree}));
14 typedef void VirtualTreeUpdateCallback(HtmlElement el, dynamic item, int depth); 15 typedef void VirtualTreeUpdateCallback(HtmlElement el, dynamic item, int depth);
15 typedef Iterable<dynamic> VritualTreeGetChildrenCallback(dynamic value); 16 typedef Iterable<dynamic> VritualTreeGetChildrenCallback(dynamic value);
16 17
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 83
83 bool isExpanded(item) { 84 bool isExpanded(item) {
84 return _expanded.contains(item); 85 return _expanded.contains(item);
85 } 86 }
86 87
87 void expand(item, 88 void expand(item,
88 {bool autoExpandSingleChildNodes: false, 89 {bool autoExpandSingleChildNodes: false,
89 bool autoExpandWholeTree: false}) { 90 bool autoExpandWholeTree: false}) {
90 if (_expanded.add(item)) _r.dirty(); 91 if (_expanded.add(item)) _r.dirty();
91 if (autoExpandWholeTree) { 92 if (autoExpandWholeTree) {
92 for (final child in _children(item)) { 93 // The tree is potentially very deep, simple recursion can produce a
93 expand(child, autoExpandWholeTree: true); 94 // Stack Overflow
95 Queue pendingNodes = new Queue();
96 pendingNodes.addAll(_children(item));
97 while (pendingNodes.isNotEmpty) {
98 final item = pendingNodes.removeFirst();
99 if (_expanded.add(item)) _r.dirty();
100 pendingNodes.addAll(_children(item));
94 } 101 }
95 } else if (autoExpandSingleChildNodes) { 102 } else if (autoExpandSingleChildNodes) {
96 var children = _children(item); 103 var children = _children(item);
97 while (children.length == 1) { 104 while (children.length == 1) {
98 _expanded.add(children.first); 105 _expanded.add(children.first);
99 children = _children(children.first); 106 children = _children(children.first);
100 } 107 }
101 } 108 }
102 } 109 }
103 110
104 void collapse(item, 111 void collapse(item,
105 {bool autoCollapseSingleChildNodes: false, 112 {bool autoCollapseSingleChildNodes: false,
106 bool autoCollapseWholeTree: false}) { 113 bool autoCollapseWholeTree: false}) {
107 if (_expanded.remove(item)) _r.dirty(); 114 if (_expanded.remove(item)) _r.dirty();
108 if (autoCollapseWholeTree) { 115 if (autoCollapseWholeTree) {
109 for (final child in _children(item)) { 116 // The tree is potentially very deep, simple recursion can produce a
110 collapse(child, autoCollapseWholeTree: true); 117 // Stack Overflow
118 Queue pendingNodes = new Queue();
119 pendingNodes.addAll(_children(item));
120 while (pendingNodes.isNotEmpty) {
121 final item = pendingNodes.removeFirst();
122 if (_expanded.remove(item)) _r.dirty();
123 pendingNodes.addAll(_children(item));
111 } 124 }
112 } else if (autoCollapseSingleChildNodes) { 125 } else if (autoCollapseSingleChildNodes) {
113 var children = _children(item); 126 var children = _children(item);
114 while (children.length == 1) { 127 while (children.length == 1) {
115 _expanded.remove(children.first); 128 _expanded.remove(children.first);
116 children = _children(children.first); 129 children = _children(children.first);
117 } 130 }
118 } 131 }
119 } 132 }
120 133
121 @override 134 @override
122 attached() { 135 attached() {
123 super.attached(); 136 super.attached();
124 _r.enable(); 137 _r.enable();
125 } 138 }
126 139
127 @override 140 @override
128 detached() { 141 detached() {
129 super.detached(); 142 super.detached();
130 _r.disable(notify: true); 143 _r.disable(notify: true);
131 children = const []; 144 children = const [];
132 } 145 }
133 146
134 VirtualCollectionElement _collection; 147 VirtualCollectionElement _collection;
135 148
136 void render() { 149 void render() {
137 if (children.length == 0) { 150 if (children.length == 0) {
138 children = [_collection]; 151 children = [_collection];
139 } 152 }
140 Iterable _toList(item) { 153
141 if (isExpanded(item)) { 154 final items = [];
142 Iterable children = _children(item); 155 final depths = new List.filled(_items.length, 0, growable: true);
143 if (children.isNotEmpty) { 156
144 return [item]..addAll(children.expand(_toList)); 157 {
158 final toDo = new Queue();
159
160 toDo.addAll(_items);
161 while (toDo.isNotEmpty) {
162 final item = toDo.removeFirst();
163
164 items.add(item);
165 if (isExpanded(item)) {
166 final children = _children(item);
167 children
168 .toList(growable: false)
169 .reversed
170 .forEach((c) => toDo.addFirst(c));
171 final depth = depths[items.length - 1];
172 depths.insertAll(
173 items.length, new List.filled(children.length, depth + 1));
145 } 174 }
146 } 175 }
147 return [item];
148 } 176 }
149 177
150 _collection.items = _items.expand(_toList); 178 _depths = depths;
151 var depth = 0; 179 _collection.items = items;
152 Iterable _toDepth(item) {
153 if (isExpanded(item)) {
154 Iterable children = _children(item);
155 if (children.isNotEmpty) {
156 depth++;
157 return children.expand(_toDepth).toList()..insert(0, --depth);
158 }
159 }
160 return [depth];
161 }
162
163 _depths = _items.expand(_toDepth).toList();
164 } 180 }
165 } 181 }
OLDNEW
« no previous file with comments | « no previous file | runtime/observatory/tests/observatory_ui/virtual_tree/element_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698