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

Unified Diff: sky/specs/style2.md

Issue 959473002: Specs: part 1 of the new approach to style (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 10 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sky/specs/style2.md
diff --git a/sky/specs/style2.md b/sky/specs/style2.md
new file mode 100644
index 0000000000000000000000000000000000000000..f53498a25b0046ff35501a5bc13b869ae6f00e7c
--- /dev/null
+++ b/sky/specs/style2.md
@@ -0,0 +1,351 @@
+Sky Style Language
+==================
+
+Note: This is a work in progress that will eventually replace
+(style.md)[style.md].
+
+The Sky style API looks like the following:
+
+```dart
+
+ // all properties can be set as strings:
+ element.style['color'] = 'blue';
+
+ // some properties have dedicated APIs
+ // color
+ element.style.color.red += 1; // 0..255
+ element.style.color.blue += 10; // 0..255
+ element.style.color.green = 255; // 0..255
+ element.style.color.alpha = 128; // 0..255
+ // transform
+ element.style.transform..reset()
+ ..translate(100, 100)
+ ..rotate(PI/8)
+ ..translate(-100, -100);
+ element.style.transform.translate(10, 0);
+ // height, width
+ element.style.height.auto = true;
+ if (element.style.height.auto)
+ element.style.height.pixels = 10;
+ element.style.height.pixels += 1;
+ element.style.height.em = 1;
+
+ // each property with a dedicated API defines a shorthand setter
+ // style.transform takes a matrix:
+ element.style.transform = new Matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
+ // style.color takes a 32bit int:
+ element.style.color = 0xFF009900;
+ // style.height and style.width takes pixels or the constant 'auto':
+ element.style.height = auto;
+ element.style.width = 100;
+ // all properties with a dedicated API can also be set to null, inherit, or initial:
+ element.style.transform = null; // unset the property
+ element.style.color = initial; // set it to its initial value
+ element.style.color = inherit; // make it get its parent's value
+
+ // you can create a blank StyleDeclaration object:
+ var style = new StyleDeclaration();
+ // you can replace an element's StyleDeclaration object wholesale:
+ element.style = style;
+ // you can clone a StyleDeclaration object:
+ var style2 = new StyleDeclaration.clone(style);
+```
+
+The dart:sky library contains the following to define this API:
+
+```dart
+import 'dart:mirrors';
+import 'dart:math';
+
+class WeakMap<Key, Value> {
+ Expando<Value> _map = new Expando<Value>();
+ operator[](Key key) => _map[key];
+ operator[]=(Key key, Value value) => _map[key] = value;
+ bool containsKey(Key key) => _map[key] != null;
+}
+
+typedef void StringSetter(Symbol propertySymbol, StyleDeclaration declaration, String value);
+typedef String StringGetter(Symbol propertySymbol, StyleDeclaration declaration);
+typedef Property ObjectConstructor(Symbol propertySymbol, StyleDeclaration declaration);
+
+class PropertyTable {
+ const PropertyTable({this.symbol, this.inherited, this.stringGetter, this.stringSetter, this.objectConstructor});
+ final Symbol symbol;
+ final bool inherited;
+ final StringSetter stringSetter;
+ final StringGetter stringGetter;
+ final ObjectConstructor objectConstructor;
+}
+
+Map<Symbol, PropertyTable> _registeredProperties = new Map<Symbol, PropertyTable>();
+void registerProperty(PropertyTable data) {
+ assert(data.symbol is Symbol);
+ assert(data.inherited is bool);
+ assert(data.stringSetter is StringSetter);
+ assert(data.stringGetter is StringGetter);
+ assert(data.objectConstructor == null || data.objectConstructor is ObjectConstructor);
+ assert(!_registeredProperties.containsKey(data.symbol));
+ _registeredProperties[data.symbol] = data;
+}
+
+@proxy
+class StyleDeclaration {
+ StyleDeclaration() { this._init(); }
+ StyleDeclaration.clone(StyleDeclaration template) { this.init(template); }
+ external void _init([StyleDeclaration template]); // O(1)
+ // This class has C++-backed internal state representing the
+ // properties known to the system. It's assumed that Property
+ // subclasses are also C++-backed and can directly manipulate this
+ // internal state.
+ // If the argument 'template' is provided, then this should be a clone
+ // of the styles of the template StyleDeclaration
+
+ operator [](String propertyName) {
+ var propertySymbol = new Symbol(propertyName);
+ if (_registeredProperties.containsKey(propertySymbol))
+ return _registeredProperties[propertySymbol].stringGetter(propertySymbol, this);
+ throw new ArgumentError(propertyName);
+ }
+
+ operator []=(String propertyName, String newValue) {
+ var propertySymbol = new Symbol(propertyName);
+ if (_registeredProperties.containsKey(propertySymbol))
+ return _registeredProperties[propertySymbol].stringSetter(propertySymbol, this, newValue);
+ throw new ArgumentError(propertyName);
+ }
+
+ // some properties expose dedicated APIs so you don't have to use string manipulation
+ WeakMap<Symbol, Property> _properties = new WeakMap<Symbol, Property>();
+ noSuchMethod(Invocation invocation) {
+ Symbol propertySymbol;
+ if (invocation.isSetter) {
+ // when it's a setter, the name will be "foo=" rather than "foo"
+ String propertyName = MirrorSystem.getName(invocation.memberName);
+ assert(propertyName[propertyName.length-1] == '=');
+ propertySymbol = new Symbol(propertyName.substring(0, propertyName.length-1));
+ } else {
+ propertySymbol = invocation.memberName;
+ }
+ Property property;
+ if (!_properties.containsKey(propertySymbol)) {
+ if (_registeredProperties.containsKey(propertySymbol)) {
+ var constructor = _registeredProperties[propertySymbol].objectConstructor;
+ if (constructor == null)
+ return super.noSuchMethod(invocation);
+ property = constructor(propertySymbol, this);
+ } else {
+ return super.noSuchMethod(invocation);
+ }
+ } else {
+ property = _properties[propertySymbol];
+ }
+ if (invocation.isMethod) {
+ if (property is Function)
+ return Function.apply(property as Function, invocation.positionalArguments, invocation.namedArguments);
+ return super.noSuchMethod(invocation);
+ }
+ if (invocation.isSetter)
+ return Function.apply(property.setter, invocation.positionalArguments, invocation.namedArguments);
+ return property;
+ }
+}
+
+const initial = const Object();
+const inherit = const Object();
+
+abstract class Property {
+ Property(this.propertySymbol, this.declaration);
+ final StyleDeclaration declaration;
+ final Symbol propertySymbol;
+
+ bool get inherited => _registeredProperties[propertySymbol].inherited;
+
+ bool get initial => _isInitial();
+ void set initial (value) {
+ if (value == true)
+ return _setInitial();
+ throw new ArgumentError(value);
+ }
+
+ bool get inherit => _isInherit();
+ void set inherit (value) {
+ if (value == true)
+ return _setInherit();
+ throw new ArgumentError(value);
+ }
+
+ void setter(dynamic value) {
+ if (value == initial)
+ return _setInitial();
+ if (value == inherit)
+ return _setInitial();
+ if (value == null)
+ return _unset();
+ throw new ArgumentError(value);
+ }
+
+ external bool _isInitial();
+ external void _setInitial();
+ external bool _isInherit();
+ external void _setInherit();
+ external void _unset();
+}
+```
+
+Sky defines the following properties, currently as part of the core,
+but eventually this will be moved to the framework:
+
+```dart
+class LengthProperty extends Property {
+ LengthProperty(Symbol propertySymbol, StyleDeclaration declaration) : super(propertySymbol, declaration);
+
+ double get pixels => _getPixels();
+ void set pixels (value) => _setPixels(value);
+
+ double get inches => _getPixels() / 96.0;
+ void set inches (value) => _setPixels(value * 96.0);
+
+ double get em => _getEm();
+ void set em (value) => _setEm(value);
+
+ void setter(dynamic value) {
+ if (value is num)
+ return _setPixels(value.toDouble());
+ return super.setter(value);
+ }
+
+ external double _getPixels();
+ // throws StateError if the value isn't in pixels
+ external void _setPixels(double value);
+
+ external double _getEm();
+ // throws StateError if the value isn't in pixels
+ external void _setEm(double value);
+}
+
+const auto = const Object();
+
+class AutoLengthProperty extends LengthProperty {
+ AutoLengthProperty(Symbol propertySymbol, StyleDeclaration declaration) : super(propertySymbol, declaration);
+
+ bool get auto => _isAuto();
+ void set auto (value) {
+ if (value == true)
+ _setAuto();
+ throw new ArgumentError(value);
+ }
+
+ void setter(dynamic value) {
+ if (value == auto)
+ return _setAuto();
+ return super.setter(value);
+ }
+
+ external bool _isAuto();
+ external void _setAuto();
+}
+
+class ColorProperty extends Property {
+ ColorProperty(Symbol propertySymbol, StyleDeclaration declaration) : super(propertySymbol, declaration);
+
+ int get alpha => _getRGBA() & 0xFF000000 >> 24;
+ void set alpha (int value) => _setRGBA(_getRGBA() & 0x00FFFFFF + value << 24);
+ int get red => _getRGBA() & 0x00FF0000 >> 16;
+ void set red (int value) => _setRGBA(_getRGBA() & 0xFF00FFFF + value << 16);
+ int get green => _getRGBA() & 0x0000FF00 >> 8;
+ void set green (int value) => _setRGBA(_getRGBA() & 0xFFFF00FF + value << 8);
+ int get blue => _getRGBA() & 0x000000FF >> 0;
+ void set blue (int value) => _setRGBA(_getRGBA() & 0xFFFFFF00 + value << 0);
+
+ int get rgba => _getRGBA();
+ void set rgba (int value) => _setRGBA(value);
+
+ void setter(dynamic value) {
+ if (value is int)
+ return _setRGBA(value);
+ return super.setter(value);
+ }
+
+ external int _getRGBA();
+ // throws StateError if the value isn't a color
+ external void _setRGBA(int value);
+}
+
+class Matrix {
+ const Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
+
+ // +- -+
+ // | a c e |
+ // | b d f |
+ // | 0 0 1 |
+ // +- -+
+
+ final double a;
+ final double b;
+ final double c;
+ final double d;
+ final double e;
+ final double f;
+}
+
+class TransformProperty extends Property {
+ TransformProperty(Symbol propertySymbol, StyleDeclaration declaration) : super(propertySymbol, declaration);
+
+ void reset() => setTransform(1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
+
+ void translate(double dx, double dy) => transform(1.0, 0.0, 0.0, 1.0, dx, dy);
+ void scale(double dw, double dh) => transform(dw, 0.0, 0.0, dh, 0.0, 0.0);
+ void rotate(double theta) => transform(cos(theta), -sin(theta), sin(theta), cos(theta), 0.0, 0.0);
+
+ // there's no "transform" getter since it would always return a new Matrix
+ // such that foo.transform == foo.transform would never be true
+ // and foo.transform = bar; bar == foo.transform would also never be true
+ // which is bad API
+
+ external Matrix getTransform();
+ // throws StateError if the value isn't a matrix
+ // returns a new matrix each time
+ external void setTransform(a, b, c, d, e, f);
+ external void transform(a, b, c, d, e, f);
+ // throws StateError if the value isn't a matrix
+}
+
+external void autoLengthPropertyStringSetter(Symbol propertySymbol, StyleDeclaration declaration, String value);
+external String autoLengthPropertyStringGetter(Symbol propertySymbol, StyleDeclaration declaration);
+external void colorPropertyStringSetter(Symbol propertySymbol, StyleDeclaration declaration, String value);
+external String colorPropertyStringGetter(Symbol propertySymbol, StyleDeclaration declaration);
+external void transformPropertyStringSetter(Symbol propertySymbol, StyleDeclaration declaration, String value);
+external String transformPropertyStringGetter(Symbol propertySymbol, StyleDeclaration declaration);
+
+void _init() {
+ registerProperty(new PropertyTable(
+ symbol: #height,
+ inherited: false,
+ stringSetter: autoLengthPropertyStringSetter,
+ stringGetter: autoLengthPropertyStringGetter,
+ objectConstructor: (Symbol propertySymbol, StyleDeclaration declaration) =>
+ new AutoLengthProperty(propertySymbol, declaration)));
+ registerProperty(new PropertyTable(
+ symbol: #width,
+ inherited: false,
+ stringSetter: autoLengthPropertyStringSetter,
+ stringGetter: autoLengthPropertyStringGetter,
+ objectConstructor: (Symbol propertySymbol, StyleDeclaration declaration) =>
+ new AutoLengthProperty(propertySymbol, declaration)));
+ registerProperty(new PropertyTable(
+ symbol: #color,
+ inherited: false,
+ stringSetter: colorPropertyStringSetter,
+ stringGetter: colorPropertyStringGetter,
+ objectConstructor: (Symbol propertySymbol, StyleDeclaration declaration) =>
+ new ColorProperty(propertySymbol, declaration)));
+ registerProperty(new PropertyTable(
+ symbol: #transform,
+ inherited: false,
+ stringSetter: transformPropertyStringSetter,
+ stringGetter: transformPropertyStringGetter,
+ objectConstructor: (Symbol propertySymbol, StyleDeclaration declaration) =>
+ new TransformProperty(propertySymbol, declaration)));
+}
+```
+
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698