| Index: client/view/view.dart
|
| diff --git a/client/view/view.dart b/client/view/view.dart
|
| index 6387d171af5a759e917833bacf738d8e739a5938..8b5d99e02fab1306c2aac6dbdc321e4926133a8c 100644
|
| --- a/client/view/view.dart
|
| +++ b/client/view/view.dart
|
| @@ -1,4 +1,4 @@
|
| -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
| +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| // for details. All rights reserved. Use of this source code is governed by a
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| @@ -168,11 +168,16 @@ class View implements Positionable {
|
| */
|
| void exitDocument() {}
|
|
|
| - /** Override this to perform behavior after the window is resized. */
|
| + /**
|
| + * Override this to perform behavior after the window is resized.
|
| + * This method is guaranteed to be called within a measurement frame. To
|
| + * manipulate the DOM, return a LayoutCallback which will be execututed
|
| + * in the normal context.
|
| + */
|
| // TODO(jmesserly): this isn't really the event we want. Ideally we want to
|
| // fire the event only if this particular View changed size. Also we should
|
| // give a view the ability to measure itself when added to the document.
|
| - void windowResized() {}
|
| + LayoutCallback windowResized() => null;
|
|
|
| /**
|
| * Registers the given listener callback to the given observable. Also
|
| @@ -317,43 +322,41 @@ class View implements Positionable {
|
| }
|
|
|
| void doLayout() {
|
| - _measureLayout().then((bool changed) {
|
| - if (changed) {
|
| - _applyLayoutToChildren();
|
| + // Callbacks to execute after all layouts are complete.
|
| + final callbacks = <LayoutCallback>[];
|
| + bool changed = false;
|
| + void _measureLayout(View v) {
|
| + assert(window.inMeasurementFrame);
|
| + LayoutCallback callback = v.windowResized();
|
| + if (callback != null) {
|
| + callbacks.add(callback);
|
| }
|
| - });
|
| - }
|
| -
|
| - Future<bool> _measureLayout() {
|
| - final changed = new Completer<bool>();
|
| - _measureLayoutHelper(changed);
|
| -
|
| - window.requestLayoutFrame(() {
|
| - if (!changed.future.isComplete) {
|
| - changed.complete(false);
|
| - }
|
| - });
|
| - return changed.future;
|
| - }
|
| -
|
| - void _measureLayoutHelper(Completer<bool> changed) {
|
| - windowResized();
|
| -
|
| - // TODO(jmesserly): this logic is more complex than it needs to be because
|
| - // we're taking pains to not initialize _layout if it's not needed. Is that
|
| - // a good tradeoff?
|
| - if (ViewLayout.hasCustomLayout(this)) {
|
| - Completer sizeCompleter = new Completer<Size>();
|
| - _node.rect.then((ElementRect rect) {
|
| - sizeCompleter.complete(
|
| - new Size(rect.client.width, rect.client.height));
|
| - });
|
| - layout.measureLayout(sizeCompleter.future, changed);
|
| - } else {
|
| - for (final child in childViews) {
|
| - child._measureLayoutHelper(changed);
|
| + // TODO(jmesserly): this logic is more complex than it needs to be
|
| + // because we're taking pains to not initialize _layout if it's not
|
| + // needed. Is that a good tradeoff?
|
| + if (ViewLayout.hasCustomLayout(v)) {
|
| + final rect = v._node.rect.client;
|
| + if (v.layout.measureLayout(rect.width, rect.height)) {
|
| + changed = true;
|
| + }
|
| + } else {
|
| + for (final child in v.childViews) {
|
| + _measureLayout(child);
|
| + }
|
| }
|
| }
|
| +
|
| + window.requestMeasurementFrame(() {
|
| + _measureLayout(this);
|
| + return () {
|
| + if (changed) {
|
| + _applyLayoutToChildren();
|
| + }
|
| + for (LayoutCallback callback in callbacks) {
|
| + callback();
|
| + }
|
| + };
|
| + });
|
| }
|
|
|
| void _applyLayoutToChildren() {
|
|
|