Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 CSSStyleDeclaration style; | 30 Future<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 = window.getComputedStyle(node, ''); | 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 { |
| 41 // TODO(jmesserly): perhaps this should be X and Y | 41 // TODO(jmesserly): perhaps this should be X and Y |
| 42 static final WIDTH = const Dimension._internal('width'); | 42 static final WIDTH = const Dimension._internal('width'); |
| 43 static final HEIGHT = const Dimension._internal('height'); | 43 static final HEIGHT = const Dimension._internal('height'); |
| 44 | 44 |
| 45 final String name; // for debugging | 45 final String name; // for debugging |
| (...skipping 18 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 | 75 |
| 75 /** The view that this layout belongs to. */ | 76 /** The view that this layout belongs to. */ |
| 76 final Positionable view; | 77 final Positionable view; |
| 77 | 78 |
| 78 /** | 79 /** |
| 79 * To get a perforant positioning model on top of the DOM, we read all | 80 * To get a perforant positioning model on top of the DOM, we read all |
| 80 * properties in the first pass while computing positions. Then we have a | 81 * properties in the first pass while computing positions. Then we have a |
| 81 * second pass that actually moves everything. | 82 * second pass that actually moves everything. |
| 82 */ | 83 */ |
| 83 int _measuredLeft, _measuredTop, _measuredWidth, _measuredHeight; | 84 int _measuredLeft, _measuredTop, _measuredWidth, _measuredHeight; |
| 84 | 85 |
| 85 ViewLayout(this.view) {} | 86 ViewLayout(this.view); |
| 86 | 87 |
| 87 /** | 88 /** |
| 88 * Creates the appropriate view layout, depending on the properties. | 89 * Creates the appropriate view layout, depending on the properties. |
| 89 */ | 90 */ |
| 90 // TODO(jmesserly): we should support user defined layouts somehow. Perhaps | 91 // TODO(jmesserly): we should support user defined layouts somehow. Perhaps |
| 91 // registered with a LayoutProvider. | 92 // registered with a LayoutProvider. |
| 92 factory ViewLayout.fromView(Positionable view) { | 93 factory ViewLayout.fromView(Positionable view) { |
| 93 if (hasCustomLayout(view)) { | 94 if (hasCustomLayout(view)) { |
| 94 return new GridLayout(view); | 95 return new GridLayout(view); |
| 95 } else { | 96 } else { |
| 96 return new ViewLayout(view); | 97 return new ViewLayout(view); |
| 97 } | 98 } |
| 98 } | 99 } |
| 99 | 100 |
| 100 static bool hasCustomLayout(Positionable view) { | 101 static bool hasCustomLayout(Positionable view) { |
| 101 return view.customStyle['display'] == "-dart-grid"; | 102 return view.customStyle['display'] == "-dart-grid"; |
| 102 } | 103 } |
| 103 | 104 |
| 104 CSSStyleDeclaration get _style() => layoutParams.style; | 105 CSSStyleDeclaration get _style() => layoutParams.style.value; |
| 105 | 106 |
| 106 int get currentWidth() => view.node.offsetWidth; | 107 void cacheExistingBrowserLayout() { |
| 107 int get currentHeight() => view.node.offsetHeight; | 108 _cachedViewRect = view.node.rect; |
| 109 } | |
| 110 | |
| 111 int get currentWidth() { | |
| 112 return _cachedViewRect.value.offset.width; | |
|
nweiz
2011/10/28 03:58:38
What happens when _cachedViewRect hasn't fired yet
Jacob
2011/10/31 22:09:50
by design it will always have fired due to appropr
nweiz
2011/11/01 00:49:22
Oh, futures throw an error when value doesn't exis
| |
| 113 } | |
| 114 | |
| 115 int get currentHeight() { | |
| 116 return _cachedViewRect.value.offset.height; | |
| 117 } | |
| 108 | 118 |
| 109 int get borderLeftWidth() => _toPixels(_style.borderLeftWidth); | 119 int get borderLeftWidth() => _toPixels(_style.borderLeftWidth); |
|
nweiz
2011/10/28 03:58:38
Can't _style be null sometimes?
Jacob
2011/10/31 22:09:50
it can't be null, however a future not available y
nweiz
2011/11/01 00:49:22
The fact that it fires a "future not completed" er
| |
| 110 int get borderTopWidth() => _toPixels(_style.borderTopWidth); | 120 int get borderTopWidth() => _toPixels(_style.borderTopWidth); |
| 111 int get borderRightWidth() => _toPixels(_style.borderRightWidth); | 121 int get borderRightWidth() => _toPixels(_style.borderRightWidth); |
| 112 int get borderBottomWidth() => _toPixels(_style.borderBottomWidth); | 122 int get borderBottomWidth() => _toPixels(_style.borderBottomWidth); |
| 113 int get borderWidth() => borderLeftWidth + borderRightWidth; | 123 int get borderWidth() => borderLeftWidth + borderRightWidth; |
| 114 int get borderHeight() => borderTopWidth + borderBottomWidth; | 124 int get borderHeight() => borderTopWidth + borderBottomWidth; |
| 115 | 125 |
|
nweiz
2011/10/28 03:58:38
Style nit: trailing whitespace
Jacob
2011/10/31 22:09:50
Done.
| |
| 116 /** Implements the custom layout computation. */ | 126 /** Implements the custom layout computation. */ |
| 117 bool measureLayout(int width, int height) => false; | 127 void measureLayout(Future<Size> size, Completer<bool> changed) { |
| 128 } | |
| 118 | 129 |
| 119 /** | 130 /** |
| 120 * Positions the view within its parent container. | 131 * Positions the view within its parent container. |
| 121 * Also performs a layout of its children. | 132 * Also performs a layout of its children. |
| 122 */ | 133 */ |
| 123 void setBounds(int left, int top, int width, int height) { | 134 void setBounds(int left, int top, int width, int height) { |
| 124 assert(width >= 0 && height >= 0); | 135 assert(width >= 0 && height >= 0); |
| 125 | 136 |
| 126 _measuredLeft = left; | 137 _measuredLeft = left; |
| 127 _measuredTop = top; | 138 _measuredTop = top; |
| 128 | 139 |
| 129 // Note: we need to save the client height | 140 // Note: we need to save the client height |
| 130 _measuredWidth = width - borderWidth; | 141 _measuredWidth = width - borderWidth; |
| 131 _measuredHeight = height - borderHeight; | 142 _measuredHeight = height - borderHeight; |
| 132 | 143 final completer = new Completer<Size>(); |
| 133 measureLayout(_measuredWidth, _measuredHeight); | 144 completer.complete(new Size(_measuredWidth, _measuredHeight)); |
| 145 measureLayout(completer.future, null); | |
| 134 } | 146 } |
| 135 | 147 |
| 136 /** Applies the layout to the node. */ | 148 /** Applies the layout to the node. */ |
| 137 void applyLayout() { | 149 void applyLayout() { |
| 138 if (_measuredLeft != null) { | 150 if (_measuredLeft != null) { |
| 139 // TODO(jmesserly): benchmark the performance of this DOM interaction | 151 // TODO(jmesserly): benchmark the performance of this DOM interaction |
| 140 final style = view.node.style; | 152 final style = view.node.style; |
| 141 style.position = 'absolute'; | 153 style.position = 'absolute'; |
| 142 style.left = '${_measuredLeft}px'; | 154 style.left = '${_measuredLeft}px'; |
| 143 style.top = '${_measuredTop}px'; | 155 style.top = '${_measuredTop}px'; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 169 [ContentSizeMode mode = null]) { | 181 [ContentSizeMode mode = null]) { |
| 170 switch (dimension) { | 182 switch (dimension) { |
| 171 case Dimension.WIDTH: | 183 case Dimension.WIDTH: |
| 172 return measureWidth(parent, mode); | 184 return measureWidth(parent, mode); |
| 173 case Dimension.HEIGHT: | 185 case Dimension.HEIGHT: |
| 174 return measureHeight(parent, mode); | 186 return measureHeight(parent, mode); |
| 175 } | 187 } |
| 176 } | 188 } |
| 177 | 189 |
| 178 int measureWidth(ViewLayout parent, ContentSizeMode mode) { | 190 int measureWidth(ViewLayout parent, ContentSizeMode mode) { |
| 179 final style = layoutParams.style; | 191 final style = layoutParams.style.value; |
| 180 switch (mode) { | 192 switch (mode) { |
| 181 case ContentSizeMode.MIN: | 193 case ContentSizeMode.MIN: |
| 182 return _styleToPixels( | 194 return _styleToPixels( |
| 183 style.minWidth, currentWidth, parent.currentWidth); | 195 style.minWidth, currentWidth, parent.currentWidth); |
| 184 | 196 |
| 185 case ContentSizeMode.MAX: | 197 case ContentSizeMode.MAX: |
| 186 return _styleToPixels( | 198 return _styleToPixels( |
| 187 style.maxWidth, currentWidth, parent.currentWidth); | 199 style.maxWidth, currentWidth, parent.currentWidth); |
| 188 } | 200 } |
| 189 } | 201 } |
| 190 | 202 |
| 191 int measureHeight(ViewLayout parent, ContentSizeMode mode) { | 203 int measureHeight(ViewLayout parent, ContentSizeMode mode) { |
| 192 final style = layoutParams.style; | 204 final style = layoutParams.style.value; |
| 193 switch (mode) { | 205 switch (mode) { |
| 194 case ContentSizeMode.MIN: | 206 case ContentSizeMode.MIN: |
| 195 return _styleToPixels( | 207 return _styleToPixels( |
| 196 style.minHeight, currentHeight, parent.currentHeight); | 208 style.minHeight, currentHeight, parent.currentHeight); |
| 197 | 209 |
| 198 case ContentSizeMode.MAX: | 210 case ContentSizeMode.MAX: |
| 199 return _styleToPixels( | 211 return _styleToPixels( |
| 200 style.maxHeight, currentHeight, parent.currentHeight); | 212 style.maxHeight, currentHeight, parent.currentHeight); |
| 201 } | 213 } |
| 202 } | 214 } |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 216 // For an unset max-content size, use the actual size | 228 // For an unset max-content size, use the actual size |
| 217 return size; | 229 return size; |
| 218 } | 230 } |
| 219 if (style.endsWith('%')) { | 231 if (style.endsWith('%')) { |
| 220 num percent = Math.parseDouble(style.substring(0, style.length - 1)); | 232 num percent = Math.parseDouble(style.substring(0, style.length - 1)); |
| 221 return ((percent / 100) * parentSize).toInt(); | 233 return ((percent / 100) * parentSize).toInt(); |
| 222 } | 234 } |
| 223 return _toPixels(style); | 235 return _toPixels(style); |
| 224 } | 236 } |
| 225 } | 237 } |
| OLD | NEW |