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

Support interpolation between currentcolor and numeric color #17219

Merged
merged 10 commits into from Jun 8, 2017

Unify specified Color type between Stylo and Servo.

  • Loading branch information
upsuper committed Jun 8, 2017
commit d0d170767dbd871839a4cdcdf5271c8fb8c5332c
@@ -4,7 +4,6 @@

//! Element nodes.

use cssparser::Color;
use devtools_traits::AttrInfo;
use dom::activation::Activatable;
use dom::attr::{Attr, AttrHelpersForLayout};
@@ -112,7 +111,7 @@ use style::stylearc::Arc;
use style::stylist::ApplicableDeclarationBlock;
use style::thread_state;
use style::values::{CSSFloat, Either};
use style::values::specified::{self, CSSColor};
use style::values::specified::{self, CSSColor, Color};
use stylesheet_loader::StylesheetOwner;

// TODO: Update focus state when the top-level browsing context gains or loses system focus,
@@ -7,34 +7,38 @@
use cssparser::{self, Color as CSSParserColor, Parser, RGBA, Token};
use itoa;
use parser::{ParserContext, Parse};
#[cfg(feature = "gecko")]
use properties::longhands::color::SystemColor;
use std::fmt;
use std::io::Write;
use style_traits::ToCss;
use super::AllowQuirks;
use values::computed::{Context, ToComputedValue};

#[cfg(not(feature = "gecko"))] pub use self::servo::Color;
#[cfg(feature = "gecko")] pub use self::gecko::Color;

#[cfg(not(feature = "gecko"))]
mod servo {
pub use cssparser::Color;
use cssparser::Parser;
use parser::{Parse, ParserContext};
/// Specified color value
#[derive(Clone, Copy, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Color {
/// The 'currentColor' keyword
CurrentColor,
/// A specific RGBA color
RGBA(RGBA),

impl Parse for Color {
fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
Color::parse(input)
}
}
/// A system color
#[cfg(feature = "gecko")]
System(SystemColor),
/// A special color keyword value used in Gecko
#[cfg(feature = "gecko")]
Special(gecko::SpecialColorKeyword),
/// Quirksmode-only rule for inheriting color from the body
#[cfg(feature = "gecko")]
InheritFromBodyQuirk,
}

no_viewport_percentage!(Color);

#[cfg(feature = "gecko")]
mod gecko {
use cssparser::{Color as CSSParserColor, Parser, RGBA};
use parser::{Parse, ParserContext};
use properties::longhands::color::SystemColor;
use std::fmt;
use style_traits::ToCss;

define_css_keyword_enum! { SpecialColorKeyword:
@@ -44,59 +48,53 @@ mod gecko {
"-moz-activehyperlinktext" => MozActiveHyperlinktext,
"-moz-visitedhyperlinktext" => MozVisitedHyperlinktext,
}
}

/// Color value including non-standard -moz prefixed values.
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Color {
/// The 'currentColor' keyword
CurrentColor,
/// A specific RGBA color
RGBA(RGBA),
/// A system color
System(SystemColor),
/// A special color keyword value used in Gecko
Special(SpecialColorKeyword),
/// Quirksmode-only rule for inheriting color from the body
InheritFromBodyQuirk,
impl From<CSSParserColor> for Color {
fn from(value: CSSParserColor) -> Self {
match value {
CSSParserColor::CurrentColor => Color::CurrentColor,
CSSParserColor::RGBA(x) => Color::RGBA(x),
}
}
}

no_viewport_percentage!(Color);

impl From<CSSParserColor> for Color {
fn from(value: CSSParserColor) -> Self {
match value {
CSSParserColor::CurrentColor => Color::CurrentColor,
CSSParserColor::RGBA(x) => Color::RGBA(x),
}
}
impl From<RGBA> for Color {
fn from(value: RGBA) -> Self {
Color::RGBA(value)
}
}

impl Parse for Color {
fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
if let Ok(value) = input.try(CSSParserColor::parse) {
Ok(value.into())
} else if let Ok(system) = input.try(SystemColor::parse) {
Ok(Color::System(system))
} else if let Ok(special) = input.try(SpecialColorKeyword::parse) {
Ok(Color::Special(special))
} else {
impl Parse for Color {
fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
if let Ok(value) = input.try(CSSParserColor::parse) {
Ok(value.into())
} else {
#[cfg(feature = "gecko")] {
if let Ok(system) = input.try(SystemColor::parse) {
Ok(Color::System(system))
} else {
gecko::SpecialColorKeyword::parse(input).map(Color::Special)
}
}
#[cfg(not(feature = "gecko"))] {
Err(())
}
}
}
}

impl ToCss for Color {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
// Standard values:
Color::CurrentColor => CSSParserColor::CurrentColor.to_css(dest),
Color::RGBA(rgba) => rgba.to_css(dest),
Color::System(system) => system.to_css(dest),

// Non-standard values:
Color::Special(special) => special.to_css(dest),
Color::InheritFromBodyQuirk => Ok(()),
}
impl ToCss for Color {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
match *self {
Color::CurrentColor => CSSParserColor::CurrentColor.to_css(dest),
Color::RGBA(rgba) => rgba.to_css(dest),
#[cfg(feature = "gecko")]
Color::System(system) => system.to_css(dest),
#[cfg(feature = "gecko")]
Color::Special(special) => special.to_css(dest),
#[cfg(feature = "gecko")]
Color::InheritFromBodyQuirk => Ok(()),
}
}
}
@@ -245,25 +243,18 @@ impl CSSColor {
impl ToComputedValue for Color {
type ComputedValue = RGBA;

#[cfg(not(feature = "gecko"))]
fn to_computed_value(&self, context: &Context) -> RGBA {
match *self {
Color::RGBA(rgba) => rgba,
Color::CurrentColor => context.inherited_style.get_color().clone_color(),
}
}

#[cfg(feature = "gecko")]
fn to_computed_value(&self, context: &Context) -> RGBA {
#[cfg(feature = "gecko")]
use gecko::values::convert_nscolor_to_rgba as to_rgba;
// It's safe to access the nsPresContext immutably during style computation.
let pres_context = unsafe { &*context.device.pres_context };
match *self {
Color::RGBA(rgba) => rgba,
Color::System(system) => to_rgba(system.to_computed_value(context)),
Color::CurrentColor => context.inherited_style.get_color().clone_color(),
#[cfg(feature = "gecko")]
Color::System(system) => to_rgba(system.to_computed_value(context)),
#[cfg(feature = "gecko")]
Color::Special(special) => {
use self::gecko::SpecialColorKeyword as Keyword;
let pres_context = unsafe { &*context.device.pres_context };
to_rgba(match special {
Keyword::MozDefaultColor => pres_context.mDefaultColor,
Keyword::MozDefaultBackgroundColor => pres_context.mBackgroundColor,
@@ -272,10 +263,12 @@ impl ToComputedValue for Color {
Keyword::MozVisitedHyperlinktext => pres_context.mVisitedLinkColor,
})
}
#[cfg(feature = "gecko")]
Color::InheritFromBodyQuirk => {
use dom::TElement;
use gecko::wrapper::GeckoElement;
use gecko_bindings::bindings::Gecko_GetBody;
let pres_context = unsafe { &*context.device.pres_context };
let body = unsafe {
Gecko_GetBody(pres_context)
};
@@ -301,20 +294,14 @@ impl ToComputedValue for Color {
impl ToComputedValue for CSSColor {
type ComputedValue = CSSParserColor;

#[cfg(not(feature = "gecko"))]
#[inline]
fn to_computed_value(&self, _context: &Context) -> CSSParserColor {
self.parsed
}

#[cfg(feature = "gecko")]
#[inline]
fn to_computed_value(&self, context: &Context) -> CSSParserColor {
match self.parsed {
Color::RGBA(rgba) => CSSParserColor::RGBA(rgba),
Color::CurrentColor => CSSParserColor::CurrentColor,
// Resolve non-standard -moz keywords to RGBA:
non_standard => CSSParserColor::RGBA(non_standard.to_computed_value(context)),
#[cfg(feature = "gecko")]
non_standard => CSSParserColor::RGBA(non_standard.to_computed_value(_context)),
}
}

@@ -2,10 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cssparser::{Color, RGBA};
use cssparser::RGBA;
use parsing::parse;
use style::values::{Auto, Either};
use style::values::specified::CSSColor;
use style::values::specified::{CSSColor, Color};
use style_traits::ToCss;

#[test]
@@ -5,11 +5,11 @@
use properties::parse;
use style::computed_values::display::T::inline_block;
use style::properties::{PropertyDeclaration, Importance, PropertyId};
use style::properties::longhands::outline_color::computed_value::T as ComputedColor;
use style::properties::parse_property_declaration_list;
use style::values::{RGBA, Auto};
use style::values::CustomIdent;
use style::values::specified::{BorderStyle, BorderSideWidth, CSSColor, Length, LengthOrPercentage};
use style::values::specified::{BorderStyle, BorderSideWidth, CSSColor};
use style::values::specified::{Length, LengthOrPercentage};
use style::values::specified::{LengthOrPercentageOrAuto, LengthOrPercentageOrAutoOrContent};
use style::values::specified::{NoCalcLength, PositionComponent};
use style::values::specified::position::Y;
@@ -111,7 +111,7 @@ mod shorthand_serialization {
let line = TextDecorationLine::OVERLINE;
let style = TextDecorationStyle::dotted;
let color = CSSColor {
parsed: ComputedColor::RGBA(RGBA::new(128, 0, 128, 255)),
parsed: RGBA::new(128, 0, 128, 255).into(),
authored: None
};

@@ -230,7 +230,7 @@ mod shorthand_serialization {
properties.push(PropertyDeclaration::BorderLeftWidth(px_10.clone()));

let blue = CSSColor {
parsed: ComputedColor::RGBA(RGBA::new(0, 0, 255, 255)),
parsed: RGBA::new(0, 0, 255, 255).into(),
authored: None
};

@@ -263,7 +263,7 @@ mod shorthand_serialization {
properties.push(PropertyDeclaration::BorderLeftWidth(px_30.clone()));

let blue = CSSColor {
parsed: ComputedColor::RGBA(RGBA::new(0, 0, 255, 255)),
parsed: RGBA::new(0, 0, 255, 255).into(),
authored: None
};

@@ -333,12 +333,12 @@ mod shorthand_serialization {
let mut properties = Vec::new();

let red = CSSColor {
parsed: ComputedColor::RGBA(RGBA::new(255, 0, 0, 255)),
parsed: RGBA::new(255, 0, 0, 255).into(),
authored: None
};

let blue = CSSColor {
parsed: ComputedColor::RGBA(RGBA::new(0, 0, 255, 255)),
parsed: RGBA::new(0, 0, 255, 255).into(),
authored: None
};

@@ -406,7 +406,7 @@ mod shorthand_serialization {
let width = BorderSideWidth::Length(Length::from_px(4f32));
let style = BorderStyle::solid;
let color = CSSColor {
parsed: ComputedColor::RGBA(RGBA::new(255, 0, 0, 255)),
parsed: RGBA::new(255, 0, 0, 255).into(),
authored: None
};

@@ -533,7 +533,7 @@ mod shorthand_serialization {
let width = BorderSideWidth::Length(Length::from_px(4f32));
let style = Either::Second(BorderStyle::solid);
let color = CSSColor {
parsed: ComputedColor::RGBA(RGBA::new(255, 0, 0, 255)),
parsed: RGBA::new(255, 0, 0, 255).into(),
authored: None
};

@@ -552,7 +552,7 @@ mod shorthand_serialization {
let width = BorderSideWidth::Length(Length::from_px(4f32));
let style = Either::First(Auto);
let color = CSSColor {
parsed: ComputedColor::RGBA(RGBA::new(255, 0, 0, 255)),
parsed: RGBA::new(255, 0, 0, 255).into(),
authored: None
};
properties.push(PropertyDeclaration::OutlineWidth(width));
@@ -160,7 +160,7 @@ fn test_parse_stylesheet() {
(PropertyDeclaration::BackgroundColor(
longhands::background_color::SpecifiedValue {
authored: Some("blue".to_owned().into_boxed_str()),
parsed: cssparser::Color::RGBA(cssparser::RGBA::new(0, 0, 255, 255)),
parsed: cssparser::RGBA::new(0, 0, 255, 255).into(),
}
),
Importance::Normal),
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.