Skip to content

Layout revamp ideas

Manuel Rego Casasnovas edited this page Apr 10, 2023 · 6 revisions

🚩 Note: This is a historical document. Information here might not reflect the current status of the Servo project. For a more recent document about Servo Layout see the following page: Servo Layout Engines Report.

This page is a loose collection of ideas for a forthcoming layout revamp. It should eventually become a design document.

Problems with layout

  • Too much emphasis on proving the concept of parallel layout and not enough on correctness. This is my (pcwalton)'s fault.

  • Developed too early, before Rust's conventions stabilized. Layout objects were originally @ boxes!

  • Unsafe. Layout objects are not a tree due to back pointers to containing blocks and so forth.

  • Three-pass design makes things hard to reason about. Layout just doesn't always work that way, particularly when floats are involved.

  • Parallelism around floats is impossible to reason about.

    • Floats are basically completely broken in general.

    • Width speculation for floats next to block formatting contexts is a totally broken approach.

    • It's not that floats are impossible to parallelize; it's that they're hard to cleanly parallelize in a way that keeps layout maintainable.

  • Margin collapse is an unholy abomination.

  • Flow/fragment distinction results in awkward duplication. Things like margin values are stored twice.

    • Hard to justify flow/fragment distinction anyway because of inline-block.
  • Pseudo-inheritance is awkward and at odds with Rust conventions.

Revamp principles

  • Use an entity-component system.

    • IDs for layout objects (entities).

    • A lot of things in layout are cross-cutting concerns. For example, box model (borders/padding/margins logic) is used to some degree by most layout objects, regardless of type. This is exactly the strong point of an ECS.

  • Emphasis on developer ergonomics above all else.

    • CSS layout is hard to get working at all. Developers need all the help they can get.
  • Write sequential-looking code with opportunistic parallelism.

  • Make layout code simple, elegant, and easy to read.

    • Goal: As nice as WeasyPrint.
  • Focus on correctness.

Details

  • All layout functions should be async.

  • Need to figure out how to effectively distribute async functions over multiple CPUs. Rayon may have something to help, or we can use futures-cpupool.

  • Values that are computed in parallel should be atomics with relaxed ordering.

    • Layout races will be bugs but not UB.

    • Make some nice helpers for this. (LayoutCell<T: AtomicRepr> where we know T can be represented as an atomic. This can also panic in debug mode when we have some kinds of races)

  • Inline layout should be a separate crate (pilcrow).

    • Rest of Rust community can be able to use it.

    • Goes well with font-kit.

    • Similar to Pango or Apple Core Text, but able to handle CSS floats in their full generality.

  • Start out with just parallelizing text shaping and block formatting context layout. That might be enough.

    • Initial goal: Lay out sidebar and main content in parallel.

Timeline

  • The inline layout library comes first.

Unknowns

  • How should we parallelize frame construction? Should we parallelize frame construction?

  • Should we consider using Facebook's Yoga to quickly get flexbox off the ground? There are Rust bindings already.

Clone this wiki locally