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

Unified Diff: sky/framework/layout.dart

Issue 1117143003: [Effen] Port fn.dart from the legacy sky.Node backend to the RenderNode backend, which is currently… (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 8 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 side-by-side diff with in-line comments
Download patch
Index: sky/framework/layout.dart
diff --git a/sky/framework/layout.dart b/sky/framework/layout.dart
new file mode 100644
index 0000000000000000000000000000000000000000..f7c175ab299e1a04aa82121bb21e580dc34cbfe2
--- /dev/null
+++ b/sky/framework/layout.dart
@@ -0,0 +1,406 @@
+library layout;
+
+import 'node.dart';
+import 'dart:sky' as sky;
+import 'dart:collection';
+
+// UTILS
+
+// Bridge to legacy CSS-like style specification
+// Eventually we'll replace this with something else
+class Style {
+ final String _className;
+ static final Map<String, Style> _cache = new HashMap<String, Style>();
+
+ static int _nextStyleId = 1;
+
+ static String _getNextClassName() { return "style${_nextStyleId++}"; }
+
+ Style extend(Style other) {
+ var className = "$_className ${other._className}";
+
+ return _cache.putIfAbsent(className, () {
+ return new Style._internal(className);
+ });
+ }
+
+ factory Style(String styles) {
+ return _cache.putIfAbsent(styles, () {
+ var className = _getNextClassName();
+ sky.Element styleNode = sky.document.createElement('style');
+ styleNode.setChild(new sky.Text(".$className { $styles }"));
+ sky.document.appendChild(styleNode);
+ return new Style._internal(className);
+ });
+ }
+
+ Style._internal(this._className);
+}
+
+class Rect {
+ const Rect(this.x, this.y, this.width, this.height);
+ final double x;
+ final double y;
+ final double width;
+ final double height;
+}
+
+
+// ABSTRACT LAYOUT
+
+class ParentData {
+ void detach() {
+ detachSiblings();
+ }
+ void detachSiblings() { } // workaround for lack of inter-class mixins in Dart
+}
+
+abstract class RenderNode extends Node {
+
+ // LAYOUT
+
+ // pos is only for use by the RenderNode that actually lays this
+ // node out, and any other nodes who happen to know exactly what
+ // kind of node that is.
+ ParentData pos;
eseidel 2015/05/08 19:15:53 parentData or something more readable than "pos"?
Hixie 2015/05/08 19:39:17 I don't know that it'd be any more readable, but h
+ void setupPos(RenderNode child) {
+ // override this to setup .pos correctly for your class
+ if (child.pos is! ParentData)
eseidel 2015/05/08 19:15:54 is!?
Hixie 2015/05/08 19:39:17 Dart for "is not".
+ child.pos = new ParentData();
+ }
+
+ void setAsChild(RenderNode child) { // only for use by subclasses
+ // call this whenever you decide a node is a child
+ assert(child != null);
+ setupPos(child);
+ super.setAsChild(child);
+ }
+ void dropChild(RenderNode child) { // only for use by subclasses
+ assert(child != null);
+ assert(child.pos != null);
+ child.pos.detach();
+ super.dropChild(child);
+ }
+
+}
+
+abstract class RenderBox extends RenderNode { }
+
+
+// GENERIC MIXIN FOR RENDER NODES THAT TAKE A LIST OF CHILDREN
+
+abstract class ContainerParentDataMixin<ChildType extends RenderNode> {
+ ChildType previousSibling;
+ ChildType nextSibling;
+ void detachSiblings() {
+ if (previousSibling != null) {
+ assert(previousSibling.pos is ContainerParentDataMixin<ChildType>);
+ assert(previousSibling != this);
+ assert(previousSibling.pos.nextSibling == this);
+ previousSibling.pos.nextSibling = nextSibling;
+ }
+ if (nextSibling != null) {
+ assert(nextSibling.pos is ContainerParentDataMixin<ChildType>);
+ assert(nextSibling != this);
+ assert(nextSibling.pos.previousSibling == this);
+ nextSibling.pos.previousSibling = previousSibling;
+ }
+ previousSibling = null;
+ nextSibling = null;
+ }
+}
+
+abstract class ContainerRenderNodeMixin<ChildType extends RenderNode, ParentDataType extends ContainerParentDataMixin<ChildType>> implements RenderNode {
+ // abstract class that has only InlineNode children
+
+ bool _debugUltimatePreviousSiblingOf(ChildType child, { ChildType equals }) {
+ assert(child.pos is ParentDataType);
+ while (child.pos.previousSibling != null) {
+ assert(child.pos.previousSibling != child);
+ child = child.pos.previousSibling;
+ assert(child.pos is ParentDataType);
+ }
+ return child == equals;
+ }
+ bool _debugUltimateNextSiblingOf(ChildType child, { ChildType equals }) {
+ assert(child.pos is ParentDataType);
+ while (child.pos.nextSibling != null) {
+ assert(child.pos.nextSibling != child);
+ child = child.pos.nextSibling;
+ assert(child.pos is ParentDataType);
+ }
+ return child == equals;
+ }
+
+ ChildType _firstChild;
+ ChildType _lastChild;
+ void add(ChildType child, { ChildType before }) {
+ assert(child != this);
+ assert(before != this);
+ assert(child != before);
+ assert(child != _firstChild);
+ assert(child != _lastChild);
+ setAsChild(child);
+ assert(child.pos is ParentDataType);
+ assert(child.pos.nextSibling == null);
+ assert(child.pos.previousSibling == null);
+ if (before == null) {
+ // append at the end (_lastChild)
+ child.pos.previousSibling = _lastChild;
+ if (_lastChild != null) {
+ assert(_lastChild.pos is ParentDataType);
+ _lastChild.pos.nextSibling = child;
+ }
+ _lastChild = child;
+ if (_firstChild == null)
+ _firstChild = child;
+ } else {
+ assert(_firstChild != null);
+ assert(_lastChild != null);
+ assert(_debugUltimatePreviousSiblingOf(before, equals: _firstChild));
+ assert(_debugUltimateNextSiblingOf(before, equals: _lastChild));
+ assert(before.pos is ParentDataType);
+ if (before.pos.previousSibling == null) {
+ // insert at the start (_firstChild); we'll end up with two or more children
+ assert(before == _firstChild);
+ child.pos.nextSibling = before;
+ before.pos.previousSibling = child;
+ _firstChild = child;
+ } else {
+ // insert in the middle; we'll end up with three or more children
+ // set up links from child to siblings
+ child.pos.previousSibling = before.pos.previousSibling;
+ child.pos.nextSibling = before;
+ // set up links from siblings to child
+ assert(child.pos.previousSibling.pos is ParentDataType);
+ assert(child.pos.nextSibling.pos is ParentDataType);
+ child.pos.previousSibling.pos.nextSibling = child;
+ child.pos.nextSibling.pos.previousSibling = child;
+ assert(before.pos.previousSibling == child);
+ }
+ }
+ markNeedsLayout();
+ }
+ void remove(ChildType child) {
+ assert(child.pos is ParentDataType);
+ assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild));
+ assert(_debugUltimateNextSiblingOf(child, equals: _lastChild));
+ if (child.pos.previousSibling == null) {
+ assert(_firstChild == child);
+ _firstChild = child.pos.nextSibling;
+ } else {
+ assert(child.pos.previousSibling.pos is ParentDataType);
+ child.pos.previousSibling.pos.nextSibling = child.pos.nextSibling;
+ }
+ if (child.pos.nextSibling == null) {
+ assert(_lastChild == child);
+ _lastChild = child.pos.previousSibling;
+ } else {
+ assert(child.pos.nextSibling.pos is ParentDataType);
+ child.pos.nextSibling.pos.previousSibling = child.pos.previousSibling;
+ }
+ child.pos.previousSibling = null;
+ child.pos.nextSibling = null;
+ dropChild(child);
+ markNeedsLayout();
+ }
+ void redepthChildren() {
+ ChildType child = _firstChild;
+ while (child != null) {
+ redepthChild(child);
+ assert(child.pos is ParentDataType);
+ child = child.pos.nextSibling;
+ }
+ }
+ void attachChildren() {
+ ChildType child = _firstChild;
+ while (child != null) {
+ child.attach();
+ assert(child.pos is ParentDataType);
+ child = child.pos.nextSibling;
+ }
+ }
+ void detachChildren() {
+ ChildType child = _firstChild;
+ while (child != null) {
+ child.detach();
+ assert(child.pos is ParentDataType);
+ child = child.pos.nextSibling;
+ }
+ }
+
+ ChildType get firstChild => _firstChild;
+ ChildType get lastChild => _lastChild;
+ ChildType childAfter(ChildType child) {
+ assert(child.pos is ParentDataType);
+ return child.pos.nextSibling;
+ }
+
+}
+
+
+// CSS SHIMS
+
+abstract class RenderCSS extends RenderBox {
+
+ dynamic debug;
+ sky.Element _skyElement;
+
+ RenderCSS(this.debug) {
+ _skyElement = createSkyElement();
+ registerEventTarget(_skyElement, this);
+ }
+
+ sky.Element createSkyElement();
+
+ void updateStyles(List<Style> styles) {
+ _skyElement.setAttribute('class', styles.map((s) => s._className).join(' '));
+ }
+
+ void updateInlineStyle(String newStyle) {
+ _skyElement.setAttribute('style', newStyle);
+ }
+
+ double get width {
+ sky.ClientRect rect = _skyElement.getBoundingClientRect();
+ return rect.width;
+ }
+
+ double get height {
+ sky.ClientRect rect = _skyElement.getBoundingClientRect();
+ return rect.height;
+ }
+
+ Rect get rect {
+ sky.ClientRect rect = _skyElement.getBoundingClientRect();
+ return new Rect(rect.left, rect.top, rect.width, rect.height);
+ }
+
+}
+
+class CSSParentData extends ParentData with ContainerParentDataMixin<RenderCSS> { }
+
+class RenderCSSContainer extends RenderCSS with ContainerRenderNodeMixin<RenderCSS, CSSParentData> {
+
+ RenderCSSContainer(debug) : super(debug);
+
+ void setupPos(RenderNode child) {
+ if (child.pos is! CSSParentData)
+ child.pos = new CSSParentData();
+ }
+
+ sky.Element createSkyElement() => sky.document.createElement('div')
+ ..setAttribute('debug', debug.toString());
+
+ void markNeedsLayout() { }
+
+ void add(RenderCSS child, { RenderCSS before }) {
+ if (before != null) {
+ assert(before._skyElement.parentNode != null);
+ assert(before._skyElement.parentNode == _skyElement);
+ }
+ super.add(child, before: before);
+ if (before != null) {
+ before._skyElement.insertBefore([child._skyElement]);
+ assert(child._skyElement.parentNode != null);
+ assert(child._skyElement.parentNode == _skyElement);
+ assert(child._skyElement.parentNode == before._skyElement.parentNode);
+ } else {
+ _skyElement.appendChild(child._skyElement);
+ }
+ }
+ void remove(RenderCSS child) {
+ child._skyElement.remove();
+ super.remove(child);
+ }
+
+}
+
+class RenderCSSText extends RenderCSS {
+
+ RenderCSSText(debug, String newData) : super(debug) {
+ data = newData;
+ }
+
+ static final Style _displayParagraph = new Style('display:paragraph');
+
+ sky.Element createSkyElement() {
+ return sky.document.createElement('div')
+ ..setChild(new sky.Text())
+ ..setAttribute('class', _displayParagraph._className)
+ ..setAttribute('debug', debug.toString());
+ }
+
+ void set data (String value) {
+ (_skyElement.firstChild as sky.Text).data = value;
+ }
+
+}
+
+class RenderCSSImage extends RenderCSS {
+
+ RenderCSSImage(debug, String src, num width, num height) : super(debug) {
+ configure(src, width, height);
+ }
+
+ sky.Element createSkyElement() {
+ return sky.document.createElement('img')
+ ..setAttribute('debug', debug.toString());
+ }
+
+ void configure(String src, num width, num height) {
+ if (_skyElement.getAttribute('src') != src)
+ _skyElement.setAttribute('src', src);
+ _skyElement.style['width'] = '${width}px';
+ _skyElement.style['height'] = '${height}px';
+ }
+
+}
+
+class RenderCSSRoot extends RenderCSSContainer {
+ RenderCSSRoot(debug) : super(debug);
+ sky.Element createSkyElement() {
+ var result = super.createSkyElement();
+ assert(result != null);
+ sky.document.appendChild(result);
+ return result;
+ }
+}
+
+
+// legacy tools
+Map<sky.EventTarget, RenderNode> _eventTargetRegistry = {};
+void registerEventTarget(sky.EventTarget e, RenderNode n) {
+ _eventTargetRegistry[e] = n;
+}
+RenderNode bridgeEventTargetToRenderNode(sky.EventTarget e) {
+ return _eventTargetRegistry[e];
+}
+
+
+
+
+String _attributes(node) {
+ if (node is! sky.Element) return '';
+ var r = '';
eseidel 2015/05/08 19:15:54 result?
Hixie 2015/05/08 19:39:16 Changed.
+ var attrs = node.getAttributes();
+ for (var attr in attrs)
+ r += ' ${attr.name}="${attr.value}"';
+ return r;
+}
+
+void _serialiseDOM(node, [String prefix = '']) {
+ if (node is sky.Text) {
+ print(prefix + 'text: "' + node.data.replaceAll('\n', '\\n') + '"');
+ return;
+ }
+ print(prefix + node.toString() + _attributes(node));
+ var children = node.getChildNodes();
+ prefix = prefix + ' ';
+ for (var child in children)
eseidel 2015/05/08 19:15:53 is var needed? Should this be a type?
Hixie 2015/05/08 19:39:17 Either var or a type is needed. The way this funct
+ _serialiseDOM(child, prefix);
+}
+
+void dumpState() {
+ _serialiseDOM(sky.document);
+}
« no previous file with comments | « sky/framework/fn.dart ('k') | sky/framework/node.dart » ('j') | sky/framework/node.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698