Skip to content

Conversation

@waywardmonkeys
Copy link
Contributor

  • Add LayoutContext::style_run_builder and a StyleRunBuilder API for constructing a Layout from contiguous, non-overlapping style runs, skipping Parley’s internal range-splitting step.
  • Redesign TextStyle as TextStyle<'family, 'settings, B> so font-family and OpenType settings can borrow independently, enabling per-run borrowed variations/features without extra allocations.
  • Update styled_text_parley to lower StyledText’s computed runs directly into StyleRunBuilder using TextStyle<'static, '_, B>.
  • Add a parity test ensuring StyleRunBuilder output matches RangedBuilder for equivalent styles.

@waywardmonkeys
Copy link
Contributor Author

This builds on top of PR #495 so only look at the right commit here ... but this shows a way to build a Layout going through less code and no resolution.

@waywardmonkeys
Copy link
Contributor Author

This is still doing some style resolution via resolve_entire_style_set ..

…n, Parley lowering)

  - Add `styled_text`: attributed text + span styles with a CSS-inspired vocabulary (`styled_text::style`), specified→computed resolution (`styled_text::resolve`), and a `StyledText`/`StyledDocument` model for block + span styling.
  - Provide deterministic inline-run resolution (including overlap handling and run coalescing) plus unit tests and doctests for the core semantics.
  - Add `styled_text_parley`: lowers `styled_text` computed runs into Parley `StyleProperty` spans to build a `parley::Layout`.
  - Add `vello_cpu_render_styled_text` example exercising the end-to-end pipeline and update workspace/CI wiring for the new crates.
…ext`

- Add `LayoutContext::style_run_builder` and a `StyleRunBuilder` API for constructing a Layout from contiguous, non-overlapping style runs, skipping Parley’s internal range-splitting step.
- Redesign `TextStyle` as `TextStyle<'family, 'settings, B>` so font-family and OpenType settings can borrow independently, enabling per-run borrowed variations/features without extra allocations.
- Update `styled_text_parley` to lower StyledText’s computed runs directly into `StyleRunBuilder` using `TextStyle<'static, '_, B>`.
- Add a parity test ensuring `StyleRunBuilder` output matches `RangedBuilder` for equivalent styles.
@nicoburns
Copy link
Collaborator

Makes a lot of sense. #387 does something very similar.

@nicoburns
Copy link
Collaborator

I will note that I think the "flat list of non-overlapping styles" model may be insufficient to represent some tree-shaped data. For example, it's going to be hard to represent <p><span style="padding: 5px"><span style="padding: 5px">hello</span></span> world</p>. Not sure what the solution is. Horizontal padding/margin/border seems like a very tricky problem in general due to bidi-reordering.

@xStrom
Copy link
Member

xStrom commented Jan 18, 2026

Why is that span example hard to represent? It's not clear to me, especially as there is no BiDi in that example.

@waywardmonkeys
Copy link
Contributor Author

@nicoburns This is probably just the first phase ... I think those sorts of things might change with time. There's a lot of stuff downstream from this.

@nicoburns
Copy link
Collaborator

Why is that span example hard to represent? It's not clear to me, especially as there is no BiDi in that example.

@xStrom The key thing is that the two spans start/end at exactly the same offset in the text. So in the model where the styles apply to glyphs in the text, how do you determine that you have "pushed" or "popped" two spans? For most styles (e.g. styles the modify the text itself) this doesn't matter: two nested spans isn't really any different to one span that applies both sets of styles. But for (horizontal) padding, the two nested spans here imply that the 5px padding should be applied twice (so an overall padding of 10px around the word "hello").

I think that to implement this you would need some kind of modelling of the tree structure within Parley (perhaps each style struct having depth: u8 and parent: Option<u16> fields or something?).

@nicoburns
Copy link
Collaborator

@waywardmonkeys Unrelated to my previous comment:

Is there a way to reuse styles with this API? For example, in <p>first<b>second</b>third</p>, the spans representing "first" and "third" would have the exact same set of styles. I believe the current TreeBuilder is taking advantage of this to simply refer to the already pushed Style rather than pushing a duplicate style. Although looking at build_layout_into it looks to me that this may result in incorrect "char_info` being set.

Basically, it might nice to have a layer of indirection between the style structs and the text ranges, so that more than one text range can point to the same style struct.

@xStrom
Copy link
Member

xStrom commented Jan 18, 2026

Regarding <p><span style="padding: 5px"><span style="padding: 5px">hello</span></span> world</p> and the double padding, maybe I'm missing something but it seems fairly trivial to flatten. You mentioned it yourself, you add the paddings together. Your style flattener needs to know which properties are additive and which are overrides. Of course for web compat you'll also get to deal with the juicy quirks of margin collapsing. However, I'm still not seeing any reason why it couldn't be described as flat resolved styles.


I haven't checked the PR but in genral style reuse via references seems like an important memory optimization. Just imagine a text where there's a bold word every now and then. You only need two actual style structs for this, not a multiple of how many bold words you have.

@waywardmonkeys
Copy link
Contributor Author

I haven't checked the PR but in genral style reuse via references seems like an important memory optimization. Just imagine a text where there's a bold word every now and then. You only need two actual style structs for this, not a multiple of how many bold words you have.

We're in the first steps of a long journey.

@nicoburns
Copy link
Collaborator

nicoburns commented Jan 18, 2026

You mentioned it yourself, you add the paddings together. Your style flattener needs to know which properties are additive and which are overrides.

Handling it as part of flattening is interesting possibility that for some reason I had not considered. I'd need to think it through, but I think this would probably work.

Of course for web compat you'll also get to deal with the juicy quirks of margin collapsing.

Luckily margin collapsing only applies to block-level elements, not inline-level elements, so we don't need to deal with this in Parley.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants