OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 /** The interface that the layout algorithms use to talk to the view. */ | 5 /** The interface that the layout algorithms use to talk to the view. */ |
6 interface Positionable { | 6 interface Positionable { |
7 ViewLayout get layout(); | 7 ViewLayout get layout(); |
8 | 8 |
9 /** Gets our custom CSS properties, as provided by the CSS preprocessor. */ | 9 /** Gets our custom CSS properties, as provided by the CSS preprocessor. */ |
10 Map<String, String> get customStyle(); | 10 Map<String, String> get customStyle(); |
11 | 11 |
12 /** Gets the root DOM used for layout. */ | 12 /** Gets the root DOM used for layout. */ |
13 Element get node(); | 13 Element get node(); |
14 | 14 |
15 /** Gets the collection of child views. */ | 15 /** Gets the collection of child views. */ |
16 Collection<Positionable> get childViews(); | 16 Collection<Positionable> get childViews(); |
17 | 17 |
18 /** Causes a view to layout its children. */ | 18 /** Causes a view to layout its children. */ |
19 void doLayout(); | 19 void doLayout(); |
20 } | 20 } |
21 | 21 |
22 | 22 |
23 /** | 23 /** |
24 * Caches the layout parameters that were specified in CSS during a layout | 24 * Caches the layout parameters that were specified in CSS during a layout |
25 * computation. These values are immutable during a layout. | 25 * computation. These values are immutable during a layout. |
26 */ | 26 */ |
27 class LayoutParams { | 27 class LayoutParams { |
28 // TODO(jmesserly): should be const, but there's a bug in DartC preventing us | 28 // TODO(jmesserly): should be const, but there's a bug in DartC preventing us |
29 // from calling "window." in an initializer. See b/5332777 | 29 // from calling "window." in an initializer. See b/5332777 |
30 Future<CSSStyleDeclaration> style; | 30 CSSStyleDeclaration style; |
31 | 31 |
32 int get layer() => 0; | 32 int get layer() => 0; |
33 | 33 |
34 LayoutParams(Element node) { | 34 LayoutParams(Element node) { |
35 style = node.computedStyle; | 35 style = node.computedStyle; |
36 } | 36 } |
37 } | 37 } |
38 | 38 |
39 // TODO(jmesserly): enums would really help here | 39 // TODO(jmesserly): enums would really help here |
40 class Dimension { | 40 class Dimension { |
(...skipping 23 matching lines...) Expand all Loading... |
64 * Abstract base class for View layout. Tracks relevant layout state. | 64 * Abstract base class for View layout. Tracks relevant layout state. |
65 * This code was inspired by code in Android's View.java; it's needed for the | 65 * This code was inspired by code in Android's View.java; it's needed for the |
66 * rest of the layout system. | 66 * rest of the layout system. |
67 */ | 67 */ |
68 class ViewLayout { | 68 class ViewLayout { |
69 /** | 69 /** |
70 * The layout parameters associated with this view and used by the parent | 70 * The layout parameters associated with this view and used by the parent |
71 * to determine how this view should be laid out. | 71 * to determine how this view should be laid out. |
72 */ | 72 */ |
73 LayoutParams layoutParams; | 73 LayoutParams layoutParams; |
74 Future<ElementRect> _cachedViewRect; | 74 int _currentWidth; |
| 75 int _currentHeight; |
75 | 76 |
76 /** The view that this layout belongs to. */ | 77 /** The view that this layout belongs to. */ |
77 final Positionable view; | 78 final Positionable view; |
78 | 79 |
79 /** | 80 /** |
80 * To get a perforant positioning model on top of the DOM, we read all | 81 * To get a perforant positioning model on top of the DOM, we read all |
81 * properties in the first pass while computing positions. Then we have a | 82 * properties in the first pass while computing positions. Then we have a |
82 * second pass that actually moves everything. | 83 * second pass that actually moves everything. |
83 */ | 84 */ |
84 int _measuredLeft, _measuredTop, _measuredWidth, _measuredHeight; | 85 int _measuredLeft, _measuredTop, _measuredWidth, _measuredHeight; |
(...skipping 10 matching lines...) Expand all Loading... |
95 return new GridLayout(view); | 96 return new GridLayout(view); |
96 } else { | 97 } else { |
97 return new ViewLayout(view); | 98 return new ViewLayout(view); |
98 } | 99 } |
99 } | 100 } |
100 | 101 |
101 static bool hasCustomLayout(Positionable view) { | 102 static bool hasCustomLayout(Positionable view) { |
102 return view.customStyle['display'] == "-dart-grid"; | 103 return view.customStyle['display'] == "-dart-grid"; |
103 } | 104 } |
104 | 105 |
105 CSSStyleDeclaration get _style() => layoutParams.style.value; | 106 CSSStyleDeclaration get _style() => layoutParams.style; |
106 | 107 |
107 void cacheExistingBrowserLayout() { | 108 void cacheExistingBrowserLayout() { |
108 _cachedViewRect = view.node.rect; | 109 assert(window.inMeasurementFrame); |
| 110 final rect = view.node.rect.offset; |
| 111 _currentWidth = rect.width; |
| 112 _currentHeight = rect.height; |
109 } | 113 } |
110 | 114 |
111 int get currentWidth() { | 115 int get currentWidth() => _currentWidth; |
112 return _cachedViewRect.value.offset.width; | 116 int get currentHeight() => _currentHeight; |
113 } | |
114 | |
115 int get currentHeight() { | |
116 return _cachedViewRect.value.offset.height; | |
117 } | |
118 | 117 |
119 int get borderLeftWidth() => _toPixels(_style.borderLeftWidth); | 118 int get borderLeftWidth() => _toPixels(_style.borderLeftWidth); |
120 int get borderTopWidth() => _toPixels(_style.borderTopWidth); | 119 int get borderTopWidth() => _toPixels(_style.borderTopWidth); |
121 int get borderRightWidth() => _toPixels(_style.borderRightWidth); | 120 int get borderRightWidth() => _toPixels(_style.borderRightWidth); |
122 int get borderBottomWidth() => _toPixels(_style.borderBottomWidth); | 121 int get borderBottomWidth() => _toPixels(_style.borderBottomWidth); |
123 int get borderWidth() => borderLeftWidth + borderRightWidth; | 122 int get borderWidth() => borderLeftWidth + borderRightWidth; |
124 int get borderHeight() => borderTopWidth + borderBottomWidth; | 123 int get borderHeight() => borderTopWidth + borderBottomWidth; |
125 | 124 |
126 /** Implements the custom layout computation. */ | 125 /** Implements the custom layout computation. */ |
127 void measureLayout(Future<Size> size, Completer<bool> changed) { | 126 bool measureLayout(int width, int height) { |
128 } | 127 } |
129 | 128 |
130 /** | 129 /** |
131 * Positions the view within its parent container. | 130 * Positions the view within its parent container. |
132 * Also performs a layout of its children. | 131 * Also performs a layout of its children. |
133 */ | 132 */ |
134 void setBounds(int left, int top, int width, int height) { | 133 void setBounds(int left, int top, int width, int height) { |
135 assert(width >= 0 && height >= 0); | 134 assert(width >= 0 && height >= 0); |
136 | 135 |
137 _measuredLeft = left; | 136 _measuredLeft = left; |
138 _measuredTop = top; | 137 _measuredTop = top; |
139 | 138 |
140 // Note: we need to save the client height | 139 // Note: we need to save the client height |
141 _measuredWidth = width - borderWidth; | 140 _measuredWidth = width - borderWidth; |
142 _measuredHeight = height - borderHeight; | 141 _measuredHeight = height - borderHeight; |
143 final completer = new Completer<Size>(); | 142 measureLayout(_measuredWidth, _measuredHeight); |
144 completer.complete(new Size(_measuredWidth, _measuredHeight)); | |
145 measureLayout(completer.future, null); | |
146 } | 143 } |
147 | 144 |
148 /** Applies the layout to the node. */ | 145 /** Applies the layout to the node. */ |
149 void applyLayout() { | 146 void applyLayout() { |
| 147 assert(!window.inMeasurementFrame); |
150 if (_measuredLeft != null) { | 148 if (_measuredLeft != null) { |
151 // TODO(jmesserly): benchmark the performance of this DOM interaction | 149 // TODO(jmesserly): benchmark the performance of this DOM interaction |
152 final style = view.node.style; | 150 final style = view.node.style; |
153 style.position = 'absolute'; | 151 style.position = 'absolute'; |
154 style.left = '${_measuredLeft}px'; | 152 style.left = '${_measuredLeft}px'; |
155 style.top = '${_measuredTop}px'; | 153 style.top = '${_measuredTop}px'; |
156 style.width = '${_measuredWidth}px'; | 154 style.width = '${_measuredWidth}px'; |
157 style.height = '${_measuredHeight}px'; | 155 style.height = '${_measuredHeight}px'; |
158 style.zIndex = '${layoutParams.layer}'; | 156 style.zIndex = '${layoutParams.layer}'; |
159 | 157 |
(...skipping 21 matching lines...) Expand all Loading... |
181 [ContentSizeMode mode = null]) { | 179 [ContentSizeMode mode = null]) { |
182 switch (dimension) { | 180 switch (dimension) { |
183 case Dimension.WIDTH: | 181 case Dimension.WIDTH: |
184 return measureWidth(parent, mode); | 182 return measureWidth(parent, mode); |
185 case Dimension.HEIGHT: | 183 case Dimension.HEIGHT: |
186 return measureHeight(parent, mode); | 184 return measureHeight(parent, mode); |
187 } | 185 } |
188 } | 186 } |
189 | 187 |
190 int measureWidth(ViewLayout parent, ContentSizeMode mode) { | 188 int measureWidth(ViewLayout parent, ContentSizeMode mode) { |
191 final style = layoutParams.style.value; | 189 final style = layoutParams.style; |
192 switch (mode) { | 190 switch (mode) { |
193 case ContentSizeMode.MIN: | 191 case ContentSizeMode.MIN: |
194 return _styleToPixels( | 192 return _styleToPixels( |
195 style.minWidth, currentWidth, parent.currentWidth); | 193 style.minWidth, currentWidth, parent.currentWidth); |
196 | 194 |
197 case ContentSizeMode.MAX: | 195 case ContentSizeMode.MAX: |
198 return _styleToPixels( | 196 return _styleToPixels( |
199 style.maxWidth, currentWidth, parent.currentWidth); | 197 style.maxWidth, currentWidth, parent.currentWidth); |
200 } | 198 } |
201 } | 199 } |
202 | 200 |
203 int measureHeight(ViewLayout parent, ContentSizeMode mode) { | 201 int measureHeight(ViewLayout parent, ContentSizeMode mode) { |
204 final style = layoutParams.style.value; | 202 final style = layoutParams.style; |
205 switch (mode) { | 203 switch (mode) { |
206 case ContentSizeMode.MIN: | 204 case ContentSizeMode.MIN: |
207 return _styleToPixels( | 205 return _styleToPixels( |
208 style.minHeight, currentHeight, parent.currentHeight); | 206 style.minHeight, currentHeight, parent.currentHeight); |
209 | 207 |
210 case ContentSizeMode.MAX: | 208 case ContentSizeMode.MAX: |
211 return _styleToPixels( | 209 return _styleToPixels( |
212 style.maxHeight, currentHeight, parent.currentHeight); | 210 style.maxHeight, currentHeight, parent.currentHeight); |
213 } | 211 } |
214 } | 212 } |
(...skipping 13 matching lines...) Expand all Loading... |
228 // For an unset max-content size, use the actual size | 226 // For an unset max-content size, use the actual size |
229 return size; | 227 return size; |
230 } | 228 } |
231 if (style.endsWith('%')) { | 229 if (style.endsWith('%')) { |
232 num percent = Math.parseDouble(style.substring(0, style.length - 1)); | 230 num percent = Math.parseDouble(style.substring(0, style.length - 1)); |
233 return ((percent / 100) * parentSize).toInt(); | 231 return ((percent / 100) * parentSize).toInt(); |
234 } | 232 } |
235 return _toPixels(style); | 233 return _toPixels(style); |
236 } | 234 } |
237 } | 235 } |
OLD | NEW |