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

Unified Diff: sky/specs/style.md

Issue 730273002: Specs: Fix markdown errors (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 6 years, 1 month 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 | « sky/examples/htmlish/framework/htmlish.sky ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sky/specs/style.md
diff --git a/sky/specs/style.md b/sky/specs/style.md
index fd3008c553f76e0137bbe8f8546c42dfdeda945d..0db40badedb3a56a2b3127307ca0787ac554c3c7 100644
--- a/sky/specs/style.md
+++ b/sky/specs/style.md
@@ -137,18 +137,22 @@ Sky Style uses whatever SelectorQuery. Maybe one day we'll make
SelectorQuery support being extended to support arbitrary selectors,
but for now, it supports:
- tagname
- #id
- .class
- [attrname]
- [attrname=value]
- :host ("host" string is fixed)
- ::pseudo-element
+```css
+tagname
+#id
+.class
+[attrname]
+[attrname=value]
+:host ("host" string is fixed)
+::pseudo-element
+```
These can be combined (without whitespace), with at most one tagname
(must be first) and at most one pseudo-element (must be last) as in:
- tagname[attrname]#id:host.class.class[attrname=value]::foo
+```css
+tagname[attrname]#id:host.class.class[attrname=value]::foo
+```
In debug mode, giving two IDs, or the same selector twice (e.g. the
same classname), or specifying other redundant or conflicting
@@ -158,96 +162,100 @@ flagged.
Alternatively, a selector can be the special value "@document",
optionally followed by a pseudo-element, as in:
- @document::bar
+```css
+@document::bar
+```
Value Parser
------------
- class StyleToken {
- constructor (String king, String value);
- readonly attribute String kind;
- // string
- // identifier
- // function (identifier + '(')
- // number
- // symbol (one of @#$%& if not immediately following numeric or preceding alphanumeric, or one of *^!?,/<[)>]+ or, if not followed by a digit, -)
- // dimension (number + identifier or number + one of @#$%&)
- // literal (one of @#$%& + alphanumeric)
- readonly attribute String value;
- readonly attribute String unit; // for 'dimension' type, this is the punctuation or identifier that follows the number, for 'literal' type, this is the punctuation that precedes it
- }
+```javascript
+class StyleToken {
+ constructor (String king, String value);
+ readonly attribute String kind;
+ // string
+ // identifier
+ // function (identifier + '(')
+ // number
+ // symbol (one of @#$%& if not immediately following numeric or preceding alphanumeric, or one of *^!?,/<[)>]+ or, if not followed by a digit, -)
+ // dimension (number + identifier or number + one of @#$%&)
+ // literal (one of @#$%& + alphanumeric)
+ readonly attribute String value;
+ readonly attribute String unit; // for 'dimension' type, this is the punctuation or identifier that follows the number, for 'literal' type, this is the punctuation that precedes it
+}
- class TokenSource {
- constructor (Array<StyleToken> tokens);
- IteratorResult next();
- TokenSourceBookmark getBookmark();
- void rewind(TokenSourceBookmark bookmark);
- }
- class TokenSourceBookmark {
- constructor ();
- // TokenSource stores unforgeable state on this object using symbols or a weakmap or some such
- }
+class TokenSource {
+ constructor (Array<StyleToken> tokens);
+ IteratorResult next();
+ TokenSourceBookmark getBookmark();
+ void rewind(TokenSourceBookmark bookmark);
+}
+class TokenSourceBookmark {
+ constructor ();
+ // TokenSource stores unforgeable state on this object using symbols or a weakmap or some such
+}
- dictionary ParsedValue {
- any value = null;
- ValueResolver? resolver = null;
- Boolean relativeDimension = false; // if true, e.g. for % lengths, the callback will be called again if an ancestor's dimensions change
- Painter? painter = null;
- }
+dictionary ParsedValue {
+ any value = null;
+ ValueResolver? resolver = null;
+ Boolean relativeDimension = false; // if true, e.g. for % lengths, the callback will be called again if an ancestor's dimensions change
+ Painter? painter = null;
+}
- // best practice convention: if you're creating a property with needsPaint, you should
- // create a new style value type for it so that it can set the paint callback right;
- // you should never use such a style type when parsing another property
-
- callback any ParserCallback (TokenSource tokens);
-
- class StyleValueType {
- constructor ();
- void addParser(ParserCallback parser);
- any parse(TokenSource tokens, Boolean root = false);
- // for each parser callback that was registered, in reverse
- // order (most recently registered first), run these steps:
- // let bookmark = tokens.getBookmark();
- // try {
- // let result = parser(tokens);
- // if (root) {
- // if (!tokens.next().done)
- // throw new Error();
- // }
- // } except {
- // tokens.rewind(bookmark);
- // }
- // (root is set when you need to parse the entire token stream to be valid)
- }
+// best practice convention: if you're creating a property with needsPaint, you should
+// create a new style value type for it so that it can set the paint callback right;
+// you should never use such a style type when parsing another property
- // note: if you define a style value type that uses other style value types, e.g. a "length pair" that accepts two lengths, then
- // if any of the subtypes have a resolver, you need to make sure you have a resolver that calls them to compute the final value
+callback any ParserCallback (TokenSource tokens);
- dictionary PropertySettings {
- String name;
- StyleValueType type; // the output from the parser is coerced to a ParsedValue
- Boolean inherits = false;
- any initialValue = null;
- Boolean needsLayout = false;
- Boolean needsPaint = false;
- }
+class StyleValueType {
+ constructor ();
+ void addParser(ParserCallback parser);
+ any parse(TokenSource tokens, Boolean root = false);
+ // for each parser callback that was registered, in reverse
+ // order (most recently registered first), run these steps:
+ // let bookmark = tokens.getBookmark();
+ // try {
+ // let result = parser(tokens);
+ // if (root) {
+ // if (!tokens.next().done)
+ // throw new Error();
+ // }
+ // } except {
+ // tokens.rewind(bookmark);
+ // }
+ // (root is set when you need to parse the entire token stream to be valid)
+}
- void registerProperty(PropertySettings propertySettings);
- // when you register a new property, document the format that is expected to be cascaded
- // (the output from the propertySettings.type parser's ParsedValue.value field after the resolver, if any, has been called)
+// note: if you define a style value type that uses other style value types, e.g. a "length pair" that accepts two lengths, then
+// if any of the subtypes have a resolver, you need to make sure you have a resolver that calls them to compute the final value
- // sky:core exports a bunch of style value types so that people can
- // extend them
- attribute StyleValueType PositiveLengthOrInfinityStyleValueType;
- attribute StyleValueType PositiveLengthOrAutoStyleValueType;
- attribute StyleValueType PositiveLengthStyleValueType;
- attribute StyleValueType DisplayStyleValueType;
-
+dictionary PropertySettings {
+ String name;
+ StyleValueType type; // the output from the parser is coerced to a ParsedValue
+ Boolean inherits = false;
+ any initialValue = null;
+ Boolean needsLayout = false;
+ Boolean needsPaint = false;
+}
+
+void registerProperty(PropertySettings propertySettings);
+ // when you register a new property, document the format that is expected to be cascaded
+ // (the output from the propertySettings.type parser's ParsedValue.value field after the resolver, if any, has been called)
+
+// sky:core exports a bunch of style value types so that people can
+// extend them
+attribute StyleValueType PositiveLengthOrInfinityStyleValueType;
+attribute StyleValueType PositiveLengthOrAutoStyleValueType;
+attribute StyleValueType PositiveLengthStyleValueType;
+attribute StyleValueType DisplayStyleValueType;
+```
Inline Styles
-------------
+```javascript
partial class Element {
readonly attribute StyleDeclarationList style;
}
@@ -261,11 +269,12 @@ class StyleDeclarationList {
}
typedef StyleDeclaration Dictionary<ParsedValue>;
-
+```
Rule Matching
-------------
+```javascript
partial class StyleElement {
Array<Rule> getRules(); // O(N) in rules
}
@@ -276,6 +285,7 @@ class Rule {
attribute String? pseudoElement; // O(1)
attribute StyleDeclaration styles; // O(1)
}
+```
Each frame, at some defined point relative to requestAnimationFrame():
- If a rule starts applying to an element, sky:core calls thatElement.style.add(rule.styles, rule.pseudoElement);
@@ -294,63 +304,69 @@ Create the flattened render tree as a tree of StyleNode objects
(described below). For each one, run the equivalent of the following
code:
- var display = node.getProperty('display');
- if (display) {
- node.layoutManager = new display(node, ownerManager);
- return true;
- }
- return false;
+```javascript
+var display = node.getProperty('display');
+if (display) {
+ node.layoutManager = new display(node, ownerManager);
+ return true;
+}
+return false;
+```
If that code returns false, then that node an all its descendants must
be dropped from the render tree.
If any node is removed in this pass relative to the previous pass, and
it has an ownerLayoutManager, then call
- ``node.ownerLayoutManager.release(node)``
+
+```node.ownerLayoutManager.release(node)```
+
...to notify the layout manager that the node went away, then set the
node's layoutManager and ownerLayoutManager attributes to null.
- callback any ValueResolver (any value, String propertyName, StyleNode node, Float containerWidth, Float containerHeight);
-
- class StyleNode {
- // this is generated before layout
- readonly attribute String text;
- readonly attribute Node? parentNode;
- readonly attribute Node? firstChild;
- readonly attribute Node? nextSibling;
-
- // access to the results of the cascade
- any getProperty(String name, String? pseudoElement = null);
- // looking at the declarations for the given pseudoElement:
- // if there's a cached value, return it
- // otherwise, if there's an applicable ParsedValue, then
- // if it has a resolver:
- // call it
- // cache the value
- // if relativeDimension is true, then mark the value as provisional
- // return the value
- // otherwise use the ParsedValue's value; cache it; return it
- // otherwise, if a pseudo-element was specified, try again without one
- // otherwise, if the property is inherited and there's a parent:
- // get it from the parent (without pseudo); cache it; return it
- // otherwise, get the default value; cache it; return it
-
- readonly attribute Boolean needsLayout; // means that a property with needsLayout:true has changed on this node or one of its descendants
- readonly attribute LayoutManager layoutManager;
-
- readonly attribute LayoutManager ownerLayoutManager; // defaults to the parentNode.layoutManager
- // if you are not the ownerLayoutManager, then ignore this StyleNode in layout() and paintChildren()
- // using walkChildren() does this for you
-
- readonly attribute Boolean needsPaint; // means that either needsLayout is true or a property with needsPaint:true has changed on this node or one of its descendants
- // needsPaint is set to false by the ownerLayoutManager's default paint() method
-
- // only the ownerLayoutManager can change these
- readonly attribute Float x; // relative to left edge of ownerLayoutManager
- readonly attribute Float y; // relative to top edge of ownerLayoutManager
- readonly attribute Float width;
- readonly attribute Float height;
- }
+```javascript
+callback any ValueResolver (any value, String propertyName, StyleNode node, Float containerWidth, Float containerHeight);
+
+class StyleNode {
+ // this is generated before layout
+ readonly attribute String text;
+ readonly attribute Node? parentNode;
+ readonly attribute Node? firstChild;
+ readonly attribute Node? nextSibling;
+
+ // access to the results of the cascade
+ any getProperty(String name, String? pseudoElement = null);
+ // looking at the declarations for the given pseudoElement:
+ // if there's a cached value, return it
+ // otherwise, if there's an applicable ParsedValue, then
+ // if it has a resolver:
+ // call it
+ // cache the value
+ // if relativeDimension is true, then mark the value as provisional
+ // return the value
+ // otherwise use the ParsedValue's value; cache it; return it
+ // otherwise, if a pseudo-element was specified, try again without one
+ // otherwise, if the property is inherited and there's a parent:
+ // get it from the parent (without pseudo); cache it; return it
+ // otherwise, get the default value; cache it; return it
+
+ readonly attribute Boolean needsLayout; // means that a property with needsLayout:true has changed on this node or one of its descendants
+ readonly attribute LayoutManager layoutManager;
+
+ readonly attribute LayoutManager ownerLayoutManager; // defaults to the parentNode.layoutManager
+ // if you are not the ownerLayoutManager, then ignore this StyleNode in layout() and paintChildren()
+ // using walkChildren() does this for you
+
+ readonly attribute Boolean needsPaint; // means that either needsLayout is true or a property with needsPaint:true has changed on this node or one of its descendants
+ // needsPaint is set to false by the ownerLayoutManager's default paint() method
+
+ // only the ownerLayoutManager can change these
+ readonly attribute Float x; // relative to left edge of ownerLayoutManager
+ readonly attribute Float y; // relative to top edge of ownerLayoutManager
+ readonly attribute Float width;
+ readonly attribute Float height;
+}
+```
The flattened tree is represented as a hierarchy of Node objects. For
any element that only contains text node children, the "text" property
@@ -365,6 +381,7 @@ Layout
sky:core registers 'display' as follows:
+```javascript
{
name: 'display',
type: sky.DisplayStyleValueType,
@@ -372,125 +389,132 @@ sky:core registers 'display' as follows:
initialValue: sky.BlockLayoutManager,
needsLayout: true,
}
+```
The following API is then used to add new layout manager types to 'display':
- void registerLayoutManager(String displayValue, LayoutManagerConstructor? layoutManager);
+```javascript
+void registerLayoutManager(String displayValue, LayoutManagerConstructor? layoutManager);
+```
sky:core by default registers:
- 'block': sky.BlockLayoutManager
- 'paragraph': sky.ParagraphLayoutManager
- 'inline': sky.InlineLayoutManager
- 'none': null
+- 'block': sky.BlockLayoutManager
+- 'paragraph': sky.ParagraphLayoutManager
+- 'inline': sky.InlineLayoutManager
+- 'none': null
Layout managers inherit from the following API:
- class LayoutManager {
- readonly attribute StyleNode node;
- constructor LayoutManager(StyleNode node);
-
- void take(StyleNode victim); // sets victim.ownerLayoutManager = this;
- // assert: victim hasn't been take()n yet during this layout
- // assert: victim.needsLayout == true
- // assert: an ancestor of victim has needsLayout == this (aka, victim is a descendant of this.node)
-
- virtual void release(StyleNode victim);
- // called when the StyleNode was removed from the tree
-
- void setChildPosition(child, x, y); // sets child.x, child.y
- void setChildX(child, y); // sets child.x
- void setChildY(child, y); // sets child.y
- void setChildSize(child, width, height); // sets child.width, child.height
- void setChildWidth(child, width); // sets child.width
- void setChildHeight(child, height); // sets child.height
- // these set needsPaint on the node and on any node impacted by this (?)
- // for setChildSize/Width/Height: if the new dimension is different than the last assumed dimensions, and
- // any StyleNodes with an ownerLayoutManager==this have cached values for getProperty() that are marked
- // as provisional, clear them
-
- Generator<StyleNode> walkChildren();
- // returns a generator that iterates over the children, skipping any whose ownerLayoutManager is not |this|
-
- Generator<StyleNode> walkChildrenBackwards();
- // returns a generator that iterates over the children backwards, skipping any whose ownerLayoutManager is not |this|
-
- void assumeDimensions(Float width, Float height);
- // sets the assumed dimensions for calls to getProperty() on StyleNodes that have this as an ownerLayoutManager
- // if the new dimension is different than the last assumed dimensions, and any StyleNodes with an
- // ownerLayoutManager==this have cached values for getProperty() that are marked as provisional, clear them
- // TODO(ianh): should we force this to match the input to layout(), when called from inside layout() and when
- // layout() has a forced width and/or height?
-
- virtual LayoutValueRange getIntrinsicWidth(Float? defaultWidth = null);
- // returns min-width, width, and max-width, normalised, defaulting to values given in LayoutValueRange
- // if argument is provided, it overrides width
-
- virtual LayoutValueRange getIntrinsicHeight(Float? defaultHeight = null);
- // returns min-height, height, and max-height, normalised, defaulting to values given in LayoutValueRange
- // if argument is provided, it overrides height
-
- virtual Dimensions layout(Number? width, Number? height);
- // returns { }
- // the return value should include the final value for whichever of the width and height arguments that is null
- // TODO(ianh): should we just grab the width and height from assumeDimensions()?
-
- void markAsPainted(); // sets this.node.needsPaint to false
- virtual void paint(RenderingSurface canvas);
- // set a clip rect on the canvas for rect(0,0,this.width,this.height)
- // call the painter of each property, in order they were registered, which on this element has a painter
- // call this.paintChildren()
- // unset the clip
- // call markAsPainted()
-
- virtual void paintChildren(RenderingSurface canvas);
- // just calls paint() for each child returned by walkChildren() whose needsPaint is true,
- // after transforming the coordinate space by translate(child.x,child.y)
- // you should skip children that will be clipped out of yourself because they're outside your bounds
-
- virtual Node hitTest(Float x, Float y);
- // default implementation uses the node's children nodes' x, y,
- // width, and height, skipping any that have width=0 or height=0, or
- // whose ownerLayoutManager is not |this|
- // default implementation walks the tree backwards from its built-in order
- // if no child is hit, then return this.node
- // override this if you changed your children's z-order, or if you used take() to
- // hoist some descendants up to be your responsibility, or if your children aren't
- // rectangular (e.g. you lay them out in a hex grid)
- // make sure to offset the value you pass your children: child.layoutManager.hitTest(x-child.x, y-child.y)
-
- }
+```
+class LayoutManager {
+ readonly attribute StyleNode node;
+ constructor LayoutManager(StyleNode node);
+
+ void take(StyleNode victim); // sets victim.ownerLayoutManager = this;
+ // assert: victim hasn't been take()n yet during this layout
+ // assert: victim.needsLayout == true
+ // assert: an ancestor of victim has needsLayout == this (aka, victim is a descendant of this.node)
+
+ virtual void release(StyleNode victim);
+ // called when the StyleNode was removed from the tree
+
+ void setChildPosition(child, x, y); // sets child.x, child.y
+ void setChildX(child, y); // sets child.x
+ void setChildY(child, y); // sets child.y
+ void setChildSize(child, width, height); // sets child.width, child.height
+ void setChildWidth(child, width); // sets child.width
+ void setChildHeight(child, height); // sets child.height
+ // these set needsPaint on the node and on any node impacted by this (?)
+ // for setChildSize/Width/Height: if the new dimension is different than the last assumed dimensions, and
+ // any StyleNodes with an ownerLayoutManager==this have cached values for getProperty() that are marked
+ // as provisional, clear them
+
+ Generator<StyleNode> walkChildren();
+ // returns a generator that iterates over the children, skipping any whose ownerLayoutManager is not |this|
+
+ Generator<StyleNode> walkChildrenBackwards();
+ // returns a generator that iterates over the children backwards, skipping any whose ownerLayoutManager is not |this|
+
+ void assumeDimensions(Float width, Float height);
+ // sets the assumed dimensions for calls to getProperty() on StyleNodes that have this as an ownerLayoutManager
+ // if the new dimension is different than the last assumed dimensions, and any StyleNodes with an
+ // ownerLayoutManager==this have cached values for getProperty() that are marked as provisional, clear them
+ // TODO(ianh): should we force this to match the input to layout(), when called from inside layout() and when
+ // layout() has a forced width and/or height?
+
+ virtual LayoutValueRange getIntrinsicWidth(Float? defaultWidth = null);
+ // returns min-width, width, and max-width, normalised, defaulting to values given in LayoutValueRange
+ // if argument is provided, it overrides width
+
+ virtual LayoutValueRange getIntrinsicHeight(Float? defaultHeight = null);
+ // returns min-height, height, and max-height, normalised, defaulting to values given in LayoutValueRange
+ // if argument is provided, it overrides height
+
+ virtual Dimensions layout(Number? width, Number? height);
+ // returns { }
+ // the return value should include the final value for whichever of the width and height arguments that is null
+ // TODO(ianh): should we just grab the width and height from assumeDimensions()?
+
+ void markAsPainted(); // sets this.node.needsPaint to false
+ virtual void paint(RenderingSurface canvas);
+ // set a clip rect on the canvas for rect(0,0,this.width,this.height)
+ // call the painter of each property, in order they were registered, which on this element has a painter
+ // call this.paintChildren()
+ // unset the clip
+ // call markAsPainted()
+
+ virtual void paintChildren(RenderingSurface canvas);
+ // just calls paint() for each child returned by walkChildren() whose needsPaint is true,
+ // after transforming the coordinate space by translate(child.x,child.y)
+ // you should skip children that will be clipped out of yourself because they're outside your bounds
+
+ virtual Node hitTest(Float x, Float y);
+ // default implementation uses the node's children nodes' x, y,
+ // width, and height, skipping any that have width=0 or height=0, or
+ // whose ownerLayoutManager is not |this|
+ // default implementation walks the tree backwards from its built-in order
+ // if no child is hit, then return this.node
+ // override this if you changed your children's z-order, or if you used take() to
+ // hoist some descendants up to be your responsibility, or if your children aren't
+ // rectangular (e.g. you lay them out in a hex grid)
+ // make sure to offset the value you pass your children: child.layoutManager.hitTest(x-child.x, y-child.y)
- dictionary LayoutValueRange {
- // negative values here should be treated as zero
- Float minimum = 0;
- Float value = 0; // ideal desired width; if it's not in the range minimum .. maximum then it overrides minimum and maximum
- (Float or Infinity) maximum = Infinity;
- }
+}
- dictionary Dimensions {
- Float width = 0;
- Float height = 0;
- }
+dictionary LayoutValueRange {
+ // negative values here should be treated as zero
+ Float minimum = 0;
+ Float value = 0; // ideal desired width; if it's not in the range minimum .. maximum then it overrides minimum and maximum
+ (Float or Infinity) maximum = Infinity;
+}
+dictionary Dimensions {
+ Float width = 0;
+ Float height = 0;
+}
+```
Given a tree of StyleNode objects rooted at /node/, the application is
rendered as follows:
- node.layoutManager.layout(screen.width, screen.height);
- node.layoutManager.paint();
-
+```javascript
+node.layoutManager.layout(screen.width, screen.height);
+node.layoutManager.paint();
+```
Paint
-----
- callback void Painter (StyleNode node, RenderingSurface canvas);
+```javascript
+callback void Painter (StyleNode node, RenderingSurface canvas);
- class RenderingSurface {
- // ...
- }
+class RenderingSurface {
+ // ...
+}
+```
The convention is that the layout manager who calls your paint will
have transformed the coordinate space so that you should assume that
« no previous file with comments | « sky/examples/htmlish/framework/htmlish.sky ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698