Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider using Taffy for Flexbox and CSS Grid support #3

Open
nicoburns opened this issue Mar 21, 2024 · 5 comments
Open

Consider using Taffy for Flexbox and CSS Grid support #3

nicoburns opened this issue Mar 21, 2024 · 5 comments

Comments

@nicoburns
Copy link

Full disclosure: I'm a maintainer of Taffy

I just saw your project on HN, and couldn't help but feel like a library I work on: Taffy https://github.com/DioxusLabs/taffy would be a perfect complement to it. We support Flexbox and CSS Grid layout (and blocks-that-contains-blocks, but I suspect you already implement that) but not any of the rest of the CSS2-style layout (we're also missing some features necessary for full web compatibility: position: static, direction: rtl, and box-sizing: content-box being the main ones off the top of my head).

Taffy is implemented in Rust, and the WASM bindings (DioxusLabs/taffy#394) are currently incomplete (Flexbox is usable with the current state of that PR - CSS Grid isn't yet), but I could look into getting those into a releasable state if you are interested.

You may also wish to consider Yoga https://github.com/facebook/yoga (which I am not affiliated with) which is implemented in C++ and has more established WASM bindings but only supports Flexbox.

@chearon
Copy link
Owner

chearon commented Mar 22, 2024

Taffy looks great! I hope I can take a deeper dive into it soon. What I'm definitely interested in is making this useable by higher-level layout libraries like Taffy and Yoga. Whatever API changes you might need for that, I would support, although since you (and Yoga I think?) target native code, I guess it would only work with your WASM build.

For the long-run, I do want to implement at least some of flexbox internally. While it is the hard path, I think great advantages come from having full control over source code in one place, similar to Serenity's ethos. (At least as long as I can make that work, who knows...).

@nicoburns
Copy link
Author

What I'm definitely interested in is making this useable by higher-level layout libraries like Taffy and Yoga

Yeah, I might need to have a think about that. This is definitely made a little trickier by the fact that they might both need to call each other down the tree. Taffy actually has a low-level API designed for this, but it's not exposed over WASM currently (and performance might well be bad). Taffy and Yoga both have the concept of a "measure function" which enable them to call out to an external implementation to measure/layout a child node. Perhaps if dropflow also had that then they can be integrating by nesting trees each time the layout type switched.

For the long-run, I do want to implement at least some of flexbox internally.

Feel free to port Taffy's code directly if you want. It's also MIT licensed and follows the spec pretty closely :) Libweb's implementation also looks good from what I've seen (I'd personally probably avoid porting Yoga as it's codebase isn't as clean (and has no grid support)). I'd expect a port to JS to work quite well, but not sure what the performance would be like. Both Taffy and Yoga are targeting realtime (60fps or even 120fps) rendering speeds for relatively large trees. Currently a tree with around 10k flexbox nodes will layout in around 4ms. That doesn't include text layout, so it's not an apples-to-apples comparison, but it seems quite a bit faster than dropflow (to be expected I guess - both because text layout is likely to be slower and because JS is likely to be slower)

I'm also looking at implementing CSS2 layout on the Rust side. Probably either in cosmic-text or parley, although porting your code directly now represents an intriguing alternative possibility (I'm particular interested to see how you've combined inline-block with birectional text).

Additionally we have a project to turn this into a modular webview by combining it with Firefox's style engine (which does selector resolution, media queries, etc and is available as a Rust crate).
The current prototype is available at https://github.com/jkelleyrtp/stylo-dioxus (but it will probably move to https://github.com/DioxusLabs/blitz once we have it up to parity with the older prototype that currently lives in that repo). We hang on on the DioxusLabs discord if you're interested (https://discord.gg/fpPedgyN).

@chearon
Copy link
Owner

chearon commented Mar 23, 2024

This is definitely made a little trickier by the fact that they might both need to call each other down the tree.

Oh, of course... having Taffy and dropflow call each other might be messy.

Feel free to port Taffy's code directly if you want. It's also MIT licensed and follows the spec pretty closely :)

I'm relieved that it doesn't look like a totally unmanageable amount of code. Are there any gaps in grid or flexbox support? My strategy for flow layout has been to get low-level/older stuff working first and then work outward, but I have wondered if I'll have to cover the spec as-needed for grid and flexbox. Ladybird did an approach like that for flow layout: last I looked they only implemented 2-3 common scenarios for floats, and they'll fill out the rest of support as they go.

Currently a tree with around 10k flexbox nodes will layout in around 4ms

Jealousy! I might have started out with Rust if I knew this would end up in a useable state. I often see a layout difference of about 10x when I compare dropflow to browsers. That can be reduced to as low as 2x but only in the best case and with clever use.

I'm also looking at implementing CSS2 layout on the Rust side. Probably either in cosmic-text or parley, although porting your code directly now represents an intriguing alternative possibility

I will say using another text layout engine may present challenges because the CSS2 spec is a text layout engine. For example, leading could be done differently by those libraries than CSS2. Using HarfBuzz directly is hard mode though; if you don't need perfect support you could skip a lot of work.

(I'm particular interested to see how you've combined inline-block with birectional text).

I treat it as neutral, so it inherits the direction of adjacent text (code).

Additionally we have a project to turn this into a modular webview by combining it with Firefox's style engine (which does selector resolution, media queries, etc and is available as a Rust crate).

Very cool, and thanks for the invite!

@nicoburns
Copy link
Author

nicoburns commented Mar 24, 2024

Jealousy! I might have started out with Rust if I knew this would end up in a useable state.

It's not too late ;)

I'm relieved that it doesn't look like a totally unmanageable amount of code. Are there any gaps in grid or flexbox support?

Yeah, it's not too bad! Regarding gaps, the roadmap issue is a good place to look. To summarise, support is actually pretty good (discrepancies with browsers (if any) are likely to be in edge cases) and the major missing pieces I'm tracking are:

  • box-sizing: content-box (we currently assume border-box)
  • position: static (so absolute position relative to a non-parent ancestor)
  • direction: rtl and associated logical style properties (e.g. we support padding-left but not padding-inline-start)
  • calc()
  • min-content, max-content, and fit-content() values for width/height. We do support these for grid track sizing functions, so the sizing logic is mostly in place. Just need to override the styles in the correct places.
  • overflow: auto (we support visible, clip, hidden, scroll)
  • writing-mode

Additionally:

  • Baseline alignment support is inefficiently implemented and hasn't been thoroughly tested.
  • For Flexbox:
  • For Grid:
    • We do not yet implement subgrids (CSS Grid level 2)
    • We do not have support for named grid lines (you have to specify placement by number or use auto-placement)
    • We do not support grid-template, grid-template-areas or grid-area syntax. All of these are syntax sugar over existing properties that we do support and do not affect sizing logic.
  • We are currently unable to test with WPT (as it requires scripting support or implementing a custom runner), but have our own test suite of 1000+ tests which compares us against Chrome. And we have real-world usage in the Bevy game engine through which we've had quite a few bugs reported and fixed.

I will say using another text layout engine may present challenges because the CSS2 spec is a text layout engine. For example, leading could be done differently by those libraries than CSS2.

These engines are all quite new and unestablished. So I'm hoping to have some sway in how they implement such things. To start with imperfect will definitely be better than none (we don't support inline-block at all at the moment), but eventually it would be nice to match web exactly. Servo's layout engine is another option that has decent CSS2 support, but they are MPL licensed which isn't ideal for integrating with a MIT codebase.

@chearon
Copy link
Owner

chearon commented Mar 26, 2024

That's impressive though. I'd expect the doesn't-work-yets above if you haven't finished flow layout yet. And I never use named grid lines anyways :)

we are not fully spec compliant for "§9.9 Intrinsic Sizes" , but neither are Chrome/Firefox. And apparently the spec may be being updated (so I'm waiting for that to settle).

I was excited when they updated this, because people are always having issues with flexboxes-in-flexboxes. If I'm not mistaken, this is the Chrome issue where they tried it, but it broke the web 😞. So browsers are still on the original spec.

The WPT scripts thing is a problem for me too. And gsnedder's reply makes me think we would have to update more tests to use the script they use in WPT, and then you would have to port that script to Rust, and I'd have to tweak it to work in dropflow. I hope one of us finds a better solution for that; it sounds like they're open to supporting more engines.

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

No branches or pull requests

2 participants