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

Side by Side Diff: sky/specs/style.md

Issue 1142853006: [Specs] Remove all the obsolete specs. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 7 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 unified diff | Download patch
« no previous file with comments | « sky/specs/script.md ('k') | sky/specs/style2.md » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 Sky Style Language
2 ==================
3
4 THIS IS NOT UP TO DATE
5
6 DO NOT IMPLEMENT THIS YET
7
8 It has not been Dartified.
9
10 It has not been converted to have a sane element.style API.
11
12 It has not been converted to have layout be interruptible using Futures.
13
14
15 Planed changes
16 --------------
17
18 Add //-to-end-of-line comments to be consistent with the script
19 language.
20
21
22 Style Parser
23 ------------
24
25 (this section is incomplete)
26
27 ### Tokenisation
28
29
30 #### Value parser
31
32
33 ##### **Value** state
34
35 If the current character is...
36
37 * '``;``': Consume the character and exit the value parser
38 successfully.
39
40 * '``@``': Consume the character and switch to the **at**
41 state.
42
43 * '``#``': Consume the character and switch to the **hash**
44 state.
45
46 * '``$``': Consume the character and switch to the **dollar**
47 state.
48
49 * '``%``': Consume the character and switch to the **percent**
50 state.
51
52 * '``&``': Consume the character and switch to the **ampersand**
53 state.
54
55 * '``'``': Set _value_ to the empty string, consume the character, and
56 switch to the **single-quoted string** state.
57
58 * '``"``': Set _value_ to the empty string, consume the character, and
59 switch to the **double-quoted string** state.
60
61 * '``-``': Consume the character, and switch to the **negative
62 integer** state.
63
64 * '``0``'-'``9``': Set _value_ to the decimal value of the current
65 character, consume the character, and switch to the **integer**
66 state.
67
68 * '``a``'-'``z``', '``A``'-'``Z``': Set _value_ to the current
69 character, consume the character, and switch to the **identifier**
70 state.
71
72 * '``*``', '``^``', '``!``', '``?``', '``,``', '``/``', '``<``',
73 '``[``', '``)``', '``>``', '``]``', '``+``': Emit a symbol token
74 with the current character as the symbol, consume the character, and
75 stay in this state.
76
77 * Anything else: Consume the character and switch to the **error**
78 state.
79
80
81 ##### **At** state
82
83 * '``0``'-'``9``', '``a``'-'``z``', '``A``'-'``Z``': Set _value_ to
84 the current character, create a literal token with the unit set to
85 ``@``, consume the character, and switch to the **literal** state.
86
87 * Anything else: Emit a symbol token with ``@`` as the symbol, and
88 switch to the **value** state without consuming the character.
89
90
91 ##### **Hash** state
92
93 * '``0``'-'``9``', '``a``'-'``z``', '``A``'-'``Z``': Set _value_ to
94 the current character, create a literal token with the unit set to
95 ``@``, consume the character, and switch to the **literal** state.
96
97 * Anything else: Emit a symbol token with ``#`` as the symbol, and
98 switch to the **value** state without consuming the character.
99
100
101 ##### **Dollar** state
102
103 * '``0``'-'``9``', '``a``'-'``z``', '``A``'-'``Z``': Set _value_ to
104 the current character, create a literal token with the unit set to
105 ``@``, consume the character, and switch to the **literal** state.
106
107 * Anything else: Emit a symbol token with ``$`` as the symbol, and
108 switch to the **value** state without consuming the character.
109
110
111 ##### **Percent** state
112
113 * '``0``'-'``9``', '``a``'-'``z``', '``A``'-'``Z``': Set _value_ to
114 the current character, create a literal token with the unit set to
115 ``@``, consume the character, and switch to the **literal** state.
116
117 * Anything else: Emit a symbol token with ``%`` as the symbol, and
118 switch to the **value** state without consuming the character.
119
120
121 ##### **Ampersand** state
122
123 * '``0``'-'``9``', '``a``'-'``z``', '``A``'-'``Z``': Set _value_ to
124 the current character, create a literal token with the unit set to
125 ``@``, consume the character, and switch to the **literal** state.
126
127 * Anything else: Emit a symbol token with ``&`` as the symbol, and
128 switch to the **value** state without consuming the character.
129
130
131 ##### TODO(ianh): more states...
132
133
134 ##### **Error** state
135
136 If the current character is...
137
138 * '``;``': Consume the character and exit the value parser in failure.
139
140 * Anything else: Consume the character and stay in this state.
141
142
143
144 Selectors
145 ---------
146
147 Sky Style uses whatever SelectorQuery. Maybe one day we'll make
148 SelectorQuery support being extended to support arbitrary selectors,
149 but for now, it supports:
150
151 ```css
152 tagname
153 #id
154 .class
155 [attrname]
156 [attrname=value]
157 :host ("host" string is fixed)
158 ::pseudo-element
159 ```
160
161 These can be combined (without whitespace), with at most one tagname
162 (must be first) and at most one pseudo-element (must be last) as in:
163
164 ```css
165 tagname[attrname]#id:host.class.class[attrname=value]::foo
166 ```
167
168 In debug mode, giving two IDs, or the same selector twice (e.g. the
169 same classname), or specifying other redundant or conflicting
170 selectors (e.g. [foo][foo=bar], or [foo=bar][foo=baz]) will be
171 flagged.
172
173 Alternatively, a selector can be the special value "@root",
174 optionally followed by a pseudo-element, as in:
175
176 ```css
177 @root::bar
178 ```
179
180
181 Value Parser
182 ------------
183
184 ```javascript
185 class StyleToken {
186 constructor (String king, String value);
187 readonly attribute String kind;
188 // string
189 // identifier
190 // function (identifier + '(')
191 // number
192 // symbol (one of @#$%& if not immediately following numeric or preceding a lphanumeric, or one of *^!?,/<[)>]+ or, if not followed by a digit, -)
193 // dimension (number + identifier or number + one of @#$%&)
194 // literal (one of @#$%& + alphanumeric)
195 readonly attribute String value;
196 readonly attribute String unit; // for 'dimension' type, this is the punctuati on or identifier that follows the number, for 'literal' type, this is the punctu ation that precedes it
197 }
198
199 class TokenSource {
200 constructor (Array<StyleToken> tokens);
201 IteratorResult next();
202 TokenSourceBookmark getBookmark();
203 void rewind(TokenSourceBookmark bookmark);
204 }
205
206 class TokenSourceBookmark {
207 constructor ();
208 // TokenSource stores unforgeable state on this object using symbols or a weak map or some such
209 }
210
211 callback ParserCallback = AbstractStyleValue (TokenSource tokens); // return if successful, throw if not
212
213 class StyleGrammar {
214 constructor ();
215 void addParser(ParserCallback parser);
216 AbstractStyleValue parse(TokenSource tokens, Boolean root = false);
217 // for each parser callback that was registered, in reverse
218 // order (most recently registered first), run these steps:
219 // let bookmark = tokens.getBookmark();
220 // try {
221 // let result = parser(tokens);
222 // if (root) {
223 // if (!tokens.next().done)
224 // throw new Error();
225 // }
226 // } except {
227 // tokens.rewind(bookmark);
228 // }
229 // (root is set when you need to parse the entire token stream to be valid)
230 }
231
232 /*
233 StyleNode
234 |
235 +-- Property
236 |
237 +-- AbstractStyleValue
238 |
239 +-- NumericStyleValue
240 | |
241 | +-- AnimatableNumericStyleValue*
242 |
243 +-- LengthStyleValue
244 | |
245 | +-- AnimatableLengthStyleValue*
246 | |
247 | +-- TransitionLengthStyleValue*
248 | |
249 | +-- PixelLengthStyleValue
250 | |
251 | +-- EmLengthStyleValue*
252 | |
253 | +-- VHLengthStyleValue*
254 | |
255 | +-- CalcLengthStyleValue*
256 |
257 +-- ColorStyleValue
258 | |
259 | +-- RGBColorStyleValue
260 | |
261 | +-- AnimatableColorStyleValue*
262 |
263 +-- AbstractOpaqueStyleValue
264 | |
265 | +-- IdentifierStyleValue
266 | | |
267 | | +-- AnimatableIdentifierStyleValue*
268 | |
269 | +-- URLStyleValue*
270 | | |
271 | | +-- AnimatableURLStyleValue*
272 | |
273 | +-- StringStyleValue*
274 | | |
275 | | +-- AnimatableStringStyleValue*
276 | |
277 | +-- ObjectStyleValue
278 |
279 +-- PrimitiveValuesListStyleValue*
280 */
281 ```
282
283 The types marked with * in the list above are not part of dart:sky,
284 and are only shown here to illustrate what kinds of extensions are
285 possible and where they would fit.
286
287 TODO(ianh): consider removing 'StyleValue' from these class names
288
289 ```javascript
290 abstract class StyleNode {
291 abstract void markDirty();
292 }
293
294 dictionary StyleValueResolverSettingsSettings {
295 Boolean firstTime = false;
296 any state = null;
297 }
298
299 class StyleValueResolverSettings {
300 // this is used as an "out" parameter for 'resolve()' below
301 constructor(StyleValueResolverSettingsSettings initial);
302 void reset(StyleValueResolverSettingsSettings initial);
303 // sets firstTime and state to given values
304 // sets layoutDependent to false
305 // sets dependencies to empty set
306 // sets lifetime to Infinity
307
308 readonly attribute Boolean firstTime;
309 // true if this is the first time this property is being resolved for this e lement,
310 // or if the last time it was resolved, the value was a different object
311
312 // attribute Boolean layoutDependent
313 void setLayoutDependent();
314 // call this if the value should be recomputed each time the ownerLayoutMana ger's dimensions change, rather than being cached
315 Boolean getLayoutDependent();
316 // returns true if setLayoutDependent has been called since the last reset()
317
318 // attribute "BitField" dependencies; // defaults to no bits set
319 void dependsOn(PropertyHandle property);
320 // if the given property doesn't have a dependency bit assigned:
321 // - assign the next bit to the property
322 // - if there's no bits left, throw
323 // set the bit on this StyleValueResolverSettings's dependencies bitfield
324 Array<PropertyHandle> getDependencies();
325 // returns an array of the PropertyHandle values for the bits that are set i n dependencies
326
327 // attribute (Float or Infinity) lifetime;
328 void setLifetime(Float age);
329 // if the new value is less than the current value of lifetime, update the c urrent value
330 (Float or Infinity) getLifetime();
331 // return current value of lfietime
332
333 attribute any state; // initially null, can be set to store value for this Ren derNode/property pair
334 // for example, TransitioningColorStyleValue would store
335 // {
336 // initial: /* color at time of transition */,
337 // target: /* color at end of transition */,
338 // start: /* time at start of transition */,
339 // }
340 // ...which would enable it to update appropriately, and would also
341 // let other transitions that come later know that you were half-way
342 // through a transition so they can shorten their time accordingly
343 //
344 // best practices: if you're storing values on the state object,
345 // then remove the values once they are no longer needed. For
346 // example, when your transition ends, set the object to null.
347 //
348 // best practices: if you're a style value that contains multiple
349 // style values, then before you call their resolve you should
350 // replace the state with a state that is specific to them, and
351 // when you get it back you should insert that value into your
352 // state somehow. For example, in a resolve()r with two child
353 // style values a and b:
354 // let ourState;
355 // if (settings.firstTime)
356 // ourState = { a: null, b: null };
357 // else
358 // ourState = settings.state;
359 // settings.state = ourState.a;
360 // let aResult = a.resolve(node, settings);
361 // ourState.a = settings.state;
362 // settings.state = ourState.b;
363 // let aResult = b.resolve(node, settings);
364 // ourState.b = settings.state;
365 // settings.state = ourState;
366 // return a + b; // or whatever
367 //
368 // best practices: if you're a style value that contains multiple
369 // style values, and all those style values are storing null, then
370 // store null yourself, instead of storing many nulls of your own.
371
372 // attribute Boolean wasStateSet;
373 Boolean getShouldSaveState();
374 // returns true if state is not null, and either state was set
375 // since the last reset, or firstTime is false.
376
377 }
378
379 class Property : StyleNode {
380 constructor (AbstractStyleDeclaration parentNode, PropertyHandle property, Abs tractStyleValue? initialValue = null);
381 readonly attribute AbstractStyleDeclaration parentNode;
382 readonly attribute PropertyHandle property;
383 readonly attribute AbstractStyleValue value;
384
385 void setValue(AbstractStyleValue? newValue);
386 // updates value and calls markDirty()
387
388 void markDirty();
389 // call parentNode.markDirty(property);
390
391 abstract any resolve(RenderNode node, StyleValueResolverSettings? settings = n ull);
392 // if value is null, returns null
393 // otherwise, returns value.resolve(property, node, settings)
394 }
395
396 abstract class AbstractStyleValue : StyleNode {
397 abstract constructor(StyleNode? parentNode = null);
398 attribute StyleNode? parentNode;
399
400 void markDirty();
401 // call this.parentNode.markDirty()
402
403 abstract any resolve(PropertyHandle property, RenderNode node, StyleValueResol verSettings? settings = null);
404 }
405
406 abstract class LengthStyleValue : AbstractStyleValue {
407 abstract Float resolve(PropertyHandle property, RenderNode node, StyleValueRes olverSettings? settings = null);
408 }
409
410 class PixelLengthStyleValue : LengthStyleValue {
411 constructor(Float number, StyleNode? parentNode = null);
412 attribute Float value;
413 // on setting, calls markDirty();
414 Float resolve(PropertyHandle property, RenderNode node, StyleValueResolverSett ings? settings = null);
415 // return value
416 }
417
418 typedef RawColor Float; // TODO(ianh): figure out what Color should be
419 class ColorStyleValue : LengthStyleValue {
420 constructor(Float red, Float green, Float blue, Float alpha, StyleNode? parent Node = null);
421 // ... color API ...
422 RawColor resolve(PropertyHandle property, RenderNode node, StyleValueResolverS ettings? settings = null);
423 }
424
425 class AbstractOpaqueStyleValue : AbstractStyleValue {
426 abstract constructor(any value, StyleNode? parentNode = null);
427 attribute any value;
428 // on setting, calls markDirty();
429 any resolve(PropertyHandle property, RenderNode node, StyleValueResolverSettin gs? settings = null);
430 // returns value
431 }
432
433 class IdentifierStyleValue : AbstractOpaqueStyleValue {
434 constructor(String value, StyleNode? parentNode = null);
435 // calls superclass constructor
436 }
437
438 /*
439 class AnimatableIdentifierStyleValue : AbstractOpaqueStyleValue {
440 constructor(String value, String newValue, AnimationFunction player, StyleNode ? parentNode = null);
441 readonly attribute String newValue;
442 readonly attribute AnimationFunction player;
443 any resolve(PropertyHandle property, RenderNode node, StyleValueResolverSettin gs? settings = null);
444 }
445 */
446
447 class ObjectStyleValue : AbstractOpaqueStyleValue {
448 constructor(any value, StyleNode? parentNode = null);
449 // calls superclass constructor
450 }
451
452 dictionary PropertySettings {
453 String? name = null; // null if the property can't be set from a <style> block
454 StyleGrammar? grammar = null; // must be non-null if name is non-null; must be null otherwise
455 Boolean inherited = false;
456 any initialValue = null;
457 Boolean needsManager = false;
458 Boolean needsLayout = false;
459 Boolean needsPaint = false;
460 // PropertyHandle propertyHandle; // assigned by registerProperty
461 // Integer dependencyBit; // assigned by StyleValueResolverSettings.dependsOn( )
462 }
463 typedef PropertyHandle Integer;
464 PropertyHandle registerProperty(PropertySettings propertySettings);
465 // registers a property with the given settings, and returns an integer >= 0
466 // that can be used to refer to this property
467
468 // dart:sky exports a bunch of style grammars so that people can extend them
469 attribute StyleGrammar PositiveLengthOrInfinityStyleGrammar; // resolves to Leng thStyleValue
470 attribute StyleGrammar PositiveLengthOrAutoStyleGrammar; // resolves to LengthSt yleValue or IdentifierStyleValue (with value 'auto')
471 attribute StyleGrammar PositiveLengthStyleGrammar; // resolves to LengthStyleVal ue
472 attribute StyleGrammar NumberGrammar; // resolves to NumericStyleValue
473 attribute StyleGrammar ColorGrammar; // resolves to ColorStyleValue
474 attribute StyleGrammar DisplayStyleGrammar; // resolves to ObjectStyleValue
475 ```
476
477 Inline Styles
478 -------------
479
480 ```javascript
481 abstract class AbstractStyleDeclarationList {
482 void addStyles(StyleDeclaration styles, String pseudoElement = ''); // O(1)
483 void removeStyles(StyleDeclaration styles, String pseudoElement = ''); // O(N) in number of declarations
484 Array<StyleDeclaration> getDeclarations(String pseudoElement = ''); // O(N) in number of declarations
485 }
486
487 class ElementStyleDeclarationList : AbstractStyleDeclarationList {
488 constructor (Element? element);
489 readonly attribute Element? element;
490
491 // there are two batches of styles in an ElementStyleDeclarationList.
492
493 // the first batch is the per-frame styles; these get (conceptually)
494 // cleared each frame, after which all the matching rules in relevant
495 // <style> blocks get added back in, followed by all the animation-
496 // derived rules; scripts can also add styles themselves, but they are
497 // dropped after the next frame
498 void addFrameStyles(StyleDeclaration styles, String pseudoElement = ''); // O( 1)
499 void clearFrameStyles();
500
501 // the second batch is the persistent styles, which remain until removed;
502 // they are accessed via the AbstractStyleDeclarationList accessors
503
504 // as StyleDeclarations are added and removed, the ElementStyleDeclarationList
505 // calls register(element) and unregister(element) respectively on those
506 // StyleDeclaration objects, where element is the element that was passed
507 // to the constructor, if not null
508 // then, it calls element.renderNode.cascadedValueChanged
509 // for each property on the object
510
511 // the inherited getDeclarations() method returns all the frame
512 // styles followed by all the persistent styles, in insertion order
513 }
514
515 class RenderNodeStyleDeclarationList : AbstractStyleDeclarationList {
516 constructor (RenderNode? renderNode);
517 readonly attribute RenderNode? renderNode;
518
519 // as StyleDeclarations are added and removed, the RenderNodeStyleDeclarationL ist
520 // calls register(renderNode) and unregister(renderNode) respectively on those
521 // StyleDeclaration objects, where renderNode is the RenderNode that was passe d
522 // to the constructor, if not null
523 // then, it calls renderNode.cascadedValueChanged
524 // for each property on the object
525 }
526
527 class StyleDeclaration {
528 constructor ();
529
530 void markDirty(PropertyHandle property);
531 // this indicates that the cascaded value of the property thinks
532 // it will now have a different result (as opposed to the cascaded
533 // value itself having changed)
534 // invoke element.renderNode.cascadedValueDirty(property, pseudoElement); fo r each
535 // currently registered consumer element/pseudoElement pair
536
537 void register((Element or RenderNode) consumer, String pseudoElement = ''); // O(1)
538 void unregister((Element or RenderNode) consumer, String pseudoElement = ''); // O(N)
539 // registers an element/pseudoElement or renderNode/pseudoElement pair with
540 // this StyleDeclaration so that a property/value on the style declaration
541 // is marked dirty, the relevant render node is informed and can then update
542 // its property cache accordingly
543
544
545 getter AbstractStyleValue? (PropertyHandle property);
546 // looks up the Property object for /property/, and returns its value
547 // null if property is missing
548
549 setter void (PropertyHandle property, AbstractStyleValue value);
550 // verify that value.parentNode is null
551 // if there is no Property object for /property/, creates one
552 // else calls its update() method to change the value
553 // update value's parentNode
554 // invoke consumer.renderNode.cascadedValueChanged(property); for each
555 // currently registered consumer
556
557 void remove(PropertyHandle property);
558 // drops the Property object for /property/ from this StyleDeclaration objec t
559 // invoke consumer.renderNode.cascadedValueChanged(property); for each
560 // currently registered consumer
561 }
562 ```
563
564 Rule Matching
565 -------------
566
567 ```javascript
568 class Rule {
569 constructor ();
570 attribute SelectorQuery selector; // O(1)
571 attribute String pseudoElement; // O(1)
572 attribute StyleDeclaration styles; // O(1)
573 }
574 ```
575
576 Each frame, at some defined point relative to requestAnimationFrame(),
577 if a Rule has started applying, or a Rule stopped applying, to an
578 element, dart:sky calls thatElement.style.clearFrameStyles() and then,
579 for each Rule that now applies, calls
580 thatElement.style.addFrameStyles() with the relevant StyleDeclaration
581 and pseudoElement from each such Rule.
582
583
584 Update the render tree
585 ----------------------
586
587 Simultaneously walk the tree rooted at the application's element
588 tree's root node, taking into account shadow trees and child
589 distribution, and the tree rooted at that Root node's RenderNode.
590
591 If you come across a node that doesn't have an assigned RenderNode,
592 then create one, placing it in the appropriate place in the RenderTree
593 tree, after any nodes marked isGhost=true, with ownerLayoutManager
594 pointing to the parent RenderNode's layoutManager, if it has one, and,
595 if it has one and autoreap is false on that layout manager, mark the
596 new node "isNew". (This means that when a node is marked isNew, the
597 layout manager has already laid out at least one frame.)
598
599 For each element, if the node's needsManager is true, call
600 getLayoutManager() on the element, and if that's not null, and if the
601 returned class isn't the same class as the current layoutManager, if
602 any, construct the given class and assign it to the RenderNode's
603 layoutManager, then set all the child RenderNodes' ownerLayoutManager
604 to that object; if it returns null, and that node already has a
605 layoutManager, then set isGhost=true for that node and all its
606 children (without changing the layoutManager). Otherwise, if it
607 returned null and there's already no layoutManager, remove the node
608 from the tree. Then, in any case, clear the needsManager bit.
609
610 When an Element or Text node is to be removed from its parent, and it
611 has a renderNode, and that renderNode has an ownerLayoutManager with
612 autoreap=false, then before actually removing the node, the node's
613 renderNode should be marked isGhost=true, and all the
614 StyleDeclarations in the relevant ElementStyleDeclarationList should
615 be added to the RenderNode's overrideStyles for use later (creating a
616 RenderNodeStyleDeclarationList if necessary).
617
618 When an Element is to be removed from its parent, regardless of the
619 above, the node's renderNode attribute should be nulled out.
620
621 When a RenderNode is added with isNew=true, call its parent
622 RenderNode's LayoutManager's childAdded() callback. When a a
623 RenderNode has its isGhost property set to true, then call it's parent
624 RenderNode's LayoutManager's childRemoved() callback.
625
626
627 ```javascript
628 dictionary PropertySettings {
629 String? name = null; // null if the property can't be set from a <style> block
630 StyleGrammar? grammar = null; // must be non-null if name is non-null; must be null otherwise
631 Boolean inherited = false;
632 any initialValue = null;
633 Boolean needsManager = false;
634 Boolean needsLayout = false;
635 Boolean needsPaint = false;
636 // PropertyHandle propertyHandle; // assigned by registerProperty
637 // Integer dependencyBit; // assigned by StyleValueResolverSettings.dependsOn( )
638 }
639
640 dictionary GetPropertySettings {
641 String pseudoElement = '';
642 Boolean forceCache = false;
643 // if set to true, will return the cached value if any, or null otherwise
644 // this is used by transitions to figure out what to transition from
645 }
646
647 class RenderNode { // implemented in C++ with no virtual tables
648 // this is generated before layout
649 readonly attribute String text;
650 readonly attribute Node? parentNode;
651 readonly attribute Node? firstChild;
652 readonly attribute Node? nextSibling;
653
654 // internal state:
655 // - back pointer to backing Node, if we're not a ghost
656 // - cache of resolved property values, mapping as follows:
657 // - pseudoElement, property => StyleValue object, resolved value, StyleVal ueResolverSettings, cascade dirty bit, value dirty bit
658 // - property state map (initially empty), as follows:
659 // - pseudoElement, property => object
660
661 any getProperty(PropertyHandle property, GetPropertySettings? settings = null) ;
662 // looking at the cached data for the given pseudoElement:
663 // if there's a cached value:
664 // if settings.forceCache is true, return the cached value
665 // if neither dirty bit is set, return the cached value
666 // if the cascade dirty bit is not set (value dirty is set) then
667 // - clear any pending lifetime-enforcing tasks for this
668 // property/pseudoElement pair on this render node
669 // - resolve the value using the same StyleValue object
670 // - with firstTime=false on the resolver settings
671 // - with the cached state object if any
672 // - jump to "cache" below
673 // if settings.forceCache is true, return null
674 // - clear any pending lifetime-enforcing tasks for this
675 // property/pseudoElement pair on this render node
676 // - if there's an override declaration with the property (with
677 // the pseudo or without), then get the value object from there
678 // and jump to "resolve" below.
679 // - if there's an element and it has a style declaration with
680 // the property (with the pseudo or without), then get the
681 // value object from there and jump to "resolve" below.
682 // - if it's not an inherited property, or if there's no parent,
683 // then get the default value and jump to "resolve" below.
684 // - call the parent render node's getProperty() with the same
685 // property but no settings, then cache that value as the value
686 // for this element with the given pseudoElement, with no
687 // StyleValue object, no resolver settings, and set the state
688 // to null.
689 // resolve:
690 // - get a new resolver settings object (or reset an existing one)
691 // - if the obtained StyleValue object is different than the
692 // cached StyleValue object, or if there is no cached
693 // object, then set the resolver settings to
694 // firstTime=true, otherwise it's the same object and set
695 // firstTime=false.
696 // - set the resolver settings' state to the current state
697 // for this pseudoElement/property combination
698 // - using the obtained StyleValue object, call resolve(),
699 // passing it this node and the resolver settings object.
700 // - jump to "cache" below
701 // cache:
702 // - update the cache with the obtained value and resolver
703 // settings
704 // - reset the dirty bits
705 // - if the resolver settings' getShouldSaveState() method
706 // returns false, then discard any cached state, otherwise,
707 // cache the new state
708 // - if the resolver settings' lifetime is not infinity, then
709 // queue a lifetime-enforcing task for the appropriate time
710 // in the future which calls cascadedValueDirty for this
711 // property/pseudoElement pair on this render node
712
713 attribute RenderNodeStyleDeclarationList overrideStyles;
714 // mutable; initially null
715 // this is used when isGhost is true, and can also be used more generally t o
716 // override styles from the layout manager (e.g. to animate a new node into view)
717 // this is the only arbitrarily mutable state of a RenderNode object
718
719 private void cascadedValueChanged(PropertyHandle property, String pseudoElemen t = '');
720 private void cascadedValueDirty(PropertyHandle property, String pseudoElement = '');
721 // - set the appropriate dirty bit on the cached data for this property/pseu doElement pair
722 // - cascade dirty for cascadedValueChanged
723 // - value dirty for cascadedValueDirty
724 // - if the property is needsManager, set needsManager to true
725 // - if the property is needsLayout, set needsLayout to true and walk up the
726 // tree setting descendantNeedsLayout
727 // - if the property is needsPaint, add the node to the list of nodes that n eed painting
728 // - if the property has a dependencyBit defined, then check the cache of al l the
729 // properties on this RenderNode, and the cache for the property in all th e child
730 // nodes and, if pseudoElement is '', the pseudoElements of this node, and ,
731 // if any of them have the relevant dependency bit set, then call
732 // thatRenderNode.cascadedValueDirty(thatProperty, thatPseudoElement)
733 // - if the property is inherited, then for each child node, and, if pseudoE lement
734 // is '', the pseudoElements of this node, if the cached value for this pr operty
735 // is present but has no StyleValue, call thatNode.cascadedValueChanged(pr operty, thatPseudoElement)
736
737 readonly attribute Boolean needsManager;
738 // means that a property with needsManager:true has changed on this node
739
740 readonly attribute Boolean needsLayout;
741 // means that either needsManager is true or a property with needsLayout:tru e has changed on this node
742 // needsLayout is set to false by the ownerLayoutManager's default layout() method
743
744 readonly attribute Boolean descendantNeedsLayout;
745 // means that some child of this node has needsLayout set to true
746 // descendantNeedsLayout is set to false by the ownerLayoutManager's default layout() method
747
748 readonly attribute LayoutManager layoutManager;
749 readonly attribute LayoutManager ownerLayoutManager; // defaults to the parent Node.layoutManager
750 // if you are not the ownerLayoutManager, then ignore this RenderNode in lay out() and paintChildren()
751 // using walkChildren() does this for you
752
753 // only the ownerLayoutManager can change these
754 readonly attribute Float x; // relative to left edge of ownerLayoutManager
755 readonly attribute Float y; // relative to top edge of ownerLayoutManager
756 readonly attribute Float width;
757 readonly attribute Float height;
758 readonly attribute Boolean isNew; // node has just been added (and maybe you w ant to animate it in)
759 readonly attribute Boolean isGhost; // node has just been removed (and maybe y ou want to animate it away)
760 }
761 ```
762
763 The flattened tree is represented as a hierarchy of Node objects. For
764 any element that only contains text node children, the "text" property
765 is set accordingly. For elements with mixed text node and non-text
766 node children, each run of text nodes is represented as a separate
767 Node with the "text" property set accordingly and the styles set as if
768 the Node inherited everything inheritable from its parent.
769
770
771 Layout
772 ------
773
774 dart:sky registers 'display' as follows:
775
776 ```javascript
777 {
778 name: 'display',
779 grammar: sky.DisplayStyleGrammar,
780 inherited: false,
781 initialValue: sky.BlockLayoutManager,
782 needsManager: true,
783 }
784 ```
785
786 The following API is then used to add new layout manager types to 'display':
787
788 ```javascript
789 void registerLayoutManager(String displayValue, LayoutManagerConstructor? layout Manager);
790 ```
791
792 dart:sky by default registers:
793
794 - 'block': sky.BlockLayoutManager
795 - 'paragraph': sky.ParagraphLayoutManager
796 - 'inline': sky.InlineLayoutManager
797 - 'none': null
798
799
800 Layout managers inherit from the following API:
801
802 ```javascript
803 callback LayoutManagerConstructor LayoutManager (RenderNode node);
804
805 class LayoutManager : EventTarget {
806 readonly attribute RenderNode node;
807 constructor LayoutManager(RenderNode node);
808 // sets needsManager to false on the node
809
810 readonly attribute Boolean autoreap;
811 // defaults to true
812 // when true, children that are added don't get set to isNew=true
813 // when true, children that are removed don't get set to isGhost=true, they' re just removed
814
815 virtual Array<EventTarget> getEventDispatchChain(); // O(N) in number of this. node's ancestors // implements EventTarget.getEventDispatchChain()
816 // let result = [];
817 // let node = this.node;
818 // while (node && node.layoutManager) {
819 // result.push(node.layoutManager);
820 // node = node.parentNode;
821 // }
822 // return result;
823
824 void setProperty(RenderNode node, PropertyHandle property, any value, String p seudoElement = ''); // O(1)
825 // replaces the value that getProperty() would return on that node with /val ue/
826 // this also clears the dependency bits, dirty bits, and sets the property s tate to null
827 // this also clears any relevant lifetime-enforcing tasks
828
829 void take(RenderNode victim); // sets victim.ownerLayoutManager = this;
830 // assert: victim hasn't been take()n yet during this layout
831 // assert: an ancestor of victim has node.layoutManager == this (aka, victim is a descendant of this.node)
832
833 virtual void release(RenderNode victim);
834 // called when the RenderNode was removed from the tree
835
836 virtual void childAdded(RenderNode child);
837 virtual void childRemoved(RenderNode child);
838 // called when a child has its isNew or isGhost attributes set respectively
839
840 void setChildPosition(child, x, y); // sets child.x, child.y
841 void setChildX(child, y); // sets child.x
842 void setChildY(child, y); // sets child.y
843 void setChildSize(child, width, height); // sets child.width, child.height
844 void setChildWidth(child, width); // sets child.width
845 void setChildHeight(child, height); // sets child.height
846 // assert: child.ownerLayoutManager == this
847 // for setChildSize/Width/Height: if the new dimension is different than the last assumed dimensions, and
848 // any RenderNodes with an ownerLayoutManager==this have cached values for g etProperty() that are marked
849 // as layout-dependent, mark them as dirty with cascadedValueDirty()
850
851 void assumeDimensions(Float width, Float height);
852 // sets the assumed dimensions for calls to getProperty() on RenderNodes tha t have this as an ownerLayoutManager,
853 // by updating renderNode width/height;
854 // if the new dimension is different than the last assumed dimensions, and a ny RenderNodes with an
855 // ownerLayoutManager==this have cached values for getProperty() that are ma rked as layout-dependent, mark them
856 // as dirty with cascadedValueDirty()
857
858 virtual LayoutValueRange getIntrinsicWidth(Float? defaultWidth = null);
859 /*
860 function getIntrinsicWidth(defaultWidth) {
861 if (defaultWidth == null) {
862 defaultWidth = this.node.getProperty('width');
863 if (typeof defaultWidth != 'number')
864 defaultWidth = 0;
865 }
866 let minWidth = this.node.getProperty('min-width');
867 if (typeof minWidth != 'number')
868 minWidth = 0;
869 let maxWidth = this.node.getProperty('max-width');
870 if (typeof maxWidth != 'number')
871 maxWidth = Infinity;
872 if (maxWidth < minWidth)
873 maxWidth = minWidth;
874 if (defaultWidth > maxWidth)
875 defaultWidth = maxWidth;
876 if (defaultWidth < minWidth)
877 defaultWidth = minWidth;
878 return {
879 minimum: minWidth,
880 value: defaultWidth,
881 maximum: maxWidth,
882 };
883 }
884 */
885
886 virtual LayoutValueRange getIntrinsicHeight(Float? defaultHeight = null);
887 /*
888 function getIntrinsicHeight(defaultHeight) {
889 if (defaultHeight == null) {
890 defaultHeight = this.node.getProperty('height');
891 if (typeof defaultHeight != 'number')
892 defaultHeight = 0;
893 }
894 let minHeight = this.node.getProperty('min-height');
895 if (typeof minHeight != 'number')
896 minHeight = 0;
897 let maxHeight = this.node.getProperty('max-height');
898 if (typeof maxHeight != 'number')
899 maxHeight = Infinity;
900 if (maxHeight < minHeight)
901 maxHeight = minHeight;
902 if (defaultHeight > maxHeight)
903 defaultHeight = maxHeight;
904 if (defaultHeight < minHeight)
905 defaultHeight = minHeight;
906 return {
907 minimum: minHeight,
908 value: defaultHeight,
909 maximum: maxHeight,
910 };
911 }
912 */
913
914 void welcomeChild(child);
915 // assert: this == child.ownerLayoutManager
916 // assert: child.isNew is true
917 // resets child.isNew
918 void reapChild(child);
919 // assert: this == child.ownerLayoutManager
920 // assert: child.isGhost is true
921 // removes the RenderNode from its parent if isGhost is true
922
923 Generator<RenderNode> walkChildren();
924 // returns a generator that iterates over the children, skipping any whose o wnerLayoutManager is not |this|
925
926 Generator<RenderNode> walkChildrenBackwards();
927 // returns a generator that iterates over the children backwards, skipping a ny whose ownerLayoutManager is not |this|
928
929 void markAsLaidOut(); // sets this.node.needsLayout and this.node.descendantNe edsLayout to false
930 virtual Dimensions layout(Float? width, Float? height);
931 // if width is null, set width to getIntrinsicWidth().value
932 // if height is null, set height to getIntrinsicHeight().value
933 // call this.assumeDimensions(width, height);
934 // call this.layoutChildren(width, height);
935 // call markAsLaidOut();
936 // return { width: width, height: height }
937 // - this should always call this.markAsLaidOut() to reset
938 // needsLayout and descendantNeedsLayout
939 // - the return value should include the final value for whichever
940 // of the width and height arguments that is null
941 // - subclasses that want to make 'auto' values dependent on the
942 // children should override this entirely, rather than
943 // overriding layoutChildren; but see layoutChildren()'s notes
944 // for how to do this
945
946 virtual void layoutChildren(Float width, Float height);
947 // default implementation does nothing
948 // - override only this (and not layout()) if you want to lay out
949 // children but not have the children affect your dimensions
950 // - always call setChildSize() and setChildPosition() after
951 // calling a child's layout() method
952 // - if the child has needsLayout or if you need to have it
953 // autosize, call its ownerLayoutManager's layout() method
954 // - otherwise if the child has needs descendantNeedsLayout, call
955 // layoutDescendants()
956
957 virtual Dimensions layoutDescendants();
958 // assert: node.needsLayout is false, node.descendantNeedsLayout is true
959 // walk children:
960 // - if it has needsLayout, call its layout() method with its
961 // current width and height, then call setChildSize() with
962 // those same dimensions
963 // - else, if it has descendantNeedsLayout, call its
964 // layoutDescendants() method
965 // call markAsLaidOut();
966 // - override this if you use take() to control more children, in
967 // which case you should call their methods too
968 // - this should always call this.markAsLaidOut() to reset
969 // needsLayout and descendantNeedsLayout
970
971 virtual void paint(RenderingSurface canvas);
972 // set a clip rect on the canvas for rect(0,0,this.width,this.height)
973 // (? we don't really have to do this; consider shadows...)
974 // call this.paintChildren(canvas)
975 // (the default implementation doesn't paint anything on top of the children )
976 // unset the clip
977 // - this gets called by the system if:
978 // - you are in your parent's current display list and it's in its parent 's and so on up to the top, and
979 // - you haven't had paint() called since the last time you were dirtied
980 // - the following things make you dirty:
981 // - dimensions of your RenderNode changed
982 // - one of your properties with needsLayout or needsPaint changed
983
984 virtual void paintChildren(RenderingSurface canvas);
985 // for each child returned by walkChildren():
986 // if child bounds intersects our bounds:
987 // call canvas.paintChild(child);
988 // - you should skip children that will be clipped out of yourself because t hey're outside your bounds
989 // - if you transform the canvas, you'll have to implement your own version of paintChildren() so
990 // that you don't skip the children that are visible in the new coordinate space but wouldn't be
991 // without the transform
992
993 virtual RenderNode hitTest(Float x, Float y);
994 // default implementation uses the node's children nodes' x, y,
995 // width, and height, skipping any that have width=0 or height=0, or
996 // whose ownerLayoutManager is not |this|
997 // default implementation walks the tree backwards from its built-in order
998 // if no child is hit, then return this.node
999 // override this if you changed your children's z-order, or if you used take () to
1000 // hoist some descendants up to be your responsibility, or if your children aren't
1001 // rectangular (e.g. you lay them out in a hex grid)
1002 // make sure to offset the value you pass your children: child.layoutManager .hitTest(x-child.x, y-child.y)
1003 }
1004
1005 dictionary LayoutValueRange {
1006 // negative values here should be treated as zero
1007 Float minimum = 0;
1008 Float value = 0; // ideal desired width; if it's not in the range minimum .. m aximum then it overrides minimum and maximum
1009 (Float or Infinity) maximum = Infinity;
1010 }
1011
1012 dictionary Dimensions {
1013 Float width = 0;
1014 Float height = 0;
1015 }
1016 ```
1017
1018
1019 Paint
1020 -----
1021
1022 Sky has a list of RenderNodes that need painting. When a RenderNode is
1023 created, it's added to this list. (See also needsPaint for another
1024 time it is added to the list.)
1025
1026 ```javascript
1027 callback void Painter (RenderNode node, RenderingSurface canvas);
1028
1029 class RenderingSurface {
1030
1031 // ... (API similar to <canvas>'s 2D API)
1032
1033 void paintChild(RenderNode node);
1034 // inserts a "paint this child" instruction in this canvas's display list.
1035 // the child's display list, transformed by the child's x and y coordinates, will be inserted into this
1036 // display list during painting.
1037 }
1038 ```
1039
1040
1041 The default framework provides global hooks for extending the painting of:
1042
1043 - borders
1044 - backgrounds
1045
1046 These are called during the default framework's layout managers'
1047 paint() functions. They are also made available so that other people
1048 can call them from their paint() functions.
1049
1050
1051
1052 Default Styles
1053 --------------
1054
1055 In the constructors for the default elements, they add to themselves
1056 StyleDeclaration objects as follows:
1057
1058 * ``span``
1059 * ``a``
1060 These all add to themselves the same declaration as follows:
1061 ```javascript
1062 let d = new StyleDeclaration();
1063 d[pDisplay] = new ObjectStyleValue(InlineLayoutManager);
1064 this.style.addStyles(d);
1065 ```
1066
1067 * ``t``
1068 This adds to itself the declaration as follows:
1069 ```javascript
1070 let d = new StyleDeclaration();
1071 d[pDisplay] = new ObjectStyleValue(ParagraphLayoutManager);
1072 this.style.addStyles(d);
1073 ```
1074
1075 The other elements don't have any default styles.
1076
1077 These declarations are all shared between all the elements (so e.g. if
1078 you reach in and change the declaration that was added to a ``span``
1079 element, you're going to change the styles of all the other
1080 default-hidden elements). (In other words, in the code snippets above,
1081 the ``d`` variable is initialised in shared code, and only the
1082 addStyles() call is per-element.)
OLDNEW
« no previous file with comments | « sky/specs/script.md ('k') | sky/specs/style2.md » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698