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

Support inline formatting in Block layout #627

Open
ArthurCose opened this issue Mar 13, 2024 · 7 comments
Open

Support inline formatting in Block layout #627

ArthurCose opened this issue Mar 13, 2024 · 7 comments
Labels
enhancement New feature or request

Comments

@ArthurCose
Copy link

What problem does this solve or what need does it fill?

Interleaving small images, buttons, and links with wrapped text. Reducing duplicated effort in downstream crates by supporting more web layout features.

What solution would you like?

Adding either an inline boolean or display_outside enum property to the Style struct, with support in compute_block_layout. Downstream crates can split text into inline blocks for taffy. Inline support appears to only be relevant for block layouts.

What alternative(s) have you considered?

  • Downstream solutions:
    • Custom block layout calculation
    • Using FlexWrap to simulate inline formatting (problems occur when any non-inline elements are encountered)

Additional context

  • Display::Block was recently added, but support for display-outside / similar does not appear on the roadmap
@ArthurCose ArthurCose added the enhancement New feature or request label Mar 13, 2024
@nicoburns
Copy link
Collaborator

Support for inline / flow layout is planned, although it will likely mostly sit outside of Taffy in a library like https://github.com/pop-os/cosmic-text or https://github.com/dfrg/parley with support on both sides for integrating the two closely.

@julia-script
Copy link
Contributor

julia-script commented Mar 25, 2024

I wonder if as an intermediary step before native support for inline/flow layout, it would possible to have a version of compute_block_layout that takes a callback to calculate inline nodes so someone implementing their own text layout calculation could leverage the existing logic for computing block layout.

Ex:
I'm currently trying to achieve something similar to the behavior below using compute_leaf_layout, which clearly isn't supposed to do that since I'm not calculating a leaf layout with it

Tree:

  • Block
    • TextNode: Lorem Ipsum Dolor
    • InlineBlock(Img)
    • TextNode: sit amet
    • Block

then in a layout that would break the text node, like

 | Lorem Ipsum |
 | Dolor <Img> |
 | sit amet    |
 | <..Block..> |

it'd be nice if compute_block_layout would call the callback on the text nodes so it would, for example, generate virtual nodes per segments (Lorem, Ipsum, Dolor, sit, amet), or run a custom computation that returns the x and y after the text node so the following nodes proceed from that position

@nicoburns
Copy link
Collaborator

@julia-script While it might be nice if Taffy could do this itself, I think you might be able to achieve something like by running a pass on the node tree to split the display: block nodes into block-containing-blocks and inline-containing-blocks before passing those nodes into Taffy. Such that for example you'd transform:

  • Block
    • TextNode: Lorem Ipsum Dolor
    • InlineBlock(Img)
    • TextNode: sit amet
    • Block

into

  • Block
    • AnonymousBlock (generated by pre-layout pass)
      • TextNode: Lorem Ipsum Dolor
      • InlineBlock(Img)
      • TextNode: sit amet
    • Block

So when you run Taffy on (a tree containing) the top-level block here, it sees a block with two children, and it will call the leaf layout callback on both. You can then run your inline layout logic for the first one.

With the high-level API there currently isn't a way to call back into the same Taffy tree to measure a nested inline-block node (which would be useful if that node was say a flexbox node rather than an image), but 1. You could currently make that work with a separate, nested, Taffy tree 2. You can integrate this much better with the low-level API (see https://docs.rs/taffy/ for high-level vs. low-level APIs) and 3. we could definitely add that.

@nicoburns
Copy link
Collaborator

nicoburns commented Mar 25, 2024

I should add that progress is being made on actual support for inline/flow layout. We haven't fully settled on an approach yet, but a number of possibilities are being pursued concurrently:

  1. I have a WIP design for implementing it in Parley (Support inline box layout linebender/parley#25)
  2. I have WIP pre-requisite PR for implementing it in Cosmic-Text (Multiple font sizes pop-os/cosmic-text#235)
  3. Servo's layout engine already implements it in components/layout_2020 and components/gfx/text. This code is MPL licensed rather than MIT like Taffy, but this might not matter if it could be made available as standalone library (but it currently tightly coupled to other parts of servo).
  4. Dropflow implements it with a compatible licence. It's in TypeScript/C++ rather than Rust, but could potentially be ported.

@julia-script
Copy link
Contributor

julia-script commented Mar 26, 2024

oh, having nested trees and separating inline from non-inline is an interesting approach. I think that will make more sense for my use case.

In fact, for my use case I will probably not even need the block elements and I might just go with inline only (and if the consumer wants to have blocks, then they can do it one level above).

I actually tried the same approach @ArthurCose mentioned

Using FlexWrap to simulate inline formatting (problems occur when any non-inline elements are encountered)

but I found that it adds a lot of overhead for large chunks of text when treating each text segment as a flex item (probably because it adds a bunch of computation that is irrelevant to text segments)

btw, is there anything planned or a recommended approach for scroll related layout calculation?

From what I've seen so far, taffy doesn't have the notion of scroll position, and elements with not all of it's children in the visible area

I'd like for example, to be able to only compute visible elements (and I imagine the preceding elements to compute the Y position, although for that I noticed that taffy runs multiple pass and one of them is used to compute the element size, skipping some of the child calculation, maybe that could be leveraged to calculate layout above the fold)

anyway, thank you for the tips, specially for the links, I'll look into those implementations

@nicoburns
Copy link
Collaborator

We now have now landed an initial version of this in Blitz (https://github.com/DioxusLabs/blitz). It's based on Parley's text layout (https://github.com/dfrg/parley), but also has additional logic directly in Blitz because HTML flow (block/inline) layout requires fixups to the tree structure (e.g. inserting "anonymous box" nodes) before performing layout. It's possible that this logic could be pulled out into taffy-style standalone library in future, but that will require some tricky design work.

@nicoburns
Copy link
Collaborator

btw, is there anything planned or a recommended approach for scroll related layout calculation?

From what I've seen so far, taffy doesn't have the notion of scroll position, and elements with not all of it's children in the visible area

Taffy does provide a content_size field in the layout. The scroll width/height can be computed from the difference between the size and the content_size. There is no support for only laying out in view nodes. That would be quite tricky to do (and there is no standard). And would make things like computing scrollbar height impossible. I would imagine frameworks building on top of Taffy having their own "virtualized scrolling" widgets that could implement this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants