Add yoga::Style::resolve() for ahead-of-time computed whole style #1455

Open
opened 2023-11-07 21:03:21 -08:00 by NickGerleman · 2 comments
NickGerleman commented 2023-11-07 21:03:21 -08:00 (Migrated from github.com)

What

We have different adhoc ways of resolving and caching from the user input style. These can often be repeated and expensive (e.g. for edge value resolution), and the APIs exposed for resolution are inconsistent.

We pass that computed style through yoga::calculateLayoutInternal, and try to remove cases where we pass a whole child Yoga node, to make it easier to reason that only layout results are being mutated.

Example

// Precomputes the full style, caching the last computed value for return
// if args match, and style not dirty
auto computedStyle = style.resolve({
  .ownerWidth = ownerWidth,
  .ownerHeight = ownerHeight,
  .viewportWidth = viewportWidth,
  .viewportHeight = viewportHeight,
});

References:

  1. https://www.w3.org/TR/css-cascade-4/#computed
### What We have different adhoc ways of resolving and caching from the user input style. These can often be repeated and expensive (e.g. for edge value resolution), and the APIs exposed for resolution are inconsistent. We pass that computed style through `yoga::calculateLayoutInternal`, and try to remove cases where we pass a whole child Yoga node, to make it easier to reason that only layout results are being mutated. ### Example ```cpp // Precomputes the full style, caching the last computed value for return // if args match, and style not dirty auto computedStyle = style.resolve({ .ownerWidth = ownerWidth, .ownerHeight = ownerHeight, .viewportWidth = viewportWidth, .viewportHeight = viewportHeight, }); ``` ### References: 1. https://www.w3.org/TR/css-cascade-4/#computed
nicoburns commented 2023-11-14 16:07:19 -08:00 (Migrated from github.com)

Not sure if you were intending to resolve percentages as part of this function (the ownerWidth/ownerHeight parameters suggest to me that you are), but it's worth noting that there can be cases where some percentages need to recompute and others don't (e.g. mid-way through laying out a node you want to recompute percentage gap but not percentage width). In which case such an "all or nothing" function may be awkward.

Taffy's solution to this is keep a struct of resolved styles on the stack of the equivalent function of calculateLayoutInternal, which we update incrementally throughout the layout process (and pass through to sub-functions by reference).


Also, as a point of terminology: "computed" values do not resolve percentages (and they couldn't because determining "computed" values is part of the style pass rather than the layout pass in browsers, and in the general case you don't have a value to resolve percentages against until you run layout). See: https://www.w3.org/TR/css-cascade-4/#stages-examples.

If you're not resolving percentages then this comment may not be relevant.

Not sure if you were intending to resolve percentages as part of this function (the ownerWidth/ownerHeight parameters suggest to me that you are), but it's worth noting that there can be cases where some percentages need to recompute and others don't (e.g. mid-way through laying out a node you want to recompute percentage gap but not percentage width). In which case such an "all or nothing" function may be awkward. Taffy's solution to this is keep a struct of resolved styles on the stack of the equivalent function of `calculateLayoutInternal`, which we update incrementally throughout the layout process (and pass through to sub-functions by reference). --- Also, as a point of terminology: "computed" values do *not* resolve percentages (and they couldn't because determining "computed" values is part of the style pass rather than the layout pass in browsers, and in the general case you don't have a value to resolve percentages against until you run layout). See: https://www.w3.org/TR/css-cascade-4/#stages-examples. If you're not resolving percentages then this comment may not be relevant.
NickGerleman commented 2023-11-14 19:49:43 -08:00 (Migrated from github.com)

Also, as a point of terminology: "computed" values do not resolve percentages

That’s a good clarification. I missed the table, but saw “Computing a relative value generally absolutizes it” and reference to percentage computation against reference, and placed the phases together.

Computed style purely derived from style is convenient to work with because it’s only ever dirtied when the style changes, and we do already do repeated work for it during layout (e.g. all the “edgeValueForColumn” type of work.

I suspect we want to add caching for resolved absolute values from relative, given the same reference, if resolution can be more expensive (i.e. if Yoga or its user needs to evaluate a parser CSS math function) I’m not quite sure what lifetime and layering for that. E.g. measure cache is kept around after the layout, but I’m not sure if a more persistent cache makes sense here.

I was looking as having computed value accessor directly accept the reference value for a single value at once to be able to cache more granularity if we needed it.

> Also, as a point of terminology: "computed" values do not resolve percentages That’s a good clarification. I missed the table, but saw “Computing a relative value generally absolutizes it” and reference to percentage computation against reference, and placed the phases together. Computed style purely derived from style is convenient to work with because it’s only ever dirtied when the style changes, and we do already do repeated work for it during layout (e.g. all the “edgeValueForColumn” type of work. I suspect we want to add caching for resolved absolute values from relative, given the same reference, if resolution can be more expensive (i.e. if Yoga or its user needs to evaluate a parser CSS math function) I’m not quite sure what lifetime and layering for that. E.g. measure cache is kept around after the layout, but I’m not sure if a more persistent cache makes sense here. I was looking as having computed value accessor directly accept the reference value for a single value at once to be able to cache more granularity if we needed it.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: DaddyFrosty/yoga#1455
No description provided.