pharo-graphics / Bloc

Low-level UI infrastructure & framework for Pharo
MIT License
81 stars 40 forks source link

[Bug] - wrong direction on BlLinearGradientPaint #270

Open Nyan11 opened 1 year ago

Nyan11 commented 1 year ago

Hello,

Description

I was trying to reproduce a gradient from a different software and i discover a strange behaviour. The direction seem to not be computed correctly when the gradient is almost vertical.

severity: High

Reproduction

First example (no bug)

We create a vertical gradient (by setting start and stop as vertical).

gradient := (BlLinearGradientPaint new) stops: { 0.0 -> Color red . 1.0 -> Color blue }.
start := 0.5 @ 0.
end := 0.5 @ 1.

gradient start: start; end: end.
back := BlBackground paint: gradient.
aBlElement := BlElement new background: back; size: 400 @ 200; yourself.
aBlElement openInNewSpace.

Output (image of a gradient : from red on the top to blue on the bottom):

image

second example (with the bug)

We create an almost vertical gradient (by setting start and stop as almost vertical).

gradient := (BlLinearGradientPaint new) stops: { 0.0 -> Color red . 1.0 -> Color blue }.
start := 0.5000001 @ 0. "here start x is realy close to end x"
end := 0.5 @ 1.

gradient start: start; end: end.
back := BlBackground paint: gradient.
aBlElement := BlElement new background: back; size: 400 @ 200; yourself.
aBlElement openInNewSpace.

Output (image of a gradient : from blue on the bottom/left to red on the top/right):

image

expected result:

The gradient should be in the same direction as the first example.

Possible fix

The bug seem to occure in the method BlLinearGradientPaint >> #matchExtent:. This method is called when the background is set to the BlElement. This method seem to transform the values start and end to fit the size of the BlElement.

When aDirection is neither 0@1 or 1@0, values of anEnd will always be equals to anExtent.

The problem seem to come from the calculation of aScaleX and aScaleY.

I'm not sure exactly what the method #matchExtent does so i cannot really fix it.

Other

pharo image : Pharo-11.0.0+build.692.sha.0c234f2f5a92b237dd22ef9429506e92e586c494 (64 Bit) bloc version : [8f3cb19] - 2023-06-22 22:34

tinchodias commented 1 year ago

Wow, the complexity of matchExtent: is notorious.

tinchodias commented 1 year ago

I think its intention is to follow the behavior in CSS:

image

Source: https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/linear-gradient

tinchodias commented 1 year ago

This should be rotating gradually:

https://github.com/pharo-graphics/Bloc/assets/3044265/eed5a2bc-3237-4459-841b-c91b227415dc

Code:

a := BlElement new
    size: 800 @ 500;
    yourself.

a forceLayout.
aSpace := BlSpace new.
aSpace
    addChild: a;
    extent: a size;
    show.

a addAnimation: 
    (BlNumberTransition new
            from: 0.0;
            to: Float twoPi;
            duration: 4 seconds;
            onStepDo: [ :t |
                | start end gradient |
                start := 0.5 asPoint.
                end := t cos @ t sin.
                gradient :=
                    BlLinearGradientPaint new
                        stops: {
                            0.0 -> Color red.
                            1.0 -> Color blue };
                        start: start;
                        end: end;
                        yourself.
                a background: gradient ];
            yourself).
tinchodias commented 1 year ago

The previous animation should smoothly rotate like:

https://github.com/pharo-graphics/Bloc/assets/3044265/330df98a-8356-4872-9ea8-b497e87c5c1f

Recorded from: https://codepen.io/t_afif/pen/jOVZywJ

(Apparently in CSS3 only recently the angle can be animated: https://dev.to/afif/we-can-finally-animate-css-gradient-kdk )

tinchodias commented 1 year ago

Maybe #274 is not so draft, opinions are welcome.

tinchodias commented 1 year ago

@Nyan11 with #274, the BUG snippet now renders as:

BlElement-322971392

tinchodias commented 1 year ago

@Nyan11 I think about changing the API:

opinion?

tinchodias commented 1 year ago

I realize current Bloc API is similar to SVG way to specify a linear gradient.

tinchodias commented 1 year ago

I'm a bit blocked on how to fix this issue, but will arrive to something. Must take into account for a consistent fix: #273