linebender / druid

A data-first Rust-native UI design toolkit.
https://linebender.org/druid/
Apache License 2.0
9.53k stars 569 forks source link

Glitches with rounded rectangles #764

Open jneem opened 4 years ago

jneem commented 4 years ago

I'm getting drawing glitches when drawing very large rounded rectangles, possibly caused by overflow somewhere. I'm not sure whether it's reasonable to expect such large rectangles to work at all, but given that widget layout happily works with infinite bounds, I think it isn't completely unreasonable. This is with gtk on linux.

Here is my attempt to draw a rounded rectangle with infinite width: infinite

Here is my attempt to draw a rounded rectangle with width 1e7: 1e7

And now with width 1e6, it works: 1e6

Sample code is here, and you can change the width on line 13 of main.rs. The clipping on line 37 actually makes no difference.

raphlinus commented 4 years ago

Given that this is on Linux, it's almost certainly an issue with Cairo, not with druid or piet. I would say it's probably not reasonable to expect drawing commands to work with infinite dimensions, though 1e7 feels like it should be within the representation range (I haven't researched why it's having trouble).

jneem commented 4 years ago

Thanks for the pointer, I'll try to narrow it down when I have a minute.

futurepaul commented 4 years ago

Just for a little clarity on infinity: an infinite box constraint is legal, but nothing should return an infinite "size" in our layout system. we're working to track these down and find a good way to warn / eliminate them: https://github.com/xi-editor/druid/issues/685

rsk700 commented 3 years ago

I've faced similar issue with very long lines, here is my code and screenshot (expected result on the left and if I use very long lines on the right)

use druid::kurbo::Line;
use druid::{widget::prelude::*, Point};
use druid::{AppLauncher, Color, PlatformError, Widget, WindowDesc};

struct CustomWidget;

impl Widget<()> for CustomWidget {
    fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut (), env: &Env) {}
    fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &(), env: &Env) {}
    fn update(&mut self, ctx: &mut UpdateCtx, old_data: &(), data: &(), env: &Env) {}
    fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, data: &(), env: &Env) -> Size {
        bc.max()
    }
    fn paint(&mut self, ctx: &mut PaintCtx, data: &(), env: &Env) {
        let bg_color = Color::rgb8(29, 29, 29);
        let line1_color = Color::rgb8(100, 0, 0);
        let line2_color = Color::rgb8(0, 100, 0);
        let rect = ctx.size().to_rect();
        ctx.fill(rect, &bg_color);
        let line1 = Line::new(Point::new(120., 100.), Point::new(300000., 300.));
        ctx.stroke(line1, &line1_color, 6.);
        let line2 = Line::new(Point::new(100., 50.), Point::new(11634286., 300.));
        ctx.stroke(line2, &line2_color, 6.);
    }
}

fn main() -> Result<(), PlatformError> {
    let window = WindowDesc::new(|| CustomWidget {});
    AppLauncher::with_window(window).launch(())
}

druidbug

Environment:

cmyr commented 3 years ago

@rsk700 is the code you provided for the left or right case?

rsk700 commented 3 years ago

@cmyr my code is for screenshot at the right (which is demonstrates issue)

cmyr commented 3 years ago

Okay, on macOS it gives me results that look like the left (with less slope)

rsk700 commented 3 years ago

to clarify, in my case two screenshots produced by exact same code with only this lines changed

this code for right screenshot

        let line1 = Line::new(Point::new(120., 100.), Point::new(300000., 300.));
        ctx.stroke(line1, &line1_color, 6.);
        let line2 = Line::new(Point::new(100., 50.), Point::new(11634286., 300.));

this for left

       let line1 = Line::new(Point::new(120., 100.), Point::new(30000., 300.));
       ctx.stroke(line1, &line1_color, 6.);
       let line2 = Line::new(Point::new(100., 50.), Point::new(11634., 300.));

I change only end point of Line