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

Normalize gradient stops #1046

Merged
merged 4 commits into from Mar 31, 2017
Merged

Normalize gradient stops #1046

merged 4 commits into from Mar 31, 2017

Conversation

@eqrion
Copy link
Contributor

eqrion commented Mar 31, 2017

Gradients can be defined with stops outside the range of [0, 1].
When this happens the gradient needs to be normalized by adjusting
the gradient stops and gradient line into an equivalent gradient
with stops in the range [0, 1].

This allows for proper repeating behavior for gradients because the
range from [first_stop, last_stop] must be repeated, not the range
[0, 1]. This also allows for proper rendering of gradients with stops
beyond the range [0, 1] because the GradientData struct only works
for stops in the range [0, 1].

LinearGradients and RadialGradients are updated to be normalized by
default. The DisplayListBuilder method for RadialGradient is updated
to be simpler and more in line with the CSS representation of a
radial-gradient(). The old method is kept for possible SVG uses in the
future, and replay capabilities.


This change is Reviewable

eqrion added 4 commits Mar 29, 2017
Gradients can be defined with stops outside the range of [0, 1].
When this happens the gradient needs to be normalized by adjusting
the gradient stops and gradient line into an equivalent gradient
with stops in the range [0, 1].

This allows for proper repeating behavior for gradients because the
range from [first_stop, last_stop] must be repeated, not the range
[0, 1]. This also allows for proper rendering of gradients with stops
beyond the range [0, 1] because the GradientData struct only works
for stops in the range [0, 1].

LinearGradients and RadialGradients are updated to be normalized by
default. The DisplayListBuilder method for RadialGradient is updated
to be simpler and more in line with the CSS representation of a
radial-gradient(). The old method is kept for possible SVG uses in the
future, and replay capabilities.
The aligned gradient fast path doesn't correctly fill all of its display
item's rect if it's gradient line doesn't intersect the whole rect. This
is because extra geometry is not added to fill in that region. This can
be fixed, but for correctness now we should use the angle gradient
shader for these cases.
@eqrion
Copy link
Contributor Author

eqrion commented Mar 31, 2017

r? @kvark @glennw
I believe this needs a version bump because of the interface change for RadialGradient.

@eqrion
Copy link
Contributor Author

eqrion commented Mar 31, 2017

An example for repeating gradients,

root:
  items:
    - type: stacking-context
      bounds: 50 50 300 300
      items:
        - type: gradient
          bounds: 0 0 300 300
          start: 0 150
          end: 300 150
          stops: [0.1, blue, 0.2, blue, 0.2, red, 0.3, red]
          repeat: true

After,
linear-repeat-good
Before,
linear-repeat-bad
An example for clamped,

---
root:
  items:
    - type: stacking-context
      bounds: 50 50 300 300
      items:
        - type: radial-gradient
          bounds: 0 0 300 300
          center: 150 150
          radius: 150 150
          stops: [0.0, red,
                  0.1, red,
                  0.1, blue,
                  0.2, blue,
                  0.2, red,
                  0.3, red,
                  0.3, blue,
                  0.4, blue,
                  0.4, red,
                  0.5, red,
                  0.5, blue,
                  0.6, blue,
                  0.6, red,
                  0.7, red,
                  0.7, blue,
                  0.8, blue,
                  0.8, red,
                  0.9, red,
                  0.9, blue,
                  1.0, blue,
                  1.0, red,
                  1.1, red,
                  1.1, blue,
                  1.2, blue,
                  1.2, red,
                  1.3, red,
                  1.3, blue,
                  1.4, blue]

After,
radial-clamp-good
Before,
GradientEntries would only hold entries up to 1.0, and the rest would be clamped to blue.

@kvark
kvark approved these changes Mar 31, 2017
Copy link
Member

kvark left a comment

Looks good overall, just one question about the tests.

// of the gradient line to where stop[0] and the end of the gradient line
// to stop[n-1]. this function adjusts the stops in place, and returns
// the amount to adjust the gradient line start and stop
fn normalize_stops(stops: &mut Vec<GradientStop>,

This comment has been minimized.

@kvark

kvark Mar 31, 2017

Member

should use &mut [GradientStop] instead of Vec

This comment has been minimized.

@eqrion

eqrion Mar 31, 2017

Author Contributor

Yes, that is better. I will update with this.

This comment has been minimized.

@eqrion

eqrion Mar 31, 2017

Author Contributor

Ah, wait normalize_stops can in the bad case clear() and add() to the list. That's why it's a Vec.

This comment has been minimized.

@kvark

kvark Mar 31, 2017

Member

ah, right

// the amount to adjust the gradient line start and stop
fn normalize_stops(stops: &mut Vec<GradientStop>,
extend_mode: ExtendMode) -> (f32, f32) {
assert!(stops.len() >= 2);

This comment has been minimized.

@kvark

kvark Mar 31, 2017

Member

nit: will technically work for stops.len()==1 too, and will crash on first() on zero, so perhaps this assert can be removed?

This comment has been minimized.

@eqrion

eqrion Mar 31, 2017

Author Contributor

Yes, I suppose it could. The motivation was mostly because CSS gradients always have at least two stops so it's nice to enforce that. Not sure on SVG. Regardless, it's not really necessary.


# fuzzy because of differences from normalization
# this might be able to be improved
fuzzy(255,1200) == repeat-linear.yaml repeat-linear-ref.yaml

This comment has been minimized.

@kvark

kvark Mar 31, 2017

Member

Why using the difference of 255 here?

This comment has been minimized.

@eqrion

eqrion Mar 31, 2017

Author Contributor

Normalizing the stops for these tests is causing some differences in stop positions. You can see the results of running without fuzzing by pasting below into here. It is kind of significant, so I am unsure whether this is a problem or unavoidable. We are normalizing the stops with the same math that Gecko uses, if that helps.

REFTEST TEST-UNEXPECTED-FAIL | reftests/gradient/repeat-linear.yaml == reftests/gradient/repeat-linear-ref.yaml | image comparison, max difference: 255, number of differing pixels: 1200
REFTEST   IMAGE 1 (TEST): data:image/png;base64,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
REFTEST   IMAGE 2 (REFERENCE): data:image/png;base64,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Oq1lC60jY/m1+g1pz/QcT2p+T23Ing9IzKTSDkh62SbpI2MtW2gdGcuv1W9Ie6bneFLz2xfIY+kL5DqtZQutI2P5tfoNac/0HE9qfk9tyJ4PSMyk0g5Ietkm6SNjLVtoHRnLr9VvSHum53hS89sXyGPpC+Q6rWULrSNj+bX6DWnP9BxPan5PbcieD0jMpNIOSHrZJukjYy1baB0Zy6/Vb0h7pud4UvPbF8hj6QvkOq1lC60jY/m1+g1pz/QcT2p+T23Ing9IzKTSDkh62SbpI2MtW2gdGcuv1W9Ie6bneFLz2xfIY+kL5DqtZQutI2P5tfoNac/0HE9qfk9tyJ4PSMyk0g5Ietkm6SNjLVtoHRnLr9VvSHum53hS89sXyGPpC+Q6rWULrSNj+bX6DWnP9BxPan5PbcieD0jMpNIOSHrZJukjYy1baB0Zy6/Vb0h7pud4UvPbF8hj6QvkOq1lC60jY/m1+g1pz/QcT2p+T23Ing9IzKTSDkh62SbpI2MtW2gdGcuv1W9Ie6bneFLz2xfIY+kL5DqtZQutI2P5tfoNac/0HE9qfk9tyJ4PSMyk0g5Ietkm6SNjLVtoHRnLr9VvSHum53hS89sXyGPpC+Q6rWULrSNj+bX6DWnP9BxPan5PbcieD0jMpNIOSHrZJukjYy1baB0Zy6/Vb0h7pud4UvPbF8hj6QvkOq1lC60jY/m1+g1pz/QcT2p+T23Ing9IzKTSDkh62SbpI2MtW2gdGcuv1W9Ie6bneFLz2xfIY+kL5DqtZQutI2P5tfoNac/0HE9qfk9tyJ4PSMyk0g5Ietkm6SNjLVtoHRnLr9VvSHum53hS89sXyGPpC+Q6rWULrSNj+bX6DWnP9BxPan5PbcieD0jMpNIOSHrZJukjYy1baB0Zy6/Vb0h7pud4UvPbF8hj6QvkOq1lC60jY/m1+g1pz/QcT2p+T23Ing9IzKTSDkh62SbpI2MtW2gdGcuv1W9Ie6bneFLz2xfIY+kL5DqtZQutI2P5tfoNac/0HE9qfk9tyJ4PSMyk0g5Ietkm6SNjLVtoHRnLr9VvSHum53hS89sXyGPpC+Q6rWULrSNj+bX6DWnP9BxPan5PbcieD0jMpNIOSHrZJukjYy1baB0Zy6/Vb0h7pud4UvPbF8hj6QvkOq1lC60jY/m1+g1pz/QcT2p+T23Ing9IzKTSDkh6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
REFTEST TEST-END | reftests/gradient/repeat-linear.yaml == reftests/gradient/repeat-linear-ref.yaml

This comment has been minimized.

@kvark

kvark Mar 31, 2017

Member

If the new code path matches gecko, why don't we update the reftests to match it?

@kvark
Copy link
Member

kvark commented Mar 31, 2017

according to IRC discussion:

  • test "repeat-linear" failure is weird
  • need to investigate with regards to Gecko tests
  • unlikely to break Servo tests, since using non-normalized gradient stops didn't work before anyway
  • thus, should be safe to merge now, then follow-up

@bors-servo r+

@bors-servo
Copy link
Contributor

bors-servo commented Mar 31, 2017

📌 Commit 398db7c has been approved by kvark

@bors-servo
Copy link
Contributor

bors-servo commented Mar 31, 2017

Testing commit 398db7c with merge 6d5f80f...

bors-servo added a commit that referenced this pull request Mar 31, 2017
Normalize gradient stops

Gradients can be defined with stops outside the range of [0, 1].
When this happens the gradient needs to be normalized by adjusting
the gradient stops and gradient line into an equivalent gradient
with stops in the range [0, 1].

This allows for proper repeating behavior for gradients because the
range from [first_stop, last_stop] must be repeated, not the range
[0, 1]. This also allows for proper rendering of gradients with stops
beyond the range [0, 1] because the GradientData struct only works
for stops in the range [0, 1].

LinearGradients and RadialGradients are updated to be normalized by
default. The DisplayListBuilder method for RadialGradient is updated
to be simpler and more in line with the CSS representation of a
radial-gradient(). The old method is kept for possible SVG uses in the
future, and replay capabilities.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/webrender/1046)
<!-- Reviewable:end -->
@bors-servo
Copy link
Contributor

bors-servo commented Mar 31, 2017

☀️ Test successful - status-travis
Approved by: kvark
Pushing 6d5f80f to master...

@bors-servo bors-servo merged commit 398db7c into servo:master Mar 31, 2017
3 checks passed
3 checks passed
continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
homu Test successful
Details
@eqrion eqrion deleted the eqrion:gradients-2 branch Apr 6, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

3 participants
You can’t perform that action at this time.