Index: sky/specs/style.md |
diff --git a/sky/specs/style.md b/sky/specs/style.md |
index 864d50a8b21453b249d66d55a6460466128e5bf1..d27aab951e4a1ab6af78e7bc7115d9ba7064997a 100644 |
--- a/sky/specs/style.md |
+++ b/sky/specs/style.md |
@@ -292,6 +292,7 @@ class StyleValueResolverSettings { |
// sets firstTime and state to given values |
// sets layoutDependent to false |
// sets dependencies to empty set |
+ // sets lifetime to Infinity |
readonly attribute Boolean firstTime; |
// true if this is the first time this property is being resolved for this element, |
@@ -312,6 +313,12 @@ class StyleValueResolverSettings { |
Array<PropertyHandle> getDependencies(); |
// returns an array of the PropertyHandle values for the bits that are set in dependencies |
+ // attribute (Float or Infinity) lifetime; |
+ void setLifetime(Float age); |
+ // if the new value is less than the current value of lifetime, update the current value |
+ (Float or Infinity) getLifetime(); |
+ // return current value of lfietime |
+ |
attribute any state; // initially null, can be set to store value for this RenderNode/property pair |
// for example, TransitioningColorStyleValue would store |
// { |
@@ -468,6 +475,7 @@ abstract class AbstractStyleDeclarationList { |
class ElementStyleDeclarationList : AbstractStyleDeclarationList { |
constructor (Element? element); |
+ readonly attribute Element? element; |
// there are two batches of styles in an ElementStyleDeclarationList. |
@@ -495,6 +503,7 @@ class ElementStyleDeclarationList : AbstractStyleDeclarationList { |
class RenderNodeStyleDeclarationList : AbstractStyleDeclarationList { |
constructor (RenderNode? renderNode); |
+ readonly attribute RenderNode? renderNode; |
// as StyleDeclarations are added and removed, the RenderNodeStyleDeclarationList |
// calls register(renderNode) and unregister(renderNode) respectively on those |
@@ -645,39 +654,51 @@ class RenderNode { // implemented in C++ with no virtual tables |
// if settings.forceCache is true, return the cached value |
// if neither dirty bit is set, return the cached value |
// if the cascade dirty bit is not set (value dirty is set) then |
- // resolve the value using the same StyleValue object |
- // - with firstTime=false on the resolver settings |
- // - with the cached state object if any |
- // - jump to "cache" below |
+ // - clear any pending lifetime-enforcing tasks for this |
+ // property/pseudoElement pair on this render node |
+ // - resolve the value using the same StyleValue object |
+ // - with firstTime=false on the resolver settings |
+ // - with the cached state object if any |
+ // - jump to "cache" below |
// if settings.forceCache is true, return null |
+ // - clear any pending lifetime-enforcing tasks for this |
+ // property/pseudoElement pair on this render node |
// - if there's an override declaration with the property (with |
- // the pseudo or without), then get the value object from there and |
- // jump to "resolve" below. |
- // - if there's an element and it has a style declaration with the property |
- // (with the pseudo or without), then get the value object from there |
+ // the pseudo or without), then get the value object from there |
// and jump to "resolve" below. |
- // - if it's not an inherited property, or if there's no parent, then get the |
- // default value and jump to "resolve" below. |
- // - call the parent render node's getProperty() with the same property |
- // but no settings, then cache that value as the value for this element |
- // with the given pseudoElement, with no StyleValue object, no resolver |
- // settings, and set the state to null. |
+ // - if there's an element and it has a style declaration with |
+ // the property (with the pseudo or without), then get the |
+ // value object from there and jump to "resolve" below. |
+ // - if it's not an inherited property, or if there's no parent, |
+ // then get the default value and jump to "resolve" below. |
+ // - call the parent render node's getProperty() with the same |
+ // property but no settings, then cache that value as the value |
+ // for this element with the given pseudoElement, with no |
+ // StyleValue object, no resolver settings, and set the state |
+ // to null. |
// resolve: |
- // - get a new resolver settings object |
- // - if the obtained StyleValue object is different than the |
- // cached StyleValue object, or if there is no cached object, then set |
- // the resolver settings to firstTime=true, otherwise it's the same object |
- // and set firstTime=false. |
- // - set the resolver settings' state to the current state for this |
- // pseudoElement/property combination |
+ // - get a new resolver settings object (or reset an existing one) |
+ // - if the obtained StyleValue object is different than the |
+ // cached StyleValue object, or if there is no cached |
+ // object, then set the resolver settings to |
+ // firstTime=true, otherwise it's the same object and set |
+ // firstTime=false. |
+ // - set the resolver settings' state to the current state |
+ // for this pseudoElement/property combination |
// - using the obtained StyleValue object, call resolve(), |
// passing it this node and the resolver settings object. |
// - jump to "cache" below |
// cache: |
- // - update the cache with the obtained value and resolver settings |
+ // - update the cache with the obtained value and resolver |
+ // settings |
// - reset the dirty bits |
- // - if the resolver settings' getShouldSaveState() method returns false, |
- // then discard any cached state, otherwise, cache the new state |
+ // - if the resolver settings' getShouldSaveState() method |
+ // returns false, then discard any cached state, otherwise, |
+ // cache the new state |
+ // - if the resolver settings' lifetime is not infinity, then |
+ // queue a lifetime-enforcing task for the appropriate time |
+ // in the future which calls cascadedValueDirty for this |
+ // property/pseudoElement pair on this render node |
readonly attribute RenderNodeStyleDeclarationList overrideStyles; |
// mutable; initially empty |
@@ -777,7 +798,7 @@ class LayoutManager : EventTarget { |
readonly attribute Boolean autoreap; |
// defaults to true |
- // when true, any children that are isNew are automatically welcomed by the default layout() |
+ // when true, children that are added don't get set to isNew=true |
// when true, children that are removed don't get set to isGhost=true, they're just removed |
virtual Array<EventTarget> getEventDispatchChain(); // O(N) in number of this.node's ancestors // implements EventTarget.getEventDispatchChain() |
@@ -790,13 +811,12 @@ class LayoutManager : EventTarget { |
// return result; |
void setProperty(RenderNode node, PropertyHandle property, any value, String pseudoElement = ''); // O(1) |
- // if called from an adjustProperties() method during the property adjustment phase, |
// replaces the value that getProperty() would return on that node with /value/ |
- // this also clears the dependency bits and sets the property state to null |
+ // this also clears the dependency bits, dirty bits, and sets the property state to null |
+ // this also clears any relevant lifetime-enforcing tasks |
void take(RenderNode 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 node.layoutManager == this (aka, victim is a descendant of this.node) |
virtual void release(RenderNode victim); |
@@ -812,24 +832,17 @@ class LayoutManager : EventTarget { |
void setChildSize(child, width, height); // sets child.width, child.height |
void setChildWidth(child, width); // sets child.width |
void setChildHeight(child, height); // sets child.height |
+ // assert: child.ownerLayoutManager == this |
// for setChildSize/Width/Height: if the new dimension is different than the last assumed dimensions, and |
// any RenderNodes with an ownerLayoutManager==this have cached values for getProperty() that are marked |
- // as layout-dependent, clear them |
- void welcomeChild(child); // resets child.isNew |
- void reapChild(child); // resets child.isGhost |
- |
- Generator<RenderNode> walkChildren(); |
- // returns a generator that iterates over the children, skipping any whose ownerLayoutManager is not |this| |
- |
- Generator<RenderNode> walkChildrenBackwards(); |
- // returns a generator that iterates over the children backwards, skipping any whose ownerLayoutManager is not |this| |
+ // as layout-dependent, mark them as dirty with cascadedValueDirty() |
void assumeDimensions(Float width, Float height); |
- // sets the assumed dimensions for calls to getProperty() on RenderNodes that have this as an ownerLayoutManager |
+ // sets the assumed dimensions for calls to getProperty() on RenderNodes that have this as an ownerLayoutManager, |
+ // by updating renderNode width/height; |
// if the new dimension is different than the last assumed dimensions, and any RenderNodes with an |
- // ownerLayoutManager==this have cached values for getProperty() that are marked as layout-dependent, 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? |
+ // ownerLayoutManager==this have cached values for getProperty() that are marked as layout-dependent, mark them |
+ // as dirty with cascadedValueDirty() |
virtual LayoutValueRange getIntrinsicWidth(Float? defaultWidth = null); |
/* |
@@ -887,24 +900,56 @@ class LayoutManager : EventTarget { |
} |
*/ |
+ void welcomeChild(child); // resets child.isNew |
+ void reapChild(child); // resets child.isGhost |
+ |
+ Generator<RenderNode> walkChildren(); |
+ // returns a generator that iterates over the children, skipping any whose ownerLayoutManager is not |this| |
+ |
+ Generator<RenderNode> walkChildrenBackwards(); |
+ // returns a generator that iterates over the children backwards, skipping any whose ownerLayoutManager is not |this| |
+ |
void markAsLaidOut(); // sets this.node.needsLayout and this.node.descendantNeedsLayout to false |
virtual Dimensions layout(Float? width, Float? height); |
- // call markAsLaidOut(); |
- // if autoreap is true: use walkChildren() to call welcomeChild() and reapChild() on each child |
// if width is null, set width to getIntrinsicWidth().value |
- // if height is null, set width height getIntrinsicHeight().value |
+ // if height is null, set height to getIntrinsicHeight().value |
// call this.assumeDimensions(width, height); |
// call this.layoutChildren(width, height); |
+ // call markAsLaidOut(); |
// return { width: width, height: height } |
- // - this should always call this.markAsLaidOut() to reset needsLayout |
- // - the return value should include the final value for whichever of the width and height arguments |
- // that is null |
- // - subclasses that want to make 'auto' values dependent on the children should override this |
- // entirely, rather than overriding layoutChildren |
+ // - this should always call this.markAsLaidOut() to reset |
+ // needsLayout and descendantNeedsLayout |
+ // - the return value should include the final value for whichever |
+ // of the width and height arguments that is null |
+ // - subclasses that want to make 'auto' values dependent on the |
+ // children should override this entirely, rather than |
+ // overriding layoutChildren; but see layoutChildren()'s notes |
+ // for how to do this |
virtual void layoutChildren(Float width, Float height); |
// default implementation does nothing |
- // - override this if you want to lay out children but not have the children affect your dimensions |
+ // - override only this (and not layout()) if you want to lay out |
+ // children but not have the children affect your dimensions |
+ // - always call setChildSize() and setChildPosition() after |
+ // calling a child's layout() method |
+ // - if the child has needsLayout or if you need to have it |
+ // autosize, call its ownerLayoutManager's layout() method |
+ // - otherwise if the child has needs descendantNeedsLayout, call |
+ // layoutDescendants() |
+ |
+ virtual Dimensions layoutDescendants(); |
+ // assert: node.needsLayout is false, node.descendantNeedsLayout is true |
+ // walk children: |
+ // - if it has needsLayout, call its layout() method with its |
+ // current width and height, then call setChildSize() with |
+ // those same dimensions |
+ // - else, if it has descendantNeedsLayout, call its |
+ // layoutDescendants() method |
+ // call markAsLaidOut(); |
+ // - override this if you use take() to control more children, in |
+ // which case you should call their methods too |
+ // - this should always call this.markAsLaidOut() to reset |
+ // needsLayout and descendantNeedsLayout |
virtual void paint(RenderingSurface canvas); |
// set a clip rect on the canvas for rect(0,0,this.width,this.height) |