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

[css-images-4] Color stop fixup: do interpolation hints function as positioned color stops? #3931

Open
danburzo opened this issue May 14, 2019 · 12 comments
Assignees

Comments

@danburzo
Copy link

danburzo commented May 14, 2019

I'm looking at adding support for color stop positions and interpolation hints to a color library I've been working on, and it's not clear for me from the spec: when fixing up color stops, and we spread color stops missing a position position evenly between the color stops which have one:

  1. If any color stop still does not have a position, then, for each run of adjacent color stops without positions, set their positions so that they are evenly spaced between the preceding and following color stops with positions.

...do the color hints count as color stops in step 3 of the process?

Here's my library's interpretation (top) vs. browser interpretation (bottom) of the following gradient:

linear-gradient(to right, blue, red, 50%, green)

Screenshot 2019-05-14 at 15 32 28

Is it normal that by introducing a color hint between red and green, the position of red shifts from 0.5 to 0.25? My mental model for the process resembled Photoshop's behavior, where moving the midpoints between two stops would not alter the position of the stops.

Screenshot 2019-05-14 at 15 46 37

@danburzo
Copy link
Author

danburzo commented May 15, 2019

A couple of other observations from the field:

1. Boundary cases for logarithm function:

I've made a quick notebook to explore how the interpolation hint's position affects the interpolation curve. For H = 0 and H = 1 the logarithm gives weird results and there might need to be some adjustments to the formula to cover it. This seems to work as expected:

const C = (P, H) => 
  H === 0 ? 1 : 
  H === 1 ? 0 : 
  Math.pow(P, Math.log(0.5) / Math.log(H));

i.e. for H = 0, paint completely with next color stop, and for H = 1 paint completely with previous color stop. (Also note that Photoshop limits H to the [0.05, 0.95] interval to avoid the extreme curves.)

2. Interpolation hint fixup example

The example below seems to suggest that there's a step 4 (possibly computation of midpoint color?), and suggests the midpoint is split into two linear gradients, which I don't think is the case anymore. (I'm also curious if that was the case in a previous iteration of the spec.)

8. linear-gradient(red, 25%, white)
   =14=>
   linear-gradient(red 0%, rgb(100%,50%,50%) 25%, white 100%) 

@danburzo danburzo changed the title [css-images-4] Do color interpolation hints take up a slot? [css-images-4] Color stop fixup: do interpolation hints function as positioned color stops? May 15, 2019
@danburzo
Copy link
Author

danburzo commented May 15, 2019

One last thing: as I was writing this comment, I realized that with this hypothetical midpoint function (and with the possible addition of easing functions in the syntax), browsers can still support their current understanding of color stop position computation (which I think is incorrect), and have a decoupled midpoint function going forward.

Update: I tried to build a stronger case for the midpoint easing function in #3935

@AmeliaBR
Copy link
Contributor

I agree that this needs to be defined more explicitly.

Given that existing implementations seem to agree, and their behavior isn't illogical, I think the spec should match implementations: color hint positions should be factored in equally with color stop positions when distributing stops without explicit positions.

It is unfortunate that this makes it difficult to expand to a generalized easing function approach, but I think your suggestion in #3935 is a good way to get around that.

@cabanier
Copy link
Member

i.e. for H = 0, paint completely with next color stop, and for H = 1 paint completely with previous color stop. (Also note that Photoshop limits H to the [0.05, 0.95] interval to avoid the extreme curves.)

FYI all implementations in browsers of the color hint move H to be in that color range

@danburzo
Copy link
Author

Ah, good to know! Also, if I interpreted the code & comments correctly, browsers will approximate the logarithm by a series of nine evenly-distributed color stops — six on the longer interval, and two on the shorter one, possibly to compensate for Skia missing a native way to render eased gradients (?)

@cabanier
Copy link
Member

Yes, I believe I used up to 9 color stops. Most of the time, it would be less.
That is an implementation detail.
The platform libraries didn't support this idiom, so I approximated it.

Ideally, the drawing libraries are extended so they actually draw the exponential ramp

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Color stop fixup: do interpolation hints function as positioned color stops?, and agreed to the following:

  • RESOLVED: Make spec match browsers on color hints / positions
The full IRC log of that discussion <AmeliaBR> Topic: Color stop fixup: do interpolation hints function as positioned color stops?
<AmeliaBR> github: https://github.com//issues/3931
<fantasai> AmeliaBR: This issue brought up with someone trying to implement gradients with color-hint syntax
<fantasai> AmeliaBR: His interpretation wasn't matching what browsers do
<fantasai> AmeliaBR: Issue is to clarify algorithm in spec to match what browsers do
<fantasai> AmeliaBR: All the browsers, or at least majority, all do the same thing
<fantasai> AmeliaBR: This has to do with color stops
<fantasai> AmeliaBR: color-stop consists of color and position
<fantasai> AmeliaBR: position can be implicit
<fantasai> AmeliaBR: evenly divide between known positions
<fantasai> AmeliaBR: color hints are different htough
<fantasai> AmeliaBR: color hints affect ???
<fantasai> AmeliaBR: Pave the cowpath / match reality request
<fantasai> TabAtkins: While I find the behavior is slightly weird
<fantasai> TabAtkins: but would have agreed with issue author initially
<fantasai> TabAtkins: Since everyone agrees, let's just spec that
<AmeliaBR> s/???/the allocation of implicit stop positions/
<fantasai> florian: Curious about what's weird about it, but if we have interop, doesn't really matter
<fantasai> TabAtkins: Weird because hint isn't a color stop, it is just a hint about how to interpret colors between
<fantasai> TabAtkins: So find it odd that it would affect positions, but eh.
<fantasai> AmeliaBR: Purpose was to adjust easing between adjacent stops
<fantasai> AmeliaBR: But because hint is expressed as a fixed position, there's interpetation that it's a position value
<fantasai> AmeliaBR: Same person that opened this opened another issue about other ways to talk about gradient easing
<fantasai> AmeliaBR: That's an interesting way of eventually creating a more logical approach in the future
<fantasai> AmeliaBR: while not conflicting with current browser implementations
<fantasai> AmeliaBR: so are interesting length issues if ppl want to follow up
<fantasai> florian: I'm sold
<fantasai> Rossen_: Anyone else?
<fantasai> Rossen_: Objections?
<fantasai> RESOLVED: Make spec match browsers on color hints / positions
<fantasai> AmeliaBR: One more point: editors are Tab, fantasai, Lea
<fantasai> AmeliaBR: Interested in making edits or should I draft up?
<fantasai> TabAtkins: I can do edits, but if you want to draft something happy to review/accept
<AmeliaBR> Scribenick: AmeliaBR

@cabanier
Copy link
Member

FWIW interpolation hints are specified as regular color stops in the spec. They just lack a color.
I'm unsure what needs to be changed in the spec.

@AmeliaBR
Copy link
Contributor

FWIW interpolation hints are specified as regular color stops in the spec.

I'm not sure how you read it that way? Color hints and color stops are defined as separate syntax elements. They need to be, to prohibit starting or ending on a hint. In step 2 of the algorithm there is a fix-up for positions that specifically applies to both hints and stops. But step 3 currently only applies to stops.

I'm also curious about your comment (#3931 (comment)) about adjusting the hint to be within a reasonable range. There should probably be some informative text in the spec about that, even if we don't stipulate the exact bounds normatively.

@danburzo
Copy link
Author

With the disclaimer that I have no insight to the history of the feature and the iterations the implementations, and the spec, went through:

I can relate to the "interpolation hints are regular color stops" angle if we assume that:

  • an interpolation hint is meant to be the position between colors A and B of a computed average color (A + B) / 2, i.e. a midpoint H.
  • with the available graphics engines, the transition between A and B through H can be at least two linear gradients (A→H, H→B), acceptably a series of linear gradients that approximate the log function, and ideally the log function implemented at the graphics engine level.

However, solely by reading the current spec and proposed algorithm of color stop positioning, I did not get that impression at all and was surprised when comparing with browser implementations.

@cabanier
Copy link
Member

an interpolation hint is meant to be the position between colors A and B of a computed average color (A + B) / 2, i.e. a midpoint H.

That is correct and the spec clearly spells this out.

with the available graphics engines, the transition between A and B through H can be at least two linear gradients (A→H, H→B), acceptably a series of linear gradients that approximate the log function, and ideally the log function implemented at the graphics engine level.

If the hint is in the middle, it's only a single linear gradient.
The approximation is an implementation detail. The spec doesn't need to call this out.

@cabanier
Copy link
Member

I'm not sure how you read it that way? Color hints and color stops are defined as separate syntax elements. They need to be, to prohibit starting or ending on a hint. In step 2 of the algorithm there is a fix-up for positions that specifically applies to both hints and stops.

Browser run the fix-up step on the position of the stops without looking if they are hints or regular color stops.

But step 3 currently only applies to stops.

I think that's because all hints should be normalized after step 2 so there's no need to call them out.

I'm also curious about your comment (#3931 (comment)) about adjusting the hint to be within a reasonable range. There should probably be some informative text in the spec about that, even if we don't stipulate the exact bounds normatively.

Yes, the spec should call out that hints that are too close will be set back to 5%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants