Closed
Bug 1465307
Opened 7 years ago
Closed 6 years ago
Extend StyleComplexColor to support other blends besides linear interpolation.
Categories
(Core :: CSS Parsing and Computation, enhancement, P3)
Core
CSS Parsing and Computation
Tracking
()
RESOLVED
FIXED
mozilla62
Tracking | Status | |
---|---|---|
firefox62 | --- | fixed |
People
(Reporter: u480271, Assigned: u480271)
References
Details
Attachments
(4 files)
Bug 1457353 exposed a change in color computation that causes SMIL <animate from="rgb(10,20,30)" by="currentColor" ... /> to fail.
Updated•7 years ago
|
Priority: -- → P3
> ::: servo/components/style/values/animated/color.rs:105
> (Diff revision 2)
> > + Complex {
> > + color: RGBA,
> > + // ratios representing the contribution of color and
> > + // currentColor to the final color, where:
> > + // `(bgRatio, fgRatio) = self.ratios`.
> > + ratios: (f32, f32)
>
> Should we split this tuple into two different variables? Actually during
> reviewing this patch I don't see which one is for bg or fg.
I've replaced the tuple with a struct with named components. I hope this makes it clean which ratio is related to what color.
> ::: servo/components/style/values/animated/color.rs:230
> (Diff revision 2)
> > - self.foreground_ratio
> > - .compute_squared_distance(&other.foreground_ratio)?)
> > + self_ratios.0.compute_squared_distance(&other_ratios.0)? +
> > + self_ratios.1.compute_squared_distance(&other_ratios.1)?)
> > + },
>
> Oh, I didn't know that we calcurate foreground_ratio as if it's in the same
> distance space for color.
Because it's possible to have the same `color` and `foreground_ratio` but different `background_ratio` I extended it. The `foreground_ratio` addition was already in the code and I can't comment on whether this is valid or not.
> ::: layout/style/StyleComplexColor.h:66
> (Diff revision 2)
> > - bool IsNumericColor() const { return mForegroundRatio == 0; }
> > - bool IsCurrentColor() const { return mForegroundRatio == 255; }
> > + bool IsAuto() const { return mTag == eAuto; }
> > + bool IsCurrentColor() const { return mTag == eCurrent; }
> >
> > bool operator==(const StyleComplexColor& aOther) const {
> > - return mForegroundRatio == aOther.mForegroundRatio &&
> > - (IsCurrentColor() || mColor == aOther.mColor) &&
> > + if (mTag != aOther.mTag) {
> > + return false;
>
> Maybe assert in the case when one is complex and the other is numeric or foreground, and they don't happen to have equal value?
In discussion on IRC with :xidorn, decided to put assert into construction of `StyleComplexColor`s instead.
(In reply to Xidorn Quan [:xidorn] UTC+10 from comment #32)
> Comment on attachment 8980195 [details]
> Bug 1457353 - P3: Disable failing SMIL tests.
>
> https://reviewboard.mozilla.org/r/246350/#review253892
>
> ::: servo/components/style/values/animated/color.rs:97
> (Diff revision 2)
> > -pub struct Color {
> > - pub color: RGBA,
> > - pub foreground_ratio: f32,
> > +pub enum Color {
> > + Numeric { color: RGBA },
> > + Current,
> > + Complex {
> > + color: RGBA,
> > + // ratios representing the contribution of color and
> > + // currentColor to the final color, where:
> > + // `(bgRatio, fgRatio) = self.ratios`.
> > + ratios: (f32, f32)
> > + },
> > }
>
> Given you are bascially duplicating the enum in `animated` and `computed`,
> you should move this enum into `generics` mod and make it generic over
> `RGBA`, then alias it in the two mods. That would allow you to avoid lots of
> duplicates below as well.
>
> Actually, I'm suspecting that we probably should move `RGBA` into `generics`
> as well and make it generic over the field type.
I moved the `Color` enum into `generics` and removed and common code from `animated::Color` and `computed::Color`.
I didn't move `RGBA` because there's only one definition in this crate. The other `RGBA` comes from the separate `cssparser` crate.
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment 9•6 years ago
|
||
mozreview-review |
Comment on attachment 8983304 [details]
Bug 1465307 - P1: Extend StyleComplexColor to support additive blending.
https://reviewboard.mozilla.org/r/249204/#review255362
Looks good to me other than From trait for ComplexColorRatios. Thanks!
::: servo/components/style/values/animated/color.rs:170
(Diff revision 1)
> - foreground_ratio: self.foreground_ratio,
> - })
> - }
> - } else if self.is_currentcolor() && other.is_numeric() {
> - Ok(Color {
> - color: other.color,
> + color: c1.animate(&c2, procedure)?,
> + }),
> + // Combinations of numeric color and currentColor
> + (Color::Foreground, Color::Numeric { color }, _) => Ok(Color::Complex {
> + color: color.clone(),
> + ratios: (other_weight, this_weight).into(),
Unfortunately, using From trait here makes this tuple unclear, which one is for bg or fg. So we should directly use ComplexColorRatios { bg: xx, fg: xx }?
::: servo/components/style/values/computed/color.rs:30
(Diff revision 1)
> +impl From<(f32, f32)> for ComplexColorRatios {
> + fn from(x: (f32, f32)) -> Self {
> + ComplexColorRatios { bg: x.0, fg: x.1 }
> + }
> +}
>
> - /// The ratio of currentcolor in complex color.
> - pub foreground_ratio: u8,
> +impl From<(f64, f64)> for ComplexColorRatios {
> + fn from(x: (f64, f64)) -> Self {
> + ComplexColorRatios {
> + bg: x.0 as f32,
> + fg: x.1 as f32,
> + }
> + }
> +}
I think these Trait shouldn't be used.
Attachment #8983304 -
Flags: review?(hikezoe) → review+
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment 18•6 years ago
|
||
mozreview-review |
Comment on attachment 8983304 [details]
Bug 1465307 - P1: Extend StyleComplexColor to support additive blending.
https://reviewboard.mozilla.org/r/249204/#review255664
Alright, looks mostly fine. Some small issues below.
::: layout/style/StyleComplexColor.h:29
(Diff revision 3)
> - * the actual algorithm.
> *
> * It can also represent an "auto" value, which is valid for some
> - * properties. See comment of mIsAuto.
> + * properties. See comment of `Tag::eAuto`.
> */
> -struct StyleComplexColor
> +class StyleComplexColor
This can probably be marked `final`.
::: layout/style/StyleComplexColor.h:32
(Diff revision 3)
> - * properties. See comment of mIsAuto.
> + * properties. See comment of `Tag::eAuto`.
> */
> -struct StyleComplexColor
> +class StyleComplexColor
> {
> - nscolor mColor;
> - uint8_t mForegroundRatio;
> +public:
> + enum Tag : uint8_t {
It seems to me nothing related to `Tag` is exposed, so maybe you can have this enum private as well.
::: layout/style/StyleComplexColor.h:33
(Diff revision 3)
> */
> -struct StyleComplexColor
> +class StyleComplexColor
> {
> - nscolor mColor;
> - uint8_t mForegroundRatio;
> +public:
> + enum Tag : uint8_t {
> - // Whether the complex color represents a computed-value time auto
> + // Whether the complex color represents a computed-value time auto
Since it is no longer a flag, it probably makes more sense to remove "Whether" from this comment and below. Something like "This represents a ..." is probably enough.
::: layout/style/StyleComplexColor.h:106
(Diff revision 3)
> * the foreground color from aFrame's ComputedStyle.
> */
> nscolor CalcColor(const nsIFrame* aFrame) const;
> -};
>
> +protected:
For a final class (which cannot be inherited by anything), `protected` section doesn't make much sense. Please just move it to `private`.
::: servo/components/style/gecko_bindings/sugar/style_complex_color.rs:9
(Diff revision 3)
> +use gecko_bindings::structs::{StyleComplexColor_Tag_eAuto, StyleComplexColor_Tag_eComplex,
> + StyleComplexColor_Tag_eForeground, StyleComplexColor_Tag_eNumeric};
I think you can add `StyleComplexColor_Tag` into `rusty-enums` in `ServoBindings.toml`, then you can just do
```rust
use gecko_bindings::structs::StyleComplexColor_Tag as Tag;
```
here, and code below can be much simplified.
Maybe this would also avoid the warning you are working around below.
::: servo/components/style/gecko_bindings/sugar/style_complex_color.rs:52
(Diff revision 3)
> }
>
> impl From<ComputedColor> for StyleComplexColor {
> fn from(other: ComputedColor) -> Self {
> + match other {
> + ComputedColor::Numeric { color } => convert_rgba_to_nscolor(&color).into(),
Maybe it would be better to just `impl From<RGBA> for StyleComplexColor`.
::: servo/components/style/gecko_bindings/sugar/style_complex_color.rs:95
(Diff revision 3)
> + bg: other.mBgRatio,
> + fg: other.mFgRatio,
> + },
> + }
> + }
> + x => panic!("Unsupport StyleComplexColor with tag {}", x),
I would prefer `unreachable` in this case over `panic`.
Also with `StyleComplexColor_Tag` being a rusty enum, you should be able to explicitly list `Tag::eAuto` here instead.
::: servo/components/style/values/animated/color.rs:109
(Diff revision 3)
> - pub color: RGBA,
> - pub foreground_ratio: f32,
> + Numeric {
> + color: RGBA,
> + },
> + Foreground,
> + Complex {
> + color: RGBA,
> + ratios: ComplexColorRatios,
> + },
I guess you can remove the names here like:
```rust
pub enum Color {
Numeric(RGBA),
Foreground,
Complex(RGBA, ComplexColorRatios),
}
```
The types themselves should already be pretty clear what they are in this case, and thus the additional names don't seem to add much value.
::: servo/components/style/values/animated/color.rs:223
(Diff revision 3)
>
> impl ComputeSquaredDistance for Color {
> #[inline]
> fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
> // All comments from the Animate impl also applies here.
> - if self.foreground_ratio == other.foreground_ratio {
> + match (*self, *other) {
Since you are returning `Ok` everywhere, you can probably have it wrap the `match` expression at the top level.
It's not a big deal, so up to which way you would prefer.
::: servo/components/style/values/animated/color.rs:228
(Diff revision 3)
> - }
> - } else if self.is_currentcolor() && other.is_numeric() {
> - Ok(
> - RGBA::transparent().compute_squared_distance(&other.color)? +
> - SquaredDistance::from_sqrt(1.),
> - )
> + (Color::Foreground, Color::Numeric { color }) => Ok(RGBA::transparent()
> + .compute_squared_distance(&color)?
> + + SquaredDistance::from_sqrt(1.)),
> + (Color::Numeric { color }, Color::Foreground) => Ok(color
> + .compute_squared_distance(&RGBA::transparent())?
> + + SquaredDistance::from_sqrt(1.)),
These two branches can be merged together. `computed_squared_distance` should be symmetric.
::: servo/components/style/values/computed/color.rs:35
(Diff revision 3)
> + Numeric {
> + /// The color
> + color: RGBA,
> + },
> +
> + /// The current foreground color.
> + Foreground,
> +
> + /// A linear combination of numeric color and currentColor.
> + /// The formula is: `color * bg_ratio + currentColor * fg_ratio`.
> + Complex {
> + /// The background color
> + color: RGBA,
> + /// The ratios of background and foreground colors in color.
> + /// `(bg_ratio, fg_ratio) = ratios`
> + ratios: ComplexColorRatios,
> + },
As I mentioned above, just using tuples in this enum should be enough.
(I still don't get why you cannot move it into generics, but I guess there are reasons. I can probably try it myself afterwards and see why that's going to be a problem.)
::: servo/components/style/values/computed/color.rs:78
(Diff revision 3)
> - self.foreground_ratio == 0
> + match *self {
> + Color::Numeric { .. } => true,
> + _ => false,
> + }
`matches!(*self, Color::Numeric { .. })`
::: servo/components/style/values/computed/color.rs:86
(Diff revision 3)
> - self.foreground_ratio == u8::max_value()
> + match *self {
> + Color::Foreground => true,
> + _ => false,
> + }
`matches!(*self, Color::Foreground)`
::: servo/components/style/values/computed/color.rs:125
(Diff revision 3)
>
> let a = p1 * a1 + p2 * a2;
> - if a == 0.0 {
> + if a <= 0. {
> return RGBA::transparent();
> }
> + let a = if a > 1. { 1. } else { a };
Maybe `f32::min(a, 1.)`.
Attachment #8983304 -
Flags: review?(xidorn+moz) → review+
Comment 19•6 years ago
|
||
mozreview-review |
Comment on attachment 8983305 [details]
Bug 1465307 - P2: Fix nsStyleBorder::mBorderColor for GCC.
https://reviewboard.mozilla.org/r/249206/#review255672
Ideally this should be moved to the first patch so that all builds work even between the patches. But it's not a big deal.
Attachment #8983305 -
Flags: review?(xidorn+moz) → review+
Comment 20•6 years ago
|
||
mozreview-review-reply |
Comment on attachment 8983304 [details]
Bug 1465307 - P1: Extend StyleComplexColor to support additive blending.
https://reviewboard.mozilla.org/r/249204/#review255664
> As I mentioned above, just using tuples in this enum should be enough.
>
> (I still don't get why you cannot move it into generics, but I guess there are reasons. I can probably try it myself afterwards and see why that's going to be a problem.)
Oh, it seems you are moving `Color` to `generics` in a later patch.
Comment 21•6 years ago
|
||
mozreview-review |
Comment on attachment 8983306 [details]
Bug 1465307 - P3: Extract {animated,computed}::Color common parts.
https://reviewboard.mozilla.org/r/249208/#review255676
There are several issues in part 1 you may want to address first, and this has some issues as well, so canceling review for now.
::: servo/components/style/values/computed/color.rs:12
(Diff revision 3)
> use cssparser::{Color as CSSParserColor, RGBA};
> use std::fmt;
> use style_traits::{CssWriter, ToCss};
> use values::animated::ToAnimatedValue;
> -use values::animated::color::{Color as AnimatedColor, RGBA as AnimatedRGBA};
> -
> +use values::animated::color::RGBA as AnimatedRGBA;
> +use values::generics::color::{Color as GenericColor, Complex, Foreground, Numeric, Transparent};
You can do
```rust
use values::generics::color as generics;
```
then in the rest of places use `generics::Color`.
::: servo/components/style/values/generics/color.rs:9
(Diff revision 3)
> +/// A trait to obtain the value of the transparent color for a color representation.
> +pub trait Transparent {
> + /// Obtain the transparent color.
> + fn transparent() -> Self;
> +}
I don't think this is necessary.
It seems that it is only used in the `transparent` function below, not anything else.
I think you can just implement the `transparent` functions for the corresponding concrete color types, rather than adding a trait and having it in the generic type.
::: servo/components/style/values/generics/color.rs:32
(Diff revision 3)
> + pub const NUMERIC: ComplexColorRatios = ComplexColorRatios { bg: 1., fg: 0. };
> + /// Ratios representing the `Foreground` color.
> + pub const FOREGROUND: ComplexColorRatios = ComplexColorRatios { bg: 0., fg: 1. };
> +}
> +
> +pub use self::Color::*;
I don't think we general do this at top mod level.
Please avoid it.
::: servo/components/style/values/generics/color.rs:110
(Diff revision 3)
> +impl<T> ToAnimatedValue for Color<T>
> +where
> + T: ToAnimatedValue,
I don't see why you need to implement this manually. This seems pretty deriveable.
If it complains about `ComplexColorRatios`, I think you can derive `ToAnimatedValue` for that as well.
Attachment #8983306 -
Flags: review?(xidorn+moz)
Comment 22•6 years ago
|
||
mozreview-review |
Comment on attachment 8983307 [details]
Bug 1465307 - P4: Enable disabled dom/smil lighting_color tests.
https://reviewboard.mozilla.org/r/249210/#review255678
Attachment #8983307 -
Flags: review?(xidorn+moz) → review+
Assignee | ||
Comment 23•6 years ago
|
||
mozreview-review-reply |
Comment on attachment 8983304 [details]
Bug 1465307 - P1: Extend StyleComplexColor to support additive blending.
https://reviewboard.mozilla.org/r/249204/#review255664
> I think you can add `StyleComplexColor_Tag` into `rusty-enums` in `ServoBindings.toml`, then you can just do
> ```rust
> use gecko_bindings::structs::StyleComplexColor_Tag as Tag;
> ```
> here, and code below can be much simplified.
>
> Maybe this would also avoid the warning you are working around below.
Thanks. I didn't about that feature in ServoBindings.toml.
Assignee | ||
Comment 24•6 years ago
|
||
mozreview-review-reply |
Comment on attachment 8983304 [details]
Bug 1465307 - P1: Extend StyleComplexColor to support additive blending.
https://reviewboard.mozilla.org/r/249204/#review255664
> `matches!(*self, Color::Numeric { .. })`
Thanks. I didn't know about that macro.
Assignee | ||
Comment 25•6 years ago
|
||
mozreview-review-reply |
Comment on attachment 8983306 [details]
Bug 1465307 - P3: Extract {animated,computed}::Color common parts.
https://reviewboard.mozilla.org/r/249208/#review255676
> I don't think this is necessary.
>
> It seems that it is only used in the `transparent` function below, not anything else.
>
> I think you can just implement the `transparent` functions for the corresponding concrete color types, rather than adding a trait and having it in the generic type.
I added that when I started making RGBA generic and then forgot to remove when I abandoned that.
> I don't think we general do this at top mod level.
>
> Please avoid it.
I was trying to get around the weird behaviour of rust where the pattern matching refers to the generic type name:
```rust
impl From<ComputedColor> for StyleComplexColor {
fn from(other: ComputedColor) -> Self {
match other {
// Matching a ComputedColor but have to specify GenericColor
GenericColor::Numeric(color) => color.into(),
GenericColor::Foreground => Self::current_color(),
GenericColor::Complex(color, ratios) => {
...
}
}
}
}```
If I import the generic names using `use values::generics::color as generics`, as you suggest, it would become:
```rust
impl From<ComputedColor> for StyleComplexColor {
fn from(other: ComputedColor) -> Self {
match other {
// Matching a ComputedColor but have to specify generics::Color
generics::Color::Numeric(color) => color.into(),
generics::Color::Foreground => Self::current_color(),
generics::Color::Complex(color, ratios) => {
...
}
}
}
}```
which is gross.
Would you be okay with:
```rust
impl From<ComputedColor> for StyleComplexColor {
fn from(other: ComputedColor) -> Self {
use GenericColor::*;
match other {
Numeric(color) => color.into(),
Foreground => Self::current_color(),
Complex(color, ratios) => {
...
}
}
}
}```
Assignee | ||
Comment 26•6 years ago
|
||
mozreview-review-reply |
Comment on attachment 8983306 [details]
Bug 1465307 - P3: Extract {animated,computed}::Color common parts.
https://reviewboard.mozilla.org/r/249208/#review255676
> I was trying to get around the weird behaviour of rust where the pattern matching refers to the generic type name:
> ```rust
> impl From<ComputedColor> for StyleComplexColor {
> fn from(other: ComputedColor) -> Self {
> match other {
> // Matching a ComputedColor but have to specify GenericColor
> GenericColor::Numeric(color) => color.into(),
> GenericColor::Foreground => Self::current_color(),
> GenericColor::Complex(color, ratios) => {
> ...
> }
> }
> }
> }```
>
> If I import the generic names using `use values::generics::color as generics`, as you suggest, it would become:
> ```rust
> impl From<ComputedColor> for StyleComplexColor {
> fn from(other: ComputedColor) -> Self {
> match other {
> // Matching a ComputedColor but have to specify generics::Color
> generics::Color::Numeric(color) => color.into(),
> generics::Color::Foreground => Self::current_color(),
> generics::Color::Complex(color, ratios) => {
> ...
> }
> }
> }
> }```
>
> which is gross.
>
> Would you be okay with:
> ```rust
> impl From<ComputedColor> for StyleComplexColor {
> fn from(other: ComputedColor) -> Self {
> use GenericColor::*;
> match other {
> Numeric(color) => color.into(),
> Foreground => Self::current_color(),
> Complex(color, ratios) => {
> ...
> }
> }
> }
> }```
https://github.com/rust-lang/rust/issues/26264
Assignee | ||
Comment 27•6 years ago
|
||
mozreview-review-reply |
Comment on attachment 8983306 [details]
Bug 1465307 - P3: Extract {animated,computed}::Color common parts.
https://reviewboard.mozilla.org/r/249208/#review255676
> You can do
> ```rust
> use values::generics::color as generics;
> ```
> then in the rest of places use `generics::Color`.
Decided not to do this as you'll see in the adjustments due to other comments.
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment 32•6 years ago
|
||
mozreview-review |
Comment on attachment 8983306 [details]
Bug 1465307 - P3: Extract {animated,computed}::Color common parts.
https://reviewboard.mozilla.org/r/249208/#review256030
::: servo/components/style/values/animated/color.rs:105
(Diff revision 4)
>
> Ok(ComplexColorRatios { bg, fg })
> }
> }
>
> #[allow(missing_docs)]
It'd better have a document here. It can just be something like
```
/// An animated value for `<color>`
```
::: servo/components/style/values/computed/color.rs:20
(Diff revision 4)
> -impl Color {
> - /// Returns a numeric color representing the given RGBA value.
> +/// This enum represents a combined color from a numeric color and
> +/// the current foreground color (currentcolor keyword).
This is no longer an enum, just an alias now. Probably something like
```
/// A computed value for `<color>`
```
would be good enough.
Attachment #8983306 -
Flags: review?(xidorn+moz) → review+
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment hidden (mozreview-request) |
Comment 39•6 years ago
|
||
Pushed by dglastonbury@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/76d098691ed0
P1: Extend StyleComplexColor to support additive blending. r=hiro,xidorn
https://hg.mozilla.org/integration/autoland/rev/31c82145a8e7
P2: Fix nsStyleBorder::mBorderColor for GCC. r=xidorn
https://hg.mozilla.org/integration/autoland/rev/85784a996d8b
P3: Extract {animated,computed}::Color common parts. r=xidorn
https://hg.mozilla.org/integration/autoland/rev/b34fa4440625
P4: Enable disabled dom/smil lighting_color tests. r=xidorn
Comment 40•6 years ago
|
||
bugherder |
https://hg.mozilla.org/mozilla-central/rev/76d098691ed0
https://hg.mozilla.org/mozilla-central/rev/31c82145a8e7
https://hg.mozilla.org/mozilla-central/rev/85784a996d8b
https://hg.mozilla.org/mozilla-central/rev/b34fa4440625
Status: NEW → RESOLVED
Closed: 6 years ago
status-firefox62:
--- → fixed
Resolution: --- → FIXED
Target Milestone: --- → mozilla62
You need to log in
before you can comment on or make changes to this bug.
Description
•