DioxusLabs / DioxusLabs/taffy

Off by one pixel layout error (potentially due to rounding issue)

Open
#803 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Rust
Stars
3.6k
Forks
226
Avg merge
10h 41m
Merged PRs (30d)
40

Description

## `taffy` version

0.7.5

## Platform

Rust

## What you did

```rust
use taffy::prelude::*;
use taffy::util::print_tree;

fn main() {
let mut tree: TaffyTree<()> = TaffyTree::new();

let text = tree
.new_leaf(Style {
size: Size {
width: length(1.0),
height: length(1.0),
},
..Default::default()
})
.unwrap();

let flex_container = tree
.new_with_children(
Style {
justify_content: Some(JustifyContent::End),
border: Rect {
top: length(1.0),
left: length(1.0),
right: length(1.0),
bottom: length(1.0),
},
grid_row: Line {
start: line(1),
end: span(4),
},
grid_column: Line {
start: line(2),
end: span(1),
},
..Default::default()
},
&[text],
)
.unwrap();

let grid_container = tree
.new_with_children(
Style {
size: Size {
width: percent(1.0),
height: percent(1.0),
},
display: Display::Grid,
// 12 by 12 grid
grid_template_rows: vec![repeat(GridTrackRepetition::Count(12), vec![fr(1.0)])],
grid_template_columns: vec![repeat(GridTrackRepetition::Count(12), vec![fr(1.0)])],
..Default::default()
},
&[flex_container],
)
.unwrap();

tree.compute_layout(
grid_container,
Size {
width: AvailableSpace::Definite(127.0),
height: AvailableSpace::Definite(29.0),
},
)
.unwrap();

print_tree(&tree, grid_container);
}
```

## What went wrong

The above layout print this:

```
TREE
└── GRID [x: 0 y: 0 w: 127 h: 29 content_w: 21 content_h: 10 border: l:0 r:0 t:0 b:0, padding: l:0 r:0 t:0 b:0] (NodeId(4294967299))
└── FLEX ROW [x: 11 y: 0 w: 10 h: 10 content_w: 9 content_h: 2 border: l:1 r:1 t:1 b:1, padding: l:0 r:0 t:0 b:0] (NodeId(4294967298))
└── LEAF [x: 9 y: 1 w: 1 h: 1 content_w: 0 content_h: 0 border: l:0 r:0 t:0 b:0, padding: l:0 r:0 t:0 b:0] (NodeId(4294967297))
```

Notice the leaf node, the parent width is 10 with border of 1. The leaf node is aligned at the right edge (justify content = end) of the parent. It should be 8, instead of 9. It produces a layout like this (`-` means empty pixel):

```
-----------┌────────┐---------------------------------------------------------------------------------------------------------
-----------│--------A---------------------------------------------------------------------------------------------------------
-----------│--------│----------------------------------------------------------------------------------------------------------
-----------│--------│----------------------------------------------------------------------------------------------------------
-----------│--------│----------------------------------------------------------------------------------------------------------
-----------│--------│----------------------------------------------------------------------------------------------------------
-----------│--------│----------------------------------------------------------------------------------------------------------
-----------│--------│----------------------------------------------------------------------------------------------------------
-----------│--------│----------------------------------------------------------------------------------------------------------
-----------└────────┘----------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------
```

The letter A is the position of the leaf node. As you can see, it is overlapping with the border.

## Additional information

### Context

I'm building a terminal UI application and using taffy as the layout engine. Due to the nature of terminal UI, off by one pixel errors are very noticeable.

### My theory

Since it doesn't happen consistently, only on some specific viewport sizes, I suspect it is caused by rounding errors. Maybe [these lines](https://github.com/DioxusLabs/taffy/blob/HEAD/src/compute/mod.rs#L216-L217) 🤔 ?

In here, the relative location of a child node is always rounded. **It doesn't take into consideration how the parent size changes due to rounding**. In my example, the parent node is shrink by 1 (from 11 to 10) after rounding, but the child node still round up. The situation is reversed if the parent grow by 1, it will create a gap of 1 pixel between the child and the parent border.

I attempted to fix it my making the child aware of how the parent's size changes. Each time we perform rounding for a child node, we pass a scale factor: how much the parent node have grow/shrink:
```
scale = layout.size.width / unrounded_layout.size.width
```

The child location (x, y) will be scale up according to the scale factor:
```
layout.location.x = round(unrounded_layout.location.x * scale_factor.width)
layout.location.y = round(unrounded_layout.location.y * scale_factor.height)
```

It did fix my cases but broke a lot of tests.

Contributor guide

Open the contributing guide

Research direction

Reproduce the 127×29 layout from the issue, then inspect src/compute/mod.rs around lines 216–217 where child positions are rounded. Compare the rounded parent and child layouts across viewport sizes, and use the existing layout tests to check any change. Done means the leaf no longer overlaps the parent border without breaking the existing test suite.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.