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

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

Issue 810173002: Specs: Revamp how styling works to make it possible (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 6 years 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/apis.md ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 Sky Style Language 1 Sky Style Language
2 ================== 2 ==================
3 3
4 Planed changes 4 Planed changes
5 -------------- 5 --------------
6 6
7 Add //-to-end-of-line comments to be consistent with the script 7 Add //-to-end-of-line comments to be consistent with the script
8 language. 8 language.
9 9
10 10
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 readonly attribute String value; 184 readonly attribute String value;
185 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 185 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
186 } 186 }
187 187
188 class TokenSource { 188 class TokenSource {
189 constructor (Array<StyleToken> tokens); 189 constructor (Array<StyleToken> tokens);
190 IteratorResult next(); 190 IteratorResult next();
191 TokenSourceBookmark getBookmark(); 191 TokenSourceBookmark getBookmark();
192 void rewind(TokenSourceBookmark bookmark); 192 void rewind(TokenSourceBookmark bookmark);
193 } 193 }
194
194 class TokenSourceBookmark { 195 class TokenSourceBookmark {
195 constructor (); 196 constructor ();
196 // TokenSource stores unforgeable state on this object using symbols or a weak map or some such 197 // TokenSource stores unforgeable state on this object using symbols or a weak map or some such
197 } 198 }
198 199
199 // TODO(ianh): this is a non-starter, we need something better to handle units a nd custom painting 200 callback ParserCallback = AbstractStyleValue (TokenSource tokens); // return if successful, throw if not
200 dictionary ParsedValue {
201 any value = null;
202 ValueResolver? resolver = null;
203 Boolean relativeDimension = false; // if true, e.g. for % lengths, the callbac k will be called again if an ancestor's dimensions change
204 Painter? painter = null;
205 }
206 201
207 // best practice convention: if you're creating a property with needsPaint, you should 202 class StyleGrammar {
208 // create a new style value type for it so that it can set the paint callback ri ght;
209 // you should never use such a style type when parsing another property
210
211 callback any ParserCallback (TokenSource tokens);
212
213 class StyleValueType {
214 constructor (); 203 constructor ();
215 void addParser(ParserCallback parser); 204 void addParser(ParserCallback parser);
216 any parse(TokenSource tokens, Boolean root = false); 205 AbstractStyleValue parse(TokenSource tokens, Boolean root = false);
217 // for each parser callback that was registered, in reverse 206 // for each parser callback that was registered, in reverse
218 // order (most recently registered first), run these steps: 207 // order (most recently registered first), run these steps:
219 // let bookmark = tokens.getBookmark(); 208 // let bookmark = tokens.getBookmark();
220 // try { 209 // try {
221 // let result = parser(tokens); 210 // let result = parser(tokens);
222 // if (root) { 211 // if (root) {
223 // if (!tokens.next().done) 212 // if (!tokens.next().done)
224 // throw new Error(); 213 // throw new Error();
225 // } 214 // }
226 // } except { 215 // } except {
227 // tokens.rewind(bookmark); 216 // tokens.rewind(bookmark);
228 // } 217 // }
229 // (root is set when you need to parse the entire token stream to be valid) 218 // (root is set when you need to parse the entire token stream to be valid)
230 } 219 }
231 220
232 // note: if you define a style value type that uses other style value types, e.g . a "length pair" that accepts two lengths, then 221 /*
233 // if any of the subtypes have a resolver, you need to make sure you have a reso lver that calls them to compute the final value 222 StyleNode
223 |
224 +-- Property
225 |
226 +-- AbstractStyleValue
227 |
228 +-- NumericStyleValue
229 | |
230 | +-- AnimatableNumericStyleValue
231 |
232 +-- LengthStyleValue
233 | |
234 | +-- AnimatableLengthStyleValue
235 | |
236 | +-- PixelLengthStyleValue
237 | |
238 | +-- EmLengthStyleValue
239 | |
240 | +-- VHLengthStyleValue
241 | |
242 | +-- CalcLengthStyleValue
243 |
244 +-- ColorStyleValue
245 | |
246 | +-- RGBColorStyleValue
247 | |
248 | +-- AnimatableColorStyleValue
249 |
250 +-- AbstractStringStyleValue
251 | |
252 | +-- IdentifierStyleValue
253 | | |
254 | | +-- AnimatableIdentifierStyleValue
255 | |
256 | +-- URLStyleValue
257 | | |
258 | | +-- AnimatableURLStyleValue
259 | |
260 | +-- StringStyleValue
261 | |
262 | +-- AnimatableStringStyleValue
263 |
264 +-- PrimitiveValuesListStyleValue
265 */
266
267 abstract class StyleNode {
268 abstract void markDirty();
269 }
270
271 class StyleValueResolverSettings {
272 // this is used as an "out" parameter for 'resolve()' below
273 constructor();
274 void reset(); // resets values to defaults so that object can be reused
275 attribute Boolean layoutDependent; // default to false
276 // set this if the value should be recomputed each time the ownerLayoutManag er's dimensions change, rather than being precomputed
277
278 // attribute "BitField" dependencies; // defaults to no bits set
279 void dependsOn(PropertyHandle property);
280 // if the given property doesn't have a dependency bit assigned:
281 // - assign the next bit to the property
282 // - if there's no bits left, throw
283 // set the bit on this StyleValueResolverSettings's dependencies bitfield
284 }
285
286 class Property : StyleNode {
287 constructor (StyleDeclaration parentNode, PropertyHandle property, AbstractSty leValue? initialValue = null);
288 readonly attribute StyleDeclaration parentNode;
289 readonly attribute PropertyHandle property;
290 readonly attribute AbstractStyleValue value;
291
292 void setValue(AbstractStyleValue? newValue);
293 // updates value and calls markDirty()
294
295 void markDirty();
296 // call parentNode.markDirty(property);
297
298 abstract any resolve(RenderNode node, StyleValueResolverSettings? settings = n ull);
299 // if value is null, returns null
300 // otherwise, returns value.resolve(property, node, settings)
301 }
302
303 abstract class AbstractStyleValue : StyleNode {
304 abstract constructor(StyleNode parentNode);
305 readonly attribute StyleNode parentNode;
306
307 void markDirty();
308 // call this.parentNode.markDirty()
309
310 abstract any resolve(PropertyHandle property, RenderNode node, StyleValueResol verSettings? settings = null);
311 }
312
313 abstract class LengthStyleValue : AbstractStyleValue {
314 abstract Float resolve(PropertyHandle property, RenderNode node, StyleValueRes olverSettings? settings = null);
315 }
316
317 class PixelLengthStyleValue : LengthStyleValue {
318 Float resolve(PropertyHandle property, RenderNode node, StyleValueResolverSett ings? settings = null);
319 }
320
321 // ...
234 322
235 dictionary PropertySettings { 323 dictionary PropertySettings {
236 String name; 324 String name;
237 StyleValueType type; // the output from the parser is coerced to a ParsedValue 325 StyleGrammar grammar;
238 Boolean inherits = false; 326 Boolean inherited = false;
239 any initialValue = null; 327 any initialValue = null;
328 Boolean needsManager = false;
240 Boolean needsLayout = false; 329 Boolean needsLayout = false;
241 Boolean needsPaint = false; 330 Boolean needsPaint = false;
331 // PropertyHandle propertyHandle; // assigned by registerProperty
332 // Integer dependencyBit; // assigned by StyleValueResolverSettings.dependsOn( )
242 } 333 }
334 typedef PropertyHandle Integer;
335 PropertyHandle registerProperty(PropertySettings propertySettings);
243 336
244 void registerProperty(PropertySettings propertySettings); 337 // sky:core exports a bunch of style grammars so that people can extend them
245 // when you register a new property, document the format that is expected to b e cascaded 338 attribute StyleGrammar PositiveLengthOrInfinityStyleGrammar; // resolves to Floa t
246 // (the output from the propertySettings.type parser's ParsedValue.value field after the resolver, if any, has been called) 339 attribute StyleGrammar PositiveLengthOrAutoStyleGrammar; // resolves to Float or null
247 340 attribute StyleGrammar PositiveLengthStyleGrammar; // resolves to Float
248 // sky:core exports a bunch of style value types so that people can 341 attribute StyleGrammar NumberGrammar; // resolves to Float
249 // extend them 342 attribute StyleGrammar ColorGrammar; // resolves to object with 'red', 'green', 'blue', and 'alpha' properties each of which is a Float 0..1
250 attribute StyleValueType PositiveLengthOrInfinityStyleValueType; 343 attribute StyleGrammar DisplayStyleGrammar; // resolves to null or LayoutManager constructor
251 attribute StyleValueType PositiveLengthOrAutoStyleValueType;
252 attribute StyleValueType PositiveLengthStyleValueType;
253 attribute StyleValueType DisplayStyleValueType;
254 ``` 344 ```
255 345
256 Inline Styles 346 Inline Styles
257 ------------- 347 -------------
258 348
259 ```javascript 349 ```javascript
260 partial class Element {
261 readonly attribute StyleDeclarationList style;
262 }
263
264 class StyleDeclarationList { 350 class StyleDeclarationList {
265 constructor (); 351 constructor (Element? element);
266 352
267 // There are two batches of styles in a StyleDeclarationList. 353 // There are two batches of styles in a StyleDeclarationList.
268 354
269 // The first batch is the per-frame styles. These get cleared each 355 // The first batch is the per-frame styles. These get cleared each
270 // frame, after which all the matching rules in relevant <style> blocks 356 // frame, after which all the matching rules in relevant <style> blocks
271 // get added back in, followed by all the animation-derived rules. 357 // get added back in, followed by all the animation-derived rules.
272 // Scripts can add styles themselves. 358 // Scripts can add styles themselves.
273 void addFrameStyles(StyleDeclaration styles, String? pseudoElement = null); // O(1) 359 void addFrameStyles(StyleDeclaration styles, String? pseudoElement = null); // O(1)
274 void clearFrameStyles(); 360 void clearFrameStyles();
275 361
276 // The second batch is the persistent styles. 362 // The second batch is the persistent styles.
277 // Once added, they remain forever until removed. 363 // Once added, they remain forever until removed.
278 void addPersistentStyles(StyleDeclaration styles, String? pseudoElement = null ); // O(1) 364 void addPersistentStyles(StyleDeclaration styles, String? pseudoElement = null ); // O(1)
279 void removePersistentStyles(StyleDeclaration styles, String? pseudoElement = n ull); // O(N) in number of declarations 365 void removePersistentStyles(StyleDeclaration styles, String? pseudoElement = n ull); // O(N) in number of declarations
280 366
367 // as StyleDeclaration are added and removed here, the StyleDeclarationList ca lls register(element) and
368 // unregister(element) respectively on those StyleDeclaration objects, where e lement is the element that
369 // was passed to the constructor, if not null
370 // then, it calls element.renderNode.cascadedValueAdded/cascadedValueRemoved f or each property on the object
371
281 // This returns all the frame styles followed by all the persistent styles, in insertion order. 372 // This returns all the frame styles followed by all the persistent styles, in insertion order.
282 Array<StyleDeclaration> getDeclarations(String? pseudoElement = null); // O(N) in number of declarations 373 Array<StyleDeclaration> getDeclarations(String? pseudoElement = null); // O(N) in number of declarations
283 } 374 }
284 375
285 class StyleDeclaration { 376 class StyleDeclaration {
286 // TODO(ianh): define this 377 void markDirty(PropertyHandle property);
378 // this indicates that the cascaded value of the property thinks
379 // it will now have a different result (as opposed to the cascaded
380 // value itself having changed)
381 // invoke element.renderNode.cascadedValueDirty(property, pseudoElement); fo r each
382 // currently registered consumer element/pseudoElement pair
383
384 void register(Element element, String? pseudoElement = null); // O(1)
385 void unregister(Element element, String? pseudoElement = null); // O(N)
386 // registers an element/pseudoElement pair with this StyleDeclaration so tha t when
387 // a property/value on the style declaration is marked dirty, the element
388 // is informed and can then clear its property cache
389
390 getter AbstractStyleValue? (PropertyHandle property);
391 // looks up the Property object for /property/, and returns its value
392 // null if property is missing
393
394 setter void (PropertyHandle property, AbstractStyleValue value);
395 // if there is no Property object for /property/, creates one
396 // else calls its update() method to change the value
397 // if the value changed:
398 // invoke consumer.renderNode.cascadedValueChanged(property); for each
399 // currently registered consumer
400 // if the value is new:
401 // invoke consumer.renderNode.cascadedValueAdded(property); for each
402 // currently registered consumer
403
404 void remove(PropertyHandle property);
405 // drops the Property object for /property/ from this StyleDeclaration objec t
406 // invoke consumer.renderNode.cascadedValueRemoved(property); for each
407 // currently registered consumer
287 } 408 }
288 ``` 409 ```
289 410
290 Rule Matching 411 Rule Matching
291 ------------- 412 -------------
292 413
293 ```javascript 414 ```javascript
294 partial class StyleElement {
295 Array<Rule> getRules(); // O(N) in rules
296 }
297
298 class Rule { 415 class Rule {
299 constructor (); 416 constructor ();
300 attribute SelectorQuery selector; // O(1) 417 attribute SelectorQuery selector; // O(1)
301 attribute String? pseudoElement; // O(1) 418 attribute String? pseudoElement; // O(1)
302 attribute StyleDeclaration styles; // O(1) 419 attribute StyleDeclaration styles; // O(1)
303 } 420 }
304 ``` 421 ```
305 422
306 Each frame, at some defined point relative to requestAnimationFrame(): 423 Each frame, at some defined point relative to requestAnimationFrame():
307 - If a rule starts applying to an element, sky:core calls thatElement.style.add (rule.styles, rule.pseudoElement); 424 - If a rule starts applying to an element, sky:core calls thatElement.style.add (rule.styles, rule.pseudoElement);
308 - If a rule stops applying to an element, sky:core calls thatElement.style.remo ve(rule.styles, rule.pseudoElement); 425 - If a rule stops applying to an element, sky:core calls thatElement.style.remo ve(rule.styles, rule.pseudoElement);
309 426
310 TODO(ianh): fix the above so that rule order is maintained 427 TODO(ianh): fix the above so that rule order is maintained
311 428
312 429
313 Cascade 430 Cascade
314 ------- 431 -------
315 432
316 For each Element, the StyleDeclarationList is conceptually flattened 433 Simultaneously walk the tree rooted at the application Document,
317 so that only the last declaration mentioning a property is left. 434 taking into account shadow trees and child distribution, and the tree
435 rooted at the document's RenderNode.
318 436
319 Create the flattened render tree as a tree of StyleNode objects 437 If you come across a node that doesn't have an assigned RenderNode,
320 (described below). For each one, run the equivalent of the following 438 then create one and mark it "isNew", and place it in the appropriate
321 code: 439 place in the RenderTree tree, after any nodes marked isGhost.
440
441 For each element, if the node's needsManager is true, call
442 getLayoutManager() on the element, and if that's not null, and if the
443 returned class isn't the same class as the current layoutManager, if
444 any, construct the given class and assign it to the RenderNode's
445 layoutManager, then set all the child RenderNodes' ownerLayoutManager
446 to that object; if it returns null, and that node already has a
447 layoutManager, then set isGhost=true for that node and all its
448 children (without changing the layoutManager). Otherwise, if it
449 returned null and there's already no layoutManager, remove the node
450 from the tree. Then, in any case, clear the needsManager bit.
451
452 When an Element or Text node is to be removed from its parent, and it
453 has a renderNode, and that renderNode has an ownerLayoutManager with
454 autoreap=false, then before actually removing the node, the node's
455 renderNode should be marked isGhost=true, and the relevant
456 StyleDeclarationList should be flattened and the values stored on the
457 RenderNode for use later.
458
459 When an Element is to be removed from its parent, regardless of the
460 above, the node's renderNode attribute should be nulled out.
461
322 462
323 ```javascript 463 ```javascript
324 var display = node.getProperty('display'); 464 callback any ValueResolver (any value, String propertyName, RenderNode node, Flo at containerWidth, Float containerHeight);
325 if (display) {
326 node.layoutManager = new display(node, ownerManager);
327 return true;
328 }
329 return false;
330 ```
331 465
332 If that code returns false, then that node an all its descendants must 466 class RenderNode { // implemented in C++ with no virtual tables
333 be dropped from the render tree.
334
335 If any node is removed in this pass relative to the previous pass, and
336 it has an ownerLayoutManager, then call
337
338 ```javascript
339 node.ownerLayoutManager.release(node)
340 ```
341
342 ...to notify the layout manager that the node went away, then set the
343 node's ownerLayoutManager attribute to null.
344
345 ```javascript
346 partial class Element {
347 readonly attribute StyleNode? layout; // TODO(ianh): come up with a better nam e (sadly "style" is taken)
348 // this will be null until the first time it is rendered
349 }
350
351 callback any ValueResolver (any value, String propertyName, StyleNode node, Floa t containerWidth, Float containerHeight);
352
353 class StyleNode { // implemented in C++ with no virtual tables
354 // this is generated before layout 467 // this is generated before layout
355 readonly attribute String text; 468 readonly attribute String text;
356 readonly attribute Node? parentNode; 469 readonly attribute Node? parentNode;
357 readonly attribute Node? firstChild; 470 readonly attribute Node? firstChild;
358 readonly attribute Node? nextSibling; 471 readonly attribute Node? nextSibling;
359 472
360 // access to the results of the cascade 473 any getProperty(PropertyHandle property, String? pseudoElement = null);
361 // only works during layout and painting 474 // looking at the cached data for the given pseudoElement:
362 any getProperty(String name, String? pseudoElement = null);
363 // throw if this isn't during layout or painting
364 // TODO(ianh): if the implementation of this does allow it to be queried the rest of the time too, relax this constraint
365 // looking at the declarations for the given pseudoElement:
366 // if there's a cached value, return it 475 // if there's a cached value, return it
367 // otherwise, if there's an applicable ParsedValue, then 476 // otherwise, figure out which StyleValue we're going to be using, in this order:
368 // if it has a resolver: 477 // - if we're isGhost, look out our cached declarations
369 // call it 478 // - look at this element's StyleDeclarations for the given pseudo-elemen t (if any)
370 // cache the value 479 // - look at this element's StyleDeclarations with no pseudo-element
371 // if relativeDimension is true, then mark the value as provisional 480 // - if it's an inherited property and there's a parent
372 // return the value 481 // - call getProperty() on the parent
373 // otherwise use the ParsedValue's value; cache it; return it 482 // otherwise use the default value
374 // otherwise, if a pseudo-element was specified, try again without one 483 // resolve the StyleValue giving it the property and node in question
375 // otherwise, if the property is inherited and there's a parent: 484 // cache the value, along with the StyleValueResolverSettings
376 // get it from the parent (without pseudo); cache it; return it 485
377 // otherwise, get the default value; cache it; return it 486 private void cascadedValueAdded(PropertyHandle property, String? pseudoElement = null);
487 private void cascadedValueRemoved(PropertyHandle property, String? pseudoEleme nt = null);
488 private void cascadedValueChanged(PropertyHandle property, String? pseudoEleme nt = null);
489 private void cascadedValueDirty(PropertyHandle property, String? pseudoElement = null);
490 // - clear the cached data for this property/pseudoElement pair
491 // - if the property is needsManager, set needsManager to true
492 // - if the property is needsLayout, set needsLayout to true and walk
493 // up the tree setting descendantNeedsLayout
494 // - if the property is needsPaint, add the node to the list of nodes that n eed painting
495 // - if the property has a dependencyBit defined, then check the cache of al l the
496 // properties on this RenderNode, and the cache for the property in all th e child
497 // nodes and (if pseudoElement is null) or the pseudoElements
498 // and if any of them have the relevant dependency bit set then call
499 // thatRenderNode.cascadedValueDirty(thatProperty, thatPseudoElement)
500 // - if the property is inherited:
501 // - call this.cascadedValueDirty(property, eachPseudoElement)
502 // - call eachChildRenderNode.cascadedValueDirty(property, null)
503
504 readonly attribute Boolean needsManager;
505 // means that a property with needsManager:true has changed on this node
378 506
379 readonly attribute Boolean needsLayout; 507 readonly attribute Boolean needsLayout;
380 // means that either needsLayout is true or a property with needsLayout:true has changed on this node 508 // means that either needsManager is true or a property with needsLayout:tru e has changed on this node
381 // needsLayout is set to false by the ownerLayoutManager's default layout() method 509 // needsLayout is set to false by the ownerLayoutManager's default layout() method
382 510
383 readonly attribute Boolean descendantNeedsLayout; 511 readonly attribute Boolean descendantNeedsLayout;
384 // means that some child of this node has needsLayout set to true 512 // means that some child of this node has needsLayout set to true
385 // descendantNeedsLayout is set to false by the ownerLayoutManager's default layout() method 513 // descendantNeedsLayout is set to false by the ownerLayoutManager's default layout() method
386 514
387 readonly attribute LayoutManager layoutManager; 515 readonly attribute LayoutManager layoutManager;
388 readonly attribute LayoutManager ownerLayoutManager; // defaults to the parent Node.layoutManager 516 readonly attribute LayoutManager ownerLayoutManager; // defaults to the parent Node.layoutManager
389 // if you are not the ownerLayoutManager, then ignore this StyleNode in layo ut() and paintChildren() 517 // if you are not the ownerLayoutManager, then ignore this RenderNode in lay out() and paintChildren()
390 // using walkChildren() does this for you 518 // using walkChildren() does this for you
391 519
392 // only the ownerLayoutManager can change these 520 // only the ownerLayoutManager can change these
393 readonly attribute Float x; // relative to left edge of ownerLayoutManager 521 readonly attribute Float x; // relative to left edge of ownerLayoutManager
394 readonly attribute Float y; // relative to top edge of ownerLayoutManager 522 readonly attribute Float y; // relative to top edge of ownerLayoutManager
395 readonly attribute Float width; 523 readonly attribute Float width;
396 readonly attribute Float height; 524 readonly attribute Float height;
397 readonly attribute Boolean isNew; // node has just been added (and maybe you w ant to animate it in) 525 readonly attribute Boolean isNew; // node has just been added (and maybe you w ant to animate it in)
398 readonly attribute Boolean isGhost; // node has just been removed (and maybe y ou want to animate it away) 526 readonly attribute Boolean isGhost; // node has just been removed (and maybe y ou want to animate it away)
399 } 527 }
400 ``` 528 ```
401 529
402 The flattened tree is represented as a hierarchy of Node objects. For 530 The flattened tree is represented as a hierarchy of Node objects. For
403 any element that only contains text node children, the "text" property 531 any element that only contains text node children, the "text" property
404 is set accordingly. For elements with mixed text node and non-text 532 is set accordingly. For elements with mixed text node and non-text
405 node children, each run of text nodes is represented as a separate 533 node children, each run of text nodes is represented as a separate
406 Node with the "text" property set accordingly and the styles set as if 534 Node with the "text" property set accordingly and the styles set as if
407 the Node inherited everything inheritable from its parent. 535 the Node inherited everything inheritable from its parent.
408 536
409 537
410 Layout 538 Layout
411 ------ 539 ------
412 540
413 sky:core registers 'display' as follows: 541 sky:core registers 'display' as follows:
414 542
415 ```javascript 543 ```javascript
416 { 544 {
417 name: 'display', 545 name: 'display',
418 type: sky.DisplayStyleValueType, 546 grammar: sky.DisplayStyleGrammar,
419 inherits: false, 547 inherited: false,
420 initialValue: sky.BlockLayoutManager, 548 initialValue: sky.BlockLayoutManager,
421 needsLayout: true, 549 needsManager: true,
422 } 550 }
423 ``` 551 ```
424 552
425 The following API is then used to add new layout manager types to 'display': 553 The following API is then used to add new layout manager types to 'display':
426 554
427 ```javascript 555 ```javascript
428 void registerLayoutManager(String displayValue, LayoutManagerConstructor? layout Manager); 556 void registerLayoutManager(String displayValue, LayoutManagerConstructor? layout Manager);
429 ``` 557 ```
430 558
431 sky:core by default registers: 559 sky:core by default registers:
432 560
433 - 'block': sky.BlockLayoutManager 561 - 'block': sky.BlockLayoutManager
434 - 'paragraph': sky.ParagraphLayoutManager 562 - 'paragraph': sky.ParagraphLayoutManager
435 - 'inline': sky.InlineLayoutManager 563 - 'inline': sky.InlineLayoutManager
436 - 'none': null 564 - 'none': null
437 565
438 566
439 Layout managers inherit from the following API: 567 Layout managers inherit from the following API:
440 568
441 ```javascript 569 ```javascript
442 class LayoutManager : EventTarget { 570 class LayoutManager : EventTarget {
443 readonly attribute StyleNode node; 571 readonly attribute RenderNode node;
444 constructor LayoutManager(StyleNode node); 572 constructor LayoutManager(RenderNode node);
573 // sets needsManager to false on the node
445 574
446 readonly attribute Boolean autoreap; 575 readonly attribute Boolean autoreap;
447 // defaults to true 576 // defaults to true
448 // when true, any children that are isNew or isGhost are welcomed/reaped imp licitly by default layout() 577 // when true, any children that are isNew are automatically welcomed by the default layout()
578 // when true, children that are removd don't get set to isGhost=true, they'r e just removed
449 579
450 virtual Array<EventTarget> getEventDispatchChain(); // O(N) in number of this. node's ancestors // implements EventTarget.getEventDispatchChain() 580 virtual Array<EventTarget> getEventDispatchChain(); // O(N) in number of this. node's ancestors // implements EventTarget.getEventDispatchChain()
451 // let result = []; 581 // let result = [];
452 // let node = this.node; 582 // let node = this.node;
453 // while (node && node.layoutManager) { 583 // while (node && node.layoutManager) {
454 // result.push(node.layoutManager); 584 // result.push(node.layoutManager);
455 // node = node.parentNode; 585 // node = node.parentNode;
456 // } 586 // }
457 // return result; 587 // return result;
458 588
459 void take(StyleNode victim); // sets victim.ownerLayoutManager = this; 589 void setProperty(RenderNode node, PropertyHandle property, any value, String? pseudoElement = null); // O(1)
590 // if called from an adjustProperties() method during the property adjustmen t phase,
591 // replaces the value that getProperty() would return on that node with /val ue/
592
593 virtual void adjustProperties();
594 // called before layout; can call setProperty to set new values
595 // note that this happens after the cascade so inheritance isn't applied to this new value
596 // also note that the value you set is a post-computation value, not an Abst ractStyleValue descendant
597 // so e.g. you can have an AnimatableColorStyleValue, get its value, and pus h it into setProperty()
598 // but you can't push the AnimatableColorStyleValue directly in, it won't do what you expect
599
600 void take(RenderNode victim); // sets victim.ownerLayoutManager = this;
460 // assert: victim hasn't been take()n yet during this layout 601 // assert: victim hasn't been take()n yet during this layout
461 // assert: victim.needsLayout == true 602 // assert: victim.needsLayout == true
462 // assert: an ancestor of victim has node.layoutManager == this (aka, victim is a descendant of this.node) 603 // assert: an ancestor of victim has node.layoutManager == this (aka, victim is a descendant of this.node)
463 604
464 virtual void release(StyleNode victim); 605 virtual void release(RenderNode victim);
465 // called when the StyleNode was removed from the tree 606 // called when the RenderNode was removed from the tree
466 607
467 void setChildPosition(child, x, y); // sets child.x, child.y 608 void setChildPosition(child, x, y); // sets child.x, child.y
468 void setChildX(child, y); // sets child.x 609 void setChildX(child, y); // sets child.x
469 void setChildY(child, y); // sets child.y 610 void setChildY(child, y); // sets child.y
470 void setChildSize(child, width, height); // sets child.width, child.height 611 void setChildSize(child, width, height); // sets child.width, child.height
471 void setChildWidth(child, width); // sets child.width 612 void setChildWidth(child, width); // sets child.width
472 void setChildHeight(child, height); // sets child.height 613 void setChildHeight(child, height); // sets child.height
473 // for setChildSize/Width/Height: if the new dimension is different than the last assumed dimensions, and 614 // for setChildSize/Width/Height: if the new dimension is different than the last assumed dimensions, and
474 // any StyleNodes with an ownerLayoutManager==this have cached values for ge tProperty() that are marked 615 // any RenderNodes with an ownerLayoutManager==this have cached values for g etProperty() that are marked
475 // as provisional, clear them 616 // as layout-dependent, clear them
476 void welcomeChild(child); // resets child.isNew 617 void welcomeChild(child); // resets child.isNew
477 void reapChild(child); // resets child.isGhost 618 void reapChild(child); // resets child.isGhost
478 619
479 Generator<StyleNode> walkChildren(); 620 Generator<RenderNode> walkChildren();
480 // returns a generator that iterates over the children, skipping any whose o wnerLayoutManager is not |this| 621 // returns a generator that iterates over the children, skipping any whose o wnerLayoutManager is not |this|
481 622
482 Generator<StyleNode> walkChildrenBackwards(); 623 Generator<RenderNode> walkChildrenBackwards();
483 // returns a generator that iterates over the children backwards, skipping a ny whose ownerLayoutManager is not |this| 624 // returns a generator that iterates over the children backwards, skipping a ny whose ownerLayoutManager is not |this|
484 625
485 void assumeDimensions(Float width, Float height); 626 void assumeDimensions(Float width, Float height);
486 // sets the assumed dimensions for calls to getProperty() on StyleNodes that have this as an ownerLayoutManager 627 // sets the assumed dimensions for calls to getProperty() on RenderNodes tha t have this as an ownerLayoutManager
487 // if the new dimension is different than the last assumed dimensions, and a ny StyleNodes with an 628 // if the new dimension is different than the last assumed dimensions, and a ny RenderNodes with an
488 // ownerLayoutManager==this have cached values for getProperty() that are ma rked as provisional, clear them 629 // ownerLayoutManager==this have cached values for getProperty() that are ma rked as layout-dependent, clear them
489 // TODO(ianh): should we force this to match the input to layout(), when cal led from inside layout() and when 630 // TODO(ianh): should we force this to match the input to layout(), when cal led from inside layout() and when
490 // layout() has a forced width and/or height? 631 // layout() has a forced width and/or height?
491 632
492 virtual LayoutValueRange getIntrinsicWidth(Float? defaultWidth = null); 633 virtual LayoutValueRange getIntrinsicWidth(Float? defaultWidth = null);
493 /* 634 /*
494 function getIntrinsicWidth(defaultWidth) { 635 function getIntrinsicWidth(defaultWidth) {
495 if (defaultWidth == null) { 636 if (defaultWidth == null) {
496 defaultWidth = this.node.getProperty('width'); 637 defaultWidth = this.node.getProperty('width');
497 if (typeof defaultWidth != 'number') 638 if (typeof defaultWidth != 'number')
498 defaultWidth = 0; 639 defaultWidth = 0;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 defaultHeight = minHeight; 680 defaultHeight = minHeight;
540 return { 681 return {
541 minimum: minHeight, 682 minimum: minHeight,
542 value: defaultHeight, 683 value: defaultHeight,
543 maximum: maxHeight, 684 maximum: maxHeight,
544 }; 685 };
545 } 686 }
546 */ 687 */
547 688
548 void markAsLaidOut(); // sets this.node.needsLayout and this.node.descendantNe edsLayout to false 689 void markAsLaidOut(); // sets this.node.needsLayout and this.node.descendantNe edsLayout to false
549 virtual Dimensions layout(Number? width, Number? height); 690 virtual Dimensions layout(Float? width, Float? height);
550 // call markAsLaidOut(); 691 // call markAsLaidOut();
551 // if autoreap is true: use walkChildren() to call welcomeChild() and reapCh ild() on each child 692 // if autoreap is true: use walkChildren() to call welcomeChild() and reapCh ild() on each child
552 // if width is null, set width to getIntrinsicWidth().value 693 // if width is null, set width to getIntrinsicWidth().value
553 // if height is null, set width height getIntrinsicHeight().value 694 // if height is null, set width height getIntrinsicHeight().value
554 // call this.assumeDimensions(width, height); 695 // call this.assumeDimensions(width, height);
555 // call this.layoutChildren(width, height); 696 // call this.layoutChildren(width, height);
556 // return { width: width, height: height } 697 // return { width: width, height: height }
557 // - this should always call this.markAsLaidOut() to reset needsLayout 698 // - this should always call this.markAsLaidOut() to reset needsLayout
558 // - the return value should include the final value for whichever of the wi dth and height arguments 699 // - the return value should include the final value for whichever of the wi dth and height arguments
559 // that is null 700 // that is null
560 // - subclasses that want to make 'auto' values dependent on the children sh ould override this 701 // - subclasses that want to make 'auto' values dependent on the children sh ould override this
561 // entirely, rather than overriding layoutChildren 702 // entirely, rather than overriding layoutChildren
562 703
563 virtual void layoutChildren(Number width, Number height); 704 virtual void layoutChildren(Float width, Float height);
564 // default implementation does nothing 705 // default implementation does nothing
565 // - override this if you want to lay out children but not have the children affect your dimensions 706 // - override this if you want to lay out children but not have the children affect your dimensions
566 707
567 virtual void paint(RenderingSurface canvas); 708 virtual void paint(RenderingSurface canvas);
568 // set a clip rect on the canvas for rect(0,0,this.width,this.height) 709 // set a clip rect on the canvas for rect(0,0,this.width,this.height)
710 // (? we don't really have to do this; consider shadows...)
569 // call the painter of each property, in order they were registered, which o n this element has a painter 711 // call the painter of each property, in order they were registered, which o n this element has a painter
570 // call this.paintChildren(canvas) 712 // call this.paintChildren(canvas)
571 // (the default implementation doesn't paint anything on top of the children ) 713 // (the default implementation doesn't paint anything on top of the children )
572 // unset the clip 714 // unset the clip
573 // - this gets called by the system if: 715 // - this gets called by the system if:
574 // - you are in your parent's current display list and it's in its parent 's and so on up to the top, and 716 // - you are in your parent's current display list and it's in its parent 's and so on up to the top, and
575 // - you haven't had paint() called since the last time you were dirtied 717 // - you haven't had paint() called since the last time you were dirtied
576 // - the following things make you dirty: 718 // - the following things make you dirty:
577 // - dimensions of your style node changed 719 // - dimensions of your RenderNode changed
578 // - one of your properties with needsLayout or needsPaint changed 720 // - one of your properties with needsLayout or needsPaint changed
579 721
580 virtual void paintChildren(RenderingSurface canvas); 722 virtual void paintChildren(RenderingSurface canvas);
581 // for each child returned by walkChildren(): 723 // for each child returned by walkChildren():
582 // if child bounds intersects our bounds: 724 // if child bounds intersects our bounds:
583 // call canvas.paintChild(child); 725 // call canvas.paintChild(child);
584 // - you should skip children that will be clipped out of yourself because t hey're outside your bounds 726 // - you should skip children that will be clipped out of yourself because t hey're outside your bounds
585 // - if you transform the canvas, you'll have to implement your own version of paintChildren() so 727 // - if you transform the canvas, you'll have to implement your own version of paintChildren() so
586 // that you don't skip the children that are visible in the new coordinate space but wouldn't be 728 // that you don't skip the children that are visible in the new coordinate space but wouldn't be
587 // without the transform 729 // without the transform
588 730
589 virtual StyleNode hitTest(Float x, Float y); 731 virtual RenderNode hitTest(Float x, Float y);
590 // default implementation uses the node's children nodes' x, y, 732 // default implementation uses the node's children nodes' x, y,
591 // width, and height, skipping any that have width=0 or height=0, or 733 // width, and height, skipping any that have width=0 or height=0, or
592 // whose ownerLayoutManager is not |this| 734 // whose ownerLayoutManager is not |this|
593 // default implementation walks the tree backwards from its built-in order 735 // default implementation walks the tree backwards from its built-in order
594 // if no child is hit, then return this.node 736 // if no child is hit, then return this.node
595 // override this if you changed your children's z-order, or if you used take () to 737 // override this if you changed your children's z-order, or if you used take () to
596 // hoist some descendants up to be your responsibility, or if your children aren't 738 // hoist some descendants up to be your responsibility, or if your children aren't
597 // rectangular (e.g. you lay them out in a hex grid) 739 // rectangular (e.g. you lay them out in a hex grid)
598 // make sure to offset the value you pass your children: child.layoutManager .hitTest(x-child.x, y-child.y) 740 // make sure to offset the value you pass your children: child.layoutManager .hitTest(x-child.x, y-child.y)
599
600 } 741 }
601 742
602 dictionary LayoutValueRange { 743 dictionary LayoutValueRange {
603 // negative values here should be treated as zero 744 // negative values here should be treated as zero
604 Float minimum = 0; 745 Float minimum = 0;
605 Float value = 0; // ideal desired width; if it's not in the range minimum .. m aximum then it overrides minimum and maximum 746 Float value = 0; // ideal desired width; if it's not in the range minimum .. m aximum then it overrides minimum and maximum
606 (Float or Infinity) maximum = Infinity; 747 (Float or Infinity) maximum = Infinity;
607 } 748 }
608 749
609 dictionary Dimensions { 750 dictionary Dimensions {
610 Float width = 0; 751 Float width = 0;
611 Float height = 0; 752 Float height = 0;
612 } 753 }
613 ``` 754 ```
614 755
615 756
616 Paint 757 Paint
617 ----- 758 -----
618 759
760 Sky has a list of RenderNodes that need painting.
761 When a RenderNode is created, it's added to this list.
762
619 ```javascript 763 ```javascript
620 callback void Painter (StyleNode node, RenderingSurface canvas); 764 callback void Painter (RenderNode node, RenderingSurface canvas);
621 765
622 class RenderingSurface { 766 class RenderingSurface {
623 767
624 // ... (API similar to <canvas>'s 2D API) 768 // ... (API similar to <canvas>'s 2D API)
625 769
626 void paintChild(StyleNode node); 770 void paintChild(RenderNode node);
627 // inserts a "paint this child" instruction in this canvas's display list. 771 // inserts a "paint this child" instruction in this canvas's display list.
628 // the child's display list, transformed by the child's x and y coordinates, will be inserted into this 772 // the child's display list, transformed by the child's x and y coordinates, will be inserted into this
629 // display list during painting. 773 // display list during painting.
630 } 774 }
631 ``` 775 ```
632 776
633 777
778 The default framework provides global hooks for extending the painting of:
779
780 - borders
781 - backgrounds
782
783 These are called during the default framework's layout managers'
784 paint() functions. They are also made available so that other people
785 can call them from their paint() functions.
786
787
788
634 Default Styles 789 Default Styles
635 -------------- 790 --------------
636 791
637 In the constructors for the default elements, they add to themselves 792 In the constructors for the default elements, they add to themselves
638 StyleDeclaration objects as follows: 793 StyleDeclaration objects as follows:
639 794
640 * ``import`` 795 * ``import``
641 * ``template`` 796 * ``template``
642 * ``style`` 797 * ``style``
643 * ``script`` 798 * ``script``
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
678 ```javascript 833 ```javascript
679 { display: { value: sky.ErrorLayoutManager } } 834 { display: { value: sky.ErrorLayoutManager } }
680 ``` 835 ```
681 836
682 The ``div`` element doesn't have any default styles. 837 The ``div`` element doesn't have any default styles.
683 838
684 These declarations are all shared between all the elements (so e.g. if 839 These declarations are all shared between all the elements (so e.g. if
685 you reach in and change the declaration that was added to a ``title`` 840 you reach in and change the declaration that was added to a ``title``
686 element, you're going to change the styles of all the other 841 element, you're going to change the styles of all the other
687 default-hidden elements). 842 default-hidden elements).
OLDNEW
« no previous file with comments | « sky/specs/apis.md ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698