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

Text clipping artifacts #286

Closed
Stumblinbear opened this issue Feb 28, 2023 · 4 comments · Fixed by #335
Closed

Text clipping artifacts #286

Stumblinbear opened this issue Feb 28, 2023 · 4 comments · Fixed by #335

Comments

@Stumblinbear
Copy link

Stumblinbear commented Feb 28, 2023

It seems as though text overflowing a clipping layer doesn't work properly. I've added the following to the animated_text test scene, around the second "Animated text!" element

const X0: f64 = 50.0;
const Y0: f64 = 450.0;
const X1: f64 = 200.0;
const Y1: f64 = 950.0;

let path = [
    PathEl::MoveTo((X0, Y0).into()),
    PathEl::LineTo((X1, Y0).into()),
    PathEl::LineTo((X1, Y0 + t * (Y1 - Y0)).into()),
    PathEl::LineTo((X1 + t * (X0 - X1), Y1).into()),
    PathEl::LineTo((X0, Y1).into()),
    PathEl::ClosePath,
];

sb.push_layer(Mix::Clip, 1.0, Affine::IDENTITY, &path);
{
    params.text.add(
        sb,
        None,
        text_size,
        None,
        Affine::translate((110.0, 700.0)),
        s,
    );
}
sb.pop_layer();

Which results in many vertical bars clipping the text, instead of the remaining text being clipped in its entirety:

image

@DJMcNab
Copy link
Member

DJMcNab commented Feb 28, 2023

I did a little bit of investigation. This (naturally) doesn't apply to only text, I made a path with 2 linetos which worked (although I couldn't reproduce with a rectangle). This also doesn't need the sub-fragment, just the path on its own worked.

And unsurprisingly, the new clipping boundary is a (16px by 16px) tile edge. It seems that the parts of the path in the left-most tile column affected by the path are still displayed. This seems likely to be an off-by-one error, I'm just not sure where.

@dfrg
Copy link
Collaborator

dfrg commented Mar 1, 2023

Nice! This was appearing in some Lottie animations but the scene complexity there made it difficult to track anything down. Narrowing this to a much smaller test case is exceptionally helpful.

DJMcNab added a commit to DJMcNab/vello that referenced this issue Mar 1, 2023
armansito added a commit to armansito/vello that referenced this issue Jun 29, 2023
When the bounding boxes of a path and its clip are disjoint (i.e. they
do not intersect) the result of their intersection is a negative
rectangle.

When calculating the intersection of the bboxes, the binning stage
ensures that the bbox is non-negative. It then normalizes the
coordinates to bin dimensions and rounds the top-left corner down
to the neareast integer and the bottom-right corner up.

However this rounding causes zero-area bounding boxes to have a non-zero
area and sends the bottom-right corner to the placed in the next bin.
This causes fully clipped out draw objects to be included in binning,
with an incorrect clip bounding box that causes them to be erroneously
drawn with partial clipping.

`binning` now takes care around this logic to make sure that a zero-area
intersected-bbox gets skipped and clipped out. `tile_alloc`, also takes
care in its logic.

Fixes linebender#286 and linebender#333
@armansito
Copy link
Collaborator

#335 fixes this bug. I added @Stumblinbear's repro code to a new test scene that demonstrates the problem and the fix.

armansito added a commit to armansito/vello that referenced this issue Jun 29, 2023
When the bounding boxes of a path and its clip are disjoint (i.e. they
do not intersect) the result of their intersection is a negative
rectangle.

When calculating the intersection of the bboxes, the binning stage
ensures that the bbox is non-negative. It then normalizes the
coordinates to bin dimensions and rounds the top-left corner down
to the neareast integer and the bottom-right corner up.

However this rounding causes zero-area bounding boxes to have a non-zero
area and sends the bottom-right corner to the placed in the next bin.
This causes fully clipped out draw objects to be included in binning,
with an incorrect clip bounding box that causes them to be erroneously
drawn with partial clipping.

`binning` now takes care around this logic to make sure that a zero-area
intersected-bbox gets skipped and clipped out. `tile_alloc`, also takes
care in its logic.

Fixes linebender#286 and linebender#333
@armansito
Copy link
Collaborator

Please re-open if you still see this issue on main.

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 a pull request may close this issue.

4 participants